001/* 002 * Copyright 2019 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.odf.content; 017 018import java.io.IOException; 019import java.util.Comparator; 020import java.util.List; 021import java.util.stream.Collectors; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.cocoon.ProcessingException; 026import org.apache.cocoon.environment.ObjectModelHelper; 027import org.apache.cocoon.environment.Request; 028import org.apache.cocoon.generation.ServiceableGenerator; 029import org.apache.cocoon.xml.AttributesImpl; 030import org.apache.cocoon.xml.XMLUtils; 031import org.apache.commons.lang3.StringUtils; 032import org.xml.sax.SAXException; 033 034import org.ametys.cms.repository.Content; 035import org.ametys.odf.ODFHelper; 036import org.ametys.odf.ProgramItem; 037import org.ametys.odf.data.EducationalPath; 038import org.ametys.plugins.repository.AmetysObjectResolver; 039 040/** 041 * Generates additional information about a ODF content 042 * 043 */ 044public class AdditionalOdfContentPropertiesGenerator extends ServiceableGenerator 045{ 046 private static final ListProgramItemComparator __LIST_PROGRAM_ITEM_COMPARATOR = new ListProgramItemComparator(); 047 048 /** The AmetysObject resolver. */ 049 protected AmetysObjectResolver _resolver; 050 /** The ODF helper */ 051 protected ODFHelper _odfHelper; 052 053 @Override 054 public void service(ServiceManager serviceManager) throws ServiceException 055 { 056 super.service(serviceManager); 057 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 058 _odfHelper = (ODFHelper) serviceManager.lookup(ODFHelper.ROLE); 059 } 060 061 @Override 062 public void generate() throws IOException, SAXException, ProcessingException 063 { 064 Request request = ObjectModelHelper.getRequest(objectModel); 065 066 String contentId = parameters.getParameter("contentId", request.getParameter("contentId")); 067 068 Content content = null; 069 if (StringUtils.isNotEmpty(contentId)) 070 { 071 content = _resolver.resolveById(contentId); 072 } 073 else 074 { 075 content = (Content) request.getAttribute(Content.class.getName()); 076 } 077 078 contentHandler.startDocument(); 079 XMLUtils.startElement(contentHandler, "odf"); 080 081 if (content instanceof ProgramItem) 082 { 083 XMLUtils.startElement(contentHandler, "programItem"); 084 saxProgramItemProperties((ProgramItem) content); 085 XMLUtils.endElement(contentHandler, "programItem"); 086 } 087 088 XMLUtils.endElement(contentHandler, "odf"); 089 contentHandler.startDocument(); 090 contentHandler.endDocument(); 091 } 092 093 /** 094 * SAX specifics properties for a program item 095 * @param programItem the program item 096 * @throws SAXException if an error occurs while saxing 097 */ 098 protected void saxProgramItemProperties(ProgramItem programItem) throws SAXException 099 { 100 _saxProgramItemAncestorPaths(programItem); 101 _saxChildProgramItems(programItem); 102 } 103 104 /** 105 * SAX all paths of program item 106 * @param programItem The program item 107 * @throws SAXException if an error occurs while saxing 108 */ 109 protected void _saxProgramItemAncestorPaths(ProgramItem programItem) throws SAXException 110 { 111 if (_odfHelper.hasParentProgramItems(programItem)) 112 { 113 List<EducationalPath> educationalPaths = _odfHelper.getEducationalPaths(programItem); 114 if (!educationalPaths.isEmpty()) 115 { 116 List<List<ProgramItem>> ancestorPaths = educationalPaths.stream() 117 .map(p -> p.getProgramItems(_resolver)) 118 .collect(Collectors.toList()); 119 120 if (!ancestorPaths.isEmpty()) 121 { 122 // Sort the list to display it 123 ancestorPaths.sort(__LIST_PROGRAM_ITEM_COMPARATOR); 124 125 XMLUtils.startElement(contentHandler, "ancestors"); 126 for (List<ProgramItem> ancestorPath : ancestorPaths) 127 { 128 XMLUtils.startElement(contentHandler, "path"); 129 for (ProgramItem ancestor : ancestorPath) 130 { 131 _saxProgramItem(ancestor); 132 } 133 XMLUtils.endElement(contentHandler, "path"); 134 } 135 136 XMLUtils.endElement(contentHandler, "ancestors"); 137 } 138 } 139 } 140 } 141 142 /** 143 * SAX the child program items 144 * @param programItem the program item 145 * @throws SAXException if an error occurs while saxing 146 */ 147 protected void _saxChildProgramItems(ProgramItem programItem) throws SAXException 148 { 149 List<ProgramItem> children = _odfHelper.getChildProgramItems(programItem); 150 151 if (!children.isEmpty()) 152 { 153 XMLUtils.startElement(contentHandler, "children"); 154 for (ProgramItem child : children) 155 { 156 _saxProgramItem(child); 157 } 158 XMLUtils.endElement(contentHandler, "children"); 159 } 160 } 161 162 /** 163 * Sax a program item 164 * @param item the program item 165 * @throws SAXException if an error occurs while saxing 166 */ 167 protected void _saxProgramItem(ProgramItem item) throws SAXException 168 { 169 Content content = (Content) item; 170 AttributesImpl attrs = new AttributesImpl(); 171 attrs.addCDATAAttribute("id", content.getId()); 172 attrs.addCDATAAttribute("code", item.getCode()); 173 XMLUtils.createElement(contentHandler, "item", attrs, content.getTitle()); 174 } 175 176 /** 177 * Comparator of {@link List} composing of {@link ProgramItem} by title. 178 */ 179 private static final class ListProgramItemComparator implements Comparator<List<ProgramItem>> 180 { 181 public int compare(List<ProgramItem> l1, List<ProgramItem> l2) 182 { 183 int l1Size = l1.size(); 184 int l2Size = l2.size(); 185 186 for (int i = 0; i < l1Size; i++) 187 { 188 if (l2Size <= i) 189 { 190 // l1 is greater than l2 191 return 1; 192 } 193 else 194 { 195 // Compare title 196 int comparing = ((Content) l1.get(i)).getTitle().compareTo(((Content) l2.get(i)).getTitle()); 197 if (comparing != 0) 198 { 199 return comparing; 200 } 201 } 202 } 203 204 // Lists are the same at the end of reading l1 205 // Then compare size of the lists 206 return Integer.compare(l1Size, l2Size); 207 } 208 } 209}