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 36748) +++ main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/AbstractCDMFrManager.java (working copy) @@ -69,14 +69,17 @@ import org.ametys.odf.courselist.CourseList.ChoiceType; import org.ametys.odf.courselist.CourseListContainer; import org.ametys.odf.enumeration.OdfEnumerationHelper; +import org.ametys.odf.observation.OdfObservationConstants; import org.ametys.odf.orgunit.OrgUnit; import org.ametys.odf.orgunit.OrgUnitFactory; import org.ametys.odf.orgunit.RootOrgUnitProvider; import org.ametys.odf.person.Person; import org.ametys.odf.person.PersonFactory; +import org.ametys.odf.program.AbstractProgram; import org.ametys.odf.program.Container; import org.ametys.odf.program.ContainerFactory; import org.ametys.odf.program.Program; +import org.ametys.odf.program.ProgramPart; import org.ametys.odf.program.SubProgram; import org.ametys.odf.program.SubProgramFactory; import org.ametys.odf.translation.ContentCopyHelper; @@ -206,10 +209,11 @@ * @param report The report for logs * @param logger The logger * @param importMode true if it is import mode + * @param programLanguage Parent program language (to select the good courses in the CDM-FR file) * @return true if changes were made * @throws WorkflowException */ - protected boolean synchronizeContent (Document doc, SynchronizableContent content, Node contentNode, SynchronizationReport report, Logger logger, boolean importMode) throws WorkflowException + protected boolean synchronizeContent (Document doc, SynchronizableContent content, Node contentNode, SynchronizationReport report, Logger logger, boolean importMode, String programLanguage) throws WorkflowException { _synchronizedContents.add(content.getId()); @@ -236,7 +240,7 @@ SynchronizableContent subProgram = getOrCreateSubProgram (metadataNode, (TraversableAmetysObject) content, content.getLanguage(), report, logger); if (subProgram != null) { - hasChanges = synchronizeContent(doc, subProgram, metadataNode, report, logger, importMode) || hasChanges; + hasChanges = synchronizeContent(doc, subProgram, metadataNode, report, logger, importMode, programLanguage) || hasChanges; } remoteChildCodes.add(_xPathProcessor.evaluateAsString(metadataNode, "code")); @@ -246,20 +250,26 @@ SynchronizableContent container = getOrCreateContainer (metadataNode, (TraversableAmetysObject) content, content.getLanguage(), report, logger); if (container != null) { - hasChanges = synchronizeContent(doc, container, metadataNode, report, logger, importMode) || hasChanges; + hasChanges = synchronizeContent(doc, container, metadataNode, report, logger, importMode, programLanguage) || hasChanges; } remoteChildCodes.add(_xPathProcessor.evaluateAsString(metadataNode, "code")); } else { - hasChanges = synchronizeMetadata (doc, content, metadataNode, report, logger, importMode) || hasChanges; + hasChanges = synchronizeMetadata (doc, content, metadataNode, report, logger, importMode, programLanguage) || hasChanges; } } // Remove local subprograms and/or containers not present in remote CDM-fr if source prevails hasChanges = _removeOldChildContentIfNecessary(content, remoteChildCodes, report, logger) || hasChanges; + // Create translation links + if (content instanceof ProgramPart || content instanceof Course) + { + linkTranslationsIfExist(content); + } + // Synchronize translated contents synchronizeTranslations(content, report, logger); @@ -357,25 +367,26 @@ * @param report The report for logs * @param logger The logger * @param importMode true if it is import mode + * @param programLanguage Parent program language (to select the good courses in the CDM-FR file) * @return true if changes were made * @throws WorkflowException */ - protected boolean synchronizeMetadata (Document doc, SynchronizableContent content, Node metadataNode, SynchronizationReport report, Logger logger, boolean importMode) throws WorkflowException + protected boolean synchronizeMetadata (Document doc, SynchronizableContent content, Node metadataNode, SynchronizationReport report, Logger logger, boolean importMode, String programLanguage) throws WorkflowException { boolean hasChanges = false; String metadataName = metadataNode.getLocalName(); - String type = metadataNode.getAttributes().getNamedItem("type").getTextContent(); + String type = metadataNode.getAttributes().getNamedItem("type").getTextContent().trim(); Node multipleItem = metadataNode.getAttributes().getNamedItem("multiple"); - boolean isMultiple = multipleItem != null && "true".equals(multipleItem.getTextContent()); + boolean isMultiple = multipleItem != null && "true".equals(multipleItem.getTextContent().trim()); if (isMultiple) { - hasChanges = synchronizeMultipleMetadata (doc, content, type, metadataName, metadataNode, report, logger, importMode) || hasChanges; + hasChanges = synchronizeMultipleMetadata (doc, content, type, metadataName, metadataNode, report, logger, importMode, programLanguage) || hasChanges; } else { - hasChanges = synchronizeSingleMetadata(doc, content, type, metadataName, metadataNode, importMode, report, logger) || hasChanges; + hasChanges = synchronizeSingleMetadata(doc, content, type, metadataName, metadataNode, importMode, programLanguage, report, logger) || hasChanges; } return hasChanges; } @@ -390,10 +401,11 @@ * @param report The report for logs * @param logger The logger * @param importMode true if it is import mode + * @param programLanguage Parent program language (to select the good courses in the CDM-FR file) * @return true if changes were made * @throws WorkflowException */ - protected boolean synchronizeMultipleMetadata (Document doc, SynchronizableContent content, String type, String metadataName, Node metadataNode, SynchronizationReport report, Logger logger, boolean importMode) throws WorkflowException + protected boolean synchronizeMultipleMetadata (Document doc, SynchronizableContent content, String type, String metadataName, Node metadataNode, SynchronizationReport report, Logger logger, boolean importMode, String programLanguage) throws WorkflowException { boolean hasChanges = false; @@ -409,7 +421,7 @@ NodeList itemNodes = metadataNode.getChildNodes(); for (int j = 0; j < itemNodes.getLength(); j++) { - String cdmCode = itemNodes.item(j).getTextContent(); + String cdmCode = itemNodes.item(j).getTextContent().trim(); Node personNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "person[@CDMid ='" + cdmCode + "']"); if (personNode != null) { @@ -430,7 +442,7 @@ report.info(infoMsg); logger.info(infoMsg); - if (synchronizeContent(doc, personContent, personNode, report, logger, personImportMode)) + if (synchronizeContent(doc, personContent, personNode, report, logger, personImportMode, programLanguage)) { applyChanges(personContent, report, logger); } @@ -485,7 +497,7 @@ NodeList itemNodes = metadataNode.getChildNodes(); for (int j = 0; j < itemNodes.getLength(); j++) { - String cdmCode = itemNodes.item(j).getTextContent(); + String cdmCode = itemNodes.item(j).getTextContent().trim(); Node ouNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "orgunit[@CDMid ='" + cdmCode + "']"); if (ouNode != null) { @@ -506,7 +518,7 @@ report.info(infoMsg); logger.info(infoMsg); - if (synchronizeContent(doc, ouContent, ouNode, report, logger, ouImportMode)) + if (synchronizeContent(doc, ouContent, ouNode, report, logger, ouImportMode, programLanguage)) { applyChanges(ouContent, report, logger); } @@ -565,12 +577,13 @@ * @param name The metadata name * @param metadataNode The DOM node * @param importMode true if it is import mode + * @param programLanguage Parent program language (to select the good courses in the CDM-FR file) * @param report the report for logs * @param logger The logger * @return true if changes were made * @throws WorkflowException */ - protected boolean synchronizeSingleMetadata(Document doc, SynchronizableContent content, String type, String name, Node metadataNode, boolean importMode, SynchronizationReport report, Logger logger) throws WorkflowException + protected boolean synchronizeSingleMetadata(Document doc, SynchronizableContent content, String type, String name, Node metadataNode, boolean importMode, String programLanguage, SynchronizationReport report, Logger logger) throws WorkflowException { if (type.equals(CDMFRConstant.IMPORT_TYPE_STRING)) { @@ -606,7 +619,7 @@ } else if (type.equals(CDMFRConstant.IMPORT_TYPE_COURSE_LIST)) { - return synchronizeCourseListContainer (doc, metadataNode, (CourseListContainer) content, report, logger, importMode); + return synchronizeCourseListContainer (doc, metadataNode, (CourseListContainer) content, report, logger, importMode, programLanguage); } else { @@ -638,7 +651,7 @@ for (int j = 0; j < metadataNodes.getLength(); j++) { Node metadataNode = metadataNodes.item(j); - metadatas.put(metadataNode.getLocalName(), metadataNode.getTextContent()); + metadatas.put(metadataNode.getLocalName(), metadataNode.getTextContent().trim()); } remoteLM.add(new LOMSheet(metadatas.get(Course.LOM_SHEET_URL), metadatas.get(Course.LOM_SHEET_LABEL))); } @@ -732,26 +745,27 @@ * @param report the report for logs * @param logger The logger * @param importMode true if it is import mode + * @param programLanguage Parent program language (to select the good courses in the CDM-FR file) * @return true if changes were made * @throws WorkflowException */ - protected boolean synchronizeCourseListContainer(Document doc, Node clNode, CourseListContainer container, SynchronizationReport report, Logger logger, boolean importMode) throws WorkflowException + protected boolean synchronizeCourseListContainer(Document doc, Node clNode, CourseListContainer container, SynchronizationReport report, Logger logger, boolean importMode, String programLanguage) throws WorkflowException { boolean hasChanges = false; - String clName = clNode.getAttributes().getNamedItem("name").getTextContent(); + String clName = clNode.getAttributes().getNamedItem("name").getTextContent().trim(); if (StringUtils.isEmpty(clName)) { clName = "Liste d'éléments pédagogiques"; } - String clCode = clNode.getAttributes().getNamedItem("code") != null ? clNode.getAttributes().getNamedItem("code").getTextContent() : null; + String clCode = clNode.getAttributes().getNamedItem("code") != null ? clNode.getAttributes().getNamedItem("code").getTextContent().trim() : null; if (StringUtils.isEmpty(clCode)) { clCode = org.ametys.runtime.util.StringUtils.generateKey(); } - String clType = clNode.getAttributes().getNamedItem("choiceType") != null ? clNode.getAttributes().getNamedItem("choiceType").getTextContent() : null; - String clEcts = clNode.getAttributes().getNamedItem("ects") != null ? clNode.getAttributes().getNamedItem("ects").getTextContent() : null; + String clType = clNode.getAttributes().getNamedItem("choiceType") != null ? clNode.getAttributes().getNamedItem("choiceType").getTextContent().trim() : null; + String clEcts = clNode.getAttributes().getNamedItem("ects") != null ? clNode.getAttributes().getNamedItem("ects").getTextContent().trim() : null; @SuppressWarnings("null") ChoiceType choiceType = StringUtils.isNotEmpty(clType) ? ChoiceType.valueOf(clType.toUpperCase()) : ChoiceType.MANDATORY; @@ -811,8 +825,8 @@ localCourseList.synchronizeMetadata(CourseList.MIN_COURSES, true); } - String min = clNode.getAttributes().getNamedItem("min").getTextContent(); - String max = clNode.getAttributes().getNamedItem("max").getTextContent(); + String min = clNode.getAttributes().getNamedItem("min").getTextContent().trim(); + String max = clNode.getAttributes().getNamedItem("max").getTextContent().trim(); if (Integer.parseInt(min) != localCourseList.getMinNumberOfCourses()) { @@ -854,8 +868,8 @@ if (choiceType.equals(ChoiceType.CHOICE)) { - String min = clNode.getAttributes().getNamedItem("min").getTextContent(); - String max = clNode.getAttributes().getNamedItem("max").getTextContent(); + String min = clNode.getAttributes().getNamedItem("min").getTextContent().trim(); + String max = clNode.getAttributes().getNamedItem("max").getTextContent().trim(); if (Integer.parseInt(min) != localCourseList.getMinNumberOfCourses()) { @@ -871,7 +885,7 @@ } // Update courses - hasChanges = synchronizeCourseList(doc, clNode, localCourseList, report, logger, importMode) || hasChanges; + hasChanges = synchronizeCourseList(doc, clNode, localCourseList, report, logger, importMode, programLanguage) || hasChanges; return hasChanges; } @@ -898,10 +912,11 @@ * @param report the report for logs * @param logger The logger * @param importMode true if it is import mode + * @param programLanguage Parent program language (to select the good courses in the CDM-FR file) * @return true if changes were made * @throws WorkflowException */ - protected boolean synchronizeCourseList(Document doc, Node clNode, CourseList courseList, SynchronizationReport report, Logger logger, boolean importMode) throws WorkflowException + protected boolean synchronizeCourseList(Document doc, Node clNode, CourseList courseList, SynchronizationReport report, Logger logger, boolean importMode, String programLanguage) throws WorkflowException { boolean hasChanges = false; @@ -913,13 +928,24 @@ NodeList itemNodes = clNode.getChildNodes(); for (int j = 0; j < itemNodes.getLength(); j++) { - String cdmCode = itemNodes.item(j).getTextContent(); - Node courseNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "course[@CDMid ='" + cdmCode + "']"); + String cdmCode = itemNodes.item(j).getTextContent().trim(); + Node courseNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "course[@CDMid = '" + cdmCode + "' and @language = '" + programLanguage + "']"); + if (courseNode == null) + { + courseNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "course[@CDMid = '" + cdmCode + "']"); + } + if (courseNode != null) { String elpCode = _xPathProcessor.evaluateAsString(courseNode, "elpCode"); - remoteCourses.put(elpCode, courseNode); - orderedCourseLists.add(elpCode); + String elpLang = _xPathProcessor.evaluateAsString(courseNode, "@language"); + if (StringUtils.isEmpty(elpLang)) + { + elpLang = programLanguage; + } + String elpKey = elpCode + "#" + elpLang; + remoteCourses.put(elpKey, courseNode); + orderedCourseLists.add(elpKey); } } @@ -927,7 +953,7 @@ for (String courseId : currentCourses) { Course course = _resolver.resolveById(courseId); - String code = course.getElpCode(); + String code = course.getElpCode() + "#" + course.getLanguage(); if (remoteCourses.containsKey(code)) { @@ -937,8 +963,8 @@ String infoMsg = "Synchronisation de l'ELP \"" + course.getTitle() + " (" + course.getCdmCode() + ")\""; report.info(infoMsg); logger.info(infoMsg); - - if (synchronizeContent(doc, course, remoteCourses.get(code), report, logger, importMode)) + + if (synchronizeContent(doc, course, remoteCourses.get(code), report, logger, importMode, programLanguage)) { applyChanges(course, report, logger); } @@ -975,7 +1001,7 @@ } } } - + String lang = _xPathProcessor.evaluateAsString(doc, "language"); if (StringUtils.isEmpty(lang)) { @@ -983,13 +1009,15 @@ } // Iterate on new course to import - for (String elpCode : remoteCourses.keySet()) + for (String elpKey : remoteCourses.keySet()) { + String elpLang = elpKey.split("#")[1]; + boolean courseImportMode = false; - Course course = getLocalCourseIfExists(remoteCourses.get(elpCode), lang, report, logger); + Course course = getLocalCourseIfExists(remoteCourses.get(elpKey), elpLang, report, logger); if (course == null) { - course = createCourse(remoteCourses.get(elpCode), lang, report, logger); + course = createCourse(remoteCourses.get(elpKey), elpLang, report, logger); courseImportMode = true; } else @@ -1005,7 +1033,7 @@ report.info(infoMsg); logger.info(infoMsg); - synchronizeContent(doc, course, remoteCourses.get(elpCode), report, logger, importMode); + synchronizeContent(doc, course, remoteCourses.get(elpKey), report, logger, importMode, programLanguage); courseList.addCourse(course.getId()); hasChanges = true; @@ -1020,7 +1048,7 @@ } // Replace the elpCode by the courseId - orderedCourseLists.set(orderedCourseLists.indexOf(elpCode), course.getId()); + orderedCourseLists.set(orderedCourseLists.indexOf(elpKey), course.getId()); } } @@ -1453,7 +1481,7 @@ * @param report The report for logs * @param logger The logger */ - protected void applyChanges (WorkflowAwareContent content, SynchronizationReport report, Logger logger) + protected void applyChanges (SynchronizableContent content, SynchronizationReport report, Logger logger) { try { @@ -1467,6 +1495,14 @@ // Notify observers that the content has been validated _observationManager.notify(new Event(_currentUserProvider.getUser(), ObservationConstants.CONTENT_MODIFIED, content)); + + if (content.isLocked()) + { + String warn = "Le contenu \"" + content.getTitle() + "\" est verrouillé : il ne peut être validé. Veuillez le déverrouiller pour pouvoir le valider."; + report.warn(warn); + logger.warn(warn); + return; + } Map inputs = new HashMap(); inputs.put(AbstractContentWorkflowComponent.RESULT_MAP_KEY, new HashMap()); @@ -1575,4 +1611,37 @@ return file; } + + /** + * Search for translated contents + * @param importedContent The imported content + * @param code The code + */ + protected void linkTranslationsIfExist (ModifiableContent importedContent) + { + Map translations = new HashMap(); + + String metadataName = importedContent instanceof ProgramPart ? AbstractProgram.CODE : Course.ELP_CODE; + String metadataValue = importedContent.getMetadataHolder().getString(metadataName); + Expression codeExpr = new SynchronizeExpression(metadataName, metadataValue); + Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, importedContent.getType()); + Expression langExpr = new LanguageExpression(Operator.NE, importedContent.getLanguage()); + Expression expr = new AndExpression(cTypeExpr, langExpr, codeExpr); + + String jcrQuery = QueryHelper.getXPathQuery(null, "ametys:content", expr, null); + AmetysObjectIterable contents = _resolver.query(jcrQuery); + + for (SynchronizableContent content : contents) + { + translations.put(content.getLanguage(), content.getId()); + + Map translations2 = TranslationHelper.getTranslations(content); + translations2.put(importedContent.getLanguage(), importedContent.getId()); + TranslationHelper.setTranslations(content, translations2); + + _observationManager.notify(new Event(_currentUserProvider.getUser(), OdfObservationConstants.ODF_CONTENT_TRANSLATED, content)); + } + + TranslationHelper.setTranslations(importedContent, translations); + } } 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 36748) +++ main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMFrImportManager.java (working copy) @@ -27,50 +27,36 @@ 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.commons.lang.StringUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import org.ametys.cms.observation.Event; import org.ametys.cms.repository.Content; -import org.ametys.cms.repository.ContentTypeExpression; -import org.ametys.cms.repository.LanguageExpression; -import org.ametys.cms.repository.ModifiableContent; import org.ametys.odf.SynchronizableContent; -import org.ametys.odf.SynchronizeExpression; import org.ametys.odf.catalog.Catalog; import org.ametys.odf.course.Course; import org.ametys.odf.courselist.CourseList; import org.ametys.odf.courselist.CourseListContainer; -import org.ametys.odf.observation.OdfObservationConstants; import org.ametys.odf.orgunit.OrgUnit; -import org.ametys.odf.program.AbstractProgram; import org.ametys.odf.program.Container; import org.ametys.odf.program.Program; import org.ametys.odf.program.ProgramFactory; import org.ametys.odf.program.SubProgram; -import org.ametys.odf.translation.TranslationHelper; import org.ametys.plugins.odfsync.ImportManager; import org.ametys.plugins.odfsync.RemoteItem; import org.ametys.plugins.odfsync.SearchRemoteItem; import org.ametys.plugins.odfsync.SynchronizationReport; import org.ametys.plugins.odfsync.cdmfr.item.CDMFrFileRemoteItem; import org.ametys.plugins.odfsync.cdmfr.searchitem.CDMFrFileSearchRemoteItem; -import org.ametys.plugins.repository.AmetysObjectIterable; import org.ametys.plugins.repository.AmetysRepositoryException; -import org.ametys.plugins.repository.query.QueryHelper; -import org.ametys.plugins.repository.query.expression.AndExpression; -import org.ametys.plugins.repository.query.expression.Expression; -import org.ametys.plugins.repository.query.expression.Expression.Operator; import org.ametys.runtime.config.Config; import org.ametys.runtime.util.parameter.ParameterHelper; import org.ametys.runtime.util.parameter.ParameterHelper.ParameterType; +import org.apache.avalon.framework.logger.Logger; +import org.apache.cocoon.ProcessingException; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; import com.opensymphony.workflow.WorkflowException; @@ -173,9 +159,7 @@ String contentId = createContent(ProgramFactory.PROGRAM_CONTENT_TYPE, contentLang, contentName, contentTitle, _programWorkflowName, 1, null); content = _resolver.resolveById(contentId); - synchronizeContent(doc, content, contentNode, report, logger, true); - - linkTranslationsIfExist (content, contentLang, contentName); + synchronizeContent(doc, content, contentNode, report, logger, true, contentLang); String catalog = ((Program) content).getCatalog(); if (StringUtils.isEmpty(catalog) && defaultCatalog != null) @@ -218,7 +202,7 @@ String infoMsg = "Synchronisation de la formation \"" + content.getTitle() + "\""; report.info(infoMsg); logger.info(infoMsg); - if (synchronizeContent(doc, content, contentNode, report, logger, false)) + if (synchronizeContent(doc, content, contentNode, report, logger, false, contentLang)) { applyChanges(content, report, logger); } @@ -248,38 +232,6 @@ return importedPrograms; } - /** - * Search for translated contents - * @param importedContent The imported content - * @param lang The lang The content language - * @param code The code - */ - protected void linkTranslationsIfExist (ModifiableContent importedContent, String lang, String code) - { - Map translations = new HashMap(); - - Expression cTypeExpr = new ContentTypeExpression(Operator.EQ, ProgramFactory.PROGRAM_CONTENT_TYPE); - Expression langExpr = new LanguageExpression(Operator.NE, importedContent.getLanguage()); - Expression codeExpr = new SynchronizeExpression(AbstractProgram.CODE, code); - Expression expr = new AndExpression(cTypeExpr, langExpr, codeExpr); - - String jcrQuery = QueryHelper.getXPathQuery(null, "ametys:content", expr, null); - AmetysObjectIterable contents = _resolver.query(jcrQuery); - - for (SynchronizableContent content : contents) - { - translations.put(content.getLanguage(), content.getId()); - - Map translations2 = TranslationHelper.getTranslations(content); - translations2.put(lang, importedContent.getId()); - TranslationHelper.setTranslations(content, translations2); - - _observationManager.notify(new Event(_currentUserProvider.getUser(), OdfObservationConstants.ODF_CONTENT_TRANSLATED, content)); - } - - TranslationHelper.setTranslations(importedContent, translations); - } - @Override public List< ? extends SearchRemoteItem> searchRemotePrograms(Map params) { Index: main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMFrSynchronizationManager.java =================================================================== --- main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMFrSynchronizationManager.java (revision 36748) +++ main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMFrSynchronizationManager.java (working copy) @@ -241,7 +241,12 @@ if (doc != null) { - Node programNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "program[@CDMid = '" + syncCode + "']"); + Node programNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "program[@CDMid = '" + syncCode + "' and @language = '" + program.getLanguage() + "']"); + if (programNode == null) + { + programNode = _xPathProcessor.selectSingleNode(doc.getFirstChild(), "program[@CDMid = '" + syncCode + "']"); + } + if (programNode == null) { String errorMsg = "La formation \"" + program.getTitle() + " (" + program.getCdmCode() + ")\" n'a pas été trouvé dans le fichier CDM-fr"; @@ -249,7 +254,7 @@ logger.error(errorMsg); return false; } - hasChanges = synchronizeContent(doc, program, programNode, report, logger, false); + hasChanges = synchronizeContent(doc, program, programNode, report, logger, false, program.getLanguage()); if (hasChanges) { @@ -373,7 +378,7 @@ for (int i = 0; i < contentNodes.getLength(); i++) { - String contentId = contentNodes.item(i).getTextContent(); + String contentId = contentNodes.item(i).getTextContent().trim(); contentToFile.put(contentId, filename); } } Index: main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMSynchronizationHelper.java =================================================================== --- main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMSynchronizationHelper.java (revision 36748) +++ main/plugin-odf-sync/src/org/ametys/plugins/odfsync/cdmfr/CDMSynchronizationHelper.java (working copy) @@ -103,7 +103,7 @@ for (int i = 0; i < entryNodes.getLength(); i++) { Node entryNode = entryNodes.item(i); - String entryName = entryNode.getAttributes().getNamedItem("name").getTextContent(); + String entryName = entryNode.getAttributes().getNamedItem("name").getTextContent().trim(); ModifiableCompositeMetadata entry = repeater.getCompositeMetadata(entryName, true); @@ -113,9 +113,9 @@ Node childNode = childNodes.item(j); String subMetadataName = childNode.getLocalName(); - String type = childNode.getAttributes().getNamedItem("type").getTextContent(); + String type = childNode.getAttributes().getNamedItem("type").getTextContent().trim(); Node multipleItem = childNode.getAttributes().getNamedItem("multiple"); - boolean isMultiple = multipleItem != null && "true".equals(multipleItem.getTextContent()); + boolean isMultiple = multipleItem != null && "true".equals(multipleItem.getTextContent().trim()); // Metadata of repeater can not be synchronizable for now hasChanges = synchronizeNoSynchronizableMetadata(content, entry, type, subMetadataName, childNode, enumerationHelper, xpathProcessor, cocoonContext, isMultiple) || hasChanges; @@ -198,7 +198,7 @@ boolean isSynchonizable = isSynchronizable(metadataNode); String constant = getConstant(metadataNode); - String value = metadataNode.getTextContent(); + String value = metadataNode.getTextContent().trim(); if (constant != null) { value = enumerationHelper.getItemCode(constant, value); @@ -240,7 +240,7 @@ public static boolean synchronizeNoSynchronizableStringMetadata(Node metadataNode, ModifiableCompositeMetadata compositeMetadata, String metadataName, OdfEnumerationHelper enumerationHelper) { String constant = getConstant(metadataNode); - String value = metadataNode.getTextContent(); + String value = metadataNode.getTextContent().trim(); if (constant != null) { value = enumerationHelper.getItemCode(constant, value); @@ -275,7 +275,7 @@ List values = new ArrayList(); for (int j = 0; j < itemNodes.getLength(); j++) { - String value = itemNodes.item(j).getTextContent(); + String value = itemNodes.item(j).getTextContent().trim(); if (constant != null) { value = enumerationHelper.getItemCode(constant, value); @@ -327,7 +327,7 @@ List values = new ArrayList(); for (int j = 0; j < itemNodes.getLength(); j++) { - String value = itemNodes.item(j).getTextContent(); + String value = itemNodes.item(j).getTextContent().trim(); if (constant != null) { value = enumerationHelper.getItemCode(constant, value); @@ -358,7 +358,7 @@ */ public static boolean synchronizeFileMetadata(Node metadataNode, SynchronizableContent content, String metadataName, Context cocoonContext, boolean importMode) { - String value = metadataNode.getTextContent(); + String value = metadataNode.getTextContent().trim(); boolean isSynchronizable = isSynchronizable(metadataNode); if (__URL_REGEXP.matcher(value).matches()) @@ -424,8 +424,8 @@ */ public static boolean synchronizeNoSynchronizableGeocodeMetadata(Node metadataNode, ModifiableCompositeMetadata compositeMetadata, String metadataName) { - double latitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("latitude").getTextContent()); - double longitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("longitude").getTextContent()); + double latitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("latitude").getTextContent().trim()); + double longitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("longitude").getTextContent().trim()); ModifiableCompositeMetadata geocodeMeta = compositeMetadata.getCompositeMetadata(metadataName, true); double oldLatitude = geocodeMeta.getDouble("latitude", 0d); @@ -454,8 +454,8 @@ { boolean isSynchonizable = isSynchronizable(metadataNode); - double latitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("latitude").getTextContent()); - double longitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("longitude").getTextContent()); + double latitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("latitude").getTextContent().trim()); + double longitude = Double.parseDouble(metadataNode.getAttributes().getNamedItem("longitude").getTextContent().trim()); if (isSynchonizable) { @@ -503,7 +503,7 @@ */ public static boolean synchronizeNoSynchronizableFileMetadata(Node metadataNode, ModifiableCompositeMetadata compositeMetadata, String metadataName, Context cocoonContext) { - String value = metadataNode.getTextContent(); + String value = metadataNode.getTextContent().trim(); if (__URL_REGEXP.matcher(value).matches()) { @@ -551,7 +551,7 @@ InputStream is = null; try { - String value = metadataNode.getTextContent(); + String value = metadataNode.getTextContent().trim(); URL url = new URL(value); is = url.openStream(); @@ -638,7 +638,7 @@ InputStream is = null; try { - String value = metadataNode.getTextContent(); + String value = metadataNode.getTextContent().trim(); URL url = new URL(value); @@ -743,7 +743,7 @@ { boolean isSynchonizable = isSynchronizable(metadataNode); - String dateAsString = metadataNode.getTextContent(); + String dateAsString = metadataNode.getTextContent().trim(); if (StringUtils.isNotEmpty(dateAsString)) { Date date = _dateFormat.parse(dateAsString); @@ -806,7 +806,7 @@ { try { - Date date = _dateFormat.parse(metadataNode.getTextContent()); + Date date = _dateFormat.parse(metadataNode.getTextContent().trim()); if (!date.equals(compositeMetadata.getDate(metadataName))) { compositeMetadata.setMetadata(metadataName, date); @@ -1062,7 +1062,7 @@ public static boolean isSynchronizable (Node node) { Node sync = node.getAttributes().getNamedItem("sync"); - return sync == null || !"false".equals(sync.getTextContent()); + return sync == null || !"false".equals(sync.getTextContent().trim()); } /** @@ -1075,7 +1075,7 @@ Node constant = node.getAttributes().getNamedItem("constant"); if (constant != null) { - return constant.getTextContent(); + return constant.getTextContent().trim(); } return null; } Index: main/plugin-odf-sync/stylesheets/cdm11/cdmfr2content.xsl =================================================================== --- main/plugin-odf-sync/stylesheets/cdm11/cdmfr2content.xsl (revision 36748) +++ main/plugin-odf-sync/stylesheets/cdm11/cdmfr2content.xsl (working copy) @@ -86,6 +86,7 @@ + Index: main/plugin-odf-sync/stylesheets/cdm11/course2content.xsl =================================================================== --- main/plugin-odf-sync/stylesheets/cdm11/course2content.xsl (revision 36748) +++ main/plugin-odf-sync/stylesheets/cdm11/course2content.xsl (working copy) @@ -24,6 +24,12 @@ + + + + + + Index: main/plugin-odf-sync/stylesheets/cdm112/cdmfr2content.xsl =================================================================== --- main/plugin-odf-sync/stylesheets/cdm112/cdmfr2content.xsl (revision 36748) +++ main/plugin-odf-sync/stylesheets/cdm112/cdmfr2content.xsl (working copy) @@ -86,6 +86,7 @@ + Index: main/plugin-odf-sync/stylesheets/cdm112/course2content.xsl =================================================================== --- main/plugin-odf-sync/stylesheets/cdm112/course2content.xsl (revision 36748) +++ main/plugin-odf-sync/stylesheets/cdm112/course2content.xsl (working copy) @@ -24,6 +24,12 @@ + + + + + + Index: main/plugin-odf-sync/stylesheets/cdmfr2content.xsl =================================================================== --- main/plugin-odf-sync/stylesheets/cdmfr2content.xsl (revision 36748) +++ main/plugin-odf-sync/stylesheets/cdmfr2content.xsl (working copy) @@ -86,6 +86,7 @@ + Index: main/plugin-odf-sync/stylesheets/course2content.xsl =================================================================== --- main/plugin-odf-sync/stylesheets/course2content.xsl (revision 36748) +++ main/plugin-odf-sync/stylesheets/course2content.xsl (working copy) @@ -24,6 +24,13 @@ + + + + + + +