]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
7fbe3e91ba029a983e989b14c4c5d08a187fcd77
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
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.
23  */
24 package org.collectionspace.services.common.context;
25
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Properties;
31
32 import javax.ws.rs.core.MultivaluedMap;
33 import javax.ws.rs.core.Request;
34 import javax.ws.rs.core.UriInfo;
35
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;
65
66 /**
67  * AbstractServiceContext
68  *
69  * $LastChangedRevision: $
70  * $LastChangedDate: $
71  */
72 /**
73  * @author pschmitz
74  *
75  * @param <IT>
76  * @param <OT>
77  */
78 /**
79  * @author pschmitz
80  *
81  * @param <IT>
82  * @param <OT>
83  */
84 @SuppressWarnings("rawtypes")
85 public abstract class AbstractServiceContextImpl<IT, OT>
86         implements ServiceContext<IT, OT> {
87
88     /** The logger. */
89     final Logger logger = LoggerFactory.getLogger(AbstractServiceContextImpl.class);
90     
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;
119         
120     /**
121      * Instantiates a new abstract service context impl.
122      */
123     private AbstractServiceContextImpl() {
124         // private constructor for singleton pattern
125     }
126     // request query params
127     /** The query params. */
128     private MultivaluedMap<String, String> queryParams;
129
130     /**
131      * Instantiates a new abstract service context impl.
132      * 
133      * @param serviceName the service name
134      * 
135      * @throws UnauthorizedException the unauthorized exception
136      */
137     protected AbstractServiceContextImpl(String serviceName, UriInfo uriInfo) throws UnauthorizedException {
138
139         //establish security context
140         securityContext = new SecurityContextImpl(uriInfo);
141         //make sure tenant context exists
142         checkTenantContext();
143
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;
151         } else {
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;
159                     logger.error(msg);
160                     throw new IllegalStateException(msg);
161                 }
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();
167                     logger.error(msg);
168                     throw new IllegalStateException(msg);
169                 }
170                 if (logger.isDebugEnabled()) {
171                     logger.debug("tenantId=" + tenantId
172                             + " service binding=" + serviceBinding.getName());
173                 }
174                 repositoryDomain = tReader.getRepositoryDomain(tenantId, serviceName);
175                 if (repositoryDomain != null) {
176                     if (logger.isDebugEnabled()) {
177                         logger.debug("tenantId=" + tenantId
178                                 + " repository doamin=" + repositoryDomain.getName());
179                     }
180                 }
181         }
182     }
183     
184     public int getTimeoutParam(UriInfo ui) {
185                 int result = DEFAULT_TX_TIMEOUT;
186
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);
192                         }
193                         
194                         if (timeoutString != null) {
195                                 try {                                   
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.",
199                                                         e);
200                                 }
201                         }
202                 }
203
204                 return result;
205         }
206     
207     @Override
208     public int getTimeoutSecs() {
209         UriInfo uriInfo = this.getUriInfo();
210         return this.getTimeoutParam(uriInfo);
211     }
212
213     /**
214      * Returns TRUE unless the "recordUpdates" query param is set with a value of either "false", "FALSE", or "0"
215      * @return
216      */
217     @Override
218     public boolean shouldUpdateCoreValues() {
219                 boolean recordUpdates = true;
220                 
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;
227                 }
228                 
229                 return recordUpdates;
230     }
231     
232         /**
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.
236          * @return
237          */
238     @Override
239     public boolean shouldForceUpdateRefnameReferences() {
240                 boolean forceUpdates = false;
241                 
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
245                         forceUpdates = true;
246                 } else if (paramValue != null && paramValue.equals(Long.toString(1))) {
247                         forceUpdates = true;
248                 }
249                 
250                 return forceUpdates;
251     }
252     
253     
254     /* (non-Javadoc)
255      * @see org.collectionspace.services.common.context.ServiceContext#getCommonPartLabel()
256      */
257     @Override
258     public String getCommonPartLabel() {
259         return getCommonPartLabel(getServiceName());
260     }
261
262     /* (non-Javadoc)
263      * @see org.collectionspace.services.common.context.ServiceContext#getCommonPartLabel(java.lang.String)
264      */
265     public String getCommonPartLabel(String schemaName) {
266         return schemaName.toLowerCase() + PART_LABEL_SEPARATOR + PART_COMMON_LABEL;
267     }
268
269     /* (non-Javadoc)
270      * @see org.collectionspace.services.common.context.ServiceContext#getPartsMetadata()
271      */
272     @Override
273     public Map<String, ObjectPartType> getPartsMetadata() {
274         if (objectPartMap.size() != 0) {
275             return objectPartMap;
276         }
277         ServiceBindingUtils.getPartsMetadata(getServiceBinding(), objectPartMap);
278         return objectPartMap;
279     }
280
281     /**
282      * Gets the properties for part.
283      * 
284      * @param partLabel the part label
285      * 
286      * @return the properties for part
287      */
288     public List<PropertyItemType> getPropertiesForPart(String partLabel) {
289         Map<String, ObjectPartType> partMap = getPartsMetadata();
290         ObjectPartType part = partMap.get(partLabel);
291         if (part == null) {
292             throw new RuntimeException("No such part found: " + partLabel);
293         }
294         List<PropertyType> propNodeList = part.getProperties();
295         return propNodeList.isEmpty() ? null : propNodeList.get(0).getItem();
296     }
297
298     /**
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.
304      */
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));
309     }
310
311     /**
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.
316      */
317     public List<String> getAllPartsPropertyValues(String propName, boolean qualified) {
318         return ServiceBindingUtils.getAllPartsPropertyValues(getServiceBinding(), propName, qualified);
319     }
320
321     /* (non-Javadoc)
322      * @see org.collectionspace.services.common.context.ServiceContext#getServiceBindingPropertyValue(java.lang.String)
323      */
324     public String getServiceBindingPropertyValue(String propName) {
325         return ServiceBindingUtils.getPropertyValue(getServiceBinding(), propName);
326     }
327
328     /**
329      * Gets the common part properties.
330      * 
331      * @return the common part properties
332      */
333     public List<PropertyItemType> getCommonPartProperties() {
334         return getPropertiesForPart(getCommonPartLabel());
335     }
336
337     /**
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.
342      */
343     public List<String> getCommonPartPropertyValues(String propName, boolean qualified) {
344         return getPropertyValuesForPart(getCommonPartLabel(), propName, qualified);
345     }
346
347     /* (non-Javadoc)
348      * @see org.collectionspace.services.common.context.ServiceContext#getQualifiedServiceName()
349      */
350     @Override
351     public String getQualifiedServiceName() {
352         return TenantBindingConfigReaderImpl.getTenantQualifiedServiceName(getTenantId(), getServiceName());
353     }
354
355     /* (non-Javadoc)
356      * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientName()
357      */
358     @Override
359     public String getRepositoryClientName() {
360         if (repositoryDomain == null) {
361             return null;
362         }
363         return repositoryDomain.getRepositoryClient();
364     }
365
366     /* (non-Javadoc)
367      * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryClientType()
368      */
369     @Override
370     public ClientType getRepositoryClientType() {
371         //assumption: there is only one repository client configured
372         return ServiceMain.getInstance().getClientType();
373     }
374
375     /* (non-Javadoc)
376      * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
377      */
378     @Override
379     public String getRepositoryDomainName() {
380         if (repositoryDomain == null) {
381             return null;
382         }
383         return repositoryDomain.getName();
384     }
385
386     /* (non-Javadoc)
387      * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryDomainName()
388      */
389     @Override
390     public String getRepositoryDomainStorageName() {
391         if (repositoryDomain == null) {
392             return null;
393         }
394         return repositoryDomain.getStorageName();
395     }
396
397     /* (non-Javadoc)
398      * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceId()
399      */
400     @Override
401     public String getRepositoryWorkspaceId() {
402         return ServiceMain.getInstance().getWorkspaceId(getTenantId(), getServiceName());
403     }
404
405     /* (non-Javadoc)
406      * @see org.collectionspace.services.common.context.ServiceContext#getRepositoryWorkspaceName()
407      */
408     @Override
409     public String getRepositoryWorkspaceName() {
410         //service name is workspace name by convention
411         return serviceBinding.getName();
412     }
413
414     /* (non-Javadoc)
415      * @see org.collectionspace.services.common.context.ServiceContext#getServiceBinding()
416      */
417     @Override
418     public ServiceBindingType getServiceBinding() {
419         return serviceBinding;
420     }
421
422     /* (non-Javadoc)
423      * @see org.collectionspace.services.common.context.ServiceContext#getServiceName()
424      */
425     @Override
426     public String getServiceName() {
427         return serviceBinding.getName();
428     }
429
430     /* (non-Javadoc)
431      * @see org.collectionspace.services.common.context.ServiceContext#getDocumentType()
432      */
433     @Override
434     public String getDocumentType() {
435         // If they have not overridden the setting, use the type of the service
436         // object.
437         return (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
438     }
439     
440     @Override
441     public String getTenantQualifiedDoctype(String docType) {
442         // If they have not overridden the setting, use the type of the service
443         // object.
444         String result = ServiceBindingUtils.getTenantQualifiedDocType(this.getTenantId(), docType);
445         
446         return result;
447     }
448     
449     @Override
450     public String getTenantQualifiedDoctype() {
451         String docType = (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
452         return getTenantQualifiedDoctype(docType);
453     }
454
455     /* (non-Javadoc)
456      * @see org.collectionspace.services.common.context.ServiceContext#setDocumentType(java.lang.String)
457      */
458     @Override
459     public void setDocumentType(String docType) {
460         overrideDocumentType = docType;
461     }
462
463     /* (non-Javadoc)
464      * @see org.collectionspace.services.common.context.ServiceContext#getSecurityContext()
465      */
466     @Override
467     public SecurityContext getSecurityContext() {
468         return securityContext;
469     }
470
471     /* (non-Javadoc)
472      * @see org.collectionspace.services.common.context.ServiceContext#getUserId()
473      */
474     @Override
475     public String getUserId() {
476         return securityContext.getUserId();
477     }
478
479     /* (non-Javadoc)
480      * @see org.collectionspace.services.common.context.ServiceContext#getTenantId()
481      */
482     @Override
483     public String getTenantId() {
484         return securityContext.getCurrentTenantId();
485     }
486
487     /* (non-Javadoc)
488      * @see org.collectionspace.services.common.context.ServiceContext#getTenantName()
489      */
490     @Override
491     public String getTenantName() {
492         return securityContext.getCurrentTenantName();
493     }
494
495     /* (non-Javadoc)
496      * @see org.collectionspace.services.common.context.ServiceContext#getInput()
497      */
498     @Override
499     public abstract IT getInput();
500
501     /* (non-Javadoc)
502      * @see org.collectionspace.services.common.context.ServiceContext#setInput(java.lang.Object)
503      */
504     @Override
505     public abstract void setInput(IT input);
506
507     /* (non-Javadoc)
508      * @see org.collectionspace.services.common.context.ServiceContext#getOutput()
509      */
510     @Override
511     public abstract OT getOutput();
512
513     /* (non-Javadoc)
514      * @see org.collectionspace.services.common.context.ServiceContext#setOutput(java.lang.Object)
515      */
516     @Override
517     public abstract void setOutput(OT output);
518
519     /* (non-Javadoc)
520      * @see org.collectionspace.services.common.context.ServiceContext#getProperties()
521      */
522     @Override
523     public Map<String, Object> getProperties() {
524         return properties;
525     }
526
527     /* (non-Javadoc)
528      * @see org.collectionspace.services.common.context.ServiceContext#setProperties(java.util.Map)
529      */
530     @Override
531     public void setProperties(Map<String, Object> props) {
532         properties.putAll(props);
533     }
534
535     /* (non-Javadoc)
536      * @see org.collectionspace.services.common.context.ServiceContext#getProperty(java.lang.String)
537      */
538     public Object getProperty(String name) {
539         return properties.get(name);
540     }
541
542     /* (non-Javadoc)
543      * @see org.collectionspace.services.common.context.ServiceContext#setProperty(java.lang.String, java.lang.Object)
544      */
545     public void setProperty(String name, Object o) {
546         properties.put(name, o);
547     }
548
549     /**
550      * checkTenantContext makss sure tenant context exists
551      *
552      * @return the string
553      *
554      * @throws UnauthorizedException the unauthorized exception
555      */
556     private void checkTenantContext() throws UnauthorizedException {
557
558         String tenantId = securityContext.getCurrentTenantId();
559         if (tenantId == null) {
560             String msg = "Could not find tenant context";
561             logger.error(msg);
562             throw new UnauthorizedException(msg);
563         }
564     }
565
566     /**
567      * Helps to filter for queries that either want to include or exclude documents in deleted workflow states.
568      * 
569      * @param queryParams
570      * @return
571      */
572     private static String buildWorkflowWhereClause(MultivaluedMap<String, String> queryParams) {
573         String result = null;
574         
575         String includeDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_NONDELETED);
576         String includeOnlyDeleted = queryParams.getFirst(WorkflowClient.WORKFLOW_QUERY_ONLY_DELETED);
577
578         if (includeDeleted != null && includeDeleted.equalsIgnoreCase(Boolean.FALSE.toString())) {      
579                 result = String.format("(ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s')",
580                                 WorkflowClient.WORKFLOWSTATE_DELETED, WorkflowClient.WORKFLOWSTATE_LOCKED_DELETED, WorkflowClient.WORKFLOWSTATE_REPLICATED_DELETED);
581         } else if (includeOnlyDeleted != null && includeOnlyDeleted.equalsIgnoreCase(Boolean.TRUE.toString())) {
582                 result = String.format("(ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s' AND ecm:currentLifeCycleState <> '%s')",
583                                 WorkflowClient.WORKFLOWSTATE_PROJECT, WorkflowClient.WORKFLOWSTATE_LOCKED, WorkflowClient.WORKFLOWSTATE_REPLICATED);
584         }
585         
586         return result;
587     }
588     
589     /**
590      * Creates the document handler instance.
591      * 
592      * @return the document handler
593      * 
594      * @throws Exception the exception
595      */
596     private DocumentHandler createDocumentHandlerInstance() throws Exception {
597         docHandler = ServiceConfigUtils.createDocumentHandlerInstance(tenantBinding, serviceBinding);
598         
599         //
600         // The docHandler for a Service can be null, but usually is not.
601         //
602         if (docHandler != null) {
603                 //
604                 // Create a default document filter
605                 //
606                 docHandler.setServiceContext(this);
607                 DocumentFilter docFilter = docHandler.createDocumentFilter();
608                 //
609                 // If the context was created with query parameters,
610                 // reflect the values of those parameters in the document filter
611                 // to specify sort ordering, pagination, etc.
612                 //
613                 MultivaluedMap<String, String> queryParameters = this.getQueryParams();
614                 if (queryParameters != null) {
615                   docFilter.setSortOrder(queryParameters);
616                   docFilter.setPagination(queryParameters);
617                   String workflowWhereClause = buildWorkflowWhereClause(queryParameters);
618                   if (workflowWhereClause != null) {
619                           docFilter.appendWhereClause(workflowWhereClause, IQueryManager.SEARCH_QUALIFIER_AND);                 
620                   }            
621         
622                 }
623                 docHandler.setDocumentFilter(docFilter);
624         }
625         
626         return docHandler;
627     }
628
629     /* (non-Javadoc)
630      * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHandler()
631      */
632     @Override
633     public DocumentHandler getDocumentHandler() throws Exception {
634         DocumentHandler result = docHandler;
635         // create a new instance if one does not yet exist
636         if (result == null) {
637             result = createDocumentHandlerInstance();
638         }
639         return result;
640     }
641
642     @Override
643     public void setDocumentHandler(DocumentHandler handler) throws Exception {
644         if (handler != null) {
645                 docHandler = handler;
646         }
647     }
648
649     /* (non-Javadoc)
650      * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHanlder(javax.ws.rs.core.MultivaluedMap)
651      */
652     @Override
653     public DocumentHandler getDocumentHandler(MultivaluedMap<String, String> queryParams) throws Exception {
654         DocumentHandler result = getDocumentHandler();
655         DocumentFilter documentFilter = result.getDocumentFilter(); //to see results in debugger variables view
656         documentFilter.setPagination(queryParams);
657         return result;
658     }
659     
660     /*
661      * If this element is set in the service binding then use it otherwise
662      * assume that asserts are NOT disabled.
663      */
664     private boolean disableValidationAsserts() {
665         boolean result;
666         Boolean disableAsserts = getServiceBinding().isDisableAsserts();
667         result = (disableAsserts != null) ? disableAsserts : false;
668         return result;
669     }
670     
671     /* (non-Javadoc)
672      * @see org.collectionspace.services.common.context.ServiceContext#getValidatorHandlers()
673      */
674     @Override
675     public List<ValidatorHandler<IT, OT>> getValidatorHandlers() throws Exception {
676         if (valHandlers != null) {
677             return valHandlers;
678         }
679         List<String> handlerClazzes = getServiceBinding().getValidatorHandler();
680         List<ValidatorHandler<IT, OT>> handlers = new ArrayList<ValidatorHandler<IT, OT>>(handlerClazzes.size());
681         ClassLoader tccl = Thread.currentThread().getContextClassLoader();
682         for (String clazz : handlerClazzes) {
683             clazz = clazz.trim();
684             try {
685                     Class<?> c = tccl.loadClass(clazz);
686                     if (disableValidationAsserts() == false) {
687                         // enable validation assertions
688                         tccl.setClassAssertionStatus(clazz, true);
689                     }
690                     if (ValidatorHandler.class.isAssignableFrom(c)) {
691                         handlers.add((ValidatorHandler) c.newInstance());
692                     }
693             } catch (ClassNotFoundException e) {
694                 String msg = String.format("Missing document validation handler: '%s'.", clazz);
695                 logger.warn(msg);
696                 logger.trace(msg, e);
697             }
698         }
699         valHandlers = handlers;
700         return valHandlers;
701     }
702     
703     /**
704      * If one doesn't already exist, use the default properties filename to load a set of properties that
705      * will be used to create an HTTP client to a CollectionSpace instance.
706      */
707     @Override
708     public AuthorityClient getClient() throws Exception {
709         AuthorityClient result = authorityClient;
710
711         if (authorityClient == null) {
712                 result = authorityClient = getClient(CollectionSpaceClient.DEFAULT_CLIENT_PROPERTIES_FILENAME);
713         }
714         
715         return result;
716     }
717     
718     /*
719      * Use the properties filename passed in to load the URL and credentials that will be used
720      * to create a new HTTP client.
721      * 
722      * Never uses or resets the this.authorityClient member.  Always creates a new HTTP client using
723      * the loaded properties.
724      * 
725      * (non-Javadoc)
726      * @see org.collectionspace.services.common.context.ServiceContext#getClient(java.lang.String)
727      */
728         @Override
729     public AuthorityClient getClient(String clientPropertiesFilename) throws Exception {
730         AuthorityClient result = null;
731         
732         Properties inProperties = Tools.loadProperties(clientPropertiesFilename, true);
733         result = getClient(inProperties);
734         
735         return result;
736     }
737     
738     public AuthorityClient getClient(Properties inProperties) throws Exception {
739         AuthorityClient result = null;
740         
741         String authorityClientClazz = getServiceBinding().getClientHandler();
742         ClassLoader tccl = Thread.currentThread().getContextClassLoader();
743         authorityClientClazz = authorityClientClazz.trim();
744         try {
745             Class<?> c = tccl.loadClass(authorityClientClazz);
746             if (AuthorityClient.class.isAssignableFrom(c)) {
747                 result = authorityClient = ((AuthorityClient) c.newInstance());
748                 result.setClientProperties(inProperties);
749             } else {
750                 logger.error(String.format("The service binding clientHandler class '%s' for '%s' service was not of type AuthorityClient.",
751                                 authorityClientClazz, this.getServiceName()));
752             }
753         } catch (ClassNotFoundException e) {
754                 String msg = String.format("Missing document validation handler: '%s'.", authorityClientClazz);
755                 logger.warn(msg);
756                 logger.trace(msg, e);
757         }
758         
759         return result;
760     }
761     
762     @Override
763     public AuthorityClient getClient(RemoteClientConfig remoteClientConfig) throws Exception {
764         AuthorityClient result = null;
765         
766         Properties properties = new Properties();
767         properties.setProperty(AuthorityClient.URL_PROPERTY, remoteClientConfig.getUrl());
768         properties.setProperty(AuthorityClient.USER_PROPERTY, remoteClientConfig.getUser());
769         properties.setProperty(AuthorityClient.PASSWORD_PROPERTY, remoteClientConfig.getPassword());
770         properties.setProperty(AuthorityClient.SSL_PROPERTY, remoteClientConfig.getSsl());
771         properties.setProperty(AuthorityClient.AUTH_PROPERTY, remoteClientConfig.getAuth());
772         //
773         // Optional values
774         String tenantId = remoteClientConfig.getTenantId();
775         if (tenantId != null) {
776                 properties.setProperty(AuthorityClient.TENANT_ID_PROPERTY, tenantId);
777         }
778         String tenantName = remoteClientConfig.getTenantName();
779         if (tenantName != null) {
780                 properties.setProperty(AuthorityClient.TENANT_NAME_PROPERTY, tenantName);
781         }
782         
783         result = getClient(properties);
784         
785         return result;
786     }
787     
788     @Override
789     public void addValidatorHandler(ValidatorHandler<IT, OT> validator) throws Exception {
790         if (valHandlers == null) {
791             valHandlers = new ArrayList<ValidatorHandler<IT, OT>>();
792         }
793         valHandlers.add(validator);
794     }
795
796     /* (non-Javadoc)
797      * @see java.lang.Object#toString()
798      */
799     @Override
800     public String toString() {
801         StringBuilder msg = new StringBuilder();
802         msg.append("AbstractServiceContext [");
803         msg.append("service name=" + serviceBinding.getName() + " ");
804         msg.append("service version=" + serviceBinding.getVersion() + " ");
805         msg.append("tenant id=" + tenantBinding.getId() + " ");
806         msg.append("tenant name=" + tenantBinding.getName() + " ");
807         msg.append(tenantBinding.getDisplayName() + " ");
808         if (repositoryDomain != null) {
809             msg.append("tenant repository domain=" + repositoryDomain.getName());
810         }
811         for (Map.Entry<String, Object> entry : properties.entrySet()) {
812             msg.append("property name=" + entry.getKey() + " value=" + entry.getValue().toString());
813         }
814         msg.append("]");
815         return msg.toString();
816     }
817
818     /* (non-Javadoc)
819      * @see org.collectionspace.services.common.context.ServiceContext#getQueryParams()
820      * 
821      * When we first created these services, the RESTEasy query parameters used to be a modifiable map.  That changed in a
822      * more recent version of RESTEasy, so we need to make a copy of the params into a modifiable map and return it instead.
823      */
824     @Override
825     public MultivaluedMap<String, String> getQueryParams() {
826
827          if (queryParams == null){
828               if (this.uriInfo != null){
829                 queryParams = this.uriInfo.getQueryParameters();
830             }
831          }
832          if (queryParams == null){
833              queryParams = new org.jboss.resteasy.specimpl.MultivaluedMapImpl<String,String>();
834         }
835         return this.queryParams;
836     }
837
838     @Override
839      public MultivaluedMap<String, String> getQueryParamsPtr() {
840            return this.queryParams;
841     }
842
843     /* (non-Javadoc)
844      * @see org.collectionspace.services.common.context.ServiceContext#setQueryParams(javax.ws.rs.core.MultivaluedMap)
845      */
846     @Override
847     public void setQueryParams(MultivaluedMap<String, String> theQueryParams) {
848         this.queryParams = theQueryParams;
849     }
850
851     @Override
852     public void setUriInfo(UriInfo ui){
853         this.uriInfo = ui;
854     }
855
856         @Override
857         public UriInfo getUriInfo() {
858                 return this.uriInfo;
859         }
860         
861         @Override
862         public Request getRequestInfo() {
863                 return this.requestInfo;
864         }
865         
866         @Override
867         public void setRequestInfo(Request requestInfo) {
868                 this.requestInfo = requestInfo;
869         }
870         
871         /*
872          * We expect the 'currentRepositorySession' member to be set only once per instance.  Also, we expect only one open repository session
873          * per HTTP request.  We'll log an error if we see more than one attempt to set a service context's current repo session.
874          * (non-Javadoc)
875          * @see org.collectionspace.services.common.context.ServiceContext#setCurrentRepositorySession(java.lang.Object)
876          */
877         @Override
878         public void setCurrentRepositorySession(Object repoSession) throws Exception {
879                 if (repoSession == null) {
880                         String errMsg = "Setting a service context's repository session to null is not allowed.";
881                         logger.error(errMsg);
882                         throw new Exception(errMsg);
883                 } else if (currentRepositorySession != null && currentRepositorySession != repoSession) {
884                         String errMsg = "The current service context's repository session was replaced.  This may cause unexpected behavior and/or data loss.";
885                         logger.error(errMsg);
886                         throw new Exception(errMsg);
887                 }
888                 
889                 currentRepositorySession = repoSession;
890                 this.currentRepoSesssionRefCount++;
891         }
892         
893         @Override
894         public void clearCurrentRepositorySession() {
895                 if (this.currentRepoSesssionRefCount > 0) {
896                         currentRepoSesssionRefCount--;
897                 }
898                 
899                 if (currentRepoSesssionRefCount == 0) {
900                         this.currentRepositorySession = null;
901                 }
902                 
903                 if (currentRepoSesssionRefCount < 0) {
904                         throw new RuntimeException("Attempted to clear/close a repository session that has already been cleared/closed.");
905                 }
906         }
907         
908         @Override
909         public Object getCurrentRepositorySession() {
910                 // TODO Auto-generated method stub
911                 return currentRepositorySession;
912         }       
913
914         @Override       
915         public RepositoryDomainType getRepositoryDomain() {
916                 return repositoryDomain;
917         }
918
919         @Override       
920         public void setRepositoryDomain(RepositoryDomainType repositoryDomain) {
921                 this.repositoryDomain = repositoryDomain;
922         }
923         
924         /**
925          * Check for a query parameter that indicates if we should force a sync even if the revision numbers indicate otherwise.
926          * @return
927          */
928         @Override
929         public boolean shouldForceSync() {
930                 boolean forceSync = false;
931                 
932                 MultivaluedMap<String, String> queryParams = getQueryParams();
933                 String paramValue = queryParams.getFirst(IClientQueryParams.FORCE_SYCN);
934                 if (paramValue != null && paramValue.equalsIgnoreCase(Boolean.TRUE.toString())) { // Find our if the caller wants us to force refname updates
935                         forceSync = true;
936                 } else if (paramValue != null && paramValue.equals(Long.toString(1))) {
937                         forceSync = true;
938                 }
939                 
940                 return forceSync;
941     }
942         
943 }