001/**
002 * Copyright 2015 DuraSpace, Inc.
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.fcrepo.oai.http;
017
018import static org.openarchives.oai._2.VerbType.GET_RECORD;
019import static org.openarchives.oai._2.VerbType.IDENTIFY;
020import static org.openarchives.oai._2.VerbType.LIST_IDENTIFIERS;
021import static org.openarchives.oai._2.VerbType.LIST_METADATA_FORMATS;
022import static org.openarchives.oai._2.VerbType.LIST_RECORDS;
023import static org.openarchives.oai._2.VerbType.LIST_SETS;
024
025import java.io.InputStream;
026import java.net.URI;
027
028import javax.inject.Inject;
029import javax.jcr.RepositoryException;
030import javax.jcr.Session;
031import javax.ws.rs.Consumes;
032import javax.ws.rs.GET;
033import javax.ws.rs.POST;
034import javax.ws.rs.Path;
035import javax.ws.rs.Produces;
036import javax.ws.rs.QueryParam;
037import javax.ws.rs.core.Context;
038import javax.ws.rs.core.MediaType;
039import javax.ws.rs.core.Response;
040import javax.ws.rs.core.UriInfo;
041import javax.xml.bind.JAXBException;
042
043import org.fcrepo.oai.service.OAIProviderService;
044import org.openarchives.oai._2.OAIPMHerrorcodeType;
045import org.openarchives.oai._2.VerbType;
046import org.springframework.beans.factory.annotation.Autowired;
047import org.springframework.context.annotation.Scope;
048
049/**
050 * The type OAI web resource.
051 *
052 * @author Frank Asseg
053 */
054@Scope("request")
055@Path("/oai")
056public class OAIWebResource {
057
058    @Inject
059    private Session session;
060
061    @Autowired
062    private OAIProviderService providerService;
063
064    /**
065     * Create set.
066     *
067     * @param uriInfo the uri info
068     * @param src the src
069     * @return the response
070     * @throws RepositoryException the repository exception
071     */
072    @POST
073    @Path("/sets")
074    @Consumes(MediaType.TEXT_XML)
075    public Response createSet(@Context final UriInfo uriInfo, final InputStream src) throws RepositoryException {
076        final String path = this.providerService.createSet(session, uriInfo, src);
077        return Response.created(URI.create(path)).build();
078    }
079
080    /**
081     * Gets OAI response.
082     *
083     * @param verbParam the verb
084     * @param identifierParam the identifier
085     * @param metadataPrefixParam the metadata prefix
086     * @param fromParam the from
087     * @param untilParam the until
088     * @param setParam the set
089     * @param resumptionToken the resumption token
090     * @param uriInfo the uri info
091     * @return the oAI response
092     * @throws RepositoryException the repository exception
093     */
094    @GET
095    @Produces(MediaType.TEXT_XML)
096    public Object getOAIResponse(
097            final @QueryParam("verb") String verbParam, final @QueryParam("identifier") String identifierParam,
098            final @QueryParam("metadataPrefix") String metadataPrefixParam, final @QueryParam("from") String fromParam,
099            final @QueryParam("until") String untilParam, final @QueryParam("set") String setParam,
100            final @QueryParam("resumptionToken") String resumptionToken, final @Context UriInfo uriInfo)
101            throws RepositoryException {
102
103        int offset = 0;
104
105        final String verb;
106        final String from;
107        final String until;
108        final String set;
109        final String metadataPrefix;
110        final String identifier;
111
112        if (resumptionToken != null && !resumptionToken.isEmpty()) {
113            /* If there's a resumption token present the data provided in the
114                base64 encoded token is used to generate the request */
115            try {
116                final ResumptionToken token = OAIProviderService.decodeResumptionToken(resumptionToken);
117                identifier = null;
118                verb = token.getVerb();
119                from = token.getFrom();
120                until = token.getUntil();
121                set = token.getSet();
122                metadataPrefix = token.getMetadataPrefix();
123                offset = token.getOffset();
124            } catch (Exception e) {
125                return providerService.error(null, null, null, OAIPMHerrorcodeType.BAD_RESUMPTION_TOKEN,
126                        "Resumption token is invalid");
127            }
128        } else {
129            /* otherwise just read the query params */
130            identifier = identifierParam;
131            verb = verbParam;
132            from = fromParam;
133            until = untilParam;
134            set = setParam;
135            metadataPrefix = metadataPrefixParam;
136        }
137
138        /* decide what to do depending on the verb passed */
139        if (verb == null) {
140            return providerService.error(null, identifier, metadataPrefix, OAIPMHerrorcodeType.BAD_ARGUMENT,
141                    "Verb is required");
142        }
143
144        /* identify response */
145        if (verb.equals(IDENTIFY.value())) {
146            try {
147                verifyEmpty(identifier, metadataPrefix, from, until, set);
148                return providerService.identify(this.session, uriInfo);
149            } catch (JAXBException | IllegalArgumentException e) {
150                return providerService.error(VerbType.IDENTIFY, identifier, metadataPrefix,
151                        OAIPMHerrorcodeType.BAD_ARGUMENT, "Invalid arguments");
152            }
153        }
154
155        /* ListMetadataFormats response */
156        if (verb.equals(LIST_METADATA_FORMATS.value())) {
157            try {
158                verifyEmpty(from, until, set);
159                return providerService.listMetadataFormats(this.session, uriInfo, identifier);
160            } catch (IllegalArgumentException e) {
161                return providerService.error(VerbType.LIST_METADATA_FORMATS, identifier, metadataPrefix,
162                        OAIPMHerrorcodeType.BAD_ARGUMENT, "Invalid arguments");
163            }
164        }
165
166        /* GetRecord response */
167        if (verb.equals(GET_RECORD.value())) {
168            try {
169                verifyEmpty(from, until, set);
170                return providerService.getRecord(this.session, uriInfo, identifier, metadataPrefix);
171
172            } catch (IllegalArgumentException e) {
173                return providerService.error(VerbType.GET_RECORD, identifier, metadataPrefix,
174                        OAIPMHerrorcodeType.BAD_ARGUMENT, "Invalid arguments");
175            }
176        }
177
178        /* list identifiers response */
179        if (verb.equals(LIST_IDENTIFIERS.value())) {
180            try {
181                verifyEmpty(identifier);
182                return providerService.listIdentifiers(this.session, uriInfo, metadataPrefix, from, until, set, offset);
183            } catch (IllegalArgumentException e) {
184                return providerService.error(VerbType.LIST_IDENTIFIERS, identifier, metadataPrefix,
185                        OAIPMHerrorcodeType.BAD_ARGUMENT, "Invalid arguments");
186            }
187        }
188
189        /* list sets response */
190        if (verb.equals(LIST_SETS.value())) {
191            try {
192                verifyEmpty(identifier);
193            } catch (IllegalArgumentException e) {
194                return providerService.error(VerbType.LIST_SETS, identifier, metadataPrefix,
195                        OAIPMHerrorcodeType.BAD_ARGUMENT, "Invalid arguments");
196            }
197            return providerService.listSets(session, uriInfo, offset);
198        }
199
200        /* list records response */
201        if (verb.equals(LIST_RECORDS.value())) {
202            try {
203                verifyEmpty(identifier);
204                return  providerService.listRecords(this.session, uriInfo, metadataPrefix, from, until, set, offset);
205            } catch (IllegalArgumentException e) {
206                return providerService.error(VerbType.LIST_SETS, identifier, metadataPrefix,
207                        OAIPMHerrorcodeType.BAD_ARGUMENT, "Invalid arguments");
208            }
209        }
210        return providerService.error(null, identifier, metadataPrefix, OAIPMHerrorcodeType.BAD_VERB,
211                "Unknown verb '" + verb + "'");
212    }
213
214    private void verifyEmpty(final String... data) throws IllegalArgumentException {
215        for (String s : data) {
216            if (s != null && !s.isEmpty()) {
217                throw new IllegalArgumentException("Wrong argument for method");
218            }
219        }
220    }
221
222}