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.lang.reflect.Method;
27 import java.util.List;
29 import javax.ws.rs.GET;
30 import javax.ws.rs.Path;
31 import javax.ws.rs.Produces;
32 import javax.ws.rs.core.MultivaluedMap;
33 import javax.ws.rs.core.Response;
34 import javax.ws.rs.core.UriInfo;
36 import org.collectionspace.services.common.CSWebApplicationException;
37 import org.collectionspace.services.common.api.Tools;
38 import org.collectionspace.services.common.context.ServiceContext;
39 import org.collectionspace.services.common.context.ServiceContextProperties;
40 import org.collectionspace.services.common.document.BadRequestException;
41 import org.collectionspace.services.common.document.DocumentException;
42 import org.collectionspace.services.common.document.DocumentHandler;
43 import org.collectionspace.services.common.document.DocumentNotFoundException;
44 import org.collectionspace.services.common.document.TransactionException;
45 import org.collectionspace.services.common.repository.RepositoryClient;
46 import org.collectionspace.services.common.repository.RepositoryClientFactory;
47 import org.collectionspace.services.common.security.UnauthorizedException;
48 import org.collectionspace.services.common.storage.StorageClient;
49 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
50 import org.jboss.resteasy.core.ResourceMethodInvoker;
51 //import org.jboss.resteasy.core.ResourceMethod;
52 import org.jboss.resteasy.spi.HttpRequest;
53 import org.jboss.resteasy.spi.metadata.ResourceMethod;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
58 * The Class AbstractCollectionSpaceResourceImpl.
60 * @param <IT> the generic type
61 * @param <OT> the generic type
63 public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
64 implements CollectionSpaceResource<IT, OT> {
66 protected final Logger logger = LoggerFactory.getLogger(this.getClass());
69 // Fields for default client factory and client
70 /** The repository client factory. */
71 private RepositoryClientFactory<IT, OT> repositoryClientFactory;
73 /** The repository client. */
74 private RepositoryClient<IT, OT> repositoryClient;
76 /** The storage client. */
77 private StorageClient storageClient;
85 protected static String extractId(Response res) {
86 MultivaluedMap<String, Object> mvm = res.getMetadata();
87 String uri = (String) ((List<Object>) mvm.get("Location")).get(0);
88 String[] segments = uri.split("/");
89 String id = segments[segments.length - 1];
94 * Instantiates a new abstract collection space resource.
96 public AbstractCollectionSpaceResourceImpl() {
97 repositoryClientFactory = (RepositoryClientFactory<IT, OT>) RepositoryClientFactory.getInstance();
101 * @see org.collectionspace.services.common.CollectionSpaceResource#getServiceName()
104 abstract public String getServiceName();
108 * @see org.collectionspace.services.common.CollectionSpaceResource#getRepositoryClient(org.collectionspace.services.common.context.ServiceContext)
111 synchronized public RepositoryClient<IT, OT> getRepositoryClient(ServiceContext<IT, OT> ctx) {
112 if(repositoryClient != null){
113 return repositoryClient;
115 repositoryClient = repositoryClientFactory.getClient(ctx.getRepositoryClientName());
116 return repositoryClient;
120 * @see org.collectionspace.services.common.CollectionSpaceResource#getStorageClient(org.collectionspace.services.common.context.ServiceContext)
123 synchronized public StorageClient getStorageClient(ServiceContext<IT, OT> ctx) {
124 if(storageClient != null) {
125 return storageClient;
127 storageClient = new JpaStorageClientImpl();
128 return storageClient;
132 * @see org.collectionspace.services.common.CollectionSpaceResource#createDocumentHandler(org.collectionspace.services.common.context.ServiceContext)
135 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx) throws Exception {
136 DocumentHandler docHandler = createDocumentHandler(ctx, ctx.getInput());
141 * Creates the document handler.
144 * @param commonPart the common part
146 * @return the document handler
148 * @throws Exception the exception
150 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx,
151 Object commonPart) throws Exception {
152 DocumentHandler docHandler = ctx.getDocumentHandler();
153 docHandler.setCommonPart(commonPart);
158 * Creates the service context.
160 * @return the service context< i t, o t>
162 * @throws Exception the exception
164 protected ServiceContext<IT, OT> createServiceContext() throws Exception {
165 ServiceContext<IT, OT> ctx = createServiceContext(this.getServiceName(),
166 (IT)null, //inputType
167 null, // The resource map
168 (UriInfo)null, // The query params
169 this.getCommonPartClass());
174 * Creates the service context.
176 * @param serviceName the service name
178 * @return the service context< i t, o t>
180 * @throws Exception the exception
182 protected ServiceContext<IT, OT> createServiceContext(String serviceName) throws Exception {
183 ServiceContext<IT, OT> ctx = createServiceContext(
185 (IT)null, // The input part
186 null, // The resource map
187 (UriInfo)null, // The queryParams
188 (Class<?>)null /*input type's Class*/);
192 protected ServiceContext<IT, OT> createServiceContext(String serviceName, UriInfo ui) throws Exception {
193 ServiceContext<IT, OT> ctx = createServiceContext(
195 (IT)null, // The input part
196 null, // The resource map
197 (UriInfo)null, // The queryParams
198 (Class<?>)null /*input type's Class*/);
204 * Creates the service context.
206 * @param serviceName the service name
207 * @param input the input
209 * @return the service context< i t, o t>
211 * @throws Exception the exception
213 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
214 IT input) throws Exception {
215 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
217 null, // The resource map
218 (UriInfo)null, /*queryParams*/
219 (Class<?>)null /*input type's Class*/);
223 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
225 UriInfo uriInfo) throws Exception {
226 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
228 null, // The resource map
229 uriInfo, /*queryParams*/
230 (Class<?>)null /*input type's Class*/);
234 protected ServiceContext<IT, OT> createServiceContext(UriInfo uriInfo) throws Exception {
235 ServiceContext<IT, OT> ctx = createServiceContext(
238 (Class<?>)null /*input type's Class*/);
243 * Creates the service context.
245 * @param input the input
247 * @return the service context< i t, o t>
249 * @throws Exception the exception
251 protected ServiceContext<IT, OT> createServiceContext(IT input) throws Exception {
252 ServiceContext<IT, OT> ctx = createServiceContext(
254 (Class<?>)null /*input type's Class*/);
258 protected ServiceContext<IT, OT> createServiceContext(IT input, UriInfo uriInfo) throws Exception {
259 ServiceContext<IT, OT> ctx = createServiceContext(
262 null ); // The class param/argument
267 * Creates the service context.
269 * @param input the input
270 * @param theClass the the class
272 * @return the service context
274 * @throws Exception the exception
276 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass) throws Exception {
277 ServiceContext<IT, OT> ctx = createServiceContext(
279 (UriInfo)null, //queryParams,
284 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass, UriInfo uriInfo) throws Exception {
285 ServiceContext<IT, OT> ctx = createServiceContext(
292 protected ServiceContext<IT, OT> createServiceContext(
294 ResourceMap resourceMap,
295 UriInfo uriInfo) throws Exception {
296 ServiceContext<IT, OT> ctx = createServiceContext(
298 null, // The input object
301 null /* the class of the input type */);
305 protected ServiceContext<IT, OT> createServiceContext(
307 ResourceMap resourceMap,
308 UriInfo uriInfo) throws Exception {
309 ServiceContext<IT, OT> ctx = createServiceContext(
310 this.getServiceName(),
314 null /* the class of the input type */);
318 protected ServiceContext<IT, OT> createServiceContext(
321 ResourceMap resourceMap,
322 UriInfo uriInfo) throws Exception {
323 ServiceContext<IT, OT> ctx = createServiceContext(
328 null /* the class of the input type */);
333 * Creates the service context.
335 * @param input the input
336 * @param queryParams the query params
337 * @param theClass the the class
339 * @return the service context< i t, o t>
341 * @throws Exception the exception
343 private ServiceContext<IT, OT> createServiceContext(
346 Class<?> theClass) throws Exception {
347 return createServiceContext(this.getServiceName(),
349 null, // The resource map
355 * Creates the service context.
357 * @param serviceName the service name
358 * @param input the input
359 * @param queryParams the query params
360 * @param theClass the the class
362 * @return the service context< i t, o t>
364 * @throws Exception the exception
366 private ServiceContext<IT, OT> createServiceContext(
369 ResourceMap resourceMap,
371 Class<?> theClass) throws Exception {
372 ServiceContext<IT, OT> ctx = getServiceContextFactory().createServiceContext(
377 theClass != null ? theClass.getPackage().getName() : null,
378 theClass != null ? theClass.getName() : null);
379 if (theClass != null) {
380 ctx.setProperty(ServiceContextProperties.ENTITY_CLASS, theClass);
387 * Gets the version string.
389 * @return the version string
391 abstract protected String getVersionString();
396 * @return the version
400 @Produces("application/xml")
401 public Version getVersion() {
402 Version result = new Version();
404 result.setVersionString(getVersionString());
409 public void checkResult(Object resultToCheck, String csid, String serviceMessage) throws CSWebApplicationException {
410 if (resultToCheck == null) {
411 Response response = Response.status(Response.Status.NOT_FOUND).entity(
412 serviceMessage + "csid=" + csid
413 + ": was not found.").type(
414 "text/plain").build();
415 throw new CSWebApplicationException(response);
419 protected void ensureCSID(String csid, String crudType) throws CSWebApplicationException {
420 ensureCSID(csid, crudType, "csid");
423 protected void ensureCSID(String csid, String crudType, String whichCsid) throws CSWebApplicationException {
424 if (logger.isDebugEnabled()) {
425 logger.debug(crudType + " for " + getClass().getName() + " with csid=" + csid);
427 if (csid == null || "".equals(csid)) {
428 logger.error(crudType + " for " + getClass().getName() + " missing csid!");
429 Response response = Response.status(Response.Status.BAD_REQUEST).entity(crudType + " failed on " + getClass().getName() + ' '+whichCsid+'=' + csid).type("text/plain").build();
430 throw new CSWebApplicationException(response);
434 protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg) throws CSWebApplicationException {
435 return bigReThrow(e, serviceMsg, "");
438 protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg, String csid) throws CSWebApplicationException {
439 boolean logException = true;
440 CSWebApplicationException result = null;
442 String detail = Tools.errorToString(e, true);
443 String detailNoTrace = Tools.errorToString(e, true, 3);
445 if (e instanceof UnauthorizedException) {
446 response = Response.status(Response.Status.UNAUTHORIZED).entity(serviceMsg + e.getMessage()).type("text/plain").build();
447 result = new CSWebApplicationException(e, response);
449 } else if (e instanceof DocumentNotFoundException) {
451 // Don't log this error unless we're in 'trace' mode
453 logException = false;
454 response = Response.status(Response.Status.NOT_FOUND).entity(serviceMsg + " on " + getClass().getName() + " csid=" + csid).type("text/plain").build();
455 result = new CSWebApplicationException(e, response);
457 } else if (e instanceof TransactionException) {
458 int code = ((TransactionException) e).getErrorCode();
459 response = Response.status(code).entity(e.getMessage()).type("text/plain").build();
460 result = new CSWebApplicationException(e, response);
462 } else if (e instanceof BadRequestException) {
463 int code = ((BadRequestException) e).getErrorCode();
465 code = Response.Status.BAD_REQUEST.getStatusCode();
468 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
469 // return new WebApplicationException(e, code);
470 result = new CSWebApplicationException(e, response);
472 } else if (e instanceof DocumentException) {
473 int code = ((DocumentException) e).getErrorCode();
475 code = Response.Status.BAD_REQUEST.getStatusCode();
478 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
479 // return new WebApplicationException(e, code);
480 result = new CSWebApplicationException(e, response);
482 } else if (e instanceof CSWebApplicationException) {
483 // subresource may have already thrown this exception
484 // so just pass it on
485 result = (CSWebApplicationException) e;
487 } else { // e is now instanceof Exception
488 response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(serviceMsg + " detail: " + detailNoTrace).type("text/plain").build();
489 result = new CSWebApplicationException(e, response);
492 // Some exceptions like DocumentNotFoundException won't be logged unless we're in 'trace' mode
494 boolean traceEnabled = logger.isTraceEnabled();
495 if (logException == true || traceEnabled == true) {
496 if (traceEnabled == true) {
497 logger.error(getClass().getName() + " detail: " + detail, e);
499 logger.error(getClass().getName() + " detail: " + detailNoTrace);
507 public boolean allowAnonymousAccess(HttpRequest request,
508 Class<?> resourceClass) {