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.authentication.spi.AuthNContext;
38 import org.collectionspace.services.client.AuthorityClient;
39 import org.collectionspace.services.client.CollectionSpaceClient;
40 import org.collectionspace.services.client.IClientQueryParams;
41 import org.collectionspace.services.client.IQueryManager;
42 import org.collectionspace.services.client.workflow.WorkflowClient;
43 import org.collectionspace.services.common.ServiceMain;
44 import org.collectionspace.services.common.api.Tools;
45 import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon;
46 import org.collectionspace.services.common.config.PropertyItemUtils;
47 import org.collectionspace.services.common.config.ServiceConfigUtils;
48 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
49 import org.collectionspace.services.common.document.DocumentHandler;
50 import org.collectionspace.services.common.document.DocumentFilter;
51 import org.collectionspace.services.common.document.ValidatorHandler;
52 import org.collectionspace.services.common.security.SecurityContext;
53 import org.collectionspace.services.common.security.SecurityContextImpl;
54 import org.collectionspace.services.common.security.UnauthorizedException;
55 import org.collectionspace.services.config.ClientType;
56 import org.collectionspace.services.config.service.ObjectPartType;
57 import org.collectionspace.services.config.service.ServiceBindingType;
58 import org.collectionspace.services.config.tenant.RemoteClientConfig;
59 import org.collectionspace.services.config.tenant.RepositoryDomainType;
60 import org.collectionspace.services.config.tenant.TenantBindingType;
61 import org.collectionspace.services.config.types.PropertyItemType;
62 import org.collectionspace.services.config.types.PropertyType;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
67 * AbstractServiceContext
69 * $LastChangedRevision: $
84 @SuppressWarnings("rawtypes")
85 public abstract class AbstractServiceContextImpl<IT, OT>
86 implements ServiceContext<IT, OT> {
89 final Logger logger = LoggerFactory.getLogger(AbstractServiceContextImpl.class);
91 /** The properties. */
92 Map<String, Object> properties = new HashMap<String, Object>();
93 /** The object part map. */
94 Map<String, ObjectPartType> objectPartMap = new HashMap<String, ObjectPartType>();
95 /** The service binding. */
96 protected ServiceBindingType serviceBinding;
97 /** The tenant binding. */
98 private TenantBindingType tenantBinding;
99 /** repository domain used by the service */
100 private RepositoryDomainType repositoryDomain;
101 /** The override document type. */
102 private String overrideDocumentType = null;
103 /** The val handlers. */
104 private List<ValidatorHandler<IT, OT>> valHandlers = null;
105 /** The authority client -use for shared authority server */
106 private AuthorityClient authorityClient = null;
107 /** The doc handler. */
108 private DocumentHandler docHandler = null;
109 /** security context */
110 private SecurityContext securityContext;
111 /** The sessions JAX-RS URI information */
112 private UriInfo uriInfo;
113 /** The JAX-RS request information */
114 private Request requestInfo;
115 /** The current repository session */
116 private Object currentRepositorySession;
117 /** A reference count for the current repository session */
118 private int currentRepoSesssionRefCount = 0;
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.
572 private static String buildWorkflowWhereClause(MultivaluedMap<String, String> queryParams) {
573 String result = null;
575 String includeDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
576 String includeOnlyDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED); // if set to true, it doesn't matter what the value is for 'includeDeleted'
578 if (includeOnlyDeleted != null) {
579 if (Tools.isTrue(includeOnlyDeleted)) {
581 // A value of 'true' for 'includeOnlyDeleted' means we're looking *only* for soft-deleted records/documents.
583 result = String.format("(ecm:currentLifeCycleState = '%s' OR ecm:currentLifeCycleState = '%s' OR ecm:currentLifeCycleState = '%s')",
584 WorkflowClient.WORKFLOWSTATE_DELETED, WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED,
585 WorkflowClient.WORKFLOWSTATE_REPLICATED_DELETED);
587 } else if (!Tools.isTrue(includeDeleted)) {
589 // We can only get here if the 'includeOnlyDeleted' query param is missing altogether.
590 // Ensure we don't return soft-deleted records
592 result = String.format("(ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s')",
593 WorkflowClient.WORKFLOWSTATE_DELETED, WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED,
594 WorkflowClient.WORKFLOWSTATE_REPLICATED_DELETED);
601 * Creates the document handler instance.
603 * @return the document handler
605 * @throws Exception the exception
607 private DocumentHandler createDocumentHandlerInstance() throws Exception {
608 docHandler = ServiceConfigUtils.createDocumentHandlerInstance(tenantBinding, serviceBinding);
611 // The docHandler for a Service can be null, but usually is not.
613 if (docHandler != null) {
615 // Create a default document filter
617 docHandler.setServiceContext(this);
618 DocumentFilter docFilter = docHandler.createDocumentFilter();
620 // If the context was created with query parameters,
621 // reflect the values of those parameters in the document filter
622 // to specify sort ordering, pagination, etc.
624 MultivaluedMap<String, String> queryParameters = this.getQueryParams();
625 if (queryParameters != null) {
626 docFilter.setSortOrder(queryParameters);
627 docFilter.setPagination(queryParameters);
628 String workflowWhereClause = buildWorkflowWhereClause(queryParameters);
629 if (workflowWhereClause != null) {
630 docFilter.appendWhereClause(workflowWhereClause, IQueryManager.SEARCH_QUALIFIER_AND);
634 docHandler.setDocumentFilter(docFilter);
641 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHandler()
644 public DocumentHandler getDocumentHandler() throws Exception {
645 DocumentHandler result = docHandler;
646 // create a new instance if one does not yet exist
647 if (result == null) {
648 result = createDocumentHandlerInstance();
654 public void setDocumentHandler(DocumentHandler handler) throws Exception {
655 if (handler != null) {
656 docHandler = handler;
661 * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHanlder(javax.ws.rs.core.MultivaluedMap)
664 public DocumentHandler getDocumentHandler(MultivaluedMap<String, String> queryParams) throws Exception {
665 DocumentHandler result = getDocumentHandler();
666 DocumentFilter documentFilter = result.getDocumentFilter(); //to see results in debugger variables view
667 documentFilter.setPagination(queryParams);
672 * If this element is set in the service binding then use it otherwise
673 * assume that asserts are NOT disabled.
675 private boolean disableValidationAsserts() {
677 Boolean disableAsserts = getServiceBinding().isDisableAsserts();
678 result = (disableAsserts != null) ? disableAsserts : false;
683 * @see org.collectionspace.services.common.context.ServiceContext#getValidatorHandlers()
686 public List<ValidatorHandler<IT, OT>> getValidatorHandlers() throws Exception {
687 if (valHandlers != null) {
690 List<String> handlerClazzes = getServiceBinding().getValidatorHandler();
691 List<ValidatorHandler<IT, OT>> handlers = new ArrayList<ValidatorHandler<IT, OT>>(handlerClazzes.size());
692 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
693 for (String clazz : handlerClazzes) {
694 clazz = clazz.trim();
696 Class<?> c = tccl.loadClass(clazz);
697 if (disableValidationAsserts() == false) {
698 // enable validation assertions
699 tccl.setClassAssertionStatus(clazz, true);
701 if (ValidatorHandler.class.isAssignableFrom(c)) {
702 handlers.add((ValidatorHandler) c.newInstance());
704 } catch (ClassNotFoundException e) {
705 String msg = String.format("Missing document validation handler: '%s'.", clazz);
707 logger.trace(msg, e);
710 valHandlers = handlers;
715 * If one doesn't already exist, use the default properties filename to load a set of properties that
716 * will be used to create an HTTP client to a CollectionSpace instance.
719 public AuthorityClient getClient() throws Exception {
720 AuthorityClient result = authorityClient;
722 if (authorityClient == null) {
723 result = authorityClient = getClient(CollectionSpaceClient.DEFAULT_CLIENT_PROPERTIES_FILENAME);
730 * Use the properties filename passed in to load the URL and credentials that will be used
731 * to create a new HTTP client.
733 * Never uses or resets the this.authorityClient member. Always creates a new HTTP client using
734 * the loaded properties.
737 * @see org.collectionspace.services.common.context.ServiceContext#getClient(java.lang.String)
740 public AuthorityClient getClient(String clientPropertiesFilename) throws Exception {
741 AuthorityClient result = null;
743 Properties inProperties = Tools.loadProperties(clientPropertiesFilename, true);
744 result = getClient(inProperties);
749 public AuthorityClient getClient(Properties inProperties) throws Exception {
750 AuthorityClient result = null;
752 String authorityClientClazz = getServiceBinding().getClientHandler();
753 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
754 authorityClientClazz = authorityClientClazz.trim();
756 Class<?> c = tccl.loadClass(authorityClientClazz);
757 if (AuthorityClient.class.isAssignableFrom(c)) {
758 result = authorityClient = ((AuthorityClient) c.newInstance());
759 result.setClientProperties(inProperties);
761 logger.error(String.format("The service binding clientHandler class '%s' for '%s' service was not of type AuthorityClient.",
762 authorityClientClazz, this.getServiceName()));
764 } catch (ClassNotFoundException e) {
765 String msg = String.format("Missing document validation handler: '%s'.", authorityClientClazz);
767 logger.trace(msg, e);
774 public AuthorityClient getClient(RemoteClientConfig remoteClientConfig) throws Exception {
775 AuthorityClient result = null;
777 Properties properties = new Properties();
778 properties.setProperty(AuthorityClient.URL_PROPERTY, remoteClientConfig.getUrl());
779 properties.setProperty(AuthorityClient.USER_PROPERTY, remoteClientConfig.getUser());
780 properties.setProperty(AuthorityClient.PASSWORD_PROPERTY, remoteClientConfig.getPassword());
781 properties.setProperty(AuthorityClient.SSL_PROPERTY, remoteClientConfig.getSsl());
782 properties.setProperty(AuthorityClient.AUTH_PROPERTY, remoteClientConfig.getAuth());
785 String tenantId = remoteClientConfig.getTenantId();
786 if (tenantId != null) {
787 properties.setProperty(AuthorityClient.TENANT_ID_PROPERTY, tenantId);
789 String tenantName = remoteClientConfig.getTenantName();
790 if (tenantName != null) {
791 properties.setProperty(AuthorityClient.TENANT_NAME_PROPERTY, tenantName);
794 result = getClient(properties);
800 public void addValidatorHandler(ValidatorHandler<IT, OT> validator) throws Exception {
801 if (valHandlers == null) {
802 valHandlers = new ArrayList<ValidatorHandler<IT, OT>>();
804 valHandlers.add(validator);
808 * @see java.lang.Object#toString()
811 public String toString() {
812 StringBuilder msg = new StringBuilder();
813 msg.append("AbstractServiceContext [");
814 msg.append("service name=" + serviceBinding.getName() + " ");
815 msg.append("service version=" + serviceBinding.getVersion() + " ");
816 msg.append("tenant id=" + tenantBinding.getId() + " ");
817 msg.append("tenant name=" + tenantBinding.getName() + " ");
818 msg.append(tenantBinding.getDisplayName() + " ");
819 if (repositoryDomain != null) {
820 msg.append("tenant repository domain=" + repositoryDomain.getName());
822 for (Map.Entry<String, Object> entry : properties.entrySet()) {
823 msg.append("property name=" + entry.getKey() + " value=" + entry.getValue().toString());
826 return msg.toString();
830 * @see org.collectionspace.services.common.context.ServiceContext#getQueryParams()
832 * When we first created these services, the RESTEasy query parameters used to be a modifiable map. That changed in a
833 * more recent version of RESTEasy, so we need to make a copy of the params into a modifiable map and return it instead.
836 public MultivaluedMap<String, String> getQueryParams() {
838 if (queryParams == null){
839 if (this.uriInfo != null){
840 queryParams = this.uriInfo.getQueryParameters();
843 if (queryParams == null){
844 queryParams = new org.jboss.resteasy.specimpl.MultivaluedMapImpl<String,String>();
846 return this.queryParams;
850 public MultivaluedMap<String, String> getQueryParamsPtr() {
851 return this.queryParams;
855 * @see org.collectionspace.services.common.context.ServiceContext#setQueryParams(javax.ws.rs.core.MultivaluedMap)
858 public void setQueryParams(MultivaluedMap<String, String> theQueryParams) {
859 this.queryParams = theQueryParams;
863 public void setUriInfo(UriInfo ui){
868 public UriInfo getUriInfo() {
873 public Request getRequestInfo() {
874 return this.requestInfo;
878 public void setRequestInfo(Request requestInfo) {
879 this.requestInfo = requestInfo;
883 * We expect the 'currentRepositorySession' member to be set only once per instance. Also, we expect only one open repository session
884 * per HTTP request. We'll log an error if we see more than one attempt to set a service context's current repo session.
886 * @see org.collectionspace.services.common.context.ServiceContext#setCurrentRepositorySession(java.lang.Object)
889 public void setCurrentRepositorySession(Object repoSession) throws Exception {
890 if (repoSession == null) {
891 String errMsg = "Setting a service context's repository session to null is not allowed.";
892 logger.error(errMsg);
893 throw new Exception(errMsg);
894 } else if (currentRepositorySession != null && currentRepositorySession != repoSession) {
895 String errMsg = "The current service context's repository session was replaced. This may cause unexpected behavior and/or data loss.";
896 logger.error(errMsg);
897 throw new Exception(errMsg);
900 currentRepositorySession = repoSession;
901 this.currentRepoSesssionRefCount++;
905 public void clearCurrentRepositorySession() {
906 if (this.currentRepoSesssionRefCount > 0) {
907 currentRepoSesssionRefCount--;
910 if (currentRepoSesssionRefCount == 0) {
911 this.currentRepositorySession = null;
914 if (currentRepoSesssionRefCount < 0) {
915 throw new RuntimeException("Attempted to clear/close a repository session that has already been cleared/closed.");
920 public Object getCurrentRepositorySession() {
921 // TODO Auto-generated method stub
922 return currentRepositorySession;
926 public RepositoryDomainType getRepositoryDomain() {
927 return repositoryDomain;
931 public void setRepositoryDomain(RepositoryDomainType repositoryDomain) {
932 this.repositoryDomain = repositoryDomain;
936 * Check for a query parameter that indicates if we should force a sync even if the revision numbers indicate otherwise.
940 public boolean shouldForceSync() {
941 boolean forceSync = false;
943 MultivaluedMap<String, String> queryParams = getQueryParams();
944 String paramValue = queryParams.getFirst(IClientQueryParams.FORCE_SYCN);
945 if (paramValue != null && paramValue.equalsIgnoreCase(Boolean.TRUE.toString())) { // Find our if the caller wants us to force refname updates
947 } else if (paramValue != null && paramValue.equals(Long.toString(1))) {