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 java.util.Properties;
32 import javax.ws.rs.core.MultivaluedMap;
33 import javax.ws.rs.core.Request;
34 import javax.ws.rs.core.UriInfo;
36 import org.collectionspace.authentication.AuthN;
37 import org.collectionspace.services.client.AuthorityClient;
38 import org.collectionspace.services.client.CollectionSpaceClient;
39 import org.collectionspace.services.client.IClientQueryParams;
40 import org.collectionspace.services.client.IQueryManager;
41 import org.collectionspace.services.client.workflow.WorkflowClient;
42 import org.collectionspace.services.common.ServiceMain;
43 import org.collectionspace.services.common.api.Tools;
44 import org.collectionspace.services.common.config.PropertyItemUtils;
45 import org.collectionspace.services.common.config.ServiceConfigUtils;
46 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
47 import org.collectionspace.services.common.document.DocumentFilter;
48 import org.collectionspace.services.common.document.DocumentHandler;
49 import org.collectionspace.services.common.document.ValidatorHandler;
50 import org.collectionspace.services.common.security.SecurityContext;
51 import org.collectionspace.services.common.security.SecurityContextImpl;
52 import org.collectionspace.services.common.security.UnauthorizedException;
53 import org.collectionspace.services.config.ClientType;
54 import org.collectionspace.services.config.service.ObjectPartType;
55 import org.collectionspace.services.config.service.ServiceBindingType;
56 import org.collectionspace.services.config.tenant.RemoteClientConfig;
57 import org.collectionspace.services.config.tenant.RepositoryDomainType;
58 import org.collectionspace.services.config.tenant.TenantBindingType;
59 import org.collectionspace.services.config.types.PropertyItemType;
60 import org.collectionspace.services.config.types.PropertyType;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
65 * AbstractServiceContext
67 * $LastChangedRevision: $
82 @SuppressWarnings("rawtypes")
83 public abstract class AbstractServiceContextImpl<IT, OT>
84 implements ServiceContext<IT, OT> {
87 final Logger logger = LoggerFactory.getLogger(AbstractServiceContextImpl.class);
89 /** The properties. */
90 Map<String, Object> properties = new HashMap<String, Object>();
91 /** The object part map. */
92 Map<String, ObjectPartType> objectPartMap = new HashMap<String, ObjectPartType>();
93 /** The service binding. */
94 protected ServiceBindingType serviceBinding;
95 /** The tenant binding. */
96 private TenantBindingType tenantBinding;
97 /** repository domain used by the service */
98 private RepositoryDomainType repositoryDomain;
99 /** The override document type. */
100 private String overrideDocumentType = null;
101 /** The val handlers. */
102 private List<ValidatorHandler<IT, OT>> valHandlers = null;
103 /** The authority client -use for shared authority server */
104 private AuthorityClient authorityClient = null;
105 /** The doc handler. */
106 private DocumentHandler docHandler = null;
107 /** security context */
108 private SecurityContext securityContext;
109 /** The sessions JAX-RS URI information */
110 private UriInfo uriInfo;
111 /** The JAX-RS request information */
112 private Request requestInfo;
113 /** The current repository session */
114 private Object currentRepositorySession;
115 /** A reference count for the current repository session */
116 private int currentRepoSesssionRefCount = 0;
117 /** Should the current transaction be rolled back when an exception is caught */
118 private boolean rollbackOnException = true;
121 * Instantiates a new abstract service context impl.
123 private AbstractServiceContextImpl() {
124 // private constructor for singleton pattern
126 // request query params
127 /** The query params. */
128 private MultivaluedMap<String, String> queryParams;
131 * Instantiates a new abstract service context impl.
133 * @param serviceName the service name
135 * @throws UnauthorizedException the unauthorized exception
137 protected AbstractServiceContextImpl(String serviceName, UriInfo uriInfo) throws UnauthorizedException {
139 //establish security context
140 securityContext = new SecurityContextImpl(uriInfo);
141 //make sure tenant context exists
142 checkTenantContext();
144 String tenantId = securityContext.getCurrentTenantId();
145 if (AuthN.ALL_TENANTS_MANAGER_TENANT_ID.equals(tenantId) ||
146 AuthN.ANONYMOUS_TENANT_ID.equals(tenantId)) {
147 // Tenant Manager has no tenant binding, so don't bother...
148 tenantBinding = null;
149 serviceBinding = null;
150 repositoryDomain = null;
152 //retrieve service bindings
153 TenantBindingConfigReaderImpl tReader =
154 ServiceMain.getInstance().getTenantBindingConfigReader();
155 tenantBinding = tReader.getTenantBinding(tenantId);
156 if (tenantBinding == null) {
157 String msg = "No tenant binding found for tenantId=" + tenantId
158 + " while processing request for service= " + serviceName;
160 throw new IllegalStateException(msg);
162 serviceBinding = tReader.getServiceBinding(tenantId, serviceName);
163 if (serviceBinding == null) {
164 String msg = "No service binding found while processing request for "
165 + serviceName + " for tenant id=" + getTenantId()
166 + " name=" + getTenantName();
168 throw new IllegalStateException(msg);
170 if (logger.isDebugEnabled()) {
171 logger.debug("tenantId=" + tenantId
172 + " service binding=" + serviceBinding.getName());
174 repositoryDomain = tReader.getRepositoryDomain(tenantId, serviceName);
175 if (repositoryDomain != null) {
176 if (logger.isDebugEnabled()) {
177 logger.debug("tenantId=" + tenantId
178 + " repository doamin=" + repositoryDomain.getName());
184 public int getTimeoutParam(UriInfo ui) {
185 int result = DEFAULT_TX_TIMEOUT;
187 MultivaluedMap<String, String> queryParams = (ui == null) ? null : ui.getQueryParameters();
188 if (queryParams != null) {
189 String timeoutString = queryParams.getFirst(IClientQueryParams.IMPORT_TIMEOUT_PARAM);
190 if (timeoutString == null) {
191 timeoutString = queryParams.getFirst(IClientQueryParams.IMPORT_TIMOUT_PARAM);
194 if (timeoutString != null) {
196 result = Integer.parseInt(timeoutString);
197 } catch (NumberFormatException e) {
198 logger.warn("Transaction timeout period parameter could not be parsed. The characters in the parameter string must all be decimal digits. The Import service will use the default timeout period instead.",
208 public int getTimeoutSecs() {
209 UriInfo uriInfo = this.getUriInfo();
210 return this.getTimeoutParam(uriInfo);
214 * Returns TRUE unless the "recordUpdates" query param is set with a value of either "false", "FALSE", or "0"
218 public boolean shouldUpdateCoreValues() {
219 boolean recordUpdates = true;
221 MultivaluedMap<String, String> queryParams = getQueryParams();
222 String paramValue = queryParams.getFirst(IClientQueryParams.UPDATE_CORE_VALUES);
223 if (paramValue != null && paramValue.equalsIgnoreCase(Boolean.FALSE.toString())) { // Find our if the caller wants us to record updates
224 recordUpdates = false;
225 } else if (paramValue != null && paramValue.equals(Long.toString(0))) {
226 recordUpdates = false;
229 return recordUpdates;
233 * Default value is 'FALSE'
234 * If this returns true, it means that the refname values in referencing objects (records that reference authority or vocabulary terms) will be updated
235 * regardless of their current value. This is sometimes needed when refname values become stale for one of several reasons.
239 public boolean shouldForceUpdateRefnameReferences() {
240 boolean forceUpdates = false;
242 MultivaluedMap<String, String> queryParams = getQueryParams();
243 String paramValue = queryParams.getFirst(IClientQueryParams.FORCE_REFNAME_UPDATES);
244 if (paramValue != null && paramValue.equalsIgnoreCase(Boolean.TRUE.toString())) { // Find our if the caller wants us to force refname updates
246 } else if (paramValue != null && paramValue.equals(Long.toString(1))) {
255 * @see org.collectionspace.services.common.context.ServiceContext#getCommonPartLabel()
258 public String getCommonPartLabel() {
259 return getCommonPartLabel(getServiceName());
263 * @see org.collectionspace.services.common.context.ServiceContext#getCommonPartLabel(java.lang.String)
265 public String getCommonPartLabel(String schemaName) {
266 return schemaName.toLowerCase() + PART_LABEL_SEPARATOR + PART_COMMON_LABEL;
270 * @see org.collectionspace.services.common.context.ServiceContext#getPartsMetadata()
273 public Map<String, ObjectPartType> getPartsMetadata() {
274 if (objectPartMap.size() != 0) {
275 return objectPartMap;
277 ServiceBindingUtils.getPartsMetadata(getServiceBinding(), objectPartMap);
278 return objectPartMap;
282 * Gets the properties for part.
284 * @param partLabel the part label
286 * @return the properties for part
288 public List<PropertyItemType> getPropertiesForPart(String partLabel) {
289 Map<String, ObjectPartType> partMap = getPartsMetadata();
290 ObjectPartType part = partMap.get(partLabel);
292 throw new RuntimeException("No such part found: " + partLabel);
294 List<PropertyType> propNodeList = part.getProperties();
295 return propNodeList.isEmpty() ? null : propNodeList.get(0).getItem();
299 * @param partLabel The name of the scehma part to search in
300 * @param propName The name of the property (or properties) to find
301 * @param qualified Whether the returned values should be qualified with the
302 * partLabel. This is when the property values are schema field references.
303 * @return List of property values for the matched property on the named schema part.
305 public List<String> getPropertyValuesForPart(String partLabel, String propName, boolean qualified) {
306 List<PropertyItemType> allProps = getPropertiesForPart(partLabel);
307 return PropertyItemUtils.getPropertyValuesByName(allProps, propName,
308 (qualified ? (partLabel + ":") : null));
312 * @param propName The name of the property (or properties) to find
313 * @param qualified Whether the returned values should be qualified with the
314 * partLabel. This is when the property values are schema field references.
315 * @return List of property values for the matched property on any schema part.
317 public List<String> getAllPartsPropertyValues(String propName, boolean qualified) {
318 return ServiceBindingUtils.getAllPartsPropertyValues(getServiceBinding(), propName, qualified);
322 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBindingPropertyValue(java.lang.String)
324 public String getServiceBindingPropertyValue(String propName) {
325 return ServiceBindingUtils.getPropertyValue(getServiceBinding(), propName);
329 * Gets the common part properties.
331 * @return the common part properties
333 public List<PropertyItemType> getCommonPartProperties() {
334 return getPropertiesForPart(getCommonPartLabel());
338 * @param propName The name of the property (or properties) to find
339 * @param qualified Whether the returned values should be qualified with the
340 * partLabel. This is when the property values are schema field references.
341 * @return List of property values for the matched property on the common schema part.
343 public List<String> getCommonPartPropertyValues(String propName, boolean qualified) {
344 return getPropertyValuesForPart(getCommonPartLabel(), propName, qualified);
348 * @see org.collectionspace.services.common.context.ServiceContext#getQualifiedServiceName()
351 public String getQualifiedServiceName() {
352 return TenantBindingConfigReaderImpl.getTenantQualifiedServiceName(getTenantId(), getServiceName());
356 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientName()
359 public String getRepositoryClientName() {
360 if (repositoryDomain == null) {
363 return repositoryDomain.getRepositoryClient();
367 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientType()
370 public ClientType getRepositoryClientType() {
371 //assumption: there is only one repository client configured
372 return ServiceMain.getInstance().getClientType();
376 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
379 public String getRepositoryDomainName() {
380 if (repositoryDomain == null) {
383 return repositoryDomain.getName();
387 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
390 public String getRepositoryDomainStorageName() {
391 if (repositoryDomain == null) {
394 return repositoryDomain.getStorageName();
398 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceId()
401 public String getRepositoryWorkspaceId() {
402 return ServiceMain.getInstance().getWorkspaceId(getTenantId(), getServiceName());
406 * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceName()
409 public String getRepositoryWorkspaceName() {
410 //service name is workspace name by convention
411 return serviceBinding.getName();
415 * @see org.collectionspace.services.common.context.ServiceContext#getServiceBinding()
418 public ServiceBindingType getServiceBinding() {
419 return serviceBinding;
423 * @see org.collectionspace.services.common.context.ServiceContext#getServiceName()
426 public String getServiceName() {
427 return serviceBinding.getName();
431 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentType()
434 public String getDocumentType() {
435 // If they have not overridden the setting, use the type of the service
437 return (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
441 public String getTenantQualifiedDoctype(String docType) {
442 // If they have not overridden the setting, use the type of the service
444 String result = ServiceBindingUtils.getTenantQualifiedDocType(this.getTenantId(), docType);
450 public String getTenantQualifiedDoctype() {
451 String docType = (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
452 return getTenantQualifiedDoctype(docType);
456 * @see org.collectionspace.services.common.context.ServiceContext#setDocumentType(java.lang.String)
459 public void setDocumentType(String docType) {
460 overrideDocumentType = docType;
464 * @see org.collectionspace.services.common.context.ServiceContext#getSecurityContext()
467 public SecurityContext getSecurityContext() {
468 return securityContext;
472 * @see org.collectionspace.services.common.context.ServiceContext#getUserId()
475 public String getUserId() {
476 return securityContext.getUserId();
480 * @see org.collectionspace.services.common.context.ServiceContext#getTenantId()
483 public String getTenantId() {
484 return securityContext.getCurrentTenantId();
488 * @see org.collectionspace.services.common.context.ServiceContext#getTenantName()
491 public String getTenantName() {
492 return securityContext.getCurrentTenantName();
496 * @see org.collectionspace.services.common.context.ServiceContext#getInput()
499 public abstract IT getInput();
502 * @see org.collectionspace.services.common.context.ServiceContext#setInput(java.lang.Object)
505 public abstract void setInput(IT input);
508 * @see org.collectionspace.services.common.context.ServiceContext#getOutput()
511 public abstract OT getOutput();
514 * @see org.collectionspace.services.common.context.ServiceContext#setOutput(java.lang.Object)
517 public abstract void setOutput(OT output);
520 * @see org.collectionspace.services.common.context.ServiceContext#getProperties()
523 public Map<String, Object> getProperties() {
528 * @see org.collectionspace.services.common.context.ServiceContext#setProperties(java.util.Map)
531 public void setProperties(Map<String, Object> props) {
532 properties.putAll(props);
536 * @see org.collectionspace.services.common.context.ServiceContext#getProperty(java.lang.String)
538 public Object getProperty(String name) {
539 return properties.get(name);
543 * @see org.collectionspace.services.common.context.ServiceContext#setProperty(java.lang.String, java.lang.Object)
545 public void setProperty(String name, Object o) {
546 properties.put(name, o);
550 * checkTenantContext makss sure tenant context exists
554 * @throws UnauthorizedException the unauthorized exception
556 private void checkTenantContext() throws UnauthorizedException {
558 String tenantId = securityContext.getCurrentTenantId();
559 if (tenantId == null) {
560 String msg = "Could not find tenant context";
562 throw new UnauthorizedException(msg);
567 * Helps to filter for queries that either want to include or exclude documents in deleted workflow states.
569 * By default, we return *all* objects/records.
574 private static String buildWorkflowWhereClause(MultivaluedMap<String, String> queryParams) {
575 String result = null;
577 String includeDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_DELETED_QP);
578 String includeOnlyDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED_QP); // if set to true, it doesn't matter what the value is for 'includeDeleted'
580 if (includeOnlyDeleted != null) {
581 if (Tools.isTrue(includeOnlyDeleted)) {
583 // A value of 'true' for 'includeOnlyDeleted' means we're looking *only* for soft-deleted records/documents.
585 result = String.format("(ecm:currentLifeCycleState = '%s' OR ecm:currentLifeCycleState = '%s' OR ecm:currentLifeCycleState = '%s')",
586 WorkflowClient.WORKFLOWSTATE_DELETED,
587 WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED,
588 WorkflowClient.WORKFLOWSTATE_REPLICATED_DELETED);
590 } else if (includeDeleted != null && Tools.isFalse(includeDeleted)) {
592 // We can only get here if the 'includeOnlyDeleted' query param is missing altogether.
593 // Ensure we don't return soft-deleted records
595 result = String.format("(ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s')",
596 WorkflowClient.WORKFLOWSTATE_DELETED,
597 WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED,
598 WorkflowClient.WORKFLOWSTATE_REPLICATED_DELETED);
605 * Creates the document handler instance.
607 * @return the document handler
609 * @throws Exception the exception
611 private DocumentHandler createDocumentHandlerInstance() throws Exception {
612 docHandler = ServiceConfigUtils.createDocumentHandlerInstance(tenantBinding, serviceBinding);
615 // The docHandler for a Service can be null, but usually is not.
617 if (docHandler != null) {
619 // Create a default document filter
621 docHandler.setServiceContext(this);
622 DocumentFilter docFilter = docHandler.createDocumentFilter();
624 // If the context was created with query parameters,
625 // reflect the values of those parameters in the document filter
626 // to specify sort ordering, pagination, etc.
628 MultivaluedMap<String, String> queryParameters = this.getQueryParams();
629 if (queryParameters != null) {
630 docFilter.setSortOrder(queryParameters);
631 docFilter.setPagination(queryParameters);
632 String workflowWhereClause = buildWorkflowWhereClause(queryParameters);
633 if (workflowWhereClause != null) {
634 docFilter.appendWhereClause(workflowWhereClause, IQueryManager.SEARCH_QUALIFIER_AND);
638 docHandler.setDocumentFilter(docFilter);
645 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHandler()
648 public DocumentHandler getDocumentHandler() throws Exception {
649 DocumentHandler result = docHandler;
650 // create a new instance if one does not yet exist
651 if (result == null) {
652 result = createDocumentHandlerInstance();
658 public void setDocumentHandler(DocumentHandler handler) throws Exception {
659 if (handler != null) {
660 docHandler = handler;
665 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHanlder(javax.ws.rs.core.MultivaluedMap)
668 public DocumentHandler getDocumentHandler(MultivaluedMap<String, String> queryParams) throws Exception {
669 DocumentHandler result = getDocumentHandler();
670 DocumentFilter documentFilter = result.getDocumentFilter(); //to see results in debugger variables view
671 documentFilter.setPagination(queryParams);
676 * If this element is set in the service binding then use it otherwise
677 * assume that asserts are NOT disabled.
679 private boolean disableValidationAsserts() {
681 Boolean disableAsserts = getServiceBinding().isDisableAsserts();
682 result = (disableAsserts != null) ? disableAsserts : false;
687 * @see org.collectionspace.services.common.context.ServiceContext#getValidatorHandlers()
690 public List<ValidatorHandler<IT, OT>> getValidatorHandlers() throws Exception {
691 if (valHandlers != null) {
694 List<String> handlerClazzes = getServiceBinding().getValidatorHandler();
695 List<ValidatorHandler<IT, OT>> handlers = new ArrayList<ValidatorHandler<IT, OT>>(handlerClazzes.size());
696 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
697 for (String clazz : handlerClazzes) {
698 clazz = clazz.trim();
700 Class<?> c = tccl.loadClass(clazz);
701 if (disableValidationAsserts() == false) {
702 // enable validation assertions
703 tccl.setClassAssertionStatus(clazz, true);
705 if (ValidatorHandler.class.isAssignableFrom(c)) {
706 handlers.add((ValidatorHandler) c.newInstance());
708 } catch (ClassNotFoundException e) {
709 String msg = String.format("Missing document validation handler: '%s'.", clazz);
711 logger.trace(msg, e);
714 valHandlers = handlers;
719 * If one doesn't already exist, use the default properties filename to load a set of properties that
720 * will be used to create an HTTP client to a CollectionSpace instance.
723 public AuthorityClient getClient() throws Exception {
724 AuthorityClient result = authorityClient;
726 if (authorityClient == null) {
727 result = authorityClient = getClient(CollectionSpaceClient.DEFAULT_CLIENT_PROPERTIES_FILENAME);
734 * Use the properties filename passed in to load the URL and credentials that will be used
735 * to create a new HTTP client.
737 * Never uses or resets the this.authorityClient member. Always creates a new HTTP client using
738 * the loaded properties.
741 * @see org.collectionspace.services.common.context.ServiceContext#getClient(java.lang.String)
744 public AuthorityClient getClient(String clientPropertiesFilename) throws Exception {
745 AuthorityClient result = null;
747 Properties inProperties = Tools.loadProperties(clientPropertiesFilename, true);
748 result = getClient(inProperties);
753 public AuthorityClient getClient(Properties inProperties) throws Exception {
754 AuthorityClient result = null;
756 String authorityClientClazz = getServiceBinding().getClientHandler();
757 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
758 authorityClientClazz = authorityClientClazz.trim();
760 Class<?> c = tccl.loadClass(authorityClientClazz);
761 if (AuthorityClient.class.isAssignableFrom(c)) {
762 result = authorityClient = ((AuthorityClient) c.newInstance());
763 result.setClientProperties(inProperties);
765 logger.error(String.format("The service binding clientHandler class '%s' for '%s' service was not of type AuthorityClient.",
766 authorityClientClazz, this.getServiceName()));
768 } catch (ClassNotFoundException e) {
769 String msg = String.format("Missing document validation handler: '%s'.", authorityClientClazz);
771 logger.trace(msg, e);
778 public AuthorityClient getClient(RemoteClientConfig remoteClientConfig) throws Exception {
779 AuthorityClient result = null;
781 Properties properties = new Properties();
782 properties.setProperty(AuthorityClient.URL_PROPERTY, remoteClientConfig.getUrl());
783 properties.setProperty(AuthorityClient.USER_PROPERTY, remoteClientConfig.getUser());
784 properties.setProperty(AuthorityClient.PASSWORD_PROPERTY, remoteClientConfig.getPassword());
785 properties.setProperty(AuthorityClient.SSL_PROPERTY, remoteClientConfig.getSsl());
786 properties.setProperty(AuthorityClient.AUTH_PROPERTY, remoteClientConfig.getAuth());
789 String tenantId = remoteClientConfig.getTenantId();
790 if (tenantId != null) {
791 properties.setProperty(AuthorityClient.TENANT_ID_PROPERTY, tenantId);
793 String tenantName = remoteClientConfig.getTenantName();
794 if (tenantName != null) {
795 properties.setProperty(AuthorityClient.TENANT_NAME_PROPERTY, tenantName);
798 result = getClient(properties);
804 public void addValidatorHandler(ValidatorHandler<IT, OT> validator) throws Exception {
805 if (valHandlers == null) {
806 valHandlers = new ArrayList<ValidatorHandler<IT, OT>>();
808 valHandlers.add(validator);
812 * @see java.lang.Object#toString()
815 public String toString() {
816 StringBuilder msg = new StringBuilder();
817 msg.append("AbstractServiceContext [");
818 msg.append("service name=" + serviceBinding.getName() + " ");
819 msg.append("service version=" + serviceBinding.getVersion() + " ");
820 msg.append("tenant id=" + tenantBinding.getId() + " ");
821 msg.append("tenant name=" + tenantBinding.getName() + " ");
822 msg.append(tenantBinding.getDisplayName() + " ");
823 if (repositoryDomain != null) {
824 msg.append("tenant repository domain=" + repositoryDomain.getName());
826 for (Map.Entry<String, Object> entry : properties.entrySet()) {
827 msg.append("property name=" + entry.getKey() + " value=" + entry.getValue().toString());
830 return msg.toString();
834 * @see org.collectionspace.services.common.context.ServiceContext#getQueryParams()
836 * When we first created these services, the RESTEasy query parameters used to be a modifiable map. That changed in a
837 * more recent version of RESTEasy, so we need to make a copy of the params into a modifiable map and return it instead.
840 public MultivaluedMap<String, String> getQueryParams() {
842 if (queryParams == null){
843 if (this.uriInfo != null){
844 queryParams = this.uriInfo.getQueryParameters();
847 if (queryParams == null){
848 queryParams = new org.jboss.resteasy.specimpl.MultivaluedMapImpl<String,String>();
850 return this.queryParams;
854 public MultivaluedMap<String, String> getQueryParamsPtr() {
855 return this.queryParams;
859 * @see org.collectionspace.services.common.context.ServiceContext#setQueryParams(javax.ws.rs.core.MultivaluedMap)
862 public void setQueryParams(MultivaluedMap<String, String> theQueryParams) {
863 this.queryParams = theQueryParams;
867 public void setUriInfo(UriInfo ui){
872 public UriInfo getUriInfo() {
877 public Request getRequestInfo() {
878 return this.requestInfo;
882 public void setRequestInfo(Request requestInfo) {
883 this.requestInfo = requestInfo;
887 * We expect the 'currentRepositorySession' member to be set only once per instance. Also, we expect only one open repository session
888 * per HTTP request. We'll log an error if we see more than one attempt to set a service context's current repo session.
890 * @see org.collectionspace.services.common.context.ServiceContext#setCurrentRepositorySession(java.lang.Object)
893 public void setCurrentRepositorySession(Object repoSession) throws Exception {
894 if (repoSession == null) {
895 String errMsg = "Setting a service context's repository session to null is not allowed.";
896 logger.error(errMsg);
897 throw new Exception(errMsg);
898 } else if (currentRepositorySession != null && currentRepositorySession != repoSession) {
899 String errMsg = "The current service context's repository session was replaced. This may cause unexpected behavior and/or data loss.";
900 logger.error(errMsg);
901 throw new Exception(errMsg);
904 currentRepositorySession = repoSession;
905 this.currentRepoSesssionRefCount++;
909 public void clearCurrentRepositorySession() {
910 if (this.currentRepoSesssionRefCount > 0) {
911 currentRepoSesssionRefCount--;
914 if (currentRepoSesssionRefCount == 0) {
915 this.currentRepositorySession = null;
918 if (currentRepoSesssionRefCount < 0) {
919 throw new RuntimeException("Attempted to clear/close a repository session that has already been cleared/closed.");
924 public Object getCurrentRepositorySession() {
925 // TODO Auto-generated method stub
926 return currentRepositorySession;
930 public RepositoryDomainType getRepositoryDomain() {
931 return repositoryDomain;
935 public void setRepositoryDomain(RepositoryDomainType repositoryDomain) {
936 this.repositoryDomain = repositoryDomain;
940 * Check for a query parameter that indicates if we should force a sync even if the revision numbers indicate otherwise.
944 public boolean shouldForceSync() {
945 boolean forceSync = false;
947 MultivaluedMap<String, String> queryParams = getQueryParams();
948 String paramValue = queryParams.getFirst(IClientQueryParams.FORCE_SYCN);
949 if (paramValue != null && paramValue.equalsIgnoreCase(Boolean.TRUE.toString())) { // Find our if the caller wants us to force refname updates
951 } else if (paramValue != null && paramValue.equals(Long.toString(1))) {
959 public void setRollbackOnException(boolean rollbackOnException) {
960 this.rollbackOnException = rollbackOnException;
964 public boolean isRollbackOnException() {
965 return this.rollbackOnException;