001/* 002 * Copyright 2012 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.oai; 017 018import java.io.IOException; 019import java.text.ParseException; 020import java.text.SimpleDateFormat; 021import java.time.ZoneOffset; 022import java.time.ZonedDateTime; 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.Collection; 026import java.util.Date; 027import java.util.TimeZone; 028 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.cocoon.ProcessingException; 033import org.apache.cocoon.environment.ObjectModelHelper; 034import org.apache.cocoon.environment.Request; 035import org.apache.cocoon.xml.XMLUtils; 036import org.apache.commons.lang3.StringUtils; 037import org.xml.sax.SAXException; 038 039import org.ametys.cms.CmsConstants; 040import org.ametys.cms.repository.Content; 041import org.ametys.core.util.DateUtils; 042import org.ametys.odf.ODFHelper; 043import org.ametys.odf.catalog.CatalogsManager; 044import org.ametys.odf.program.Program; 045import org.ametys.odf.program.ProgramFactory; 046import org.ametys.plugins.repository.AmetysObjectIterable; 047import org.ametys.plugins.repository.UnknownAmetysObjectException; 048import org.ametys.plugins.repository.query.SortCriteria; 049import org.ametys.plugins.repository.query.expression.AndExpression; 050import org.ametys.plugins.repository.query.expression.DateExpression; 051import org.ametys.plugins.repository.query.expression.Expression; 052import org.ametys.plugins.repository.query.expression.Expression.Operator; 053import org.ametys.plugins.repository.query.expression.ExpressionContext; 054 055/** 056 * Generator for the <code>ListIdentifiers</code> verb. 057 */ 058public class ListIdentifiersGenerator extends AbstractOAIVerbGenerator implements Serviceable 059{ 060 /** The OAI-PMH Sets Extension Point*/ 061 private OaiSetExtensionPoint _oaiSetEP; 062 063 private CatalogsManager _catalogsManager; 064 065 private ODFHelper _odfHelper; 066 067 @Override 068 public void service(ServiceManager serviceManager) throws ServiceException 069 { 070 _oaiSetEP = (OaiSetExtensionPoint) serviceManager.lookup(OaiSetExtensionPoint.ROLE); 071 _catalogsManager = (CatalogsManager) serviceManager.lookup(CatalogsManager.ROLE); 072 _odfHelper = (ODFHelper) serviceManager.lookup(ODFHelper.ROLE); 073 } 074 075 @Override 076 protected Collection<String> getRequiredParameters() 077 { 078 return Arrays.asList("verb", "metadataPrefix"); 079 } 080 081 @Override 082 protected Collection<String> getAllowedParameters() 083 { 084 return Arrays.asList("verb", "from", "until", "metadataPrefix", "resumptionToken", "set"); 085 } 086 087 @Override 088 protected void generateVerb() throws IOException, SAXException, ProcessingException 089 { 090 Request request = ObjectModelHelper.getRequest(objectModel); 091 092 String token = request.getParameter("resumptionToken"); 093 094 if (StringUtils.isNotEmpty(token)) 095 { 096 generateError("badResumptionToken ", "This repository does not support resumption tokens"); 097 return; 098 } 099 100 String metadataPrefix = request.getParameter("metadataPrefix"); 101 102 if (!metadataPrefix.equals("cdm") && !metadataPrefix.equals("oai_dc")) 103 { 104 generateError("cannotDisseminateFormat", "The value of the metadataPrefix argument is not supported by the repository."); 105 return; 106 } 107 108 SimpleDateFormat fullFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); 109 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 110 TimeZone tz = TimeZone.getTimeZone("UTC"); 111 fullFormat.setTimeZone(tz); 112 format.setTimeZone(tz); 113 114 ArrayList<Expression> expressions = new ArrayList<>(); 115 116 try 117 { 118 String fromParam = request.getParameter("from"); 119 120 if (fromParam != null) 121 { 122 Date from; 123 if (fromParam.indexOf('T') == -1) 124 { 125 from = format.parse(fromParam); 126 } 127 else 128 { 129 from = fullFormat.parse(fromParam); 130 } 131 132 expressions.add(new DateExpression("lastModified", Operator.GE, from, ExpressionContext.newInstance().withInternal(true))); 133 } 134 135 String untilParam = request.getParameter("until"); 136 137 if (untilParam != null) 138 { 139 Date until; 140 if (untilParam.indexOf('T') == -1) 141 { 142 until = format.parse(untilParam); 143 } 144 else 145 { 146 until = fullFormat.parse(untilParam); 147 } 148 149 expressions.add(new DateExpression("lastModified", Operator.LE, until, ExpressionContext.newInstance().withInternal(true))); 150 } 151 } 152 catch (ParseException ex) 153 { 154 generateError("badArgument", "One or more aguments are malformed."); 155 return; 156 } 157 158 OaiSet oaiSet = null; 159 String set = request.getParameter("set"); 160 161 if (StringUtils.isNotEmpty(set)) 162 { 163 oaiSet = _oaiSetEP.getExtension(set); 164 if (oaiSet == null) 165 { 166 generateError("noRecordsMatch", "The set specified as an argument does not exists."); 167 return; 168 } 169 } 170 171 Expression expression = new AndExpression(expressions.toArray(new Expression[]{})); 172 173 SortCriteria sortCriteria = new SortCriteria(); 174 sortCriteria.addCriterion(Content.ATTRIBUTE_TITLE, true, true); 175 176 try (AmetysObjectIterable<Program> programs = oaiSet != null 177 ? oaiSet.getRecords(expression, sortCriteria) 178 // FIXME Generate identifier for language "fr" and default catalog only 179 : _odfHelper.getProgramItems(ProgramFactory.PROGRAM_CONTENT_TYPE, null, _catalogsManager.getDefaultCatalogName(), "fr", expression, sortCriteria)) 180 { 181 182 XMLUtils.startElement(contentHandler, getTagName()); 183 184 for (Program program : programs) 185 { 186 try 187 { 188 String[] labels = program.getAllLabels(); 189 190 if (Arrays.asList(labels).contains(CmsConstants.LIVE_LABEL)) 191 { 192 program.switchToLabel(CmsConstants.LIVE_LABEL); 193 saxProgram(program); 194 } 195 } 196 catch (UnknownAmetysObjectException e) 197 { 198 // no "Live" label, continue 199 } 200 } 201 202 XMLUtils.endElement(contentHandler, getTagName()); 203 } 204 } 205 206 /** 207 * Returns the surrounding tag name. 208 * @return the surrounding tag name. 209 */ 210 protected String getTagName() 211 { 212 return "ListIdentifiers"; 213 } 214 215 /** 216 * Generate the program information. 217 * @param program the program 218 * @throws SAXException if an error occurs 219 */ 220 protected void saxProgram(Program program) throws SAXException 221 { 222 XMLUtils.startElement(contentHandler, "header"); 223 224 XMLUtils.createElement(contentHandler, "identifier", program.getCDMId()); 225 226 ZonedDateTime date = program.getLastModified(); 227 XMLUtils.createElement(contentHandler, "datestamp", DateUtils.zonedDateTimeToString(date, ZoneOffset.UTC, "yyyy-MM-dd'T'HH:mm:ssXXX")); 228 229 XMLUtils.endElement(contentHandler, "header"); 230 } 231}