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