]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
893c4e0be253cded5e9d5aff562e4bf5d5df80e8
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
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.
23  */
24 package org.collectionspace.services.common;
25
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.ws.rs.GET;
31 import javax.ws.rs.Path;
32 import javax.ws.rs.Produces;
33 import javax.ws.rs.core.Context;
34 import javax.ws.rs.core.MultivaluedMap;
35 import javax.ws.rs.core.Response;
36 import javax.ws.rs.core.UriInfo;
37
38 import org.collectionspace.services.client.CollectionSpaceClient;
39 import org.collectionspace.services.common.CSWebApplicationException;
40 import org.collectionspace.services.common.api.Tools;
41 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
42 import org.collectionspace.services.common.context.MultipartServiceContext;
43 import org.collectionspace.services.common.context.ServiceContext;
44 import org.collectionspace.services.common.context.ServiceContextProperties;
45 import org.collectionspace.services.common.document.BadRequestException;
46 import org.collectionspace.services.common.document.DocumentException;
47 import org.collectionspace.services.common.document.DocumentHandler;
48 import org.collectionspace.services.common.document.DocumentNotFoundException;
49 import org.collectionspace.services.common.document.TransactionException;
50 import org.collectionspace.services.common.repository.RepositoryClient;
51 import org.collectionspace.services.common.repository.RepositoryClientFactory;
52 import org.collectionspace.services.common.security.UnauthorizedException;
53 import org.collectionspace.services.common.storage.StorageClient;
54 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
55 import org.collectionspace.services.config.service.ServiceBindingType;
56 import org.collectionspace.services.description.ServiceDescription;
57 import org.jboss.resteasy.spi.HttpRequest;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 /**
62  * The Class AbstractCollectionSpaceResourceImpl.
63  *
64  * @param <IT> the generic type
65  * @param <OT> the generic type
66  */
67 public abstract class AbstractCollectionSpaceResourceImpl<IT, OT>
68         implements CollectionSpaceResource<IT, OT> {
69
70     protected final Logger logger = LoggerFactory.getLogger(this.getClass());
71
72     protected final ServiceContext<IT, OT> NULL_CONTEXT = null;
73     // Fields for default client factory and client
74     /** The repository client factory. */
75     private RepositoryClientFactory<IT, OT> repositoryClientFactory;
76     
77     /** The repository client. */
78     private RepositoryClient<IT, OT> repositoryClient;
79     
80     /** The storage client. */
81     private StorageClient storageClient;
82     
83     /**
84      * Extract id.
85      *
86      * @param res the res
87      * @return the string
88      */
89     protected static String extractId(Response res) {
90         MultivaluedMap<String, Object> mvm = res.getMetadata();
91         String uri = (String) ((List<Object>) mvm.get("Location")).get(0);
92         String[] segments = uri.split("/");
93         String id = segments[segments.length - 1];
94         return id;
95     }
96             
97     /**
98      * Instantiates a new abstract collection space resource.
99      */
100     public AbstractCollectionSpaceResourceImpl() {
101         repositoryClientFactory = (RepositoryClientFactory<IT, OT>) RepositoryClientFactory.getInstance();
102     }
103
104     /* (non-Javadoc)
105      * @see org.collectionspace.services.common.CollectionSpaceResource#getServiceName()
106      */
107     @Override
108     abstract public String getServiceName();
109
110
111     /* (non-Javadoc)
112      * @see org.collectionspace.services.common.CollectionSpaceResource#getRepositoryClient(org.collectionspace.services.common.context.ServiceContext)
113      */
114     @Override
115     synchronized public RepositoryClient<IT, OT> getRepositoryClient(ServiceContext<IT, OT> ctx) {
116         if (repositoryClient != null){
117             return repositoryClient;
118         }
119         repositoryClient = repositoryClientFactory.getClient(ctx.getRepositoryClientName());
120         return repositoryClient;
121     }
122
123     /* (non-Javadoc)
124      * @see org.collectionspace.services.common.CollectionSpaceResource#getStorageClient(org.collectionspace.services.common.context.ServiceContext)
125      */
126     @Override
127     synchronized public StorageClient getStorageClient(ServiceContext<IT, OT> ctx) {
128         if(storageClient != null) {
129             return storageClient;
130         }
131         storageClient = new JpaStorageClientImpl();
132         return storageClient;
133     }
134     
135     /* (non-Javadoc)
136      * @see org.collectionspace.services.common.CollectionSpaceResource#createDocumentHandler(org.collectionspace.services.common.context.ServiceContext)
137      */
138     @Override
139     public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx) throws Exception {
140         DocumentHandler docHandler = createDocumentHandler(ctx, ctx.getInput());
141         return docHandler;
142     }
143     
144     /**
145      * Creates the document handler.
146      * 
147      * @param ctx the ctx
148      * @param commonPart the common part
149      * 
150      * @return the document handler
151      * 
152      * @throws Exception the exception
153      */
154     public DocumentHandler createDocumentHandler(ServiceContext<IT, OT> ctx,
155                 Object commonPart) throws Exception {
156         DocumentHandler docHandler = ctx.getDocumentHandler();
157         docHandler.setCommonPart(commonPart);
158         return docHandler;
159     }    
160     
161     /**
162      * Creates the service context.
163      * 
164      * @return the service context< i t, o t>
165      * 
166      * @throws Exception the exception
167      */
168     protected ServiceContext<IT, OT> createServiceContext() throws Exception {          
169         ServiceContext<IT, OT> ctx = createServiceContext(this.getServiceName(),
170                         (IT)null, //inputType
171                         null, // The resource map
172                         (UriInfo)null, // The query params
173                         this.getCommonPartClass());
174         return ctx;
175     }    
176     
177     /**
178      * Creates the service context.
179      * 
180      * @param serviceName the service name
181      * 
182      * @return the service context< i t, o t>
183      * 
184      * @throws Exception the exception
185      */
186     protected ServiceContext<IT, OT> createServiceContext(String serviceName) throws Exception {        
187         ServiceContext<IT, OT> ctx = createServiceContext(
188                         serviceName,
189                         (IT)null, // The input part
190                         null, // The resource map
191                         (UriInfo)null, // The queryParams
192                         (Class<?>)null  /*input type's Class*/);
193         return ctx;
194     }
195     
196     protected ServiceContext<IT, OT> createServiceContext(String serviceName, UriInfo ui) throws Exception {            
197         ServiceContext<IT, OT> ctx = createServiceContext(
198                         serviceName,
199                         (IT)null, // The input part
200                         null, // The resource map
201                         (UriInfo)null, // The queryParams
202                         (Class<?>)null  /*input type's Class*/);
203         ctx.setUriInfo(ui);
204         return ctx;
205     }    
206     
207     /**
208      * Creates the service context.
209      * 
210      * @param serviceName the service name
211      * @param input the input
212      * 
213      * @return the service context< i t, o t>
214      * 
215      * @throws Exception the exception
216      */
217     protected ServiceContext<IT, OT> createServiceContext(String serviceName,
218                 IT input) throws Exception {            
219         ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
220                         input,
221                         null, // The resource map
222                         (UriInfo)null, /*queryParams*/
223                         (Class<?>)null  /*input type's Class*/);
224         return ctx;
225     }
226     
227     protected ServiceContext<IT, OT> createServiceContext(String serviceName,
228                 IT input,
229                 UriInfo uriInfo) throws Exception {     
230         ServiceContext<IT, OT> ctx = createServiceContext(serviceName,
231                         input,
232                         null, // The resource map
233                         uriInfo, /*queryParams*/
234                         (Class<?>)null  /*input type's Class*/);
235         return ctx;
236     }
237     
238     protected ServiceContext<IT, OT> createServiceContext(UriInfo uriInfo) throws Exception {
239         ServiceContext<IT, OT> ctx = createServiceContext(
240                         (IT)null, /*input*/
241                         uriInfo,
242                         (Class<?>)null  /*input type's Class*/);
243         return ctx;
244     }
245
246     /**
247      * Creates the service context.
248      * 
249      * @param input the input
250      * 
251      * @return the service context< i t, o t>
252      * 
253      * @throws Exception the exception
254      */
255     protected ServiceContext<IT, OT> createServiceContext(IT input) throws Exception {          
256         ServiceContext<IT, OT> ctx = createServiceContext(
257                         input,
258                         (Class<?>)null /*input type's Class*/);
259         return ctx;
260     }
261     
262     protected ServiceContext<IT, OT> createServiceContext(IT input, UriInfo uriInfo) throws Exception {         
263         ServiceContext<IT, OT> ctx = createServiceContext(
264                         input,
265                         uriInfo,
266                         null ); // The class param/argument
267         return ctx;
268     }    
269     
270     /**
271      * Creates the service context.
272      * 
273      * @param input the input
274      * @param theClass the the class
275      * 
276      * @return the service context
277      * 
278      * @throws Exception the exception
279      */
280     protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass) throws Exception {       
281         ServiceContext<IT, OT> ctx = createServiceContext(
282                         input,
283                         (UriInfo)null, //queryParams,
284                         theClass);
285         return ctx;
286     }
287     
288     protected ServiceContext<IT, OT> createServiceContext(IT input, Class<?> theClass, UriInfo uriInfo) throws Exception {      
289         ServiceContext<IT, OT> ctx = createServiceContext(
290                         input,
291                         uriInfo,
292                         theClass);
293         return ctx;
294     }
295     
296     protected ServiceContext<IT, OT> createServiceContext(
297                 String serviceName,
298                 ResourceMap resourceMap,
299                 UriInfo uriInfo) throws Exception {
300         ServiceContext<IT, OT> ctx = createServiceContext(
301                         serviceName,
302                         null, // The input object
303                         resourceMap,
304                         uriInfo,
305                         null /* the class of the input type */);
306         return ctx;
307     }
308         
309     protected ServiceContext<IT, OT> createServiceContext(
310                 IT input,
311                 ResourceMap resourceMap,
312                 UriInfo uriInfo) throws Exception {
313         ServiceContext<IT, OT> ctx = createServiceContext(
314                         this.getServiceName(),
315                         input,
316                         resourceMap,
317                         uriInfo,
318                         null /* the class of the input type */);
319         return ctx;
320     }
321     
322     protected ServiceContext<IT, OT> createServiceContext(
323                 String serviceName,
324                 IT input,
325                 ResourceMap resourceMap,
326                 UriInfo uriInfo) throws Exception {
327         ServiceContext<IT, OT> ctx = createServiceContext(
328                         serviceName,
329                         input,
330                         resourceMap,
331                         uriInfo,
332                         null /* the class of the input type */);
333         return ctx;
334     }
335         
336     /**
337      * Creates the service context.
338      * 
339      * @param input the input
340      * @param queryParams the query params
341      * @param theClass the the class
342      * 
343      * @return the service context< i t, o t>
344      * 
345      * @throws Exception the exception
346      */
347     private ServiceContext<IT, OT> createServiceContext(
348                 IT input,
349                 UriInfo uriInfo,
350                 Class<?> theClass) throws Exception {
351         return createServiceContext(this.getServiceName(),
352                         input,
353                         null, // The resource map
354                         uriInfo,
355                         theClass);
356     }
357
358     /**
359      * Creates the service context.
360      * 
361      * @param serviceName the service name
362      * @param input the input
363      * @param queryParams the query params
364      * @param theClass the the class
365      * 
366      * @return the service context< i t, o t>
367      * 
368      * @throws Exception the exception
369      */
370     private ServiceContext<IT, OT> createServiceContext(
371                 String serviceName,
372                 IT input,
373                 ResourceMap resourceMap,
374                 UriInfo uriInfo,
375                 Class<?> theClass) throws Exception {
376         ServiceContext<IT, OT> ctx = getServiceContextFactory().createServiceContext(
377                         serviceName,
378                         input,
379                         resourceMap,
380                         uriInfo,
381                         theClass != null ? theClass.getPackage().getName() : null,
382                         theClass != null ? theClass.getName() : null);
383         if (theClass != null) {
384             ctx.setProperty(ServiceContextProperties.ENTITY_CLASS, theClass);
385         }
386         
387         return ctx;
388     }
389         
390     /**
391      * Gets the version string.
392      * 
393      * @return the version string
394      */
395     abstract protected String getVersionString();
396     
397     /**
398      * Gets the version.
399      * 
400      * @return the version
401      */
402     @GET
403     @Path("/version")    
404     @Produces("application/xml")
405     public Version getVersion() {
406         Version result = new Version();
407         
408         result.setVersionString(getVersionString());
409         
410         return result;
411     }
412     
413     /*
414      * Get the service description
415      */
416     @GET
417     @Path(CollectionSpaceClient.SERVICE_DESCRIPTION_PATH)
418     public ServiceDescription getDescription(@Context UriInfo uriInfo) {
419         ServiceDescription result = null;
420
421         ServiceContext  ctx = null;
422         try {
423             ctx = createServiceContext(uriInfo);
424             result = getDescription(ctx);
425         } catch (Exception e) {
426                 String errMsg = String.format("Request to get service description information for the '%s' service failed.",
427                                 this.getServiceContextFactory());
428             throw bigReThrow(e, errMsg);
429         }
430         
431         return result;
432     }
433     
434     /**
435      * Each resource can override this method if they need to.
436      * 
437      * @param ctx
438      * @return
439      */
440     public ServiceDescription getDescription(ServiceContext ctx) {
441         ServiceDescription result = new ServiceDescription();
442         
443         result.setDocumentType(getDocType(ctx.getTenantId()));
444         
445         return result;
446     }    
447
448     public void checkResult(Object resultToCheck, String csid, String serviceMessage) throws CSWebApplicationException {
449         if (resultToCheck == null) {
450             Response response = Response.status(Response.Status.NOT_FOUND).entity(
451                     serviceMessage + "csid=" + csid
452                     + ": was not found.").type(
453                     "text/plain").build();
454             throw new CSWebApplicationException(response);
455         }
456     }
457
458     protected void ensureCSID(String csid, String crudType) throws CSWebApplicationException {
459         ensureCSID(csid, crudType, "csid");
460     }
461
462     protected void ensureCSID(String csid, String crudType, String whichCsid) throws CSWebApplicationException {
463            if (logger.isDebugEnabled()) {
464                logger.debug(crudType + " for " + getClass().getName() + " with csid=" + csid);
465            }
466            if (csid == null || "".equals(csid)) {
467                logger.error(crudType + " for " + getClass().getName() + " missing csid!");
468                Response response = Response.status(Response.Status.BAD_REQUEST).entity(crudType + " failed on " + getClass().getName() + ' '+whichCsid+'=' + csid).type("text/plain").build();
469                throw new CSWebApplicationException(response);
470            }
471        }
472
473     protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg) throws CSWebApplicationException {
474         return bigReThrow(e, serviceMsg, "");
475     }
476
477     protected CSWebApplicationException bigReThrow(Exception e, String serviceMsg, String csid) throws CSWebApplicationException {
478         boolean logException = true;
479         CSWebApplicationException result = null;
480         Response response;
481         String detail = Tools.errorToString(e, true);
482         String detailNoTrace = Tools.errorToString(e, true, 3);
483         
484         if (e instanceof UnauthorizedException) {
485             response = Response.status(Response.Status.UNAUTHORIZED).entity(serviceMsg + e.getMessage()).type("text/plain").build();
486             result = new CSWebApplicationException(e, response);
487
488         } else if (e instanceof DocumentNotFoundException) {
489                 //
490                 // Don't log this error unless we're in 'trace' mode
491                 //
492                 logException = false;
493             response = Response.status(Response.Status.NOT_FOUND).entity(serviceMsg + " on " + getClass().getName() + " csid=" + csid).type("text/plain").build();
494             result = new CSWebApplicationException(e, response);
495             
496         } else if (e instanceof TransactionException) {
497             int code = ((TransactionException) e).getErrorCode();
498             response = Response.status(code).entity(e.getMessage()).type("text/plain").build();
499             result = new CSWebApplicationException(e, response);
500
501         } else if (e instanceof BadRequestException) {
502             int code = ((BadRequestException) e).getErrorCode();
503             if (code == 0) {
504                 code = Response.Status.BAD_REQUEST.getStatusCode();
505             }
506             // CSPACE-1110
507             response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
508             // return new WebApplicationException(e, code);
509             result = new CSWebApplicationException(e, response);
510
511         } else if (e instanceof DocumentException) {
512             int code = ((DocumentException) e).getErrorCode();
513             if (code == 0){
514                code = Response.Status.BAD_REQUEST.getStatusCode();
515             }
516             // CSPACE-1110
517             response = Response.status(code).entity(serviceMsg + e.getMessage()).type("text/plain").build();
518             // return new WebApplicationException(e, code);
519             result = new CSWebApplicationException(e, response);
520            
521         } else if (e instanceof CSWebApplicationException) {
522             // subresource may have already thrown this exception
523             // so just pass it on
524             result = (CSWebApplicationException) e;
525
526         } else { // e is now instanceof Exception
527             response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(serviceMsg + " detail: " + detailNoTrace).type("text/plain").build();
528             result = new CSWebApplicationException(e, response);
529         }
530         //
531         // Some exceptions like DocumentNotFoundException won't be logged unless we're in 'trace' mode
532         //
533         boolean traceEnabled = logger.isTraceEnabled();
534         if (logException == true || traceEnabled == true) {
535                 if (traceEnabled == true) {
536                         logger.error(getClass().getName() + " detail: " + detail, e);
537                 } else {
538                         logger.error(getClass().getName() + " detail: " + detailNoTrace);
539                 }
540         }
541         
542         return result;
543     }
544     
545         @Override
546         public boolean allowAnonymousAccess(HttpRequest request,
547                         Class<?> resourceClass) {
548                 return false;
549         }
550         
551     /**
552      * Returns a UriRegistry entry: a map of tenant-qualified URI templates
553      * for the current resource, for all tenants
554      * 
555      * @return a map of URI templates for the current resource, for all tenants
556      */
557     public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries() {
558         Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
559                 new HashMap<UriTemplateRegistryKey,StoredValuesUriTemplate>();
560         List<String> tenantIds = getTenantBindingsReader().getTenantIds();
561         for (String tenantId : tenantIds) {
562                 uriRegistryEntriesMap.putAll(getUriRegistryEntries(tenantId, getDocType(tenantId), UriTemplateFactory.RESOURCE));
563         }
564         return uriRegistryEntriesMap;
565     }
566     
567     /**
568      * Returns a resource's document type.
569      * 
570      * @param tenantId
571      * @return
572      */
573     @Override
574     public String getDocType(String tenantId) {
575         return getDocType(tenantId, getServiceName());
576     }
577
578     /**
579      * Returns the document type associated with a specified service, within a specified tenant.
580      * 
581      * @param tenantId a tenant ID
582      * @param serviceName a service name
583      * @return the Nuxeo document type associated with that service and tenant.
584      */
585     // FIXME: This method may properly belong in a different services package or class.
586     // Also, we need to check for any existing methods that may duplicate this one.
587     protected String getDocType(String tenantId, String serviceName) {
588         String docType = "";
589         if (Tools.isBlank(tenantId)) {
590             return docType;
591         }
592         ServiceBindingType sb = getTenantBindingsReader().getServiceBinding(tenantId, serviceName);
593         if (sb == null) {
594             return docType;
595         }
596         docType = sb.getObject().getName(); // Reads the Document Type from tenant bindings configuration
597         return docType;
598     }
599
600         /**
601      * Returns a UriRegistry entry: a map of tenant-qualified URI templates
602      * for the current resource, for a specified tenants
603      * 
604      * @return a map of URI templates for the current resource, for a specified tenant
605      */
606     @Override
607     public Map<UriTemplateRegistryKey,StoredValuesUriTemplate> getUriRegistryEntries(String tenantId,
608             String docType, UriTemplateFactory.UriTemplateType type) {
609         Map<UriTemplateRegistryKey,StoredValuesUriTemplate> uriRegistryEntriesMap =
610                 new HashMap<UriTemplateRegistryKey,StoredValuesUriTemplate>();
611         UriTemplateRegistryKey key;
612         if (Tools.isBlank(tenantId) || Tools.isBlank(docType)) {
613             return uriRegistryEntriesMap;
614         }
615         key = new UriTemplateRegistryKey();
616         key.setTenantId(tenantId);
617         key.setDocType(docType); 
618         uriRegistryEntriesMap.put(key, getUriTemplate(type));
619         return uriRegistryEntriesMap;
620     }
621     
622     /**
623      * Returns a URI template of the appropriate type, populated with the
624      * current service name as one of its stored values.
625      *      * 
626      * @param type a URI template type
627      * @return a URI template of the appropriate type.
628      */
629     @Override
630     public StoredValuesUriTemplate getUriTemplate(UriTemplateFactory.UriTemplateType type) {
631         Map<String,String> storedValuesMap = new HashMap<String,String>();
632         storedValuesMap.put(UriTemplateFactory.SERVICENAME_VAR, getServiceName());
633         StoredValuesUriTemplate template =
634                 UriTemplateFactory.getURITemplate(type, storedValuesMap);
635         return template;
636     }
637
638     /**
639      * Returns a reader for reading values from tenant bindings configuration
640      * 
641      * @return a tenant bindings configuration reader
642      */
643     @Override
644     public TenantBindingConfigReaderImpl getTenantBindingsReader() {
645         return ServiceMain.getInstance().getTenantBindingConfigReader();
646     }
647         
648 }