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}