### Eclipse Workspace Patch 1.0
#P Ametys - Plugin ODF Sync
Index: main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/AbstractCDMFrManager.java
===================================================================
--- main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/AbstractCDMFrManager.java	(revision 16258)
+++ main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/AbstractCDMFrManager.java	(working copy)
@@ -15,6 +15,8 @@
  */
 package org.ametys.plugins.odfsync.cdmfr;
 
+import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -28,12 +30,13 @@
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
-import org.apache.excalibur.source.SourceResolver;
+import org.apache.cocoon.ProcessingException;
 import org.apache.excalibur.xml.dom.DOMParser;
 import org.apache.excalibur.xml.xpath.XPathProcessor;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
 
 import org.ametys.cms.observation.Event;
 import org.ametys.cms.observation.ObservationConstants;
@@ -60,9 +63,11 @@
 import org.ametys.odf.program.SubProgramFactory;
 import org.ametys.odf.workflow.CreateODFContentFunction;
 import org.ametys.plugins.odfsync.SynchronizationReport;
+import org.ametys.plugins.odfsync.cdmfr.transformers.CDMFrSyncTransformer;
 import org.ametys.plugins.repository.AmetysObject;
 import org.ametys.plugins.repository.AmetysObjectIterable;
 import org.ametys.plugins.repository.AmetysObjectResolver;
+import org.ametys.plugins.repository.AmetysRepositoryException;
 import org.ametys.plugins.repository.TraversableAmetysObject;
 import org.ametys.plugins.repository.query.QueryHelper;
 import org.ametys.plugins.repository.query.expression.AndExpression;
@@ -70,8 +75,10 @@
 import org.ametys.plugins.repository.query.expression.Expression.Operator;
 import org.ametys.plugins.repository.version.VersionableAmetysObject;
 import org.ametys.plugins.workflow.Workflow;
+import org.ametys.runtime.config.Config;
 import org.ametys.runtime.user.CurrentUserProvider;
 
+import com.opensymphony.workflow.InvalidActionException;
 import com.opensymphony.workflow.WorkflowException;
 import com.opensymphony.workflow.spi.Step;
 
@@ -90,15 +97,12 @@
     protected OdfConstantsProvider _provider;
     /** The DOM parser. */
     protected DOMParser _domParser;
-    /** Ametys object resolver. */
-    protected SourceResolver _sourceResolver;
     /** Observer manager. */
     protected ObservationManager _observerManager;
     /** Current user provider */
     protected CurrentUserProvider _currentUserProvider;
-    
-    /** XSL file path. */
-    protected String _xslFile;
+    /** Current user provider */
+    protected CDMFrSyncExtensionPoint _cdmFrSyncExtensionPoint;
     
     /** Workflow name for program */
     protected String _programWorkflowName;
@@ -117,17 +121,14 @@
         _xPathProcessor = (XPathProcessor) manager.lookup(XPathProcessor.ROLE);
         _provider = (OdfConstantsProvider) manager.lookup(OdfConstantsProvider.ROLE);
         _domParser = (DOMParser) manager.lookup(DOMParser.ROLE);
-        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
         _observerManager = (ObservationManager) manager.lookup(ObservationManager.ROLE);
         _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE);
-        
+        _cdmFrSyncExtensionPoint = (CDMFrSyncExtensionPoint) manager.lookup(CDMFrSyncExtensionPoint.ROLE);
     }
     
     @Override
     public void configure(Configuration configuration) throws ConfigurationException
     {
-        _xslFile = configuration.getChild("xsl-transform").getValue(null);
-        
         _programWorkflowName = configuration.getChild("program-workflow-name").getValue(null);
         _courseWorkflowName = configuration.getChild("course-workflow-name").getValue(null);
         _orgUnitWorkflowName = configuration.getChild("orgunit-workflow-name").getValue(null);
@@ -140,6 +141,25 @@
      */
     protected abstract Logger getLogger ();
     
+    protected void validateContent (SynchronizableContent content, String contentName, SynchronizationReport report) throws AmetysRepositoryException, WorkflowException
+    {
+        Map<String, Object> inputs = new HashMap<String, Object>();
+        inputs.put(AbstractContentWorkflowComponent.RESULT_MAP_KEY, new HashMap<String, Object>());
+        inputs.put(AbstractContentWorkflowComponent.CONTENT_KEY, content);
+        
+        try
+        {
+            _workflow.doAction(content.getWorkflowId(), 999, inputs);
+            report.info("La formation " + contentName + " a automatiquement été validée.");
+        }
+        catch (InvalidActionException e)
+        {
+            String msg = "La formation " + contentName + " n'a pas pu être validée.";
+            getLogger().warn(msg, e);
+            report.warn(msg);
+        }
+    }
+    
     /**
      * Synchronize content 
      * @param doc The root document
@@ -771,4 +791,32 @@
         String actionId = "8" + currentStepId + "0";
         _workflow.doAction(content.getWorkflowId(), Integer.valueOf(actionId), inputs);
     }
+    
+    /**
+     * Transform the document depending of it structure.
+     * @param document Document to transform.
+     * @param report Report for errors.
+     * @return The transformed document.
+     * @throws IOException
+     * @throws ProcessingException 
+     */
+    protected Document transformDocument (Document document, SynchronizationReport report) throws IOException, SAXException, ProcessingException
+    {
+        CDMFrSyncTransformer transformer = _cdmFrSyncExtensionPoint.getTransformer(document);
+        if (transformer == null)
+        {
+            String msg = "Aucun transformer CDM-fr ne correspond à cette structure.";
+            report.error(msg);
+            getLogger().error(msg);
+            return null;
+        }
+        
+        return transformer.transform(document);
+    }
+
+    protected File getCDMFrDirectory ()
+    {
+        String dirPath = Config.getInstance().getValueAsString("odf.cdmfr.search.repository");
+        return new File(dirPath);
+    }
 }
Index: main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMFrImportManager.java
===================================================================
--- main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMFrImportManager.java	(revision 16258)
+++ main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMFrImportManager.java	(working copy)
@@ -23,13 +23,12 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.avalon.framework.logger.Logger;
+import org.apache.cocoon.ProcessingException;
 import org.apache.commons.io.IOUtils;
-import org.apache.excalibur.source.Source;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -53,7 +52,6 @@
 import org.ametys.plugins.odfsync.cdmfr.item.CDMFrFileRemoteItem;
 import org.ametys.plugins.odfsync.cdmfr.searchitem.CDMFrFileSearchRemoteItem;
 import org.ametys.plugins.repository.AmetysRepositoryException;
-import org.ametys.runtime.config.Config;
 import org.ametys.runtime.util.LoggerFactory;
 import org.ametys.runtime.util.parameter.ParameterHelper;
 import org.ametys.runtime.util.parameter.ParameterHelper.ParameterType;
@@ -116,57 +114,54 @@
     {
         List<Program> importedPrograms = new ArrayList<Program>();
         
-        InputStream is = null;
         try
         {
-            // Parsing
-            HashMap<String, Object> parameters = new HashMap<String, Object>();
-            parameters.put("source", stream);
-            parameters.put("xslFile", _xslFile);
-            Source src = _sourceResolver.resolveURI("cocoon://_plugins/odf-sync/cdmfr/import/file", null, parameters);
-
             // XML to Content
-            is = src.getInputStream();
-            Document doc = _domParser.parseDocument(new InputSource(is));
+            Document doc = _domParser.parseDocument(new InputSource(stream));
+            doc = transformDocument(doc, report);
 
-            // Import programs
-            report.info("Import des formations ...");
-            
-            NodeList nodes = doc.getElementsByTagName("program");
-            
-            for (int i = 0; i < nodes.getLength(); i++)
+            if (doc != null)
             {
-                Node contentNode = nodes.item(i);
-                // String cdmId = contentNode.getAttributes().getNamedItem("CDMid").getTextContent();
-                String contentName = _xPathProcessor.evaluateAsString(contentNode, "code");
+                // Import programs
+                report.info("Import des formations ...");
                 
-                SynchronizableContent content = getContent(ProgramFactory.PROGRAM_CONTENT_TYPE, "code", contentName);
-                if (content == null)
+                NodeList nodes = doc.getElementsByTagName("program");
+                
+                for (int i = 0; i < nodes.getLength(); i++)
                 {
-                    try
+                    Node contentNode = nodes.item(i);
+                    // String cdmId = contentNode.getAttributes().getNamedItem("CDMid").getTextContent();
+                    String contentName = _xPathProcessor.evaluateAsString(contentNode, "code");
+                    
+                    SynchronizableContent content = getContent(ProgramFactory.PROGRAM_CONTENT_TYPE, "code", contentName);
+                    if (content == null)
                     {
-                        // Create program
-                        String contentTitle = _xPathProcessor.evaluateAsString(contentNode, "title");
-                        report.info("Création de la formation " + contentName);
-                        String contentId = createContent(ProgramFactory.PROGRAM_CONTENT_TYPE, contentName, contentTitle, _programWorkflowName, 1, null);
-                        content = _resolver.resolveById(contentId);
-                        synchronizeContent(doc, content, contentNode, report, true);
-                        
-                        importedPrograms.add((Program) content);
+                        try
+                        {
+                            // Create program
+                            String contentTitle = _xPathProcessor.evaluateAsString(contentNode, "title");
+                            report.info("Création de la formation " + contentName);
+                            String contentId = createContent(ProgramFactory.PROGRAM_CONTENT_TYPE, contentName, contentTitle, _programWorkflowName, 1, null);
+                            content = _resolver.resolveById(contentId);
+                            synchronizeContent(doc, content, contentNode, report, true);
+                            validateContent(content, contentName, report);
+                            
+                            importedPrograms.add((Program) content);
+                        }
+                        catch (WorkflowException e) 
+                        {
+                            report.error("Une erreur est survenue lors de la création du contenu " + contentName, e);
+                        }
                     }
-                    catch (WorkflowException e) 
+                    else
                     {
-                        report.error("Une erreur est survenue lors de la création du contenu " + contentName, e);
+                        synchronizeContent(doc, content, contentNode, report, true);
+                        report.info("La formation " + contentName + " existe déjà, elle ne sera pas recrée");
                     }
                 }
-                else
-                {
-                    synchronizeContent(doc, content, contentNode, report, true);
-                    report.info("La formation " + contentName + " existe déjà, elle ne sera pas recrée");
-                }
+                
+                report.info(importedPrograms.size() + " formation(s) ont été importées");
             }
-            
-            report.info(importedPrograms.size() + " formation(s) ont été importées");
         }
         catch (IOException e)
         {
@@ -176,9 +171,9 @@
         {
             throw new AmetysRepositoryException("A problem occured while parsing the input stream.", e);
         }
-        finally
+        catch (ProcessingException e)
         {
-            IOUtils.closeQuietly(is);
+            throw new AmetysRepositoryException("A problem occured while transforming the document.", e);
         }
         
         return importedPrograms;
@@ -193,8 +188,7 @@
         
         FileFilter filter = new CDMFRFileFilter(fileName, lastModifiedAfter, lastModifiedBefore);
         
-        String path = Config.getInstance().getValueAsString("odf.cdmfr.search.repository");
-        File repository = new File(path);
+        File repository = getCDMFrDirectory();
 
         List<CDMFrFileSearchRemoteItem> items = new ArrayList<CDMFrFileSearchRemoteItem>();
         
@@ -221,9 +215,8 @@
         Date lastModifiedBefore = (Date) ParameterHelper.castValue(params.get("lastModifiedBefore"), ParameterType.DATE);
         
         FileFilter filter = new CDMFRFileFilter(fileName, lastModifiedAfter, lastModifiedBefore);
-        
-        String path = Config.getInstance().getValueAsString("odf.cdmfr.search.repository");
-        File repository = new File(path);
+
+        File repository = getCDMFrDirectory();
 
         File[] cdmfrFiles = repository.listFiles(filter);
         if (cdmfrFiles != null && cdmfrFiles.length > 0)
#P Ametys - Template ODFWEB
Index: webapp/cms/WEB-INF/param/workflow-program.xml
===================================================================
--- webapp/cms/WEB-INF/param/workflow-program.xml	(revision 16250)
+++ webapp/cms/WEB-INF/param/workflow-program.xml	(working copy)
@@ -78,6 +78,9 @@
 					<condition type="avalon">
 						<arg name="role">org.ametys.cms.workflow.LockCondition</arg>
 					</condition>
+					<condition type="avalon">
+						<arg name="role">org.ametys.odf.workflow.MandatoryProgramMetadataCondition</arg>
+					</condition>
 				</conditions>
 			</restrict-to>
 			<pre-functions>
Index: webapp/cms/WEB-INF/param/workflow-program-publication.xml
===================================================================
--- webapp/cms/WEB-INF/param/workflow-program-publication.xml	(revision 16250)
+++ webapp/cms/WEB-INF/param/workflow-program-publication.xml	(working copy)
@@ -73,6 +73,9 @@
 					<condition type="avalon">
 						<arg name="role">org.ametys.cms.workflow.LockCondition</arg>
 					</condition>
+					<condition type="avalon">
+						<arg name="role">org.ametys.odf.workflow.MandatoryProgramMetadataCondition</arg>
+					</condition>
 				</conditions>
 			</restrict-to>
 			<pre-functions>