2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.common;
26 import java.util.List;
28 import javax.ws.rs.GET;
29 import javax.ws.rs.Path;
30 import javax.ws.rs.Produces;
31 import javax.ws.rs.core.MultivaluedMap;
32 import javax.ws.rs.core.Response;
33 import javax.ws.rs.core.UriInfo;
35 import org.collectionspace.services.common.CSWebApplicationException;
36 import org.collectionspace.services.common.api.Tools;
37 import org.collectionspace.services.common.context.ServiceContext;
38 import org.collectionspace.services.common.context.ServiceContextProperties;
39 import org.collectionspace.services.common.document.BadRequestException;
40 import org.collectionspace.services.common.document.DocumentException;
41 import org.collectionspace.services.common.document.DocumentHandler;
42 import org.collectionspace.services.common.document.DocumentNotFoundException;
43 import org.collectionspace.services.common.document.TransactionException;
44 import org.collectionspace.services.common.repository.RepositoryClient;
45 import org.collectionspace.services.common.repository.RepositoryClientFactory;
46 import org.collectionspace.services.common.security.UnauthorizedException;
47 import org.collectionspace.services.common.storage.StorageClient;
48 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
49 import org.jboss.resteasy.core.ResourceMethod;
50 import org.jboss.resteasy.spi.HttpRequest;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
55 * The Class AbstractCollectionSpaceResourceImpl.
57 * @param <IT> the generic type
58 * @param <OT> the generic type
60 public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
61 implements CollectionSpaceResource<IT, OT> {
63 protected final Logger logger = LoggerFactory.getLogger(this.getClass());
66 // Fields for default client factory and client
67 /** The repository client factory. */
68 private RepositoryClientFactory<IT, OT> repositoryClientFactory;
70 /** The repository client. */
71 private RepositoryClient<IT, OT> repositoryClient;
73 /** The storage client. */
74 private StorageClient storageClient;
82 protected static String extractId(Response res) {
83 MultivaluedMap<String, Object> mvm = res.getMetadata();
84 String uri = (String) ((List<Object>) mvm.get("Location")).get(0);
85 String[] segments = uri.split("/");
86 String id = segments[segments.length - 1];
91 * Instantiates a new abstract collection space resource.
93 public AbstractCollectionSpaceResourceImpl() {
94 repositoryClientFactory = (RepositoryClientFactory<IT, OT>) RepositoryClientFactory.getInstance();
98 * @see org.collectionspace.services.common.CollectionSpaceResource#getServiceName()
101 abstract public String getServiceName();
105 * @see org.collectionspace.services.common.CollectionSpaceResource#getRepositoryClient(org.collectionspace.services.common.context.ServiceContext)
108 synchronized public RepositoryClient<IT, OT> getRepositoryClient(ServiceContext<IT, OT> ctx) {
109 if(repositoryClient != null){
110 return repositoryClient;
112 repositoryClient = repositoryClientFactory.getClient(ctx.getRepositoryClientName());
113 return repositoryClient;
117 * @see org.collectionspace.services.common.CollectionSpaceResource#getStorageClient(org.collectionspace.services.common.context.ServiceContext)
120 synchronized public StorageClient getStorageClient(ServiceContext<IT, OT> ctx) {
121 if(storageClient != null) {
122 return storageClient;
124 storageClient = new JpaStorageClientImpl();
125 return storageClient;
129 * @see org.collectionspace.services.common.CollectionSpaceResource#createDocumentHandler(org.collectionspace.services.common.context.ServiceContext)
132 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx) throws Exception {
133 DocumentHandler docHandler = createDocumentHandler(ctx, ctx.getInput());
138 * Creates the document handler.
141 * @param commonPart the common part
143 * @return the document handler
145 * @throws Exception the exception
147 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx,
148 Object commonPart) throws Exception {
149 DocumentHandler docHandler = ctx.getDocumentHandler();
150 docHandler.setCommonPart(commonPart);
155 * Creates the service context.
157 * @return the service context< i t, o t>
159 * @throws Exception the exception
161 protected ServiceContext<IT, OT> createServiceContext() throws Exception {
162 ServiceContext<IT, OT> ctx = createServiceContext(this.getServiceName(),
163 (IT)null, //inputType
164 null, // The resource map
165 (UriInfo)null, // The query params
166 this.getCommonPartClass());
171 * Creates the service context.
173 * @param serviceName the service name
175 * @return the service context< i t, o t>
177 * @throws Exception the exception
179 protected ServiceContext<IT, OT> createServiceContext(String serviceName) throws Exception {
180 ServiceContext<IT, OT> ctx = createServiceContext(
182 (IT)null, // The input part
183 null, // The resource map
184 (UriInfo)null, // The queryParams
185 (Class<?>)null /*input type's Class*/);
189 protected ServiceContext<IT, OT> createServiceContext(String serviceName, UriInfo ui) throws Exception {
190 ServiceContext<IT, OT> ctx = createServiceContext(
192 (IT)null, // The input part
193 null, // The resource map
194 (UriInfo)null, // The queryParams
195 (Class<?>)null /*input type's Class*/);
201 * Creates the service context.
203 * @param serviceName the service name
204 * @param input the input
206 * @return the service context< i t, o t>
208 * @throws Exception the exception
210 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
211 IT input) throws Exception {
212 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
214 null, // The resource map
215 (UriInfo)null, /*queryParams*/
216 (Class<?>)null /*input type's Class*/);
220 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
222 UriInfo uriInfo) throws Exception {
223 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
225 null, // The resource map
226 uriInfo, /*queryParams*/
227 (Class<?>)null /*input type's Class*/);
231 protected ServiceContext<IT, OT> createServiceContext(UriInfo uriInfo) throws Exception {
232 ServiceContext<IT, OT> ctx = createServiceContext(
235 (Class<?>)null /*input type's Class*/);
240 * Creates the service context.
242 * @param input the input
244 * @return the service context< i t, o t>
246 * @throws Exception the exception
248 protected ServiceContext<IT, OT> createServiceContext(IT input) throws Exception {
249 ServiceContext<IT, OT> ctx = createServiceContext(
251 (Class<?>)null /*input type's Class*/);
255 protected ServiceContext<IT, OT> createServiceContext(IT input, UriInfo uriInfo) throws Exception {
256 ServiceContext<IT, OT> ctx = createServiceContext(
259 null ); // The class param/argument
264 * Creates the service context.
266 * @param input the input
267 * @param theClass the the class
269 * @return the service context
271 * @throws Exception the exception
273 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass) throws Exception {
274 ServiceContext<IT, OT> ctx = createServiceContext(
276 (UriInfo)null, //queryParams,
281 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass, UriInfo uriInfo) throws Exception {
282 ServiceContext<IT, OT> ctx = createServiceContext(
289 protected ServiceContext<IT, OT> createServiceContext(
291 ResourceMap resourceMap,
292 UriInfo uriInfo) throws Exception {
293 ServiceContext<IT, OT> ctx = createServiceContext(
295 null, // The input object
298 null /* the class of the input type */);
302 protected ServiceContext<IT, OT> createServiceContext(
304 ResourceMap resourceMap,
305 UriInfo uriInfo) throws Exception {
306 ServiceContext<IT, OT> ctx = createServiceContext(
307 this.getServiceName(),
311 null /* the class of the input type */);
315 protected ServiceContext<IT, OT> createServiceContext(
318 ResourceMap resourceMap,
319 UriInfo uriInfo) throws Exception {
320 ServiceContext<IT, OT> ctx = createServiceContext(
325 null /* the class of the input type */);
330 * Creates the service context.
332 * @param input the input
333 * @param queryParams the query params
334 * @param theClass the the class
336 * @return the service context< i t, o t>
338 * @throws Exception the exception
340 private ServiceContext<IT, OT> createServiceContext(
343 Class<?> theClass) throws Exception {
344 return createServiceContext(this.getServiceName(),
346 null, // The resource map
352 * Creates the service context.
354 * @param serviceName the service name
355 * @param input the input
356 * @param queryParams the query params
357 * @param theClass the the class
359 * @return the service context< i t, o t>
361 * @throws Exception the exception
363 private ServiceContext<IT, OT> createServiceContext(
366 ResourceMap resourceMap,
368 Class<?> theClass) throws Exception {
369 ServiceContext<IT, OT> ctx = getServiceContextFactory().createServiceContext(
374 theClass != null ? theClass.getPackage().getName() : null,
375 theClass != null ? theClass.getName() : null);
376 if (theClass != null) {
377 ctx.setProperty(ServiceContextProperties.ENTITY_CLASS, theClass);
384 * Gets the version string.
386 * @return the version string
388 abstract protected String getVersionString();
393 * @return the version
397 @Produces("application/xml")
398 public Version getVersion() {
399 Version result = new Version();
401 result.setVersionString(getVersionString());
406 public void checkResult(Object resultToCheck, String csid, String serviceMessage) throws CSWebApplicationException {
407 if (resultToCheck == null) {
408 Response response = Response.status(Response.Status.NOT_FOUND).entity(
409 serviceMessage + "csid=" + csid
410 + ": was not found.").type(
411 "text/plain").build();
412 throw new CSWebApplicationException(response);
416 protected void ensureCSID(String csid, String crudType) throws CSWebApplicationException {
417 ensureCSID(csid, crudType, "csid");
420 protected void ensureCSID(String csid, String crudType, String whichCsid) throws CSWebApplicationException {
421 if (logger.isDebugEnabled()) {
422 logger.debug(crudType + " for " + getClass().getName() + " with csid=" + csid);
424 if (csid == null || "".equals(csid)) {
425 logger.error(crudType + " for " + getClass().getName() + " missing csid!");
426 Response response = Response.status(Response.Status.BAD_REQUEST).entity(crudType + " failed on " + getClass().getName() + ' '+whichCsid+'=' + csid).type("text/plain").build();
427 throw new CSWebApplicationException(response);
431 protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg) throws CSWebApplicationException {
432 return bigReThrow(e, serviceMsg, "");
435 protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg, String csid) throws CSWebApplicationException {
436 boolean logException = true;
437 CSWebApplicationException result = null;
439 String detail = Tools.errorToString(e, true);
440 String detailNoTrace = Tools.errorToString(e, true, 3);
442 if (e instanceof UnauthorizedException) {
443 response = Response.status(Response.Status.UNAUTHORIZED).entity(serviceMsg + e.getMessage()).type("text/plain").build();
444 result = new CSWebApplicationException(e, response);
446 } else if (e instanceof DocumentNotFoundException) {
448 // Don't log this error unless we're in 'trace' mode
450 logException = false;
451 response = Response.status(Response.Status.NOT_FOUND).entity(serviceMsg + " on " + getClass().getName() + " csid=" + csid).type("text/plain").build();
452 result = new CSWebApplicationException(e, response);
454 } else if (e instanceof TransactionException) {
455 int code = ((TransactionException) e).getErrorCode();
456 response = Response.status(code).entity(e.getMessage()).type("text/plain").build();
457 result = new CSWebApplicationException(e, response);
459 } else if (e instanceof BadRequestException) {
460 int code = ((BadRequestException) e).getErrorCode();
462 code = Response.Status.BAD_REQUEST.getStatusCode();
465 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
466 // return new WebApplicationException(e, code);
467 result = new CSWebApplicationException(e, response);
469 } else if (e instanceof DocumentException) {
470 int code = ((DocumentException) e).getErrorCode();
472 code = Response.Status.BAD_REQUEST.getStatusCode();
475 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
476 // return new WebApplicationException(e, code);
477 result = new CSWebApplicationException(e, response);
479 } else if (e instanceof CSWebApplicationException) {
480 // subresource may have already thrown this exception
481 // so just pass it on
482 result = (CSWebApplicationException) e;
484 } else { // e is now instanceof Exception
485 response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(serviceMsg + " detail: " + detailNoTrace).type("text/plain").build();
486 result = new CSWebApplicationException(e, response);
489 // Some exceptions like DocumentNotFoundException won't be logged unless we're in 'trace' mode
491 boolean traceEnabled = logger.isTraceEnabled();
492 if (logException == true || traceEnabled == true) {
493 if (traceEnabled == true) {
494 logger.error(getClass().getName() + " detail: " + detail, e);
496 logger.error(getClass().getName() + " detail: " + detailNoTrace);
504 public boolean allowAnonymousAccess(HttpRequest request,
505 ResourceMethod method) {