001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.odfsync.cdmfr.components.impl; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.HashSet; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import javax.jcr.RepositoryException; 026 027import org.apache.avalon.framework.configuration.Configuration; 028import org.apache.avalon.framework.configuration.ConfigurationException; 029import org.apache.commons.lang3.StringUtils; 030import org.slf4j.Logger; 031import org.w3c.dom.Document; 032import org.w3c.dom.Node; 033 034import org.ametys.cms.content.external.ExternalizableMetadataHelper; 035import org.ametys.cms.contenttype.ContentType; 036import org.ametys.cms.repository.ContentQueryHelper; 037import org.ametys.cms.repository.ContentTypeExpression; 038import org.ametys.cms.repository.LanguageExpression; 039import org.ametys.cms.repository.ModifiableDefaultContent; 040import org.ametys.odf.ProgramItem; 041import org.ametys.odf.enumeration.OdfReferenceTableHelper; 042import org.ametys.odf.program.AbstractProgram; 043import org.ametys.odf.program.ProgramFactory; 044import org.ametys.odf.program.ProgramPart; 045import org.ametys.odf.program.SubProgram; 046import org.ametys.odf.program.TraversableProgramPart; 047import org.ametys.plugins.repository.AmetysObjectIterable; 048import org.ametys.plugins.repository.query.expression.AndExpression; 049import org.ametys.plugins.repository.query.expression.Expression; 050import org.ametys.plugins.repository.query.expression.Expression.Operator; 051import org.ametys.plugins.repository.query.expression.StringExpression; 052import org.ametys.runtime.config.Config; 053 054/** 055 * Component to import a CDM-fr input stream from a remote server with co-accredited mode. 056 */ 057public class CoAccreditedRemoteImportCDMFrComponent extends RemoteImportCDMFrComponent 058{ 059 /** The list of metadata to copy for mention program */ 060 protected Set<String> _mentionMetadataPaths; 061 062 private Map<String, String> _degree2MentionMap; 063 private ContentType _mentionContentType; 064 private String _mention; 065 private String _programToLinkCode; 066 067 @Override 068 public void initialize() throws Exception 069 { 070 super.initialize(); 071 072 _degree2MentionMap = new HashMap<>(); 073 _degree2MentionMap.put(Config.getInstance().getValueAsString("odf.programs.degree.license"), OdfReferenceTableHelper.MENTION_LICENCE); 074 _degree2MentionMap.put(Config.getInstance().getValueAsString("odf.programs.degree.licensepro"), OdfReferenceTableHelper.MENTION_LICENCEPRO); 075 _degree2MentionMap.put(Config.getInstance().getValueAsString("odf.programs.degree.master"), OdfReferenceTableHelper.MENTION_MASTER); 076 077 _mentionContentType = _contentTypeEP.getExtension(getProgramWfDescription().getContentType()); 078 } 079 080 @Override 081 public void configure(Configuration configuration) throws ConfigurationException 082 { 083 super.configure(configuration); 084 085 _mentionMetadataPaths = new HashSet<>(); 086 Configuration mentionConf = configuration.getChild("mention"); 087 if (mentionConf != null) 088 { 089 Configuration metadatas = mentionConf.getChild("metadata-to-copy"); 090 if (metadatas != null) 091 { 092 for (Configuration metadataConf : metadatas.getChildren()) 093 { 094 String metadataPath = metadataConf.getAttribute("path"); 095 _mentionMetadataPaths.add(metadataPath); 096 } 097 } 098 } 099 } 100 101 @Override 102 protected void additionalParameters(Map<String, Object> parameters) 103 { 104 _mention = null; 105 super.additionalParameters(parameters); 106 } 107 108 @Override 109 protected ModifiableDefaultContent _importOrSynchronizeContent(Document doc, Node contentNode, ContentWorkflowDescription wfDescription, String title, String lang, String catalog, String syncCode, Logger logger) 110 { 111 ContentWorkflowDescription contentWfDescription = wfDescription; 112 113 if (contentNode.getLocalName().equals(_TAG_PROGRAM)) 114 { 115 String educationKind = _xPathProcessor.evaluateAsString(contentNode, AbstractProgram.EDUCATION_KIND); 116 String mention = _xPathProcessor.evaluateAsString(contentNode, AbstractProgram.MENTION); 117 118 // This is a co-accredited program 119 if (StringUtils.isNotBlank(mention) && "parcours".equals(educationKind)) 120 { 121 // Change the workflow description of the program to subprogram 122 contentWfDescription = getSubProgramWfDescription(); 123 124 // Get or create the mention from the program 125 _mention = _getOrCreateMention(doc, contentNode, mention, lang, catalog, logger); 126 127 // Store the content to link to the mention 128 _programToLinkCode = syncCode; 129 } 130 } 131 132 return super._importOrSynchronizeContent(doc, contentNode, contentWfDescription, title, lang, catalog, syncCode, logger); 133 } 134 135 private String _getOrCreateMention(Document doc, Node contentNode, String mentionCode, String lang, String catalog, Logger logger) 136 { 137 String degreeCode = _xPathProcessor.evaluateAsString(contentNode, AbstractProgram.DEGREE); 138 139 String mentionType = _degree2MentionMap.get(degreeCode); 140 if (mentionType == null) 141 { 142 String mentionId = _getIdFromCDMThenCode(mentionType, mentionCode); 143 if (mentionId == null) 144 { 145 ModifiableDefaultContent mention = _getMention(mentionCode, degreeCode, lang, catalog); 146 if (mention == null) 147 { 148 mention = _createMention(doc, contentNode, mentionId, catalog, lang, logger); 149 } 150 return mention != null ? mention.getId() : null; 151 } 152 else 153 { 154 logger.error("Il n'y a pas de code associé à la mention {}. La formation n'a pas été importée.", mentionCode); 155 _nbError++; 156 } 157 } 158 else 159 { 160 logger.error("Il n'y a pas de type de mention (licence, licence pro, master) associée au diplôme {}. La formation n'a pas été importée.", degreeCode); 161 _nbError++; 162 } 163 164 return null; 165 } 166 167 private ModifiableDefaultContent _createMention(Document doc, Node contentNode, String mentionId, String catalog, String lang, Logger logger) 168 { 169 String contentTitle = _odfRefTableHelper.getItemLabel(null, mentionId, lang); 170 ContentWorkflowDescription wfDescription = getProgramWfDescription(); 171 Map<String, Object> resultMap = _synchroComponent.createContentAction(wfDescription.getContentType(), wfDescription.getWorkflowName(), wfDescription.getInitialActionId(), lang, contentTitle, _contentPrefix, logger); 172 if ((boolean) resultMap.getOrDefault("error", false)) 173 { 174 _nbError++; 175 } 176 177 ModifiableDefaultContent mention = (ModifiableDefaultContent) resultMap.get("content"); 178 179 if (mention != null) 180 { 181 boolean hasChanges = false; 182 if (catalog != null) 183 { 184 hasChanges = ExternalizableMetadataHelper.setMetadata(mention.getMetadataHolder(), ProgramItem.METADATA_CATALOG, catalog); 185 } 186 187 hasChanges = _synchronizeMentionMetadata(doc, contentNode, mention, AbstractProgram.DEGREE, lang, logger) || hasChanges; 188 hasChanges = _synchronizeMentionMetadata(doc, contentNode, mention, AbstractProgram.MENTION, lang, logger) || hasChanges; 189 hasChanges = _synchronizeMentionMetadata(doc, contentNode, mention, AbstractProgram.DOMAIN, lang, logger) || hasChanges; 190 191 for (String metadataPath : _mentionMetadataPaths) 192 { 193 hasChanges = _synchronizeMentionMetadata(doc, contentNode, mention, metadataPath, lang, logger) || hasChanges; 194 } 195 196 _saveContentChanges(mention, wfDescription.getContentType(), hasChanges, logger); 197 } 198 199 return mention; 200 } 201 202 private ModifiableDefaultContent _getMention(String mentionCode, String degreeCode, String lang, String catalog) 203 { 204 List<Expression> expList = new ArrayList<>(); 205 expList.add(new ContentTypeExpression(Operator.EQ, ProgramFactory.PROGRAM_CONTENT_TYPE)); 206 expList.add(new LanguageExpression(Operator.EQ, lang)); 207 expList.add(new StringExpression(ProgramItem.METADATA_CATALOG, Operator.EQ, catalog)); 208 expList.add(new StringExpression(AbstractProgram.DEGREE, Operator.EQ, degreeCode)); 209 expList.add(new StringExpression(AbstractProgram.MENTION, Operator.EQ, mentionCode)); 210 211 AndExpression andExp = new AndExpression(expList.toArray(new Expression[expList.size()])); 212 String xPathQuery = ContentQueryHelper.getContentXPathQuery(andExp); 213 214 AmetysObjectIterable<ModifiableDefaultContent> contents = _resolver.query(xPathQuery); 215 216 if (contents.getSize() > 0) 217 { 218 return contents.iterator().next(); 219 } 220 221 return null; 222 } 223 224 @Override 225 protected void additionalOperationsBeforeSave(ModifiableDefaultContent content, Logger logger) throws RepositoryException 226 { 227 if (_mention != null && content instanceof SubProgram && content.getMetadataHolder().getString(getIdField()).equals(_programToLinkCode)) 228 { 229 boolean hasChanges = false; 230 231 ModifiableDefaultContent mentionContent = _resolver.resolveById(_mention); 232 233 // Relier le programme à la mention 234 hasChanges = _synchroComponent.updateRelation(mentionContent.getMetadataHolder(), TraversableProgramPart.METADATA_CHILD_PROGRAM_PARTS, content, false) || hasChanges; 235 if (_synchroComponent.updateRelation(content.getMetadataHolder(), ProgramPart.METADATA_PARENT_PROGRAM_PARTS, _mention, false)) 236 { 237 _saveContentChanges(content, getSubProgramWfDescription().getContentType(), true, logger); 238 } 239 240 // Mettre les composantes de la mention à jour 241 List<String> orgunits = ((SubProgram) content).getOrgUnits(); 242 for (String orgunit : orgunits) 243 { 244 hasChanges = _synchroComponent.updateRelation(mentionContent.getMetadataHolder(), AbstractProgram.ORG_UNITS_REFERENCES, orgunit, false) || hasChanges; 245 } 246 247 if (hasChanges) 248 { 249 _saveContentChanges(mentionContent, _mentionContentType.getId(), hasChanges, logger); 250 } 251 } 252 } 253 254 private boolean _synchronizeMentionMetadata(Document doc, Node contentNode, ModifiableDefaultContent mention, String metadataPath, String lang, Logger logger) 255 { 256 Node metadataNode = _xPathProcessor.selectSingleNode(contentNode, metadataPath); 257 if (metadataNode != null) 258 { 259 return _synchronizeMetadata(doc, metadataNode, mention, metadataPath, metadataPath, _mentionContentType, lang, logger); 260 } 261 return false; 262 } 263}