1 package org.collectionspace.services.jaxrs;
3 import javax.servlet.ServletContextEvent;
4 import javax.ws.rs.core.Response;
6 import org.jboss.resteasy.core.Dispatcher;
7 import org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap;
9 import org.collectionspace.authentication.CSpaceTenant;
10 import org.collectionspace.services.account.Tenant;
11 import org.collectionspace.services.account.TenantResource;
12 import org.collectionspace.services.authorization.AuthZ;
13 import org.collectionspace.services.client.AuthorityClient;
15 import org.collectionspace.services.common.CSWebApplicationException;
16 import org.collectionspace.services.common.ResourceMap;
17 import org.collectionspace.services.common.ServiceMain;
18 import org.collectionspace.services.common.api.RefName;
19 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
20 import org.collectionspace.services.common.vocabulary.AuthorityResource;
22 import org.collectionspace.services.config.service.AuthorityInstanceType;
23 import org.collectionspace.services.config.service.ServiceBindingType;
24 import org.collectionspace.services.config.service.ServiceBindingType.AuthorityInstanceList;
25 import org.collectionspace.services.config.service.Term;
26 import org.collectionspace.services.config.service.TermList;
27 import org.collectionspace.services.config.tenant.TenantBindingType;
29 import java.lang.reflect.Constructor;
30 import java.util.Date;
31 import java.util.Hashtable;
32 import java.util.List;
33 import java.util.logging.Level;
35 public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
37 java.util.logging.Logger logger = java.util.logging.Logger.getAnonymousLogger();
38 static final String RESET_AUTHORITIES_PROPERTY = "org.collectionspace.services.authorities.reset";
39 private static final String QUICK_BOOT_PROPERTY = "org.collectionspace.services.quickboot";
42 public void contextInitialized(ServletContextEvent event) {
45 // This call to super instantiates and initializes our JAX-RS application class.
46 // The application class is org.collectionspace.services.jaxrs.CollectionSpaceJaxRsApplication.
48 logger.log(Level.INFO, String.format("%tc [INFO] Starting up the CollectionSpace Services' JAX-RS application.", new Date()));
49 super.contextInitialized(event);
50 CollectionSpaceJaxRsApplication app = (CollectionSpaceJaxRsApplication)deployment.getApplication();
51 Dispatcher disp = deployment.getDispatcher();
52 disp.getDefaultContextObjects().put(ResourceMap.class, app.getResourceMap());
54 String quickBoot = System.getProperty(QUICK_BOOT_PROPERTY, Boolean.FALSE.toString()); // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
55 if (Boolean.valueOf(quickBoot) == false) {
56 String resetAuthsString = System.getProperty(RESET_AUTHORITIES_PROPERTY, Boolean.FALSE.toString()); // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
57 initializeAuthorities(app.getResourceMap(), Boolean.valueOf(resetAuthsString));
60 logger.log(Level.INFO, String.format("%tc [INFO] CollectionSpace Services' JAX-RS application started.", new Date()));
61 } catch (Exception e) {
63 throw new RuntimeException(e);
69 public void contextDestroyed(ServletContextEvent event) {
70 logger.log(Level.INFO, "[INFO] Shutting down the CollectionSpace Services' JAX-RS application.");
71 //Do something if needed.
72 logger.log(Level.INFO, "[INFO] CollectionSpace Services' JAX-RS application stopped.");
76 * Initialize all authorities and vocabularies defined in the service bindings.
80 public void initializeAuthorities(ResourceMap resourceMap, boolean reset) throws Exception {
81 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
82 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
83 for (TenantBindingType tenantBindings : tenantBindingsTable.values()) {
84 CSpaceTenant tenant = new CSpaceTenant(tenantBindings.getId(), tenantBindings.getName());
85 if (shouldInitializeAuthorities(tenant, reset) == true) {
86 logger.log(Level.INFO, String.format("Initializing vocabularies and authorities of tenant '%s'.",
88 for (ServiceBindingType serviceBinding : tenantBindings.getServiceBindings()) {
89 AuthorityInstanceList element = serviceBinding.getAuthorityInstanceList();
90 if (element != null && element.getAuthorityInstance() != null) {
91 List<AuthorityInstanceType> authorityInstanceList = element.getAuthorityInstance();
92 for (AuthorityInstanceType authorityInstance : authorityInstanceList) {
94 initializeAuthorityInstance(resourceMap, authorityInstance, serviceBinding, tenant, reset);
95 } catch (Exception e) {
96 logger.log(Level.SEVERE, "Could not initialize authorities and authority terms: " + e.getMessage());
103 // If we made it this far, we've either created the tenant's authorities and terms or we've reset them. Either way,
104 // we should mark the isAuthoritiesInitialized field of the tenant to 'true'.
106 setAuthoritiesInitialized(tenant, true);
111 @SuppressWarnings("rawtypes")
112 private AuthorityClient getAuthorityClient(String classname) throws Exception {
113 Class clazz = Class.forName(classname.trim());
114 Constructor co = clazz.getConstructor(null);
115 Object classInstance = co.newInstance(null);
116 return (AuthorityClient) classInstance;
119 private boolean shouldInitializeAuthorities(CSpaceTenant cspaceTenant, boolean reset) {
120 AuthZ.get().login(); // login as super admin
121 TenantResource tenantResource = new TenantResource();
122 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
125 // If the tenant's authorities have been initialized and
126 // we're not being asked to reset them, we'll return 'false'
127 // making any changes
129 return tenantState.isAuthoritiesInitialized() == false || reset == true;
132 private void setAuthoritiesInitialized(CSpaceTenant cspaceTenant, boolean initState) {
133 AuthZ.get().login(); // login as super admin
134 TenantResource tenantResource = new TenantResource();
135 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
137 tenantState.setAuthoritiesInitialized(initState);
138 tenantResource.updateTenant(cspaceTenant.getId(), tenantState);
143 * Check to see if an an authority instance and its corresponding terms exist. If not, try to create them.
145 private void initializeAuthorityInstance(ResourceMap resourceMap,
146 AuthorityInstanceType authorityInstance,
147 ServiceBindingType serviceBinding,
148 CSpaceTenant cspaceTenant,
149 boolean reset) throws Exception {
151 Response response = null;
152 String serviceName = serviceBinding.getName();
154 AuthZ.get().login(cspaceTenant);
155 String clientClassName = serviceBinding.getClientHandler();
156 AuthorityClient client = getAuthorityClient(clientClassName);
157 String authoritySpecifier = RefName.shortIdToPath(authorityInstance.getTitleRef()); // e.g., urn:cspace:name(ulan)
160 // Test to see if the authority instance exists already.
162 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(serviceName.toLowerCase());
164 response = authorityResource.get(null, null, authoritySpecifier);
165 } catch (CSWebApplicationException e) {
166 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
170 // If it doesn't exist (status is not 200), then try to create the authority instance
172 status = response.getStatus();
173 if (status != Response.Status.OK.getStatusCode()) {
174 String xmlPayload = client.createAuthorityInstance(authorityInstance.getTitleRef(), authorityInstance.getTitle());
175 response = authorityResource.createAuthority(xmlPayload);
176 status = response.getStatus();
177 if (status != Response.Status.CREATED.getStatusCode()) {
178 throw new CSWebApplicationException(response);
182 if (status == Response.Status.OK.getStatusCode()) {
183 logger.log(Level.FINE, String.format("Authority of type '%s' with the short ID of '%s' existed already.",
184 serviceName, authorityInstance.getTitleRef()));
185 } else if (status == Response.Status.CREATED.getStatusCode()) {
186 logger.log(Level.FINE, String.format("Created a new authority of type '%s' with the short ID of '%s'.",
187 serviceName, authorityInstance.getTitleRef()));
189 logger.log(Level.WARNING, String.format("Unknown status '%d' encountered when creating or fetching authority of type '%s' with the short ID of '%s'.",
190 serviceName, authorityInstance.getTitleRef()));
194 // Next, try to create or verify the authority terms.
196 initializeAuthorityInstanceTerms(authorityResource, client, authoritySpecifier, resourceMap, authorityInstance, serviceName, cspaceTenant);
199 private void initializeAuthorityInstanceTerms(
200 AuthorityResource authorityResource,
201 AuthorityClient client,
202 String authoritySpecifier,
203 ResourceMap resourceMap,
204 AuthorityInstanceType authorityInstance,
206 CSpaceTenant tenant) throws Exception {
209 Response response = null;
211 TermList termListElement = authorityInstance.getTermList();
212 if (termListElement == null) {
216 for (Term term : termListElement.getTerm()) {
218 // Check to see if the term already exists
221 String termSpecifier = RefName.shortIdToPath(term.getId());
222 authorityResource.getAuthorityItem(null, null, resourceMap, authoritySpecifier, termSpecifier);
223 status = Response.Status.OK.getStatusCode();
224 } catch (CSWebApplicationException e) {
225 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
226 status = response.getStatus();
230 // If the term doesn't exist, create it.
232 if (status != Response.Status.OK.getStatusCode()) {
233 String termShortId = term.getId();
234 String termDisplayName = term.getContent().trim();
235 String xmlPayload = client.createAuthorityItemInstance(termShortId, termDisplayName);
237 authorityResource.createAuthorityItem(resourceMap, null, authoritySpecifier, xmlPayload);
238 logger.log(Level.FINE, String.format("Tenant:%s:Created a new term '%s:%s' in the authority of type '%s' with the short ID of '%s'.",
239 tenant.getName(), termDisplayName, termShortId, serviceName, authorityInstance.getTitleRef()));
240 } catch (CSWebApplicationException e) {
241 response = e.getResponse();
242 status = response.getStatus();
243 if (status != Response.Status.CREATED.getStatusCode()) {
244 throw new CSWebApplicationException(response);