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.ConfigUtils;
20 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
21 import org.collectionspace.services.common.vocabulary.AuthorityResource;
23 import org.collectionspace.services.config.service.AuthorityInstanceType;
24 import org.collectionspace.services.config.service.ServiceBindingType;
25 import org.collectionspace.services.config.service.ServiceBindingType.AuthorityInstanceList;
26 import org.collectionspace.services.config.service.Term;
27 import org.collectionspace.services.config.service.TermList;
28 import org.collectionspace.services.config.tenant.TenantBindingType;
29 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
31 import org.nuxeo.elasticsearch.ElasticSearchComponent;
32 import org.nuxeo.elasticsearch.api.ElasticSearchService;
33 import org.nuxeo.runtime.api.Framework;
35 import java.lang.reflect.Constructor;
36 import java.util.Date;
37 import java.util.Hashtable;
38 import java.util.List;
39 import java.util.logging.Level;
41 public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
43 java.util.logging.Logger logger = java.util.logging.Logger.getAnonymousLogger();
44 static final String RESET_AUTHORITIES_PROPERTY = "org.collectionspace.services.authorities.reset";
45 private static final String RESET_ELASTICSEARCH_INDEX_PROPERTY = "org.collectionspace.services.elasticsearch.reset";
46 private static final String QUICK_BOOT_PROPERTY = "org.collectionspace.services.quickboot";
49 public void contextInitialized(ServletContextEvent event) {
52 // This call to super instantiates and initializes our JAX-RS application class.
53 // The application class is org.collectionspace.services.jaxrs.CollectionSpaceJaxRsApplication.
55 logger.log(Level.INFO, String.format("%tc [INFO] Starting up the CollectionSpace Services' JAX-RS application.", new Date()));
56 super.contextInitialized(event);
57 CollectionSpaceJaxRsApplication app = (CollectionSpaceJaxRsApplication)deployment.getApplication();
58 Dispatcher disp = deployment.getDispatcher();
59 disp.getDefaultContextObjects().put(ResourceMap.class, app.getResourceMap());
61 String quickBoot = System.getProperty(QUICK_BOOT_PROPERTY, Boolean.FALSE.toString()); // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
62 if (Boolean.valueOf(quickBoot) == false) {
63 String resetAuthsString = System.getProperty(RESET_AUTHORITIES_PROPERTY, Boolean.FALSE.toString()); // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
64 initializeAuthorities(app.getResourceMap(), Boolean.valueOf(resetAuthsString));
66 String resetElasticsearchIndexString = System.getProperty(RESET_ELASTICSEARCH_INDEX_PROPERTY, Boolean.FALSE.toString()); // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
68 if (Boolean.valueOf(resetElasticsearchIndexString) == true) {
69 resetElasticSearchIndex();
73 logger.log(Level.INFO, String.format("%tc [INFO] CollectionSpace Services' JAX-RS application started.", new Date()));
74 } catch (Exception e) {
76 throw new RuntimeException(e);
82 public void contextDestroyed(ServletContextEvent event) {
83 logger.log(Level.INFO, "[INFO] Shutting down the CollectionSpace Services' JAX-RS application.");
84 //Do something if needed.
85 logger.log(Level.INFO, "[INFO] CollectionSpace Services' JAX-RS application stopped.");
88 public void resetElasticSearchIndex() throws Exception {
89 ElasticSearchComponent es = (ElasticSearchComponent) Framework.getService(ElasticSearchService.class);
91 for (String repositoryName : es.getRepositoryNames()) {
92 logger.log(Level.INFO, String.format("%tc [INFO] Rebuilding Elasticsearch index for repository %s", new Date(), repositoryName));
94 es.dropAndInitRepositoryIndex(repositoryName);
97 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
98 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
100 for (TenantBindingType tenantBinding : tenantBindingsTable.values()) {
101 CSpaceTenant tenant = new CSpaceTenant(tenantBinding.getId(), tenantBinding.getName());
103 AuthZ.get().login(tenant);
105 for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
106 Boolean isElasticsearchIndexed = serviceBinding.isElasticsearchIndexed();
107 String servicesRepoDomainName = serviceBinding.getRepositoryDomain();
109 if (isElasticsearchIndexed && servicesRepoDomainName != null && servicesRepoDomainName.trim().isEmpty() == false) {
110 String repositoryName = ConfigUtils.getRepositoryName(tenantBinding, servicesRepoDomainName);
111 String docType = serviceBinding.getObject().getName();
112 String tenantQualifiedDocType = NuxeoUtils.getTenantQualifiedDocType(tenantBinding.getId(), docType);
114 logger.log(Level.INFO, String.format("%tc [INFO] Starting Elasticsearch reindexing for docType %s in repository %s", new Date(), tenantQualifiedDocType, repositoryName));
116 es.runReindexingWorker(repositoryName, String.format("SELECT ecm:uuid FROM %s", tenantQualifiedDocType));
123 * Initialize all authorities and vocabularies defined in the service bindings.
127 public void initializeAuthorities(ResourceMap resourceMap, boolean reset) throws Exception {
128 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
129 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
130 for (TenantBindingType tenantBindings : tenantBindingsTable.values()) {
131 CSpaceTenant tenant = new CSpaceTenant(tenantBindings.getId(), tenantBindings.getName());
132 if (shouldInitializeAuthorities(tenant, reset) == true) {
133 logger.log(Level.INFO, String.format("Initializing vocabularies and authorities of tenant '%s'.",
135 for (ServiceBindingType serviceBinding : tenantBindings.getServiceBindings()) {
136 AuthorityInstanceList element = serviceBinding.getAuthorityInstanceList();
137 if (element != null && element.getAuthorityInstance() != null) {
138 List<AuthorityInstanceType> authorityInstanceList = element.getAuthorityInstance();
139 for (AuthorityInstanceType authorityInstance : authorityInstanceList) {
141 initializeAuthorityInstance(resourceMap, authorityInstance, serviceBinding, tenant, reset);
142 } catch (Exception e) {
143 logger.log(Level.SEVERE, "Could not initialize authorities and authority terms: " + e.getMessage());
150 // If we made it this far, we've either created the tenant's authorities and terms or we've reset them. Either way,
151 // we should mark the isAuthoritiesInitialized field of the tenant to 'true'.
153 setAuthoritiesInitialized(tenant, true);
158 @SuppressWarnings("rawtypes")
159 private AuthorityClient getAuthorityClient(String classname) throws Exception {
160 Class clazz = Class.forName(classname.trim());
161 Constructor co = clazz.getConstructor(null);
162 Object classInstance = co.newInstance(null);
163 return (AuthorityClient) classInstance;
166 private boolean shouldInitializeAuthorities(CSpaceTenant cspaceTenant, boolean reset) {
167 AuthZ.get().login(); // login as super admin
168 TenantResource tenantResource = new TenantResource();
169 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
172 // If the tenant's authorities have been initialized and
173 // we're not being asked to reset them, we'll return 'false'
174 // making any changes
176 return tenantState.isAuthoritiesInitialized() == false || reset == true;
179 private void setAuthoritiesInitialized(CSpaceTenant cspaceTenant, boolean initState) {
180 AuthZ.get().login(); // login as super admin
181 TenantResource tenantResource = new TenantResource();
182 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
184 tenantState.setAuthoritiesInitialized(initState);
185 tenantResource.updateTenant(cspaceTenant.getId(), tenantState);
190 * Check to see if an an authority instance and its corresponding terms exist. If not, try to create them.
192 private void initializeAuthorityInstance(ResourceMap resourceMap,
193 AuthorityInstanceType authorityInstance,
194 ServiceBindingType serviceBinding,
195 CSpaceTenant cspaceTenant,
196 boolean reset) throws Exception {
198 Response response = null;
199 String serviceName = serviceBinding.getName();
201 AuthZ.get().login(cspaceTenant);
202 String clientClassName = serviceBinding.getClientHandler();
203 AuthorityClient client = getAuthorityClient(clientClassName);
204 String authoritySpecifier = RefName.shortIdToPath(authorityInstance.getTitleRef()); // e.g., urn:cspace:name(ulan)
207 // Test to see if the authority instance exists already.
209 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(serviceName.toLowerCase());
211 response = authorityResource.get(null, null, authoritySpecifier);
212 } catch (CSWebApplicationException e) {
213 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
217 // If it doesn't exist (status is not 200), then try to create the authority instance
219 status = response.getStatus();
220 if (status != Response.Status.OK.getStatusCode()) {
221 String xmlPayload = client.createAuthorityInstance(authorityInstance.getTitleRef(), authorityInstance.getTitle());
222 response = authorityResource.createAuthority(xmlPayload);
223 status = response.getStatus();
224 if (status != Response.Status.CREATED.getStatusCode()) {
225 throw new CSWebApplicationException(response);
229 if (status == Response.Status.OK.getStatusCode()) {
230 logger.log(Level.FINE, String.format("Authority of type '%s' with the short ID of '%s' existed already.",
231 serviceName, authorityInstance.getTitleRef()));
232 } else if (status == Response.Status.CREATED.getStatusCode()) {
233 logger.log(Level.FINE, String.format("Created a new authority of type '%s' with the short ID of '%s'.",
234 serviceName, authorityInstance.getTitleRef()));
236 logger.log(Level.WARNING, String.format("Unknown status '%d' encountered when creating or fetching authority of type '%s' with the short ID of '%s'.",
237 serviceName, authorityInstance.getTitleRef()));
241 // Next, try to create or verify the authority terms.
243 initializeAuthorityInstanceTerms(authorityResource, client, authoritySpecifier, resourceMap, authorityInstance, serviceName, cspaceTenant);
246 private void initializeAuthorityInstanceTerms(
247 AuthorityResource authorityResource,
248 AuthorityClient client,
249 String authoritySpecifier,
250 ResourceMap resourceMap,
251 AuthorityInstanceType authorityInstance,
253 CSpaceTenant tenant) throws Exception {
256 Response response = null;
258 TermList termListElement = authorityInstance.getTermList();
259 if (termListElement == null) {
263 for (Term term : termListElement.getTerm()) {
265 // Check to see if the term already exists
268 String termSpecifier = RefName.shortIdToPath(term.getId());
269 authorityResource.getAuthorityItem(null, null, resourceMap, authoritySpecifier, termSpecifier);
270 status = Response.Status.OK.getStatusCode();
271 } catch (CSWebApplicationException e) {
272 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
273 status = response.getStatus();
277 // If the term doesn't exist, create it.
279 if (status != Response.Status.OK.getStatusCode()) {
280 String termShortId = term.getId();
281 String termDisplayName = term.getContent().trim();
282 String xmlPayload = client.createAuthorityItemInstance(termShortId, termDisplayName);
284 authorityResource.createAuthorityItem(resourceMap, null, authoritySpecifier, xmlPayload);
285 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'.",
286 tenant.getName(), termDisplayName, termShortId, serviceName, authorityInstance.getTitleRef()));
287 } catch (CSWebApplicationException e) {
288 response = e.getResponse();
289 status = response.getStatus();
290 if (status != Response.Status.CREATED.getStatusCode()) {
291 throw new CSWebApplicationException(response);