1 package org.collectionspace.services.jaxrs;
3 import static org.nuxeo.elasticsearch.ElasticSearchConstants.ES_ENABLED_PROPERTY;
5 import javax.servlet.ServletContextEvent;
6 import javax.ws.rs.core.Response;
8 import org.jboss.resteasy.core.Dispatcher;
9 import org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap;
11 import org.collectionspace.authentication.CSpaceTenant;
12 import org.collectionspace.services.account.Tenant;
13 import org.collectionspace.services.account.TenantResource;
14 import org.collectionspace.services.authorization.AuthZ;
15 import org.collectionspace.services.client.AuthorityClient;
17 import org.collectionspace.services.common.CSWebApplicationException;
18 import org.collectionspace.services.common.ResourceMap;
19 import org.collectionspace.services.common.ServiceMain;
20 import org.collectionspace.services.common.api.RefName;
21 import org.collectionspace.services.common.config.ConfigUtils;
22 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
23 import org.collectionspace.services.common.vocabulary.AuthorityResource;
25 import org.collectionspace.services.config.service.AuthorityInstanceType;
26 import org.collectionspace.services.config.service.ServiceBindingType;
27 import org.collectionspace.services.config.service.ServiceBindingType.AuthorityInstanceList;
28 import org.collectionspace.services.config.service.Term;
29 import org.collectionspace.services.config.service.TermList;
30 import org.collectionspace.services.config.tenant.TenantBindingType;
31 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
33 import org.nuxeo.elasticsearch.ElasticSearchComponent;
34 import org.nuxeo.elasticsearch.api.ElasticSearchService;
35 import org.nuxeo.runtime.api.Framework;
37 import java.lang.reflect.Constructor;
38 import java.util.Date;
39 import java.util.Hashtable;
40 import java.util.List;
41 import java.util.logging.Level;
43 public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
45 java.util.logging.Logger logger = java.util.logging.Logger.getAnonymousLogger();
46 static final String RESET_AUTHORITIES_PROPERTY = "org.collectionspace.services.authorities.reset";
47 private static final String RESET_ELASTICSEARCH_INDEX_PROPERTY = "org.collectionspace.services.elasticsearch.reset";
48 private static final String QUICK_BOOT_PROPERTY = "org.collectionspace.services.quickboot";
51 public void contextInitialized(ServletContextEvent event) {
54 // This call to super instantiates and initializes our JAX-RS application class.
55 // The application class is org.collectionspace.services.jaxrs.CollectionSpaceJaxRsApplication.
57 logger.log(Level.INFO, String.format("%tc [INFO] Starting up the CollectionSpace Services' JAX-RS application.", new Date()));
58 super.contextInitialized(event);
59 CollectionSpaceJaxRsApplication app = (CollectionSpaceJaxRsApplication)deployment.getApplication();
60 Dispatcher disp = deployment.getDispatcher();
61 disp.getDefaultContextObjects().put(ResourceMap.class, app.getResourceMap());
63 String quickBoot = System.getProperty(QUICK_BOOT_PROPERTY, Boolean.FALSE.toString()); // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
64 if (Boolean.valueOf(quickBoot) == false) {
65 String resetAuthsString = System.getProperty(RESET_AUTHORITIES_PROPERTY, Boolean.FALSE.toString()); // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
66 initializeAuthorities(app.getResourceMap(), Boolean.valueOf(resetAuthsString));
68 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
70 if (Boolean.valueOf(resetElasticsearchIndexString) == true) {
71 resetElasticSearchIndex();
75 logger.log(Level.INFO, String.format("%tc [INFO] CollectionSpace Services' JAX-RS application started.", new Date()));
76 } catch (Exception e) {
78 throw new RuntimeException(e);
84 public void contextDestroyed(ServletContextEvent event) {
85 logger.log(Level.INFO, "[INFO] Shutting down the CollectionSpace Services' JAX-RS application.");
86 //Do something if needed.
87 logger.log(Level.INFO, "[INFO] CollectionSpace Services' JAX-RS application stopped.");
90 public void resetElasticSearchIndex() throws Exception {
91 boolean isEnabled = Boolean.parseBoolean(Framework.getProperty(ES_ENABLED_PROPERTY, "true"));
97 ElasticSearchComponent es = (ElasticSearchComponent) Framework.getService(ElasticSearchService.class);
99 for (String repositoryName : es.getRepositoryNames()) {
100 logger.log(Level.INFO, String.format("%tc [INFO] Rebuilding Elasticsearch index for repository %s", new Date(), repositoryName));
102 es.dropAndInitRepositoryIndex(repositoryName);
105 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
106 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
108 for (TenantBindingType tenantBinding : tenantBindingsTable.values()) {
109 CSpaceTenant tenant = new CSpaceTenant(tenantBinding.getId(), tenantBinding.getName());
111 AuthZ.get().login(tenant);
113 for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
114 Boolean isElasticsearchIndexed = serviceBinding.isElasticsearchIndexed();
115 String servicesRepoDomainName = serviceBinding.getRepositoryDomain();
117 if (isElasticsearchIndexed && servicesRepoDomainName != null && servicesRepoDomainName.trim().isEmpty() == false) {
118 String repositoryName = ConfigUtils.getRepositoryName(tenantBinding, servicesRepoDomainName);
119 String docType = NuxeoUtils.getTenantQualifiedDocType(tenantBinding.getId(), serviceBinding.getObject().getName());
121 logger.log(Level.INFO, String.format("%tc [INFO] Starting Elasticsearch reindexing for docType %s in repository %s", new Date(), docType, repositoryName));
123 es.runReindexingWorker(repositoryName, String.format("SELECT ecm:uuid FROM %s", docType));
130 * Initialize all authorities and vocabularies defined in the service bindings.
134 public void initializeAuthorities(ResourceMap resourceMap, boolean reset) throws Exception {
135 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
136 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
137 for (TenantBindingType tenantBindings : tenantBindingsTable.values()) {
138 CSpaceTenant tenant = new CSpaceTenant(tenantBindings.getId(), tenantBindings.getName());
139 if (shouldInitializeAuthorities(tenant, reset) == true) {
140 logger.log(Level.INFO, String.format("Initializing vocabularies and authorities of tenant '%s'.",
142 for (ServiceBindingType serviceBinding : tenantBindings.getServiceBindings()) {
143 AuthorityInstanceList element = serviceBinding.getAuthorityInstanceList();
144 if (element != null && element.getAuthorityInstance() != null) {
145 List<AuthorityInstanceType> authorityInstanceList = element.getAuthorityInstance();
146 for (AuthorityInstanceType authorityInstance : authorityInstanceList) {
148 initializeAuthorityInstance(resourceMap, authorityInstance, serviceBinding, tenant, reset);
149 } catch (Exception e) {
150 logger.log(Level.SEVERE, "Could not initialize authorities and authority terms: " + e.getMessage());
157 // If we made it this far, we've either created the tenant's authorities and terms or we've reset them. Either way,
158 // we should mark the isAuthoritiesInitialized field of the tenant to 'true'.
160 setAuthoritiesInitialized(tenant, true);
165 @SuppressWarnings("rawtypes")
166 private AuthorityClient getAuthorityClient(String classname) throws Exception {
167 Class clazz = Class.forName(classname.trim());
168 Constructor co = clazz.getConstructor(null);
169 Object classInstance = co.newInstance(null);
170 return (AuthorityClient) classInstance;
173 private boolean shouldInitializeAuthorities(CSpaceTenant cspaceTenant, boolean reset) {
174 AuthZ.get().login(); // login as super admin
175 TenantResource tenantResource = new TenantResource();
176 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
179 // If the tenant's authorities have been initialized and
180 // we're not being asked to reset them, we'll return 'false'
181 // making any changes
183 return tenantState.isAuthoritiesInitialized() == false || reset == true;
186 private void setAuthoritiesInitialized(CSpaceTenant cspaceTenant, boolean initState) {
187 AuthZ.get().login(); // login as super admin
188 TenantResource tenantResource = new TenantResource();
189 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
191 tenantState.setAuthoritiesInitialized(initState);
192 tenantResource.updateTenant(cspaceTenant.getId(), tenantState);
197 * Check to see if an an authority instance and its corresponding terms exist. If not, try to create them.
199 private void initializeAuthorityInstance(ResourceMap resourceMap,
200 AuthorityInstanceType authorityInstance,
201 ServiceBindingType serviceBinding,
202 CSpaceTenant cspaceTenant,
203 boolean reset) throws Exception {
205 Response response = null;
206 String serviceName = serviceBinding.getName();
208 AuthZ.get().login(cspaceTenant);
209 String clientClassName = serviceBinding.getClientHandler();
210 AuthorityClient client = getAuthorityClient(clientClassName);
211 String authoritySpecifier = RefName.shortIdToPath(authorityInstance.getTitleRef()); // e.g., urn:cspace:name(ulan)
214 // Test to see if the authority instance exists already.
216 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(serviceName.toLowerCase());
218 response = authorityResource.get(null, null, null, authoritySpecifier);
219 } catch (CSWebApplicationException e) {
220 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
224 // If it doesn't exist (status is not 200), then try to create the authority instance
226 status = response.getStatus();
227 if (status != Response.Status.OK.getStatusCode()) {
228 String xmlPayload = client.createAuthorityInstance(authorityInstance.getTitleRef(), authorityInstance.getTitle());
229 response = authorityResource.createAuthority(xmlPayload);
230 status = response.getStatus();
231 if (status != Response.Status.CREATED.getStatusCode()) {
232 throw new CSWebApplicationException(response);
236 if (status == Response.Status.OK.getStatusCode()) {
237 logger.log(Level.FINE, String.format("Authority of type '%s' with the short ID of '%s' existed already.",
238 serviceName, authorityInstance.getTitleRef()));
239 } else if (status == Response.Status.CREATED.getStatusCode()) {
240 logger.log(Level.FINE, String.format("Created a new authority of type '%s' with the short ID of '%s'.",
241 serviceName, authorityInstance.getTitleRef()));
243 logger.log(Level.WARNING, String.format("Unknown status '%d' encountered when creating or fetching authority of type '%s' with the short ID of '%s'.",
244 serviceName, authorityInstance.getTitleRef()));
248 // Next, try to create or verify the authority terms.
250 initializeAuthorityInstanceTerms(authorityResource, client, authoritySpecifier, resourceMap, authorityInstance, serviceName, cspaceTenant);
253 private void initializeAuthorityInstanceTerms(
254 AuthorityResource authorityResource,
255 AuthorityClient client,
256 String authoritySpecifier,
257 ResourceMap resourceMap,
258 AuthorityInstanceType authorityInstance,
260 CSpaceTenant tenant) throws Exception {
263 Response response = null;
265 TermList termListElement = authorityInstance.getTermList();
266 if (termListElement == null) {
270 for (Term term : termListElement.getTerm()) {
272 // Check to see if the term already exists
275 String termSpecifier = RefName.shortIdToPath(term.getId());
276 authorityResource.getAuthorityItem(null, null, resourceMap, authoritySpecifier, termSpecifier);
277 status = Response.Status.OK.getStatusCode();
278 } catch (CSWebApplicationException e) {
279 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
280 status = response.getStatus();
284 // If the term doesn't exist, create it.
286 if (status != Response.Status.OK.getStatusCode()) {
287 String termShortId = term.getId();
288 String termDisplayName = term.getContent().trim();
289 String xmlPayload = client.createAuthorityItemInstance(termShortId, termDisplayName);
291 authorityResource.createAuthorityItem(resourceMap, null, authoritySpecifier, xmlPayload);
292 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'.",
293 tenant.getName(), termDisplayName, termShortId, serviceName, authorityInstance.getTitleRef()));
294 } catch (CSWebApplicationException e) {
295 response = e.getResponse();
296 status = response.getStatus();
297 if (status != Response.Status.CREATED.getStatusCode()) {
298 throw new CSWebApplicationException(response);