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.context;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
30 import javax.ws.rs.core.MultivaluedMap;
31 import javax.ws.rs.core.UriInfo;
33 import org.collectionspace.services.client.IQueryManager;
34 import org.collectionspace.services.client.workflow.WorkflowClient;
35 import org.collectionspace.services.common.ClientType;
36 import org.collectionspace.services.common.ServiceMain;
37 import org.collectionspace.services.common.config.PropertyItemUtils;
38 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
39 import org.collectionspace.services.common.document.DocumentHandler;
40 import org.collectionspace.services.common.document.DocumentFilter;
41 import org.collectionspace.services.common.document.ValidatorHandler;
42 import org.collectionspace.services.common.security.SecurityContext;
43 import org.collectionspace.services.common.security.SecurityContextImpl;
44 import org.collectionspace.services.common.security.UnauthorizedException;
45 import org.collectionspace.services.common.service.ObjectPartType;
46 import org.collectionspace.services.common.service.ServiceBindingType;
47 import org.collectionspace.services.common.tenant.RepositoryDomainType;
48 import org.collectionspace.services.common.tenant.TenantBindingType;
49 import org.collectionspace.services.common.types.PropertyItemType;
50 import org.collectionspace.services.common.types.PropertyType;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
55 * AbstractServiceContext
57 * $LastChangedRevision: $
72 public abstract class AbstractServiceContextImpl<IT, OT>
73 implements ServiceContext<IT, OT> {
76 final Logger logger = LoggerFactory.getLogger(AbstractServiceContextImpl.class);
77 /** The properties. */
78 Map<String, Object> properties = new HashMap<String, Object>();
79 /** The object part map. */
80 Map<String, ObjectPartType> objectPartMap = new HashMap<String, ObjectPartType>();
81 /** The service binding. */
82 protected ServiceBindingType serviceBinding;
83 /** The tenant binding. */
84 private TenantBindingType tenantBinding;
85 /** repository domain used by the service */
86 private RepositoryDomainType repositoryDomain;
87 /** The override document type. */
88 private String overrideDocumentType = null;
89 /** The val handlers. */
90 private List<ValidatorHandler<IT, OT>> valHandlers = null;
91 /** The doc handler. */
92 private DocumentHandler docHandler = null;
93 /** security context */
94 private SecurityContext securityContext;
96 private UriInfo uriInfo;
99 * Instantiates a new abstract service context impl.
101 private AbstractServiceContextImpl() {
102 // private constructor for singleton pattern
104 // request query params
105 /** The query params. */
106 private MultivaluedMap<String, String> queryParams;
109 * Instantiates a new abstract service context impl.
111 * @param serviceName the service name
113 * @throws UnauthorizedException the unauthorized exception
115 protected AbstractServiceContextImpl(String serviceName) throws UnauthorizedException {
117 //establish security context
118 securityContext = new SecurityContextImpl();
119 //make sure tenant context exists
120 checkTenantContext();
122 //retrieve service bindings
123 TenantBindingConfigReaderImpl tReader =
124 ServiceMain.getInstance().getTenantBindingConfigReader();
125 String tenantId = securityContext.getCurrentTenantId();
126 tenantBinding = tReader.getTenantBinding(tenantId);
127 if (tenantBinding == null) {
128 String msg = "No tenant binding found for tenantId=" + tenantId
129 + " while processing request for service= " + serviceName;
131 throw new IllegalStateException(msg);
133 serviceBinding = tReader.getServiceBinding(tenantId, serviceName);
134 if (serviceBinding == null) {
135 String msg = "No service binding found while processing request for "
136 + serviceName + " for tenant id=" + getTenantId()
137 + " name=" + getTenantName();
139 throw new IllegalStateException(msg);
141 if (logger.isDebugEnabled()) {
142 logger.debug("tenantId=" + tenantId
143 + " service binding=" + serviceBinding.getName());
145 repositoryDomain = tReader.getRepositoryDomain(tenantId, serviceName);
146 if (repositoryDomain != null) {
147 if (logger.isDebugEnabled()) {
148 logger.debug("tenantId=" + tenantId
149 + " repository doamin=" + repositoryDomain.getName());
155 * @see org.collectionspace.services.common.context.ServiceContext#getCommonPartLabel()
158 public String getCommonPartLabel() {
159 return getCommonPartLabel(getServiceName());
163 * @see org.collectionspace.services.common.context.ServiceContext#getCommonPartLabel(java.lang.String)
165 public String getCommonPartLabel(String schemaName) {
166 return schemaName.toLowerCase() + PART_LABEL_SEPARATOR + PART_COMMON_LABEL;
170 * @see org.collectionspace.services.common.context.ServiceContext#getPartsMetadata()
173 public Map<String, ObjectPartType> getPartsMetadata() {
174 if (objectPartMap.size() != 0) {
175 return objectPartMap;
177 ServiceBindingUtils.getPartsMetadata(getServiceBinding(), objectPartMap);
178 return objectPartMap;
182 * Gets the properties for part.
184 * @param partLabel the part label
186 * @return the properties for part
188 public List<PropertyItemType> getPropertiesForPart(String partLabel) {
189 Map<String, ObjectPartType> partMap = getPartsMetadata();
190 ObjectPartType part = partMap.get(partLabel);
192 throw new RuntimeException("No such part found: " + partLabel);
194 List<PropertyType> propNodeList = part.getProperties();
195 return propNodeList.isEmpty() ? null : propNodeList.get(0).getItem();
199 * @param partLabel The name of the scehma part to search in
200 * @param propName The name of the property (or properties) to find
201 * @param qualified Whether the returned values should be qualified with the
202 * partLabel. This is when the property values are schema field references.
203 * @return List of property values for the matched property on the named schema part.
205 public List<String> getPropertyValuesForPart(String partLabel, String propName, boolean qualified) {
206 List<PropertyItemType> allProps = getPropertiesForPart(partLabel);
207 return PropertyItemUtils.getPropertyValuesByName(allProps, propName,
208 (qualified ? (partLabel + ":") : null));
212 * @param propName The name of the property (or properties) to find
213 * @param qualified Whether the returned values should be qualified with the
214 * partLabel. This is when the property values are schema field references.
215 * @return List of property values for the matched property on any schema part.
217 public List<String> getAllPartsPropertyValues(String propName, boolean qualified) {
218 return ServiceBindingUtils.getAllPartsPropertyValues(getServiceBinding(), propName, qualified);
222 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBindingPropertyValue(java.lang.String)
224 public String getServiceBindingPropertyValue(String propName) {
225 return ServiceBindingUtils.getPropertyValue(getServiceBinding(), propName);
229 * Gets the common part properties.
231 * @return the common part properties
233 public List<PropertyItemType> getCommonPartProperties() {
234 return getPropertiesForPart(getCommonPartLabel());
238 * @param propName The name of the property (or properties) to find
239 * @param qualified Whether the returned values should be qualified with the
240 * partLabel. This is when the property values are schema field references.
241 * @return List of property values for the matched property on the common schema part.
243 public List<String> getCommonPartPropertyValues(String propName, boolean qualified) {
244 return getPropertyValuesForPart(getCommonPartLabel(), propName, qualified);
248 * @see org.collectionspace.services.common.context.ServiceContext#getQualifiedServiceName()
251 public String getQualifiedServiceName() {
252 return TenantBindingConfigReaderImpl.getTenantQualifiedServiceName(getTenantId(), getServiceName());
256 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientName()
259 public String getRepositoryClientName() {
260 if (repositoryDomain == null) {
263 return repositoryDomain.getRepositoryClient();
267 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientType()
270 public ClientType getRepositoryClientType() {
271 //assumption: there is only one repository client configured
272 return ServiceMain.getInstance().getClientType();
276 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
279 public String getRepositoryDomainName() {
280 if (repositoryDomain == null) {
283 return repositoryDomain.getName();
287 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
290 public String getRepositoryDomainStorageName() {
291 if (repositoryDomain == null) {
294 return repositoryDomain.getStorageName();
298 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceId()
301 public String getRepositoryWorkspaceId() {
302 return ServiceMain.getInstance().getWorkspaceId(getTenantId(), getServiceName());
306 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceName()
309 public String getRepositoryWorkspaceName() {
310 //service name is workspace name by convention
311 return serviceBinding.getName();
315 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBinding()
318 public ServiceBindingType getServiceBinding() {
319 return serviceBinding;
323 * @see org.collectionspace.services.common.context.ServiceContext#getServiceName()
326 public String getServiceName() {
327 return serviceBinding.getName();
331 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentType()
334 public String getDocumentType() {
335 // If they have not overridden the setting, use the type of the service
337 return (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
341 public String getTenantQualifiedDoctype(String docType) {
342 // If they have not overridden the setting, use the type of the service
344 String result = ServiceBindingUtils.getTenantQualifiedDocType(this.getTenantId(), docType);
350 public String getTenantQualifiedDoctype() {
351 String docType = (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
352 return getTenantQualifiedDoctype(docType);
356 * @see org.collectionspace.services.common.context.ServiceContext#setDocumentType(java.lang.String)
359 public void setDocumentType(String docType) {
360 overrideDocumentType = docType;
364 * @see org.collectionspace.services.common.context.ServiceContext#getSecurityContext()
367 public SecurityContext getSecurityContext() {
368 return securityContext;
372 * @see org.collectionspace.services.common.context.ServiceContext#getUserId()
375 public String getUserId() {
376 return securityContext.getUserId();
380 * @see org.collectionspace.services.common.context.ServiceContext#getTenantId()
383 public String getTenantId() {
384 return securityContext.getCurrentTenantId();
388 * @see org.collectionspace.services.common.context.ServiceContext#getTenantName()
391 public String getTenantName() {
392 return securityContext.getCurrentTenantName();
396 * @see org.collectionspace.services.common.context.ServiceContext#getInput()
399 public abstract IT getInput();
402 * @see org.collectionspace.services.common.context.ServiceContext#setInput(java.lang.Object)
405 public abstract void setInput(IT input);
408 * @see org.collectionspace.services.common.context.ServiceContext#getOutput()
411 public abstract OT getOutput();
414 * @see org.collectionspace.services.common.context.ServiceContext#setOutput(java.lang.Object)
417 public abstract void setOutput(OT output);
420 * @see org.collectionspace.services.common.context.ServiceContext#getProperties()
423 public Map<String, Object> getProperties() {
428 * @see org.collectionspace.services.common.context.ServiceContext#setProperties(java.util.Map)
431 public void setProperties(Map<String, Object> props) {
432 properties.putAll(props);
436 * @see org.collectionspace.services.common.context.ServiceContext#getProperty(java.lang.String)
438 public Object getProperty(String name) {
439 return properties.get(name);
443 * @see org.collectionspace.services.common.context.ServiceContext#setProperty(java.lang.String, java.lang.Object)
445 public void setProperty(String name, Object o) {
446 properties.put(name, o);
450 * checkTenantContext makss sure tenant context exists
454 * @throws UnauthorizedException the unauthorized exception
456 private void checkTenantContext() throws UnauthorizedException {
458 String tenantId = securityContext.getCurrentTenantId();
459 if (tenantId == null) {
460 String msg = "Could not find tenant context";
462 throw new UnauthorizedException(msg);
466 private static String buildWorkflowWhereClause(MultivaluedMap<String, String> queryParams) {
467 String result = null;
469 String includeDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
470 if (includeDeleted != null && includeDeleted.equalsIgnoreCase(Boolean.FALSE.toString())) {
471 result = "ecm:currentLifeCycleState <> 'deleted'";
478 * Creates the document handler instance.
480 * @return the document handler
482 * @throws Exception the exception
484 private DocumentHandler createDocumentHandlerInstance() throws Exception {
485 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
486 Class<?> c = tccl.loadClass(getDocumentHandlerClass());
487 if (DocumentHandler.class.isAssignableFrom(c)) {
488 docHandler = (DocumentHandler) c.newInstance();
490 throw new IllegalArgumentException("Not of type "
491 + DocumentHandler.class.getCanonicalName());
494 // Create a default document filter
496 docHandler.setServiceContext(this);
497 DocumentFilter docFilter = docHandler.createDocumentFilter();
499 // If the context was created with query parameters,
500 // reflect the values of those parameters in the document filter
501 // to specify sort ordering, pagination, etc.
503 if (this.getQueryParams() != null) {
504 docFilter.setSortOrder(this.getQueryParams());
505 docFilter.setPagination(this.getQueryParams());
506 String workflowWhereClause = buildWorkflowWhereClause(queryParams);
507 if (workflowWhereClause != null) {
508 docFilter.appendWhereClause(workflowWhereClause, IQueryManager.SEARCH_QUALIFIER_AND);
512 docHandler.setDocumentFilter(docFilter);
518 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHandler()
521 public DocumentHandler getDocumentHandler() throws Exception {
522 DocumentHandler result = docHandler;
523 // create a new instance if one does not yet exist
524 if (result == null) {
525 result = createDocumentHandlerInstance();
531 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHanlder(javax.ws.rs.core.MultivaluedMap)
534 public DocumentHandler getDocumentHandler(MultivaluedMap<String, String> queryParams) throws Exception {
535 DocumentHandler result = getDocumentHandler();
536 DocumentFilter documentFilter = result.getDocumentFilter(); //to see results in debugger variables view
537 documentFilter.setPagination(queryParams);
542 * Gets the document handler class.
544 * @return the document handler class
546 private String getDocumentHandlerClass() {
547 if (serviceBinding.getDocumentHandler() == null
548 || serviceBinding.getDocumentHandler().isEmpty()) {
549 String msg = "Missing documentHandler in service binding for "
550 + getServiceName() + " for tenant id=" + getTenantId()
551 + " name=" + getTenantName();
553 throw new IllegalStateException(msg);
555 return serviceBinding.getDocumentHandler().trim();
559 * If this element is set in the service binding then use it otherwise
560 * assume that asserts are NOT disabled.
562 private boolean disableValidationAsserts() {
564 Boolean disableAsserts = getServiceBinding().isDisableAsserts();
565 result = (disableAsserts != null) ? disableAsserts : false;
570 * @see org.collectionspace.services.common.context.ServiceContext#getValidatorHandlers()
573 public List<ValidatorHandler<IT, OT>> getValidatorHandlers() throws Exception {
574 if (valHandlers != null) {
577 List<String> handlerClazzes = getServiceBinding().getValidatorHandler();
578 List<ValidatorHandler<IT, OT>> handlers = new ArrayList<ValidatorHandler<IT, OT>>(handlerClazzes.size());
579 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
580 for (String clazz : handlerClazzes) {
581 clazz = clazz.trim();
582 Class<?> c = tccl.loadClass(clazz);
583 if (disableValidationAsserts() == false) {
584 // enable validation assertions
585 tccl.setClassAssertionStatus(clazz, true);
587 if (ValidatorHandler.class.isAssignableFrom(c)) {
588 handlers.add((ValidatorHandler) c.newInstance());
591 valHandlers = handlers;
596 * @see java.lang.Object#toString()
599 public String toString() {
600 StringBuilder msg = new StringBuilder();
601 msg.append("AbstractServiceContext [");
602 msg.append("service name=" + serviceBinding.getName() + " ");
603 msg.append("service version=" + serviceBinding.getVersion() + " ");
604 msg.append("tenant id=" + tenantBinding.getId() + " ");
605 msg.append("tenant name=" + tenantBinding.getName() + " ");
606 msg.append(tenantBinding.getDisplayName() + " ");
607 if (repositoryDomain != null) {
608 msg.append("tenant repository domain=" + repositoryDomain.getName());
610 for (Map.Entry<String, Object> entry : properties.entrySet()) {
611 msg.append("property name=" + entry.getKey() + " value=" + entry.getValue().toString());
614 return msg.toString();
618 * @see org.collectionspace.services.common.context.ServiceContext#getQueryParams()
621 public MultivaluedMap<String, String> getQueryParams() {
623 if (queryParams == null){
624 if (this.uriInfo != null){
625 queryParams = this.uriInfo.getQueryParameters();
628 if (queryParams == null){
629 queryParams = new org.jboss.resteasy.specimpl.MultivaluedMapImpl<String,String>();
631 return this.queryParams;
635 public MultivaluedMap<String, String> getQueryParamsPtr() {
636 return this.queryParams;
640 * @see org.collectionspace.services.common.context.ServiceContext#setQueryParams(javax.ws.rs.core.MultivaluedMap)
643 public void setQueryParams(MultivaluedMap<String, String> theQueryParams) {
644 this.queryParams = theQueryParams;
648 public void setUriInfo(UriInfo ui){
653 public UriInfo getUriInfo(){