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.jboss.resteasy.spi.metadata.ResourceMethod;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
56 * The Class AbstractCollectionSpaceResourceImpl.
58 * @param <IT> the generic type
59 * @param <OT> the generic type
61 public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
62 implements CollectionSpaceResource<IT, OT> {
64 protected final Logger logger = LoggerFactory.getLogger(this.getClass());
67 // Fields for default client factory and client
68 /** The repository client factory. */
69 private RepositoryClientFactory<IT, OT> repositoryClientFactory;
71 /** The repository client. */
72 private RepositoryClient<IT, OT> repositoryClient;
74 /** The storage client. */
75 private StorageClient storageClient;
83 protected static String extractId(Response res) {
84 MultivaluedMap<String, Object> mvm = res.getMetadata();
85 String uri = (String) ((List<Object>) mvm.get("Location")).get(0);
86 String[] segments = uri.split("/");
87 String id = segments[segments.length - 1];
92 * Instantiates a new abstract collection space resource.
94 public AbstractCollectionSpaceResourceImpl() {
95 repositoryClientFactory = (RepositoryClientFactory<IT, OT>) RepositoryClientFactory.getInstance();
99 * @see org.collectionspace.services.common.CollectionSpaceResource#getServiceName()
102 abstract public String getServiceName();
106 * @see org.collectionspace.services.common.CollectionSpaceResource#getRepositoryClient(org.collectionspace.services.common.context.ServiceContext)
109 synchronized public RepositoryClient<IT, OT> getRepositoryClient(ServiceContext<IT, OT> ctx) {
110 if(repositoryClient != null){
111 return repositoryClient;
113 repositoryClient = repositoryClientFactory.getClient(ctx.getRepositoryClientName());
114 return repositoryClient;
118 * @see org.collectionspace.services.common.CollectionSpaceResource#getStorageClient(org.collectionspace.services.common.context.ServiceContext)
121 synchronized public StorageClient getStorageClient(ServiceContext<IT, OT> ctx) {
122 if(storageClient != null) {
123 return storageClient;
125 storageClient = new JpaStorageClientImpl();
126 return storageClient;
130 * @see org.collectionspace.services.common.CollectionSpaceResource#createDocumentHandler(org.collectionspace.services.common.context.ServiceContext)
133 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx) throws Exception {
134 DocumentHandler docHandler = createDocumentHandler(ctx, ctx.getInput());
139 * Creates the document handler.
142 * @param commonPart the common part
144 * @return the document handler
146 * @throws Exception the exception
148 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx,
149 Object commonPart) throws Exception {
150 DocumentHandler docHandler = ctx.getDocumentHandler();
151 docHandler.setCommonPart(commonPart);
156 * Creates the service context.
158 * @return the service context< i t, o t>
160 * @throws Exception the exception
162 protected ServiceContext<IT, OT> createServiceContext() throws Exception {
163 ServiceContext<IT, OT> ctx = createServiceContext(this.getServiceName(),
164 (IT)null, //inputType
165 null, // The resource map
166 (UriInfo)null, // The query params
167 this.getCommonPartClass());
172 * Creates the service context.
174 * @param serviceName the service name
176 * @return the service context< i t, o t>
178 * @throws Exception the exception
180 protected ServiceContext<IT, OT> createServiceContext(String serviceName) throws Exception {
181 ServiceContext<IT, OT> ctx = createServiceContext(
183 (IT)null, // The input part
184 null, // The resource map
185 (UriInfo)null, // The queryParams
186 (Class<?>)null /*input type's Class*/);
190 protected ServiceContext<IT, OT> createServiceContext(String serviceName, UriInfo ui) throws Exception {
191 ServiceContext<IT, OT> ctx = createServiceContext(
193 (IT)null, // The input part
194 null, // The resource map
195 (UriInfo)null, // The queryParams
196 (Class<?>)null /*input type's Class*/);
202 * Creates the service context.
204 * @param serviceName the service name
205 * @param input the input
207 * @return the service context< i t, o t>
209 * @throws Exception the exception
211 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
212 IT input) throws Exception {
213 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
215 null, // The resource map
216 (UriInfo)null, /*queryParams*/
217 (Class<?>)null /*input type's Class*/);
221 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
223 UriInfo uriInfo) throws Exception {
224 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
226 null, // The resource map
227 uriInfo, /*queryParams*/
228 (Class<?>)null /*input type's Class*/);
232 protected ServiceContext<IT, OT> createServiceContext(UriInfo uriInfo) throws Exception {
233 ServiceContext<IT, OT> ctx = createServiceContext(
236 (Class<?>)null /*input type's Class*/);
241 * Creates the service context.
243 * @param input the input
245 * @return the service context< i t, o t>
247 * @throws Exception the exception
249 protected ServiceContext<IT, OT> createServiceContext(IT input) throws Exception {
250 ServiceContext<IT, OT> ctx = createServiceContext(
252 (Class<?>)null /*input type's Class*/);
256 protected ServiceContext<IT, OT> createServiceContext(IT input, UriInfo uriInfo) throws Exception {
257 ServiceContext<IT, OT> ctx = createServiceContext(
260 null ); // The class param/argument
265 * Creates the service context.
267 * @param input the input
268 * @param theClass the the class
270 * @return the service context
272 * @throws Exception the exception
274 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass) throws Exception {
275 ServiceContext<IT, OT> ctx = createServiceContext(
277 (UriInfo)null, //queryParams,
282 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass, UriInfo uriInfo) throws Exception {
283 ServiceContext<IT, OT> ctx = createServiceContext(
290 protected ServiceContext<IT, OT> createServiceContext(
292 ResourceMap resourceMap,
293 UriInfo uriInfo) throws Exception {
294 ServiceContext<IT, OT> ctx = createServiceContext(
296 null, // The input object
299 null /* the class of the input type */);
303 protected ServiceContext<IT, OT> createServiceContext(
305 ResourceMap resourceMap,
306 UriInfo uriInfo) throws Exception {
307 ServiceContext<IT, OT> ctx = createServiceContext(
308 this.getServiceName(),
312 null /* the class of the input type */);
316 protected ServiceContext<IT, OT> createServiceContext(
319 ResourceMap resourceMap,
320 UriInfo uriInfo) throws Exception {
321 ServiceContext<IT, OT> ctx = createServiceContext(
326 null /* the class of the input type */);
331 * Creates the service context.
333 * @param input the input
334 * @param queryParams the query params
335 * @param theClass the the class
337 * @return the service context< i t, o t>
339 * @throws Exception the exception
341 private ServiceContext<IT, OT> createServiceContext(
344 Class<?> theClass) throws Exception {
345 return createServiceContext(this.getServiceName(),
347 null, // The resource map
353 * Creates the service context.
355 * @param serviceName the service name
356 * @param input the input
357 * @param queryParams the query params
358 * @param theClass the the class
360 * @return the service context< i t, o t>
362 * @throws Exception the exception
364 private ServiceContext<IT, OT> createServiceContext(
367 ResourceMap resourceMap,
369 Class<?> theClass) throws Exception {
370 ServiceContext<IT, OT> ctx = getServiceContextFactory().createServiceContext(
375 theClass != null ? theClass.getPackage().getName() : null,
376 theClass != null ? theClass.getName() : null);
377 if (theClass != null) {
378 ctx.setProperty(ServiceContextProperties.ENTITY_CLASS, theClass);
385 * Gets the version string.
387 * @return the version string
389 abstract protected String getVersionString();
394 * @return the version
398 @Produces("application/xml")
399 public Version getVersion() {
400 Version result = new Version();
402 result.setVersionString(getVersionString());
407 public void checkResult(Object resultToCheck, String csid, String serviceMessage) throws CSWebApplicationException {
408 if (resultToCheck == null) {
409 Response response = Response.status(Response.Status.NOT_FOUND).entity(
410 serviceMessage + "csid=" + csid
411 + ": was not found.").type(
412 "text/plain").build();
413 throw new CSWebApplicationException(response);
417 protected void ensureCSID(String csid, String crudType) throws CSWebApplicationException {
418 ensureCSID(csid, crudType, "csid");
421 protected void ensureCSID(String csid, String crudType, String whichCsid) throws CSWebApplicationException {
422 if (logger.isDebugEnabled()) {
423 logger.debug(crudType + " for " + getClass().getName() + " with csid=" + csid);
425 if (csid == null || "".equals(csid)) {
426 logger.error(crudType + " for " + getClass().getName() + " missing csid!");
427 Response response = Response.status(Response.Status.BAD_REQUEST).entity(crudType + " failed on " + getClass().getName() + ' '+whichCsid+'=' + csid).type("text/plain").build();
428 throw new CSWebApplicationException(response);
432 protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg) throws CSWebApplicationException {
433 return bigReThrow(e, serviceMsg, "");
436 protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg, String csid) throws CSWebApplicationException {
437 boolean logException = true;
438 CSWebApplicationException result = null;
440 String detail = Tools.errorToString(e, true);
441 String detailNoTrace = Tools.errorToString(e, true, 3);
443 if (e instanceof UnauthorizedException) {
444 response = Response.status(Response.Status.UNAUTHORIZED).entity(serviceMsg + e.getMessage()).type("text/plain").build();
445 result = new CSWebApplicationException(e, response);
447 } else if (e instanceof DocumentNotFoundException) {
449 // Don't log this error unless we're in 'trace' mode
451 logException = false;
452 response = Response.status(Response.Status.NOT_FOUND).entity(serviceMsg + " on " + getClass().getName() + " csid=" + csid).type("text/plain").build();
453 result = new CSWebApplicationException(e, response);
455 } else if (e instanceof TransactionException) {
456 int code = ((TransactionException) e).getErrorCode();
457 response = Response.status(code).entity(e.getMessage()).type("text/plain").build();
458 result = new CSWebApplicationException(e, response);
460 } else if (e instanceof BadRequestException) {
461 int code = ((BadRequestException) e).getErrorCode();
463 code = Response.Status.BAD_REQUEST.getStatusCode();
466 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
467 // return new WebApplicationException(e, code);
468 result = new CSWebApplicationException(e, response);
470 } else if (e instanceof DocumentException) {
471 int code = ((DocumentException) e).getErrorCode();
473 code = Response.Status.BAD_REQUEST.getStatusCode();
476 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
477 // return new WebApplicationException(e, code);
478 result = new CSWebApplicationException(e, response);
480 } else if (e instanceof CSWebApplicationException) {
481 // subresource may have already thrown this exception
482 // so just pass it on
483 result = (CSWebApplicationException) e;
485 } else { // e is now instanceof Exception
486 response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(serviceMsg + " detail: " + detailNoTrace).type("text/plain").build();
487 result = new CSWebApplicationException(e, response);
490 // Some exceptions like DocumentNotFoundException won't be logged unless we're in 'trace' mode
492 boolean traceEnabled = logger.isTraceEnabled();
493 if (logException == true || traceEnabled == true) {
494 if (traceEnabled == true) {
495 logger.error(getClass().getName() + " detail: " + detail, e);
497 logger.error(getClass().getName() + " detail: " + detailNoTrace);
505 public boolean allowAnonymousAccess(HttpRequest request,
506 ResourceMethod method) {