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}