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.security.acl.Group;
27 import java.util.ArrayList;
28 import java.util.Enumeration;
29 import java.util.HashMap;
30 import java.util.List;
33 import javax.security.auth.Subject;
34 import javax.security.jacc.PolicyContext;
35 import javax.security.jacc.PolicyContextException;
36 import javax.ws.rs.core.MultivaluedMap;
38 import org.collectionspace.authentication.AuthN;
39 import org.collectionspace.authentication.CSpaceTenant;
41 import org.collectionspace.services.common.ClientType;
42 import org.collectionspace.services.common.ServiceMain;
43 import org.collectionspace.services.common.config.PropertyItemUtils;
44 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
45 import org.collectionspace.services.common.document.DocumentHandler;
46 import org.collectionspace.services.common.document.DocumentFilter;
47 import org.collectionspace.services.common.document.ValidatorHandler;
48 import org.collectionspace.services.common.security.UnauthorizedException;
49 import org.collectionspace.services.common.service.ObjectPartType;
50 import org.collectionspace.services.common.service.ServiceBindingType;
51 import org.collectionspace.services.common.service.ServiceObjectType;
52 import org.collectionspace.services.common.tenant.TenantBindingType;
53 import org.collectionspace.services.common.types.PropertyItemType;
54 import org.collectionspace.services.common.types.PropertyType;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
59 * AbstractServiceContext
61 * $LastChangedRevision: $
64 public abstract class AbstractServiceContextImpl<IT, OT>
65 implements ServiceContext<IT, OT> {
68 final Logger logger = LoggerFactory.getLogger(AbstractServiceContextImpl.class);
70 /** The properties. */
71 Map<String, Object> properties = new HashMap<String, Object>();
73 /** The object part map. */
74 Map<String, ObjectPartType> objectPartMap = new HashMap<String, ObjectPartType>();
76 /** The service binding. */
77 private ServiceBindingType serviceBinding;
79 /** The tenant binding. */
80 private TenantBindingType tenantBinding;
82 /** The override document type. */
83 private String overrideDocumentType = null;
85 /** The val handlers. */
86 private List<ValidatorHandler> valHandlers = null;
88 /** The doc handler. */
89 private DocumentHandler docHandler = null;
91 private AbstractServiceContextImpl() {} // private constructor for singleton pattern
93 // request query params
94 private MultivaluedMap<String, String> queryParams;
97 * Instantiates a new abstract service context impl.
99 * @param serviceName the service name
101 * @throws UnauthorizedException the unauthorized exception
103 protected AbstractServiceContextImpl(String serviceName) throws UnauthorizedException {
104 TenantBindingConfigReaderImpl tReader =
105 ServiceMain.getInstance().getTenantBindingConfigReader();
106 //FIXME retrieveTenantId is not working consistently in non-auth mode
107 //TODO: get tenant binding from security context
108 String tenantId = retrieveTenantId();
109 if (tenantId == null) {
110 //for testing purposes
111 tenantId = "1"; //hardcoded for movingimages.us
113 tenantBinding = tReader.getTenantBinding(tenantId);
114 if (tenantBinding == null) {
115 String msg = "No tenant binding found for tenantId=" + tenantId
116 + " while processing request for service= " + serviceName;
118 throw new IllegalStateException(msg);
120 serviceBinding = tReader.getServiceBinding(tenantId, serviceName);
121 if (serviceBinding == null) {
122 String msg = "No service binding found while processing request for "
123 + serviceName + " for tenant id=" + getTenantId()
124 + " name=" + getTenantName();
126 throw new IllegalStateException(msg);
128 if (logger.isDebugEnabled()) {
129 logger.debug("tenantId=" + tenantId
130 + " service binding=" + serviceBinding.getName());
135 * getCommonPartLabel get common part label
139 public String getCommonPartLabel() {
140 return getCommonPartLabel(getServiceName());
144 * getCommonPartLabel get common part label
147 public String getCommonPartLabel(String schemaName) {
148 return schemaName.toLowerCase() + PART_LABEL_SEPERATOR + PART_COMMON_LABEL;
152 * @see org.collectionspace.services.common.context.ServiceContext#getPartsMetadata()
155 public Map<String, ObjectPartType> getPartsMetadata() {
156 if (objectPartMap.size() != 0) {
157 return objectPartMap;
159 ServiceBindingUtils.getPartsMetadata(getServiceBinding(), objectPartMap);
160 return objectPartMap;
164 * Gets the properties for part.
166 * @param partLabel the part label
168 * @return the properties for part
170 public List<PropertyItemType> getPropertiesForPart(String partLabel) {
171 Map<String, ObjectPartType> partMap = getPartsMetadata();
172 ObjectPartType part = partMap.get(partLabel);
174 throw new RuntimeException("No such part found: "+partLabel);
176 List<PropertyType> propNodeList = part.getProperties();
177 return propNodeList.isEmpty()?null:propNodeList.get(0).getItem();
181 * Gets the property values for part.
183 * @param partLabel the part label
184 * @param propName the prop name
186 * @return the property values for part
188 public List<String> getPropertyValuesForPart(String partLabel, String propName) {
189 List<PropertyItemType> allProps = getPropertiesForPart(partLabel);
190 return PropertyItemUtils.getPropertyValuesByName(allProps, propName);
194 * Gets the all parts property values.
196 * @param propName the prop name
198 * @return the all parts property values
200 public List<String> getAllPartsPropertyValues(String propName) {
201 return ServiceBindingUtils.getAllPartsPropertyValues(getServiceBinding(), propName);
205 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBindingPropertyValue(java.lang.String)
207 public String getServiceBindingPropertyValue(String propName) {
208 return ServiceBindingUtils.getPropertyValue(getServiceBinding(), propName);
212 * Gets the common part properties.
214 * @return the common part properties
216 public List<PropertyItemType> getCommonPartProperties() {
217 return getPropertiesForPart(getCommonPartLabel());
221 * Gets the common part property values.
223 * @param propName the prop name
225 * @return the common part property values
227 public List<String> getCommonPartPropertyValues(String propName) {
228 return getPropertyValuesForPart(getCommonPartLabel(), propName);
232 * @see org.collectionspace.services.common.context.ServiceContext#getQualifiedServiceName()
235 public String getQualifiedServiceName() {
236 return TenantBindingConfigReaderImpl.getTenantQualifiedServiceName(getTenantId(), getServiceName());
240 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientName()
243 public String getRepositoryClientName() {
244 if (serviceBinding.getRepositoryClient() == null) {
247 return serviceBinding.getRepositoryClient().trim();
251 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientType()
254 public ClientType getRepositoryClientType() {
255 //assumption: there is only one repository client configured
256 return ServiceMain.getInstance().getClientType();
260 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
263 public String getRepositoryDomainName() {
264 return tenantBinding.getRepositoryDomain();
268 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceId()
271 public String getRepositoryWorkspaceId() {
272 TenantBindingConfigReaderImpl tbConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
273 return tbConfigReader.getWorkspaceId(getTenantId(), getServiceName());
277 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceName()
280 public String getRepositoryWorkspaceName() {
281 //service name is workspace name by convention
282 return serviceBinding.getName();
286 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBinding()
289 public ServiceBindingType getServiceBinding() {
290 return serviceBinding;
294 * @see org.collectionspace.services.common.context.ServiceContext#getServiceName()
297 public String getServiceName() {
298 return serviceBinding.getName();
302 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentType()
305 public String getDocumentType() {
306 // If they have not overridden the setting, use the type of the service
308 return (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
312 * @see org.collectionspace.services.common.context.ServiceContext#setDocumentType(java.lang.String)
315 public void setDocumentType(String docType) {
316 overrideDocumentType = docType;
320 * @see org.collectionspace.services.common.context.ServiceContext#getTenantId()
323 public String getTenantId() {
324 return tenantBinding.getId();
328 * @see org.collectionspace.services.common.context.ServiceContext#getTenantName()
331 public String getTenantName() {
332 return tenantBinding.getName();
336 * @see org.collectionspace.services.common.context.ServiceContext#getInput()
339 public abstract IT getInput();
342 * @see org.collectionspace.services.common.context.ServiceContext#setInput(java.lang.Object)
345 public abstract void setInput(IT input);
348 * @see org.collectionspace.services.common.context.ServiceContext#getOutput()
351 public abstract OT getOutput();
354 * @see org.collectionspace.services.common.context.ServiceContext#setOutput(java.lang.Object)
357 public abstract void setOutput(OT output);
360 * @see org.collectionspace.services.common.context.ServiceContext#getProperties()
363 public Map<String, Object> getProperties() {
368 * @see org.collectionspace.services.common.context.ServiceContext#setProperties(java.util.Map)
371 public void setProperties(Map<String, Object> props) {
372 properties.putAll(props);
376 * @see org.collectionspace.services.common.context.ServiceContext#getProperty(java.lang.String)
378 public Object getProperty(String name) {
379 return properties.get(name);
383 * @see org.collectionspace.services.common.context.ServiceContext#setProperty(java.lang.String, java.lang.Object)
385 public void setProperty(String name, Object o) {
386 properties.put(name, o);
391 * Retrieve tenant id.
395 * @throws UnauthorizedException the unauthorized exception
397 private String retrieveTenantId() throws UnauthorizedException {
399 String[] tenantIds = AuthN.get().getTenantIds();
400 if (tenantIds.length == 0) {
401 String msg = "Could not find tenant context";
403 throw new UnauthorizedException(msg);
405 //TODO: if a user is associated with more than one tenants, the tenant
406 //id should be matched with the one sent over the wire
411 * Creates the document handler instance.
413 * @return the document handler
415 * @throws Exception the exception
417 private DocumentHandler createDocumentHandlerInstance() throws Exception {
418 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
419 Class c = tccl.loadClass(getDocumentHandlerClass());
420 if (DocumentHandler.class.isAssignableFrom(c)) {
421 docHandler = (DocumentHandler) c.newInstance();
423 throw new IllegalArgumentException("Not of type "
424 + DocumentHandler.class.getCanonicalName());
427 // create a default document filter with pagination if the context
428 // was created with query params
430 docHandler.setServiceContext(this);
431 DocumentFilter docFilter = docHandler.createDocumentFilter();
432 docFilter.setPagination(this.getQueryParams());
433 docHandler.setDocumentFilter(docFilter);
439 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHandler()
442 public DocumentHandler getDocumentHandler() throws Exception {
443 DocumentHandler result = docHandler;
444 // create a new instance if one does not yet exist
445 if (result == null) {
446 result = createDocumentHandlerInstance();
452 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHanlder(javax.ws.rs.core.MultivaluedMap)
455 public DocumentHandler getDocumentHandler(MultivaluedMap<String, String> queryParams) throws Exception {
456 DocumentHandler result = getDocumentHandler();
457 DocumentFilter documentFilter = result.getDocumentFilter(); //to see results in debugger variables view
458 documentFilter.setPagination(queryParams);
463 * Gets the document handler class.
465 * @return the document handler class
467 private String getDocumentHandlerClass() {
468 if (serviceBinding.getDocumentHandler() == null
469 || serviceBinding.getDocumentHandler().isEmpty()) {
470 String msg = "Missing documentHandler in service binding for "
471 + getServiceName() + " for tenant id=" + getTenantId()
472 + " name=" + getTenantName();
474 throw new IllegalStateException(msg);
476 return serviceBinding.getDocumentHandler().trim();
480 * @see org.collectionspace.services.common.context.ServiceContext#getValidatorHandlers()
483 public List<ValidatorHandler> getValidatorHandlers() throws Exception {
484 if (valHandlers != null) {
487 List<String> handlerClazzes = getServiceBinding().getValidatorHandler();
488 List<ValidatorHandler> handlers = new ArrayList<ValidatorHandler>(handlerClazzes.size());
489 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
490 for (String clazz : handlerClazzes) {
491 clazz = clazz.trim();
492 Class c = tccl.loadClass(clazz);
493 if (ValidatorHandler.class.isAssignableFrom(c)) {
494 handlers.add((ValidatorHandler) c.newInstance());
497 valHandlers = handlers;
502 * @see java.lang.Object#toString()
505 public String toString() {
506 StringBuilder msg = new StringBuilder();
507 msg.append("AbstractServiceContext [");
508 msg.append("service name=" + serviceBinding.getName() + " ");
509 msg.append("service version=" + serviceBinding.getVersion() + " ");
510 msg.append("tenant id=" + tenantBinding.getId() + " ");
511 msg.append("tenant name=" + tenantBinding.getName() + " ");
512 msg.append(tenantBinding.getDisplayName() + " ");
513 msg.append("tenant repository domain=" + tenantBinding.getRepositoryDomain());
514 for (Map.Entry<String, Object> entry : properties.entrySet()) {
515 msg.append("property name=" + entry.getKey() + " value=" + entry.getValue().toString());
518 return msg.toString();
522 public MultivaluedMap<String, String> getQueryParams() {
523 return this.queryParams;
527 public void setQueryParams(MultivaluedMap<String, String> queryParams) {
528 this.queryParams = queryParams;