001/* 002 * Copyright 2010 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.odfweb.program; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Optional; 027import java.util.stream.Collectors; 028 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.cocoon.ProcessingException; 032import org.apache.cocoon.environment.ObjectModelHelper; 033import org.apache.cocoon.environment.Request; 034import org.apache.cocoon.generation.ServiceableGenerator; 035import org.apache.cocoon.xml.AttributesImpl; 036import org.apache.cocoon.xml.XMLUtils; 037import org.xml.sax.SAXException; 038 039import org.ametys.cms.data.ContentValue; 040import org.ametys.odf.orgunit.OrgUnit; 041import org.ametys.odf.program.Program; 042import org.ametys.odf.program.ProgramFactory; 043import org.ametys.odf.program.ProgramPart; 044import org.ametys.odf.program.SubProgram; 045import org.ametys.plugins.odfweb.repository.OdfPageHandler; 046import org.ametys.plugins.repository.AmetysObjectIterable; 047import org.ametys.plugins.repository.AmetysObjectResolver; 048import org.ametys.plugins.repository.UnknownAmetysObjectException; 049import org.ametys.runtime.model.ModelItem; 050import org.ametys.web.repository.page.Page; 051import org.ametys.web.repository.page.ZoneItem; 052 053/** 054 * Generates the exhaustive list of programs. 055 */ 056public class ProgramListGenerator extends ServiceableGenerator 057{ 058 /** The ametys object resolver. */ 059 protected AmetysObjectResolver _ametysResolver; 060 061 /** Handler for root */ 062 protected OdfPageHandler _odfPageHandler; 063 064 @Override 065 public void service(ServiceManager serviceManager) throws ServiceException 066 { 067 super.service(serviceManager); 068 _ametysResolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 069 _odfPageHandler = (OdfPageHandler) serviceManager.lookup(OdfPageHandler.ROLE); 070 } 071 072 @Override 073 public void generate() throws IOException, SAXException, ProcessingException 074 { 075 Request request = ObjectModelHelper.getRequest(objectModel); 076 077 String site = parameters.getParameter("site", (String) request.getAttribute("site")); 078 String lang = parameters.getParameter("lang", (String) request.getAttribute("sitemapLanguage")); 079 String catalog = parameters.getParameter("catalog", (String) request.getAttribute("catalog")); 080 081 ZoneItem zoneItem = (ZoneItem) request.getAttribute(ZoneItem.class.getName()); 082 String[] filteredByOrgUnits = zoneItem.getServiceParameters().getValue("orgunitlist", false, new String[0]); 083 084 Page rootPage = _odfPageHandler.getOdfRootPage(site, lang, catalog); 085 if (rootPage == null) 086 { 087 throw new IllegalArgumentException("There is no ODF root page for catalog '" + catalog + "' and language '" + lang + "'."); 088 } 089 090 AmetysObjectIterable<Program> programs = _odfPageHandler.getProgramsWithRestrictions(rootPage, null, null, null, null); 091 092 contentHandler.startDocument(); 093 094 AttributesImpl atts = new AttributesImpl(); 095 atts.addCDATAAttribute("root-page-path", rootPage.getPathInSitemap()); 096 097 XMLUtils.startElement(contentHandler, "programs", atts); 098 099 HashMap<String, List<String>> metadataFilters = new HashMap<>(); 100 101 if (filteredByOrgUnits.length > 0) 102 { 103 List<String> filteredByOrgUnitsAsList = Arrays.asList(filteredByOrgUnits); 104 metadataFilters.put("orgUnit", filteredByOrgUnitsAsList); 105 106 for (Program program : programs) 107 { 108 // Check at least one program's org units belongs to the filtered list 109 List<String> orgUnits = program.getOrgUnits(); 110 111 boolean found = false; 112 for (String ouId : orgUnits) 113 { 114 try 115 { 116 OrgUnit ou = _ametysResolver.resolveById(ouId); 117 if (_isEqualOrHasParentInList(ou, filteredByOrgUnitsAsList)) 118 { 119 found = true; 120 break; 121 } 122 } 123 catch (UnknownAmetysObjectException e) 124 { 125 getLogger().error("The OrgUnit with id '" + ouId + "' does not exist anymore. It will be ignored.", e); 126 } 127 128 } 129 130 if (found) 131 { 132 saxProgram(program, metadataFilters); 133 } 134 } 135 } 136 else 137 { 138 for (Program program : programs) 139 { 140 saxProgram(program, metadataFilters); 141 } 142 } 143 XMLUtils.endElement(contentHandler, "programs"); 144 145 contentHandler.endDocument(); 146 } 147 148 private boolean _isEqualOrHasParentInList (OrgUnit ou, List<String> filteredOrgUnits) 149 { 150 if (filteredOrgUnits.contains(ou.getId())) 151 { 152 return true; 153 } 154 155 // Check parents 156 OrgUnit parentOrgUnit = ou.getParentOrgUnit(); 157 while (parentOrgUnit != null) 158 { 159 if (filteredOrgUnits.contains(parentOrgUnit.getId())) 160 { 161 return true; 162 } 163 parentOrgUnit = parentOrgUnit.getParentOrgUnit(); 164 } 165 166 return false; 167 } 168 169 /** 170 * SAX a program. 171 * @param program The program to SAX. 172 * @param attributeFilters Filters to apply to the attributes 173 * @throws SAXException If an error occurs while SAXing 174 * @throws IOException If an error occurs while retrieving content. 175 */ 176 public void saxProgram(Program program, HashMap<String, List<String>> attributeFilters) throws SAXException, IOException 177 { 178 Map<String, ModelItem> enumeratedAttributes = _odfPageHandler.getEnumeratedAttributes(ProgramFactory.PROGRAM_CONTENT_TYPE, true); 179 180 AttributesImpl atts = new AttributesImpl(); 181 atts.addCDATAAttribute("id", program.getId()); 182 atts.addCDATAAttribute("name", program.getName()); 183 atts.addCDATAAttribute("title", program.getTitle()); 184 185 XMLUtils.startElement(contentHandler, "program", atts); 186 187 for (String attributePath : enumeratedAttributes.keySet()) 188 { 189 List<String> values = Optional.ofNullable(program.getValue(attributePath)) 190 .map(this::_valuesAsList) 191 .orElse(Collections.emptyList()) 192 .stream() 193 .filter(value -> value instanceof String || value instanceof ContentValue) 194 .map(value -> value instanceof ContentValue ? ((ContentValue) value).getContentId() : (String) value) 195 .collect(Collectors.toList()); 196 197 AttributesImpl attrs = new AttributesImpl(); 198 attrs.addCDATAAttribute("path", attributePath); 199 200 XMLUtils.startElement(contentHandler, "metadata", attrs); 201 for (String value : values) 202 { 203 if (_filterAttributes(attributePath, value, attributeFilters)) 204 { 205 XMLUtils.createElement(contentHandler, "value", value); 206 } 207 } 208 XMLUtils.endElement(contentHandler, "metadata"); 209 } 210 211 for (ProgramPart programPart : program.getProgramPartChildren()) 212 { 213 if (programPart instanceof SubProgram) 214 { 215 saxSubProgram((SubProgram) programPart); 216 } 217 } 218 219 XMLUtils.endElement(contentHandler, "program"); 220 } 221 222 private List<Object> _valuesAsList(Object values) 223 { 224 if (values instanceof Collection<?>) 225 { 226 return new ArrayList<>((Collection<?>) values); 227 } 228 else if (values instanceof Object[]) 229 { 230 return Arrays.asList((Object[]) values); 231 } 232 else 233 { 234 return Arrays.asList(values); 235 } 236 } 237 238 private boolean _filterAttributes(String attributePath, String value, HashMap<String, List<String>> attributeFilters) 239 { 240 if (attributePath.equals("orgUnit") && attributeFilters.containsKey("orgUnit")) 241 { 242 try 243 { 244 OrgUnit ou = _ametysResolver.resolveById(value); 245 return _isEqualOrHasParentInList(ou, attributeFilters.get("orgUnit")); 246 } 247 catch (UnknownAmetysObjectException e) 248 { 249 getLogger().error("The OrgUnit with id '" + value + "' does not exist anymore. It will be ignored.", e); 250 return false; 251 } 252 253 } 254 return true; 255 } 256 257 /** 258 * SAX a subprogram. 259 * @param subProgram The subprogram to SAX. 260 * @throws SAXException If an error occurs while SAXing 261 */ 262 protected void saxSubProgram (SubProgram subProgram) throws SAXException 263 { 264 AttributesImpl atts = new AttributesImpl(); 265 266 atts.addCDATAAttribute("id", subProgram.getId()); 267 atts.addCDATAAttribute("name", subProgram.getName()); 268 atts.addCDATAAttribute("title", subProgram.getTitle()); 269 270 XMLUtils.createElement(contentHandler, "subprogram", atts); 271 } 272 273 /** 274 * SAX a value. 275 * @param name the criterion name. 276 * @param value the criterion value. 277 * @throws SAXException SAX error 278 */ 279 protected void saxCriterionValue(String name, String value) throws SAXException 280 { 281 AttributesImpl attrs = new AttributesImpl(); 282 attrs.addCDATAAttribute("name", name); 283 attrs.addCDATAAttribute("value", value); 284 XMLUtils.createElement(contentHandler, "criterion", attrs); 285 } 286}