2 * This document is a part of the source code and related artifacts
\r
3 * for CollectionSpace, an open source collections management system
\r
4 * for museums and related institutions:
\r
6 * http://www.collectionspace.org
\r
7 * http://wiki.collectionspace.org
\r
9 * Copyright 2009 University of California at Berkeley
\r
11 * Licensed under the Educational Community License (ECL), Version 2.0.
\r
12 * You may not use this file except in compliance with this License.
\r
14 * You may obtain a copy of the ECL 2.0 License at
\r
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
\r
18 * Unless required by applicable law or agreed to in writing, software
\r
19 * distributed under the License is distributed on an "AS IS" BASIS,
\r
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
21 * See the License for the specific language governing permissions and
\r
22 * limitations under the License.
\r
24 package org.collectionspace.services.common;
\r
26 import java.util.List;
\r
28 import javax.ws.rs.GET;
\r
29 import javax.ws.rs.Path;
\r
30 import javax.ws.rs.Produces;
\r
31 import javax.ws.rs.WebApplicationException;
\r
32 import javax.ws.rs.core.MultivaluedMap;
\r
33 import javax.ws.rs.core.Response;
\r
34 import javax.ws.rs.core.UriInfo;
\r
36 import org.collectionspace.services.common.api.Tools;
\r
37 import org.collectionspace.services.common.context.ServiceContext;
\r
38 import org.collectionspace.services.common.context.ServiceContextProperties;
\r
39 import org.collectionspace.services.common.document.BadRequestException;
\r
40 import org.collectionspace.services.common.document.DocumentException;
\r
41 import org.collectionspace.services.common.document.DocumentHandler;
\r
42 import org.collectionspace.services.common.document.DocumentNotFoundException;
\r
43 import org.collectionspace.services.common.document.TransactionException;
\r
44 import org.collectionspace.services.common.repository.RepositoryClient;
\r
45 import org.collectionspace.services.common.repository.RepositoryClientFactory;
\r
46 import org.collectionspace.services.common.security.UnauthorizedException;
\r
47 import org.collectionspace.services.common.storage.StorageClient;
\r
48 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
\r
49 import org.jboss.resteasy.client.ClientResponse;
\r
50 import org.slf4j.Logger;
\r
51 import org.slf4j.LoggerFactory;
\r
54 * The Class AbstractCollectionSpaceResourceImpl.
\r
56 * @param <IT> the generic type
\r
57 * @param <OT> the generic type
\r
59 public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
\r
60 implements CollectionSpaceResource<IT, OT> {
\r
62 protected final Logger logger = LoggerFactory.getLogger(this.getClass());
\r
65 // Fields for default client factory and client
\r
66 /** The repository client factory. */
\r
67 private RepositoryClientFactory repositoryClientFactory;
\r
69 /** The repository client. */
\r
70 private RepositoryClient repositoryClient;
\r
72 /** The storage client. */
\r
73 private StorageClient storageClient;
\r
78 * @param res the res
\r
79 * @return the string
\r
81 protected static String extractId(Response res) {
\r
82 MultivaluedMap<String, Object> mvm = res.getMetadata();
\r
83 String uri = (String) ((List<Object>) mvm.get("Location")).get(0);
\r
84 String[] segments = uri.split("/");
\r
85 String id = segments[segments.length - 1];
\r
90 * Instantiates a new abstract collection space resource.
\r
92 public AbstractCollectionSpaceResourceImpl() {
\r
93 repositoryClientFactory = RepositoryClientFactory.getInstance();
\r
97 * @see org.collectionspace.services.common.CollectionSpaceResource#getServiceName()
\r
100 abstract public String getServiceName();
\r
104 * @see org.collectionspace.services.common.CollectionSpaceResource#getRepositoryClient(org.collectionspace.services.common.context.ServiceContext)
\r
107 synchronized public RepositoryClient getRepositoryClient(ServiceContext<IT, OT> ctx) {
\r
108 if(repositoryClient != null){
\r
109 return repositoryClient;
\r
111 repositoryClient = repositoryClientFactory.getClient(ctx.getRepositoryClientName());
\r
112 return repositoryClient;
\r
116 * @see org.collectionspace.services.common.CollectionSpaceResource#getStorageClient(org.collectionspace.services.common.context.ServiceContext)
\r
119 synchronized public StorageClient getStorageClient(ServiceContext<IT, OT> ctx) {
\r
120 if(storageClient != null) {
\r
121 return storageClient;
\r
123 storageClient = new JpaStorageClientImpl();
\r
124 return storageClient;
\r
128 * @see org.collectionspace.services.common.CollectionSpaceResource#createDocumentHandler(org.collectionspace.services.common.context.ServiceContext)
\r
131 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx) throws Exception {
\r
132 DocumentHandler docHandler = createDocumentHandler(ctx, ctx.getInput());
\r
137 * Creates the document handler.
\r
139 * @param ctx the ctx
\r
140 * @param commonPart the common part
\r
142 * @return the document handler
\r
144 * @throws Exception the exception
\r
146 public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx,
\r
147 Object commonPart) throws Exception {
\r
148 DocumentHandler docHandler = ctx.getDocumentHandler();
\r
149 docHandler.setCommonPart(commonPart);
\r
154 * Creates the service context.
\r
156 * @return the service context< i t, o t>
\r
158 * @throws Exception the exception
\r
160 protected ServiceContext<IT, OT> createServiceContext() throws Exception {
\r
161 ServiceContext<IT, OT> ctx = createServiceContext(this.getServiceName(),
\r
162 (IT)null, //inputType
\r
163 null, // The resource map
\r
164 (UriInfo)null, // The query params
\r
165 this.getCommonPartClass());
\r
170 * Creates the service context.
\r
172 * @param serviceName the service name
\r
174 * @return the service context< i t, o t>
\r
176 * @throws Exception the exception
\r
178 protected ServiceContext<IT, OT> createServiceContext(String serviceName) throws Exception {
\r
179 ServiceContext<IT, OT> ctx = createServiceContext(
\r
181 (IT)null, // The input part
\r
182 null, // The resource map
\r
183 (UriInfo)null, // The queryParams
\r
184 (Class<?>)null /*input type's Class*/);
\r
188 protected ServiceContext<IT, OT> createServiceContext(String serviceName, UriInfo ui) throws Exception {
\r
189 ServiceContext<IT, OT> ctx = createServiceContext(
\r
191 (IT)null, // The input part
\r
192 null, // The resource map
\r
193 (UriInfo)null, // The queryParams
\r
194 (Class<?>)null /*input type's Class*/);
\r
195 ctx.setUriInfo(ui);
\r
200 * Creates the service context.
\r
202 * @param serviceName the service name
\r
203 * @param input the input
\r
205 * @return the service context< i t, o t>
\r
207 * @throws Exception the exception
\r
209 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
\r
210 IT input) throws Exception {
\r
211 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
\r
213 null, // The resource map
\r
214 (UriInfo)null, /*queryParams*/
\r
215 (Class<?>)null /*input type's Class*/);
\r
219 protected ServiceContext<IT, OT> createServiceContext(String serviceName,
\r
221 UriInfo uriInfo) throws Exception {
\r
222 ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
\r
224 null, // The resource map
\r
225 uriInfo, /*queryParams*/
\r
226 (Class<?>)null /*input type's Class*/);
\r
230 protected ServiceContext<IT, OT> createServiceContext(UriInfo uriInfo) throws Exception {
\r
231 ServiceContext<IT, OT> ctx = createServiceContext(
\r
232 (IT)null, /*input*/
\r
234 (Class<?>)null /*input type's Class*/);
\r
239 * Creates the service context.
\r
241 * @param input the input
\r
243 * @return the service context< i t, o t>
\r
245 * @throws Exception the exception
\r
247 protected ServiceContext<IT, OT> createServiceContext(IT input) throws Exception {
\r
248 ServiceContext<IT, OT> ctx = createServiceContext(
\r
250 (Class<?>)null /*input type's Class*/);
\r
254 protected ServiceContext<IT, OT> createServiceContext(IT input, UriInfo uriInfo) throws Exception {
\r
255 ServiceContext<IT, OT> ctx = createServiceContext(
\r
258 null ); // The class param/argument
\r
263 * Creates the service context.
\r
265 * @param input the input
\r
266 * @param theClass the the class
\r
268 * @return the service context
\r
270 * @throws Exception the exception
\r
272 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass) throws Exception {
\r
273 ServiceContext<IT, OT> ctx = createServiceContext(
\r
275 (UriInfo)null, //queryParams,
\r
280 protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass, UriInfo uriInfo) throws Exception {
\r
281 ServiceContext<IT, OT> ctx = createServiceContext(
\r
288 protected ServiceContext<IT, OT> createServiceContext(
\r
289 String serviceName,
\r
290 ResourceMap resourceMap,
\r
291 UriInfo uriInfo) throws Exception {
\r
292 ServiceContext<IT, OT> ctx = createServiceContext(
\r
294 null, // The input object
\r
297 null /* the class of the input type */);
\r
301 protected ServiceContext<IT, OT> createServiceContext(
\r
303 ResourceMap resourceMap,
\r
304 UriInfo uriInfo) throws Exception {
\r
305 ServiceContext<IT, OT> ctx = createServiceContext(
\r
306 this.getServiceName(),
\r
310 null /* the class of the input type */);
\r
314 protected ServiceContext<IT, OT> createServiceContext(
\r
315 String serviceName,
\r
317 ResourceMap resourceMap,
\r
318 UriInfo uriInfo) throws Exception {
\r
319 ServiceContext<IT, OT> ctx = createServiceContext(
\r
324 null /* the class of the input type */);
\r
329 * Creates the service context.
\r
331 * @param input the input
\r
332 * @param queryParams the query params
\r
333 * @param theClass the the class
\r
335 * @return the service context< i t, o t>
\r
337 * @throws Exception the exception
\r
339 private ServiceContext<IT, OT> createServiceContext(
\r
342 Class<?> theClass) throws Exception {
\r
343 return createServiceContext(this.getServiceName(),
\r
345 null, // The resource map
\r
351 * Creates the service context.
\r
353 * @param serviceName the service name
\r
354 * @param input the input
\r
355 * @param queryParams the query params
\r
356 * @param theClass the the class
\r
358 * @return the service context< i t, o t>
\r
360 * @throws Exception the exception
\r
362 private ServiceContext<IT, OT> createServiceContext(
\r
363 String serviceName,
\r
365 ResourceMap resourceMap,
\r
367 Class<?> theClass) throws Exception {
\r
368 ServiceContext<IT, OT> ctx = getServiceContextFactory().createServiceContext(
\r
373 theClass != null ? theClass.getPackage().getName() : null,
\r
374 theClass != null ? theClass.getName() : null);
\r
375 if (theClass != null) {
\r
376 ctx.setProperty(ServiceContextProperties.ENTITY_CLASS, theClass);
\r
383 * Gets the version string.
\r
385 * @return the version string
\r
387 abstract protected String getVersionString();
\r
390 * Gets the version.
\r
392 * @return the version
\r
396 @Produces("application/xml")
\r
397 public Version getVersion() {
\r
398 Version result = new Version();
\r
400 result.setVersionString(getVersionString());
\r
405 public void checkResult(Object resultToCheck, String csid, String serviceMessage) throws WebApplicationException {
\r
406 if (resultToCheck == null) {
\r
407 Response response = Response.status(Response.Status.NOT_FOUND).entity(
\r
408 serviceMessage + "csid=" + csid
\r
409 + ": was not found.").type(
\r
410 "text/plain").build();
\r
411 throw new WebApplicationException(response);
\r
415 protected void ensureCSID(String csid, String crudType) throws WebApplicationException {
\r
416 ensureCSID(csid, crudType, "csid");
\r
419 protected void ensureCSID(String csid, String crudType, String whichCsid) throws WebApplicationException {
\r
420 if (logger.isDebugEnabled()) {
\r
421 logger.debug(crudType + " for " + getClass().getName() + " with csid=" + csid);
\r
423 if (csid == null || "".equals(csid)) {
\r
424 logger.error(crudType + " for " + getClass().getName() + " missing csid!");
\r
425 Response response = Response.status(Response.Status.BAD_REQUEST).entity(crudType + " failed on " + getClass().getName() + ' '+whichCsid+'=' + csid).type("text/plain").build();
\r
426 throw new WebApplicationException(response);
\r
430 protected WebApplicationException bigReThrow(Exception e, String serviceMsg) throws WebApplicationException {
\r
431 return bigReThrow(e, serviceMsg, "");
\r
434 protected WebApplicationException bigReThrow(Exception e, String serviceMsg, String csid) throws WebApplicationException {
\r
435 boolean logException = true;
\r
436 WebApplicationException result = null;
\r
439 String detail = Tools.errorToString(e, true);
\r
440 String detailNoTrace = Tools.errorToString(e, true, 3);
\r
441 if (e instanceof UnauthorizedException) {
\r
442 response = Response.status(Response.Status.UNAUTHORIZED).entity(serviceMsg + e.getMessage()).type("text/plain").build();
\r
443 result = new WebApplicationException(response);
\r
445 } else if (e instanceof DocumentNotFoundException) {
\r
447 // Don't log this error unless we're in 'trace' mode
\r
449 logException = false;
\r
450 response = Response.status(Response.Status.NOT_FOUND).entity(serviceMsg + " on " + getClass().getName() + " csid=" + csid).type("text/plain").build();
\r
451 result = new WebApplicationException(response);
\r
453 } else if (e instanceof TransactionException) {
\r
454 int code = ((TransactionException) e).getErrorCode();
\r
455 response = Response.status(code).entity(e.getMessage()).type("text/plain").build();
\r
456 result = new WebApplicationException(response);
\r
458 } else if (e instanceof BadRequestException) {
\r
459 int code = ((BadRequestException) e).getErrorCode();
\r
461 code = Response.Status.BAD_REQUEST.getStatusCode();
\r
464 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
\r
465 // return new WebApplicationException(e, code);
\r
466 result = new WebApplicationException(response);
\r
468 } else if (e instanceof DocumentException) {
\r
469 int code = ((DocumentException) e).getErrorCode();
\r
471 code = Response.Status.BAD_REQUEST.getStatusCode();
\r
474 response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
\r
475 // return new WebApplicationException(e, code);
\r
476 result = new WebApplicationException(response);
\r
478 } else if (e instanceof WebApplicationException) {
\r
479 // subresource may have already thrown this exception
\r
480 // so just pass it on
\r
481 result = (WebApplicationException) e;
\r
483 } else { // e is now instanceof Exception
\r
484 response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(serviceMsg + " detail: " + detailNoTrace).type("text/plain").build();
\r
485 result = new WebApplicationException(response);
\r
488 // Some exceptions like DocumentNotFoundException won't be logged unless we're in 'trace' mode
\r
490 boolean traceEnabled = logger.isTraceEnabled();
\r
491 if (logException == true || traceEnabled == true) {
\r
492 if (traceEnabled == true) {
\r
493 logger.error(getClass().getName() + " detail: " + detail, e);
\r
495 logger.error(getClass().getName() + " detail: " + detailNoTrace);
\r