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 = serviceBinding.getObject().getName();
120 String tenantQualifiedDocType = NuxeoUtils.getTenantQualifiedDocType(tenantBinding.getId(), docType);
122 logger.log(Level.INFO, String.format("%tc [INFO] Starting Elasticsearch reindexing for docType %s in repository %s", new Date(), tenantQualifiedDocType, repositoryName));
124 es.runReindexingWorker(repositoryName, String.format("SELECT ecm:uuid FROM %s", tenantQualifiedDocType));
131 * Initialize all authorities and vocabularies defined in the service bindings.
135 public void initializeAuthorities(ResourceMap resourceMap, boolean reset) throws Exception {
136 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
137 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
138 for (TenantBindingType tenantBindings : tenantBindingsTable.values()) {
139 CSpaceTenant tenant = new CSpaceTenant(tenantBindings.getId(), tenantBindings.getName());
140 if (shouldInitializeAuthorities(tenant, reset) == true) {
141 logger.log(Level.INFO, String.format("Initializing vocabularies and authorities of tenant '%s'.",
143 for (ServiceBindingType serviceBinding : tenantBindings.getServiceBindings()) {
144 AuthorityInstanceList element = serviceBinding.getAuthorityInstanceList();
145 if (element != null && element.getAuthorityInstance() != null) {
146 List<AuthorityInstanceType> authorityInstanceList = element.getAuthorityInstance();
147 for (AuthorityInstanceType authorityInstance : authorityInstanceList) {
149 initializeAuthorityInstance(resourceMap, authorityInstance, serviceBinding, tenant, reset);
150 } catch (Exception e) {
151 logger.log(Level.SEVERE, "Could not initialize authorities and authority terms: " + e.getMessage());
158 // If we made it this far, we've either created the tenant's authorities and terms or we've reset them. Either way,
159 // we should mark the isAuthoritiesInitialized field of the tenant to 'true'.
161 setAuthoritiesInitialized(tenant, true);
166 @SuppressWarnings("rawtypes")
167 private AuthorityClient getAuthorityClient(String classname) throws Exception {
168 Class clazz = Class.forName(classname.trim());
169 Constructor co = clazz.getConstructor(null);
170 Object classInstance = co.newInstance(null);
171 return (AuthorityClient) classInstance;
174 private boolean shouldInitializeAuthorities(CSpaceTenant cspaceTenant, boolean reset) {
175 AuthZ.get().login(); // login as super admin
176 TenantResource tenantResource = new TenantResource();
177 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
180 // If the tenant's authorities have been initialized and
181 // we're not being asked to reset them, we'll return 'false'
182 // making any changes
184 return tenantState.isAuthoritiesInitialized() == false || reset == true;
187 private void setAuthoritiesInitialized(CSpaceTenant cspaceTenant, boolean initState) {
188 AuthZ.get().login(); // login as super admin
189 TenantResource tenantResource = new TenantResource();
190 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
192 tenantState.setAuthoritiesInitialized(initState);
193 tenantResource.updateTenant(cspaceTenant.getId(), tenantState);
198 * Check to see if an an authority instance and its corresponding terms exist. If not, try to create them.
200 private void initializeAuthorityInstance(ResourceMap resourceMap,
201 AuthorityInstanceType authorityInstance,
202 ServiceBindingType serviceBinding,
203 CSpaceTenant cspaceTenant,
204 boolean reset) throws Exception {
206 Response response = null;
207 String serviceName = serviceBinding.getName();
209 AuthZ.get().login(cspaceTenant);
210 String clientClassName = serviceBinding.getClientHandler();
211 AuthorityClient client = getAuthorityClient(clientClassName);
212 String authoritySpecifier = RefName.shortIdToPath(authorityInstance.getTitleRef()); // e.g., urn:cspace:name(ulan)
215 // Test to see if the authority instance exists already.
217 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(serviceName.toLowerCase());
219 response = authorityResource.get(null, null, null, authoritySpecifier);
220 } catch (CSWebApplicationException e) {
221 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
225 // If it doesn't exist (status is not 200), then try to create the authority instance
227 status = response.getStatus();
228 if (status != Response.Status.OK.getStatusCode()) {
229 String xmlPayload = client.createAuthorityInstance(authorityInstance.getTitleRef(), authorityInstance.getTitle());
230 response = authorityResource.createAuthority(xmlPayload);
231 status = response.getStatus();
232 if (status != Response.Status.CREATED.getStatusCode()) {
233 throw new CSWebApplicationException(response);
237 if (status == Response.Status.OK.getStatusCode()) {
238 logger.log(Level.FINE, String.format("Authority of type '%s' with the short ID of '%s' existed already.",
239 serviceName, authorityInstance.getTitleRef()));
240 } else if (status == Response.Status.CREATED.getStatusCode()) {
241 logger.log(Level.FINE, String.format("Created a new authority of type '%s' with the short ID of '%s'.",
242 serviceName, authorityInstance.getTitleRef()));
244 logger.log(Level.WARNING, String.format("Unknown status '%d' encountered when creating or fetching authority of type '%s' with the short ID of '%s'.",
245 serviceName, authorityInstance.getTitleRef()));
249 // Next, try to create or verify the authority terms.
251 initializeAuthorityInstanceTerms(authorityResource, client, authoritySpecifier, resourceMap, authorityInstance, serviceName, cspaceTenant);
254 private void initializeAuthorityInstanceTerms(
255 AuthorityResource authorityResource,
256 AuthorityClient client,
257 String authoritySpecifier,
258 ResourceMap resourceMap,
259 AuthorityInstanceType authorityInstance,
261 CSpaceTenant tenant) throws Exception {
264 Response response = null;
266 TermList termListElement = authorityInstance.getTermList();
267 if (termListElement == null) {
271 for (Term term : termListElement.getTerm()) {
273 // Check to see if the term already exists
276 String termSpecifier = RefName.shortIdToPath(term.getId());
277 authorityResource.getAuthorityItem(null, null, resourceMap, authoritySpecifier, termSpecifier);
278 status = Response.Status.OK.getStatusCode();
279 } catch (CSWebApplicationException e) {
280 response = e.getResponse(); // If the authority doesn't exist, we expect a 404 error
281 status = response.getStatus();
285 // If the term doesn't exist, create it.
287 if (status != Response.Status.OK.getStatusCode()) {
288 String termShortId = term.getId();
289 String termDisplayName = term.getContent().trim();
290 String xmlPayload = client.createAuthorityItemInstance(termShortId, termDisplayName);
292 authorityResource.createAuthorityItem(resourceMap, null, authoritySpecifier, xmlPayload);
293 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'.",
294 tenant.getName(), termDisplayName, termShortId, serviceName, authorityInstance.getTitleRef()));
295 } catch (CSWebApplicationException e) {
296 response = e.getResponse();
297 status = response.getStatus();
298 if (status != Response.Status.CREATED.getStatusCode()) {
299 throw new CSWebApplicationException(response);