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