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.apache.commons.lang3.StringUtils; 026import org.apache.xpath.XPathAPI; 027import org.w3c.dom.Document; 028import org.w3c.dom.Element; 029import org.w3c.dom.NamedNodeMap; 030import org.w3c.dom.Node; 031 032import org.ametys.cms.repository.Content; 033import org.ametys.core.util.dom.DOMUtils; 034import org.ametys.odf.courselist.CourseList; 035import org.ametys.plugins.odfsync.cdmfr.ImportCDMFrContext; 036import org.ametys.plugins.odfsync.cdmfr.components.ImportCDMFrComponent; 037import org.ametys.plugins.odfsync.utils.ContentWorkflowDescription; 038import org.ametys.runtime.model.ElementDefinition; 039import org.ametys.runtime.model.Model; 040import org.ametys.runtime.model.ModelHelper; 041import org.ametys.runtime.model.ModelItem; 042import org.ametys.runtime.model.ModelItemContainer; 043import org.ametys.runtime.model.ModelViewItem; 044import org.ametys.runtime.model.ViewElement; 045import org.ametys.runtime.model.ViewItemContainer; 046 047/** 048 * This class provides methods to extract course list's values from a CMD-fr import document 049 */ 050public class ImportCourseListValuesExtractor extends ImportCDMFrValuesExtractor 051{ 052 /** 053 * Creates an import course list values extractor 054 * @param element the DOM element containing the XML values 055 * @param factory the values extractor factory 056 * @param component the import CDM-fr component 057 * @param context the import context 058 * @param models the model of the extracted values 059 */ 060 public ImportCourseListValuesExtractor(Element element, ImportCDMFrValuesExtractorFactory factory, ImportCDMFrComponent component, ImportCDMFrContext context, Model... models) 061 { 062 this(element, factory, component, context, Arrays.asList(models)); 063 } 064 065 /** 066 * Creates an import course list values extractor 067 * @param element the DOM element containing the XML values 068 * @param factory the values extractor factory 069 * @param component the import CDM-fr component 070 * @param context the imported content's context 071 * @param modelItemContainers the model of the extracted values 072 */ 073 public ImportCourseListValuesExtractor(Element element, ImportCDMFrValuesExtractorFactory factory, ImportCDMFrComponent component, ImportCDMFrContext context, Collection<? extends ModelItemContainer> modelItemContainers) 074 { 075 super(element, factory, component, context, modelItemContainers); 076 } 077 078 @SuppressWarnings("unchecked") 079 @Override 080 protected void _fillViewItemContainerFromXML(Element element, ViewItemContainer viewItemContainer, Collection<? extends ModelItemContainer> modelItemContainers) throws Exception 081 { 082 NamedNodeMap attributes = element.getAttributes(); 083 for (int i = 0; i < attributes.getLength(); i++) 084 { 085 Node attribute = attributes.item(i); 086 087 Optional<ModelItem> optionalModelItem = _getModelItemFromNodeName(element, attribute.getNodeName(), modelItemContainers); 088 if (optionalModelItem.isPresent()) 089 { 090 ModelItem modelItem = optionalModelItem.get(); 091 092 ModelViewItem modelViewItem = new ViewElement(); 093 modelViewItem.setDefinition(modelItem); 094 095 viewItemContainer.addViewItem(modelViewItem); 096 } 097 } 098 099 if (DOMUtils.hasChildElement(element, _MULTIPLE_DATA_ITEM_TAG)) 100 { 101 ModelItem childCoursesModelItem = ModelHelper.getModelItem(CourseList.CHILD_COURSES, modelItemContainers); 102 103 ModelViewItem modelViewItem = new ViewElement(); 104 modelViewItem.setDefinition(childCoursesModelItem); 105 106 viewItemContainer.addViewItem(modelViewItem); 107 } 108 } 109 110 @Override 111 protected boolean _hasChildForAttribute(Element element, String attributeName) 112 { 113 return CourseList.CHILD_COURSES.equals(attributeName) 114 ? DOMUtils.hasChildElement(element, _MULTIPLE_DATA_ITEM_TAG) 115 : element.hasAttribute(attributeName); 116 } 117 118 @Override 119 protected <T> Object _extractElementValue(Element parent, ElementDefinition<T> definition, Optional<Object> additionalData) throws Exception 120 { 121 String attributePath = definition.getPath(); 122 if (CourseList.CHILD_COURSES.equals(attributePath)) 123 { 124 Document doc = _context.getDocument(); 125 String lang = _context.getLang(); 126 List<Content> courses = new ArrayList<>(); 127 List<Element> children = DOMUtils.getChildElementsByTagName(parent, _MULTIPLE_DATA_ITEM_TAG); 128 for (Element child : children) 129 { 130 String courseSyncCode = child.getTextContent().trim(); 131 132 Element courseElement = (Element) XPathAPI.selectSingleNode(doc.getFirstChild(), "course[@CDMid = '" + courseSyncCode + "' and @language = '" + lang + "']"); 133 if (courseElement == null) 134 { 135 courseElement = (Element) XPathAPI.selectSingleNode(doc.getFirstChild(), "course[@CDMid = '" + courseSyncCode + "']"); 136 } 137 138 if (courseElement != null) 139 { 140 String courseCatalog = _component.getCatalogName(courseElement); 141 if (courseCatalog != null && !courseCatalog.equals(_context.getCatalog())) 142 { 143 String cdmCode = DOMUtils.getChildElementByTagName(courseElement, "cdmCode").getTextContent(); 144 _context.getLogger().error("The course '{}' belongs to a different catalog than the one from the imported/synchronized program : '{}' vs '{}'. No synchronization will be done on this course.", cdmCode, courseCatalog, _context.getCatalog()); 145 } 146 else 147 { 148 ImportCDMFrContext courseContext = new ImportCDMFrContext(_context); 149 String elpLang = courseElement.getAttribute("language"); 150 if (StringUtils.isNotEmpty(elpLang)) 151 { 152 courseContext.setLang(elpLang); 153 } 154 155 String title = DOMUtils.getChildElementByTagName(courseElement, "title").getTextContent(); 156 Content course = _component.importOrSynchronizeContent(courseElement, ContentWorkflowDescription.COURSE_WF_DESCRIPTION, title, courseSyncCode, courseContext); 157 CollectionUtils.addIgnoreNull(courses, course); 158 } 159 } 160 } 161 return courses.toArray(new Content[courses.size()]); 162 } 163 else 164 { 165 String attribute = parent.getAttribute(attributePath); 166 if (StringUtils.isNotEmpty(attribute)) 167 { 168 return CourseList.CHOICE_TYPE.equals(attributePath) 169 ? attribute.toUpperCase() 170 : definition.getType().castValue(attribute); 171 } 172 else 173 { 174 return null; 175 } 176 } 177 } 178}