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: $
76 public abstract class AbstractServiceContextImpl<IT, OT>
77 implements ServiceContext<IT, OT> {
80 final Logger logger = LoggerFactory.getLogger(AbstractServiceContextImpl.class);
82 /** The properties. */
83 Map<String, Object> properties = new HashMap<String, Object>();
85 /** The object part map. */
86 Map<String, ObjectPartType> objectPartMap = new HashMap<String, ObjectPartType>();
88 /** The service binding. */
89 private ServiceBindingType serviceBinding;
91 /** The tenant binding. */
92 private TenantBindingType tenantBinding;
94 /** The override document type. */
95 private String overrideDocumentType = null;
97 /** The val handlers. */
98 private List<ValidatorHandler> valHandlers = null;
100 /** The doc handler. */
101 private DocumentHandler docHandler = null;
103 private AbstractServiceContextImpl() {} // private constructor for singleton pattern
105 // request 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 {
116 TenantBindingConfigReaderImpl tReader =
117 ServiceMain.getInstance().getTenantBindingConfigReader();
118 //FIXME retrieveTenantId is not working consistently in non-auth mode
119 //TODO: get tenant binding from security context
120 String tenantId = retrieveTenantId();
121 if (tenantId == null) {
122 //for testing purposes
123 tenantId = "1"; //hardcoded for movingimages.us
125 tenantBinding = tReader.getTenantBinding(tenantId);
126 if (tenantBinding == null) {
127 String msg = "No tenant binding found for tenantId=" + tenantId
128 + " while processing request for service= " + serviceName;
130 throw new IllegalStateException(msg);
132 serviceBinding = tReader.getServiceBinding(tenantId, serviceName);
133 if (serviceBinding == null) {
134 String msg = "No service binding found while processing request for "
135 + serviceName + " for tenant id=" + getTenantId()
136 + " name=" + getTenantName();
138 throw new IllegalStateException(msg);
140 if (logger.isDebugEnabled()) {
141 logger.debug("tenantId=" + tenantId
142 + " service binding=" + serviceBinding.getName());
147 * getCommonPartLabel get common part label
151 public String getCommonPartLabel() {
152 return getCommonPartLabel(getServiceName());
156 * getCommonPartLabel get common part label
159 public String getCommonPartLabel(String schemaName) {
160 return schemaName.toLowerCase() + PART_LABEL_SEPERATOR + PART_COMMON_LABEL;
164 * @see org.collectionspace.services.common.context.ServiceContext#getPartsMetadata()
167 public Map<String, ObjectPartType> getPartsMetadata() {
168 if (objectPartMap.size() != 0) {
169 return objectPartMap;
171 ServiceBindingUtils.getPartsMetadata(getServiceBinding(), objectPartMap);
172 return objectPartMap;
176 * Gets the properties for part.
178 * @param partLabel the part label
180 * @return the properties for part
182 public List<PropertyItemType> getPropertiesForPart(String partLabel) {
183 Map<String, ObjectPartType> partMap = getPartsMetadata();
184 ObjectPartType part = partMap.get(partLabel);
186 throw new RuntimeException("No such part found: "+partLabel);
188 List<PropertyType> propNodeList = part.getProperties();
189 return propNodeList.isEmpty()?null:propNodeList.get(0).getItem();
193 * @param partLabel The name of the scehma part to search in
194 * @param propName The name of the property (or properties) to find
195 * @param qualified Whether the returned values should be qualified with the
196 * partLabel. This is when the property values are schema field references.
197 * @return List of property values for the matched property on the named schema part.
199 public List<String> getPropertyValuesForPart(String partLabel, String propName, boolean qualified) {
200 List<PropertyItemType> allProps = getPropertiesForPart(partLabel);
201 return PropertyItemUtils.getPropertyValuesByName(allProps, propName,
202 (qualified?(partLabel+":"):null));
206 * @param propName The name of the property (or properties) to find
207 * @param qualified Whether the returned values should be qualified with the
208 * partLabel. This is when the property values are schema field references.
209 * @return List of property values for the matched property on any schema part.
211 public List<String> getAllPartsPropertyValues(String propName, boolean qualified) {
212 return ServiceBindingUtils.getAllPartsPropertyValues(getServiceBinding(), propName, qualified);
216 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBindingPropertyValue(java.lang.String)
218 public String getServiceBindingPropertyValue(String propName) {
219 return ServiceBindingUtils.getPropertyValue(getServiceBinding(), propName);
223 * Gets the common part properties.
225 * @return the common part properties
227 public List<PropertyItemType> getCommonPartProperties() {
228 return getPropertiesForPart(getCommonPartLabel());
232 * @param propName The name of the property (or properties) to find
233 * @param qualified Whether the returned values should be qualified with the
234 * partLabel. This is when the property values are schema field references.
235 * @return List of property values for the matched property on the common schema part.
237 public List<String> getCommonPartPropertyValues(String propName, boolean qualified) {
238 return getPropertyValuesForPart(getCommonPartLabel(), propName, qualified);
242 * @see org.collectionspace.services.common.context.ServiceContext#getQualifiedServiceName()
245 public String getQualifiedServiceName() {
246 return TenantBindingConfigReaderImpl.getTenantQualifiedServiceName(getTenantId(), getServiceName());
250 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientName()
253 public String getRepositoryClientName() {
254 if (serviceBinding.getRepositoryClient() == null) {
257 return serviceBinding.getRepositoryClient().trim();
261 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientType()
264 public ClientType getRepositoryClientType() {
265 //assumption: there is only one repository client configured
266 return ServiceMain.getInstance().getClientType();
270 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
273 public String getRepositoryDomainName() {
274 return tenantBinding.getRepositoryDomain();
278 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceId()
281 public String getRepositoryWorkspaceId() {
282 TenantBindingConfigReaderImpl tbConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
283 return tbConfigReader.getWorkspaceId(getTenantId(), getServiceName());
287 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceName()
290 public String getRepositoryWorkspaceName() {
291 //service name is workspace name by convention
292 return serviceBinding.getName();
296 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBinding()
299 public ServiceBindingType getServiceBinding() {
300 return serviceBinding;
304 * @see org.collectionspace.services.common.context.ServiceContext#getServiceName()
307 public String getServiceName() {
308 return serviceBinding.getName();
312 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentType()
315 public String getDocumentType() {
316 // If they have not overridden the setting, use the type of the service
318 return (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
322 * @see org.collectionspace.services.common.context.ServiceContext#setDocumentType(java.lang.String)
325 public void setDocumentType(String docType) {
326 overrideDocumentType = docType;
330 * @see org.collectionspace.services.common.context.ServiceContext#getTenantId()
333 public String getTenantId() {
334 return tenantBinding.getId();
338 * @see org.collectionspace.services.common.context.ServiceContext#getTenantName()
341 public String getTenantName() {
342 return tenantBinding.getName();
346 * @see org.collectionspace.services.common.context.ServiceContext#getInput()
349 public abstract IT getInput();
352 * @see org.collectionspace.services.common.context.ServiceContext#setInput(java.lang.Object)
355 public abstract void setInput(IT input);
358 * @see org.collectionspace.services.common.context.ServiceContext#getOutput()
361 public abstract OT getOutput();
364 * @see org.collectionspace.services.common.context.ServiceContext#setOutput(java.lang.Object)
367 public abstract void setOutput(OT output);
370 * @see org.collectionspace.services.common.context.ServiceContext#getProperties()
373 public Map<String, Object> getProperties() {
378 * @see org.collectionspace.services.common.context.ServiceContext#setProperties(java.util.Map)
381 public void setProperties(Map<String, Object> props) {
382 properties.putAll(props);
386 * @see org.collectionspace.services.common.context.ServiceContext#getProperty(java.lang.String)
388 public Object getProperty(String name) {
389 return properties.get(name);
393 * @see org.collectionspace.services.common.context.ServiceContext#setProperty(java.lang.String, java.lang.Object)
395 public void setProperty(String name, Object o) {
396 properties.put(name, o);
401 * Retrieve tenant id.
405 * @throws UnauthorizedException the unauthorized exception
407 private String retrieveTenantId() throws UnauthorizedException {
409 String[] tenantIds = AuthN.get().getTenantIds();
410 if (tenantIds.length == 0) {
411 String msg = "Could not find tenant context";
413 throw new UnauthorizedException(msg);
415 //TODO: if a user is associated with more than one tenants, the tenant
416 //id should be matched with the one sent over the wire
421 * Creates the document handler instance.
423 * @return the document handler
425 * @throws Exception the exception
427 private DocumentHandler createDocumentHandlerInstance() throws Exception {
428 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
429 Class c = tccl.loadClass(getDocumentHandlerClass());
430 if (DocumentHandler.class.isAssignableFrom(c)) {
431 docHandler = (DocumentHandler) c.newInstance();
433 throw new IllegalArgumentException("Not of type "
434 + DocumentHandler.class.getCanonicalName());
437 // create a default document filter with pagination if the context
438 // was created with query params
440 docHandler.setServiceContext(this);
441 DocumentFilter docFilter = docHandler.createDocumentFilter();
442 docFilter.setPagination(this.getQueryParams());
443 docHandler.setDocumentFilter(docFilter);
449 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHandler()
452 public DocumentHandler getDocumentHandler() throws Exception {
453 DocumentHandler result = docHandler;
454 // create a new instance if one does not yet exist
455 if (result == null) {
456 result = createDocumentHandlerInstance();
462 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHanlder(javax.ws.rs.core.MultivaluedMap)
465 public DocumentHandler getDocumentHandler(MultivaluedMap<String, String> queryParams) throws Exception {
466 DocumentHandler result = getDocumentHandler();
467 DocumentFilter documentFilter = result.getDocumentFilter(); //to see results in debugger variables view
468 documentFilter.setPagination(queryParams);
473 * Gets the document handler class.
475 * @return the document handler class
477 private String getDocumentHandlerClass() {
478 if (serviceBinding.getDocumentHandler() == null
479 || serviceBinding.getDocumentHandler().isEmpty()) {
480 String msg = "Missing documentHandler in service binding for "
481 + getServiceName() + " for tenant id=" + getTenantId()
482 + " name=" + getTenantName();
484 throw new IllegalStateException(msg);
486 return serviceBinding.getDocumentHandler().trim();
490 * @see org.collectionspace.services.common.context.ServiceContext#getValidatorHandlers()
493 public List<ValidatorHandler> getValidatorHandlers() throws Exception {
494 if (valHandlers != null) {
497 List<String> handlerClazzes = getServiceBinding().getValidatorHandler();
498 List<ValidatorHandler> handlers = new ArrayList<ValidatorHandler>(handlerClazzes.size());
499 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
500 for (String clazz : handlerClazzes) {
501 clazz = clazz.trim();
502 Class c = tccl.loadClass(clazz);
503 if (ValidatorHandler.class.isAssignableFrom(c)) {
504 handlers.add((ValidatorHandler) c.newInstance());
507 valHandlers = handlers;
512 * @see java.lang.Object#toString()
515 public String toString() {
516 StringBuilder msg = new StringBuilder();
517 msg.append("AbstractServiceContext [");
518 msg.append("service name=" + serviceBinding.getName() + " ");
519 msg.append("service version=" + serviceBinding.getVersion() + " ");
520 msg.append("tenant id=" + tenantBinding.getId() + " ");
521 msg.append("tenant name=" + tenantBinding.getName() + " ");
522 msg.append(tenantBinding.getDisplayName() + " ");
523 msg.append("tenant repository domain=" + tenantBinding.getRepositoryDomain());
524 for (Map.Entry<String, Object> entry : properties.entrySet()) {
525 msg.append("property name=" + entry.getKey() + " value=" + entry.getValue().toString());
528 return msg.toString();
532 public MultivaluedMap<String, String> getQueryParams() {
533 return this.queryParams;
537 public void setQueryParams(MultivaluedMap<String, String> queryParams) {
538 this.queryParams = queryParams;