2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.common.context;
26 import java.security.acl.Group;
27 import java.util.ArrayList;
28 import java.util.Enumeration;
29 import java.util.HashMap;
30 import java.util.List;
33 import javax.security.auth.Subject;
34 import javax.security.jacc.PolicyContext;
35 import javax.security.jacc.PolicyContextException;
36 import org.collectionspace.authentication.CSpaceTenant;
38 import org.collectionspace.services.common.ClientType;
39 import org.collectionspace.services.common.ServiceMain;
40 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
41 import org.collectionspace.services.common.document.DocumentHandler;
42 import org.collectionspace.services.common.document.ValidatorHandler;
43 import org.collectionspace.services.common.security.UnauthorizedException;
44 import org.collectionspace.services.common.service.ObjectPartType;
45 import org.collectionspace.services.common.service.ServiceBindingType;
46 import org.collectionspace.services.common.service.ServiceObjectType;
47 import org.collectionspace.services.common.tenant.TenantBindingType;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 * AbstractServiceContext
54 * $LastChangedRevision: $
57 public abstract class AbstractServiceContextImpl<IT, OT>
58 implements ServiceContext<IT, OT> {
60 final Logger logger = LoggerFactory.getLogger(AbstractServiceContextImpl.class);
61 Map<String, Object> properties = new HashMap<String, Object>();
62 Map<String, ObjectPartType> objectPartMap = new HashMap<String, ObjectPartType>();
63 private ServiceBindingType serviceBinding;
64 private TenantBindingType tenantBinding;
65 private String overrideDocumentType = null;
66 private List<ValidatorHandler> valHandlers = null;
67 private DocumentHandler docHandler = null;
69 public AbstractServiceContextImpl(String serviceName) throws UnauthorizedException {
70 TenantBindingConfigReaderImpl tReader =
71 ServiceMain.getInstance().getTenantBindingConfigReader();
72 //FIXME retrieveTenantId is not working consistently in non-auth mode
73 //TODO: get tenant binding from security context
74 String tenantId = retrieveTenantId();
75 if (tenantId == null) {
76 //for testing purposes
77 tenantId = "1"; //hardcoded for movingimages.us
79 tenantBinding = tReader.getTenantBinding(tenantId);
80 if (tenantBinding == null) {
81 String msg = "No tenant binding found for tenantId=" + tenantId
82 + " while processing request for service= " + serviceName;
84 throw new IllegalStateException(msg);
86 serviceBinding = tReader.getServiceBinding(tenantId, serviceName);
87 if (serviceBinding == null) {
88 String msg = "No service binding found while processing request for "
89 + serviceName + " for tenant id=" + getTenantId()
90 + " name=" + getTenantName();
92 throw new IllegalStateException(msg);
94 if (logger.isDebugEnabled()) {
95 logger.debug("tenantId=" + tenantId
96 + " service binding=" + serviceBinding.getName());
101 * getCommonPartLabel get common part label
105 public String getCommonPartLabel() {
106 return getCommonPartLabel(getServiceName());
110 * getCommonPartLabel get common part label
113 public String getCommonPartLabel(String schemaName) {
114 return schemaName.toLowerCase() + PART_LABEL_SEPERATOR + PART_COMMON_LABEL;
118 public Map<String, ObjectPartType> getPartsMetadata() {
119 if (objectPartMap.size() != 0) {
120 return objectPartMap;
122 ServiceBindingType serviceBinding = getServiceBinding();
123 ServiceObjectType objectType = serviceBinding.getObject();
124 List<ObjectPartType> objectPartTypes = objectType.getPart();
125 for (ObjectPartType objectPartType : objectPartTypes) {
126 objectPartMap.put(objectPartType.getLabel(), objectPartType);
128 return objectPartMap;
132 public String getQualifiedServiceName() {
133 return TenantBindingConfigReaderImpl.getTenantQualifiedServiceName(getTenantId(), getServiceName());
137 public String getRepositoryClientName() {
138 if (serviceBinding.getRepositoryClient() == null) {
141 return serviceBinding.getRepositoryClient().trim();
145 public ClientType getRepositoryClientType() {
146 //assumption: there is only one repository client configured
147 return ServiceMain.getInstance().getClientType();
151 public String getRepositoryDomainName() {
152 return tenantBinding.getRepositoryDomain();
156 public String getRepositoryWorkspaceId() {
157 TenantBindingConfigReaderImpl tbConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
158 return tbConfigReader.getWorkspaceId(getTenantId(), getServiceName());
162 public String getRepositoryWorkspaceName() {
163 //service name is workspace name by convention
164 return serviceBinding.getName();
168 public ServiceBindingType getServiceBinding() {
169 return serviceBinding;
173 public String getServiceName() {
174 return serviceBinding.getName();
178 public String getDocumentType() {
179 // If they have not overridden the setting, use the type of the service
181 return (overrideDocumentType != null) ? overrideDocumentType : serviceBinding.getObject().getName();
185 public void setDocumentType(String docType) {
186 overrideDocumentType = docType;
190 public String getTenantId() {
191 return tenantBinding.getId();
195 public String getTenantName() {
196 return tenantBinding.getName();
200 public abstract IT getInput();
203 public abstract void setInput(IT input);
206 public abstract OT getOutput();
209 public abstract void setOutput(OT output);
212 public Map<String, Object> getProperties() {
217 public void setProperties(Map<String, Object> props) {
218 properties.putAll(props);
221 public Object getProperty(String name) {
222 return properties.get(name);
225 public void setProperty(String name, Object o) {
226 properties.put(name, o);
228 private static final String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
230 private String retrieveTenantId() throws UnauthorizedException {
232 String tenantId = null;
233 Subject caller = null;
234 Set<Group> groups = null;
236 caller = (Subject) PolicyContext.getContext(SUBJECT_CONTEXT_KEY);
237 if (caller == null) {
238 //logger.warn("security not enabled...");
241 groups = caller.getPrincipals(Group.class);
242 if (groups != null && groups.size() == 0) {
243 //TODO: find out why subject is not null
244 if (logger.isDebugEnabled()) {
245 logger.debug("no tenant(s) found!");
249 } catch (PolicyContextException pce) {
250 String msg = "Could not retrieve principal information";
251 logger.error(msg, pce);
252 throw new UnauthorizedException(msg);
254 for (Group g : groups) {
255 if ("Tenants".equals(g.getName())) {
256 Enumeration members = g.members();
257 while (members.hasMoreElements()) {
258 CSpaceTenant tenant = (CSpaceTenant) members.nextElement();
259 tenantId = tenant.getId();
260 if (logger.isDebugEnabled()) {
261 logger.debug("found tenant id=" + tenant.getId()
262 + " name=" + tenant.getName());
267 //TODO: if a user is associated with more than one tenants, the tenant
268 //id should be matched with sent over the wire
269 if (tenantId == null) {
270 String msg = "Could not find tenant context";
272 throw new UnauthorizedException(msg);
278 public DocumentHandler getDocumentHandler() throws Exception {
279 if (docHandler != null) {
282 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
283 Class c = tccl.loadClass(getDocumentHandlerClass());
284 if (DocumentHandler.class.isAssignableFrom(c)) {
285 docHandler = (DocumentHandler) c.newInstance();
287 throw new IllegalArgumentException("Not of type " +
288 DocumentHandler.class.getCanonicalName());
290 docHandler.setServiceContext(this);
294 private String getDocumentHandlerClass() {
295 if (serviceBinding.getDocumentHandler() == null
296 || serviceBinding.getDocumentHandler().isEmpty()) {
297 String msg = "Missing documentHandler in service binding for "
298 + getServiceName() + " for tenant id=" + getTenantId()
299 + " name=" + getTenantName();
301 throw new IllegalStateException(msg);
303 return serviceBinding.getDocumentHandler().trim();
307 public List<ValidatorHandler> getValidatorHandlers() throws Exception {
308 if (valHandlers != null) {
311 List<String> handlerClazzes = getServiceBinding().getValidatorHandler();
312 List<ValidatorHandler> handlers = new ArrayList<ValidatorHandler>(handlerClazzes.size());
313 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
314 for (String clazz : handlerClazzes) {
315 clazz = clazz.trim();
316 Class c = tccl.loadClass(clazz);
317 if (ValidatorHandler.class.isAssignableFrom(c)) {
318 handlers.add((ValidatorHandler) c.newInstance());
321 valHandlers = handlers;
326 public String toString() {
327 StringBuilder msg = new StringBuilder();
328 msg.append("AbstractServiceContext [");
329 msg.append("service name=" + serviceBinding.getName() + " ");
330 msg.append("service version=" + serviceBinding.getVersion() + " ");
331 msg.append("tenant id=" + tenantBinding.getId() + " ");
332 msg.append("tenant name=" + tenantBinding.getName() + " ");
333 msg.append(tenantBinding.getDisplayName() + " ");
334 msg.append("tenant repository domain=" + tenantBinding.getRepositoryDomain());
335 for (Map.Entry<String, Object> entry : properties.entrySet()) {
336 msg.append("property name=" + entry.getKey() + " value=" + entry.getValue().toString());
339 return msg.toString();