001/* 002 * Copyright 2021 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.extractor; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.List; 022import java.util.Optional; 023 024import org.apache.commons.collections4.CollectionUtils; 025import org.w3c.dom.Element; 026 027import org.ametys.cms.repository.Content; 028import org.ametys.core.util.dom.DOMUtils; 029import org.ametys.odf.course.Course; 030import org.ametys.plugins.odfsync.cdmfr.ImportCDMFrContext; 031import org.ametys.plugins.odfsync.cdmfr.components.ImportCDMFrComponent; 032import org.ametys.plugins.odfsync.utils.ContentWorkflowDescription; 033import org.ametys.plugins.repository.data.extractor.xml.XMLValuesExtractorAdditionalDataGetter; 034import org.ametys.runtime.model.ElementDefinition; 035import org.ametys.runtime.model.Model; 036import org.ametys.runtime.model.ModelHelper; 037import org.ametys.runtime.model.ModelItem; 038import org.ametys.runtime.model.ModelItemContainer; 039 040/** 041 * This class provides methods to extract course's values from a CMD-fr import document 042 */ 043public class ImportCourseValuesExtractor extends ImportCDMFrValuesExtractor 044{ 045 /** Tag to identify a coursePart */ 046 protected static final String _TAG_COURSEPART = "coursePart"; 047 048 /** The imported content's synchronization code */ 049 protected String _synchronizationCode; 050 051 /** 052 * Creates an import course values extractor 053 * @param element the DOM element containing the XML values 054 * @param factory the values extractor factory 055 * @param component the import CDM-fr component 056 * @param synchronizationCode the imported content's synchronization code 057 * @param context the import context 058 * @param additionalDataGetter the getter that retrieves needed additional data by types 059 * @param models the model of the extracted values 060 */ 061 public ImportCourseValuesExtractor(Element element, ImportCDMFrValuesExtractorFactory factory, ImportCDMFrComponent component, String synchronizationCode, ImportCDMFrContext context, XMLValuesExtractorAdditionalDataGetter additionalDataGetter, Model... models) 062 { 063 this(element, factory, component, synchronizationCode, context, additionalDataGetter, Arrays.asList(models)); 064 } 065 066 /** 067 * Creates an import course values extractor 068 * @param element the DOM element containing the XML values 069 * @param factory the values extractor factory 070 * @param component the import CDM-fr component 071 * @param synchronizationCode the imported content's synchronization code 072 * @param context the imported content's context 073 * @param additionalDataGetter the getter that retrieves needed additional data by types 074 * @param modelItemContainers the model of the extracted values 075 */ 076 public ImportCourseValuesExtractor(Element element, ImportCDMFrValuesExtractorFactory factory, ImportCDMFrComponent component, String synchronizationCode, ImportCDMFrContext context, XMLValuesExtractorAdditionalDataGetter additionalDataGetter, Collection<? extends ModelItemContainer> modelItemContainers) 077 { 078 super(element, factory, component, context, additionalDataGetter, modelItemContainers); 079 080 _synchronizationCode = synchronizationCode; 081 } 082 083 @Override 084 protected Optional<ModelItem> _getModelItemFromNodeName(Element parent, String nodeName, Collection< ? extends ModelItemContainer> modelItemContainers) 085 { 086 if (_TAG_COURSELIST.equals(nodeName)) 087 { 088 return Optional.of(ModelHelper.getModelItem(Course.CHILD_COURSE_LISTS, modelItemContainers)); 089 } 090 else if (_TAG_COURSEPART.equals(nodeName)) 091 { 092 return Optional.of(ModelHelper.getModelItem(Course.CHILD_COURSE_PARTS, modelItemContainers)); 093 } 094 else 095 { 096 return super._getModelItemFromNodeName(parent, nodeName, modelItemContainers); 097 } 098 } 099 100 @Override 101 protected boolean _hasChildForAttribute(Element element, String attributeName) 102 { 103 if (Course.CHILD_COURSE_LISTS.equals(attributeName)) 104 { 105 return DOMUtils.hasChildElement(element, _TAG_COURSELIST); 106 } 107 else if (Course.CHILD_COURSE_PARTS.equals(attributeName)) 108 { 109 return DOMUtils.hasChildElement(element, _TAG_COURSEPART); 110 } 111 else 112 { 113 return super._hasChildForAttribute(element, attributeName); 114 } 115 } 116 117 @Override 118 protected <T> Object _extractElementValue(Element parent, ElementDefinition<T> definition, Optional<Object> additionalData) throws Exception 119 { 120 String attributePath = definition.getPath(); 121 if (Course.CHILD_COURSE_LISTS.equals(attributePath)) 122 { 123 List<Content> courseLists = new ArrayList<>(); 124 List<Element> children = DOMUtils.getChildElementsByTagName(parent, _TAG_COURSELIST); 125 126 int courseListPosition = 0; 127 for (Element child : children) 128 { 129 String title = _getAttributeOrDefault(child, "name", "Liste d'éléments pédagogiques"); 130 // For courseList from another source than Ametys, there is no unique code, then a code is generated with the parent ID and the position in the parent : [parentId]-[position] 131 courseListPosition++; 132 String subContentSyncCode = _getAttributeOrDefault(child, "code", _synchronizationCode + "-" + courseListPosition); 133 Content subContent = _component.importOrSynchronizeContent(child, ContentWorkflowDescription.COURSELIST_WF_DESCRIPTION, title, subContentSyncCode, _context); 134 CollectionUtils.addIgnoreNull(courseLists, subContent); 135 } 136 137 return courseLists.toArray(new Content[courseLists.size()]); 138 } 139 else if (Course.CHILD_COURSE_PARTS.equals(attributePath)) 140 { 141 List<Content> courseParts = new ArrayList<>(); 142 List<Element> children = DOMUtils.getChildElementsByTagName(parent, _TAG_COURSEPART); 143 144 for (Element child : children) 145 { 146 String title = DOMUtils.getChildElementByTagName(child, "title").getTextContent(); 147 Element subContentSyncCodeElement = DOMUtils.getChildElementByTagName(child, "code"); 148 String subContentSyncCode = subContentSyncCodeElement != null 149 ? subContentSyncCodeElement.getTextContent() 150 : org.ametys.core.util.StringUtils.generateKey().toUpperCase(); 151 Content subContent = _component.importOrSynchronizeContent(child, ContentWorkflowDescription.COURSEPART_WF_DESCRIPTION, title, subContentSyncCode, _context); 152 CollectionUtils.addIgnoreNull(courseParts, subContent); 153 } 154 155 return courseParts.toArray(new Content[courseParts.size()]); 156 } 157 else 158 { 159 return super._extractElementValue(parent, definition, additionalData); 160 } 161 } 162}