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