]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
abc0e7ea13d2c4ba83e2cb14f401ab427559191f
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.jaxrs;
2
3 import static org.nuxeo.elasticsearch.ElasticSearchConstants.ES_ENABLED_PROPERTY;
4
5 import javax.servlet.ServletContextEvent;
6 import javax.ws.rs.core.PathSegment;
7 import javax.ws.rs.core.Response;
8 import javax.ws.rs.core.UriInfo;
9
10 import org.jboss.resteasy.core.Dispatcher;
11 import org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap;
12 import org.jboss.resteasy.specimpl.PathSegmentImpl;
13 import org.collectionspace.authentication.AuthN;
14 import org.collectionspace.authentication.CSpaceTenant;
15 import org.collectionspace.services.account.Tenant;
16 import org.collectionspace.services.account.TenantResource;
17 import org.collectionspace.services.authorization.AuthZ;
18 import org.collectionspace.services.client.AbstractCommonListUtils;
19 import org.collectionspace.services.client.AuthorityClient;
20 import org.collectionspace.services.client.CollectionSpaceClient;
21 import org.collectionspace.services.client.PayloadOutputPart;
22 import org.collectionspace.services.client.PoxPayloadOut;
23 import org.collectionspace.services.client.ReportClient;
24 import org.collectionspace.services.client.workflow.WorkflowClient;
25 import org.collectionspace.services.common.CSWebApplicationException;
26 import org.collectionspace.services.common.ResourceMap;
27 import org.collectionspace.services.common.ServiceMain;
28 import org.collectionspace.services.common.api.RefName;
29 import org.collectionspace.services.common.config.ConfigUtils;
30 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
31 import org.collectionspace.services.common.query.UriInfoImpl;
32 import org.collectionspace.services.common.vocabulary.AuthorityResource;
33
34 import org.collectionspace.services.config.service.AuthorityInstanceType;
35 import org.collectionspace.services.config.service.ServiceBindingType;
36 import org.collectionspace.services.config.service.ServiceBindingType.AuthorityInstanceList;
37 import org.collectionspace.services.config.service.Term;
38 import org.collectionspace.services.config.service.TermList;
39 import org.collectionspace.services.config.tenant.TenantBindingType;
40 import org.collectionspace.services.config.types.PropertyItemType;
41 import org.collectionspace.services.config.types.PropertyType;
42 import org.collectionspace.services.jaxb.AbstractCommonList;
43 import org.collectionspace.services.jaxb.AbstractCommonList.ListItem;
44 import org.collectionspace.services.nuxeo.util.NuxeoUtils;
45 import org.collectionspace.services.report.ReportResource;
46 import org.nuxeo.elasticsearch.ElasticSearchComponent;
47 import org.nuxeo.elasticsearch.api.ElasticSearchService;
48 import org.nuxeo.runtime.api.Framework;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import java.io.File;
53 import java.lang.reflect.Constructor;
54 import java.net.URI;
55 import java.net.URLEncoder;
56 import java.nio.charset.StandardCharsets;
57 import java.nio.file.Files;
58 import java.util.Arrays;
59 import java.util.HashSet;
60 import java.util.Hashtable;
61 import java.util.List;
62 import java.util.Set;
63
64 public class CSpaceResteasyBootstrap extends ResteasyBootstrap {
65         private static final Logger logger = LoggerFactory.getLogger(CSpaceResteasyBootstrap.class);
66
67         private static final String RESET_AUTHORITIES_PROPERTY = "org.collectionspace.services.authorities.reset";
68         private static final String RESET_ELASTICSEARCH_INDEX_PROPERTY = "org.collectionspace.services.elasticsearch.reset";
69         private static final String RESET_REPORTS_PROPERTY = "org.collectionspace.services.reports.reset";
70         private static final String QUICK_BOOT_PROPERTY = "org.collectionspace.services.quickboot";
71         private static final String REPORT_PROPERTY = "report";
72
73         @Override
74         public void contextInitialized(ServletContextEvent event) {
75                 try {
76                         //
77                         // This call to super instantiates and initializes our JAX-RS application class.
78                         // The application class is org.collectionspace.services.jaxrs.CollectionSpaceJaxRsApplication.
79                         //
80                         logger.info("Starting up the CollectionSpace Services JAX-RS application.");
81                         super.contextInitialized(event);
82                         CollectionSpaceJaxRsApplication app = (CollectionSpaceJaxRsApplication)deployment.getApplication();
83                         Dispatcher disp = deployment.getDispatcher();
84                         disp.getDefaultContextObjects().put(ResourceMap.class, app.getResourceMap());
85
86                         // Property can be set in the tomcat/bin/setenv.sh (or setenv.bat) file
87                         String quickBoot = System.getProperty(QUICK_BOOT_PROPERTY, Boolean.FALSE.toString());
88
89                         if (Boolean.valueOf(quickBoot) == false) {
90                                 // The below properties can be set in the tomcat/bin/setenv.sh (or setenv.bat) file.
91                                 String resetAuthsString = System.getProperty(RESET_AUTHORITIES_PROPERTY, Boolean.FALSE.toString());
92                                 String resetElasticsearchIndexString = System.getProperty(RESET_ELASTICSEARCH_INDEX_PROPERTY, Boolean.FALSE.toString());
93                                 String resetReportsString = System.getProperty(RESET_REPORTS_PROPERTY, Boolean.TRUE.toString());
94
95                                 initializeAuthorities(app.getResourceMap(), Boolean.valueOf(resetAuthsString));
96
97                                 if (Boolean.valueOf(resetElasticsearchIndexString) == true) {
98                                         resetElasticSearchIndex();
99                                 }
100
101                                 if (Boolean.valueOf(resetReportsString) == true) {
102                                         resetReports();
103                                 }
104                         }
105
106                         logger.info("CollectionSpace Services JAX-RS application started.");
107                 } catch (Exception e) {
108                         e.printStackTrace();
109                         throw new RuntimeException(e);
110                 }
111         }
112
113
114         @Override
115         public void contextDestroyed(ServletContextEvent event) {
116                 logger.info("Shutting down the CollectionSpace Services JAX-RS application.");
117                 //Do something if needed.
118                 logger.info("CollectionSpace Services JAX-RS application stopped.");
119         }
120
121         public void resetReports() throws Exception {
122                 logger.info("Resetting reports");
123
124                 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
125                 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
126
127                 for (TenantBindingType tenantBinding : tenantBindingsTable.values()) {
128                         ServiceBindingType reportServiceBinding = null;
129
130                         for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
131                                 if (serviceBinding.getName().toLowerCase().trim().equals(ReportClient.SERVICE_NAME)) {
132                                         reportServiceBinding = serviceBinding;
133
134                                         break;
135                                 }
136                         }
137
138                         Set<String> reportNames = new HashSet<String>();
139
140                         if (reportServiceBinding != null) {
141                                 for (PropertyType property : reportServiceBinding.getProperties()) {
142                                         for (PropertyItemType item : property.getItem()) {
143                                                 if (item.getKey().equals(REPORT_PROPERTY)) {
144                                                         reportNames.add(item.getValue());
145                                                 }
146                                         }
147                                 }
148                         }
149
150                         if (reportNames.size() > 0) {
151                                 CSpaceTenant tenant = new CSpaceTenant(tenantBinding.getId(), tenantBinding.getName());
152
153                                 resetTenantReports(tenant, reportNames);
154                         }
155                 }
156         }
157
158         private void resetTenantReports(CSpaceTenant tenant, Set<String> reportNames) throws Exception {
159                 logger.info("Resetting reports for tenant {}", tenant.getId());
160
161                 AuthZ.get().login(tenant);
162
163                 CollectionSpaceJaxRsApplication app = (CollectionSpaceJaxRsApplication) deployment.getApplication();
164                 ResourceMap resourceMap = app.getResourceMap();
165                 ReportResource reportResource = (ReportResource) resourceMap.get(ReportClient.SERVICE_NAME);
166
167                 for (String reportName : reportNames) {
168                         File reportMetadataFile = ReportResource.getReportMetadataFile(reportName);
169
170                         if (!reportMetadataFile.exists()) {
171                                 logger.warn(
172                                         "Metadata file not found for report {} at {}",
173                                         reportName, reportMetadataFile.getAbsolutePath());
174
175                                 continue;
176                         }
177
178                         String payload = new String(Files.readAllBytes(reportMetadataFile.toPath()));
179                         String reportFilename = reportName + ".jrxml";
180
181                         UriInfo uriInfo = new UriInfoImpl(
182                                 new URI(""),
183                                 new URI(""),
184                                 "",
185                                 "pgSz=0&filename=" + URLEncoder.encode(reportFilename, StandardCharsets.UTF_8.toString()),
186                                 Arrays.asList((PathSegment) new PathSegmentImpl("", false))
187                         );
188
189                         AbstractCommonList list = reportResource.getList(uriInfo);
190
191                         if (list.getTotalItems() == 0) {
192                                 logger.info("Adding report " + reportName);
193
194                                 try {
195                                         reportResource.create(resourceMap, null, payload);
196                                 } catch(Exception e) {
197                                         logger.error(e.getMessage(), e);
198                                 }
199                         } else {
200                                 for (ListItem item : list.getListItem()) {
201                                         String csid = AbstractCommonListUtils.ListItemGetCSID(item);
202
203                                         // Update an existing report iff:
204                                         // - it was created autmatically (i.e., by the SPRING_ADMIN user)
205                                         // - it was last updated automatically (i.e., by the SPRING_ADMIN user)
206                                         // - it is not soft-deleted
207
208                                         PoxPayloadOut reportPayload = reportResource.getResourceFromCsid(null, null, csid);
209                                         PayloadOutputPart corePart = reportPayload.getPart(CollectionSpaceClient.COLLECTIONSPACE_CORE_SCHEMA);
210
211                                         String createdBy = corePart.asElement().selectSingleNode(CollectionSpaceClient.COLLECTIONSPACE_CORE_CREATED_BY).getText();
212                                         String updatedBy = corePart.asElement().selectSingleNode(CollectionSpaceClient.COLLECTIONSPACE_CORE_UPDATED_BY).getText();
213                                         String workflowState = corePart.asElement().selectSingleNode(CollectionSpaceClient.COLLECTIONSPACE_CORE_WORKFLOWSTATE).getText();
214
215                                         if (
216                                                 createdBy.equals(AuthN.SPRING_ADMIN_USER)
217                                                 && updatedBy.equals(AuthN.SPRING_ADMIN_USER)
218                                                 && !workflowState.equals(WorkflowClient.WORKFLOWSTATE_DELETED)
219                                         ) {
220                                                 logger.info("Updating report {} with csid {}", reportName, csid);
221
222                                                 try {
223                                                         reportResource.update(resourceMap, null, csid, payload);
224                                                 } catch (Exception e) {
225                                                         logger.error(e.getMessage(), e);
226                                                 }
227                                         } else {
228                                                 logger.info(
229                                                         "Not updating report {} with csid {} - it was not auto-created, or was updated or soft-deleted",
230                                                         reportName, csid);
231                                         }
232                                 }
233                         }
234                 }
235         }
236
237         public void resetElasticSearchIndex() throws Exception {
238                 boolean isEnabled = Boolean.parseBoolean(Framework.getProperty(ES_ENABLED_PROPERTY, "true"));
239
240                 if (!isEnabled) {
241                         return;
242                 }
243
244                 ElasticSearchComponent es = (ElasticSearchComponent) Framework.getService(ElasticSearchService.class);
245
246                 for (String repositoryName : es.getRepositoryNames()) {
247                         logger.info("Rebuilding Elasticsearch index for repository {}", repositoryName);
248
249                         es.dropAndInitRepositoryIndex(repositoryName);
250                 }
251
252                 TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
253                 Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
254
255                 for (TenantBindingType tenantBinding : tenantBindingsTable.values()) {
256                         CSpaceTenant tenant = new CSpaceTenant(tenantBinding.getId(), tenantBinding.getName());
257
258                         AuthZ.get().login(tenant);
259
260                         for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
261                                 Boolean isElasticsearchIndexed = serviceBinding.isElasticsearchIndexed();
262                                 String servicesRepoDomainName = serviceBinding.getRepositoryDomain();
263
264                                 if (isElasticsearchIndexed && servicesRepoDomainName != null && servicesRepoDomainName.trim().isEmpty() == false) {
265                                         String repositoryName = ConfigUtils.getRepositoryName(tenantBinding, servicesRepoDomainName);
266                                         String docType = NuxeoUtils.getTenantQualifiedDocType(tenantBinding.getId(), serviceBinding.getObject().getName());
267
268                                         logger.info("Starting Elasticsearch reindexing for docType {} in repository {}", docType, repositoryName);
269
270                                         es.runReindexingWorker(repositoryName, String.format("SELECT ecm:uuid FROM %s", docType));
271                                 }
272                         }
273                 }
274         }
275
276     /**
277      * Initialize all authorities and vocabularies defined in the service bindings.
278      * @param resourceMap
279      * @throws Exception
280      */
281     public void initializeAuthorities(ResourceMap resourceMap, boolean reset) throws Exception {
282         TenantBindingConfigReaderImpl tenantBindingConfigReader = ServiceMain.getInstance().getTenantBindingConfigReader();
283         Hashtable<String, TenantBindingType> tenantBindingsTable = tenantBindingConfigReader.getTenantBindings(false);
284         for (TenantBindingType tenantBindings : tenantBindingsTable.values()) {
285                         CSpaceTenant tenant = new CSpaceTenant(tenantBindings.getId(), tenantBindings.getName());
286                         if (shouldInitializeAuthorities(tenant, reset) == true) {
287                                 logger.info("Initializing vocabularies and authorities of tenant '{}'.", tenant.getId());
288                         for (ServiceBindingType serviceBinding : tenantBindings.getServiceBindings()) {
289                                 AuthorityInstanceList element = serviceBinding.getAuthorityInstanceList();
290                                 if (element != null && element.getAuthorityInstance() != null) {
291                                         List<AuthorityInstanceType> authorityInstanceList = element.getAuthorityInstance();
292                                         for (AuthorityInstanceType authorityInstance : authorityInstanceList) {
293                                                 try {
294                                                         initializeAuthorityInstance(resourceMap, authorityInstance, serviceBinding, tenant, reset);
295                                                 } catch (Exception e) {
296                                                         logger.error("Could not initialize authorities and authority terms: " + e.getMessage());
297                                                         throw e;
298                                                 }
299                                         }
300                                 }
301                         }
302                         //
303                         // If we made it this far, we've either created the tenant's authorities and terms or we've reset them.  Either way,
304                         // we should mark the isAuthoritiesInitialized field of the tenant to 'true'.
305                         //
306                         setAuthoritiesInitialized(tenant, true);
307                         }
308         }
309         }
310
311     @SuppressWarnings("rawtypes")
312         private AuthorityClient getAuthorityClient(String classname) throws Exception {
313         Class clazz = Class.forName(classname.trim());
314         Constructor co = clazz.getConstructor(null);
315         Object classInstance = co.newInstance(null);
316         return (AuthorityClient) classInstance;
317     }
318
319     private boolean shouldInitializeAuthorities(CSpaceTenant cspaceTenant, boolean reset) {
320                 AuthZ.get().login(); // login as super admin
321                 TenantResource tenantResource = new TenantResource();
322                 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
323
324                 //
325                 // If the tenant's authorities have been initialized and
326                 // we're not being asked to reset them, we'll return 'false'
327                 // making any changes
328                 //
329                 return tenantState.isAuthoritiesInitialized() == false || reset == true;
330     }
331
332     private void setAuthoritiesInitialized(CSpaceTenant cspaceTenant, boolean initState) {
333                 AuthZ.get().login(); // login as super admin
334                 TenantResource tenantResource = new TenantResource();
335                 Tenant tenantState = tenantResource.getTenant(cspaceTenant.getId());
336
337                 tenantState.setAuthoritiesInitialized(initState);
338                 tenantResource.updateTenant(cspaceTenant.getId(), tenantState);
339         }
340
341
342     /*
343      * Check to see if an an authority instance and its corresponding terms exist.  If not, try to create them.
344      */
345     private void initializeAuthorityInstance(ResourceMap resourceMap,
346                 AuthorityInstanceType authorityInstance,
347                 ServiceBindingType serviceBinding,
348                 CSpaceTenant cspaceTenant,
349                 boolean reset) throws Exception {
350         int status = -1;
351         Response response = null;
352                 String serviceName = serviceBinding.getName();
353
354                 AuthZ.get().login(cspaceTenant);
355                 String clientClassName = serviceBinding.getClientHandler();
356                 AuthorityClient client = getAuthorityClient(clientClassName);
357                 String authoritySpecifier = RefName.shortIdToPath(authorityInstance.getTitleRef());  // e.g., urn:cspace:name(ulan)
358
359                 //
360                 // Test to see if the authority instance exists already.
361                 //
362                 AuthorityResource authorityResource = (AuthorityResource) resourceMap.get(serviceName.toLowerCase());
363                 try {
364                         response = authorityResource.get(null, null, null, authoritySpecifier);
365                 } catch (CSWebApplicationException e) {
366                         response = e.getResponse();  // If the authority doesn't exist, we expect a 404 error
367                 }
368
369                 //
370                 // If it doesn't exist (status is not 200), then try to create the authority instance
371                 //
372                 status = response.getStatus();
373                 if (status != Response.Status.OK.getStatusCode()) {
374                         String xmlPayload = client.createAuthorityInstance(authorityInstance.getTitleRef(), authorityInstance.getTitle());
375                         response = authorityResource.createAuthority(xmlPayload);
376                         status = response.getStatus();
377                         if (status != Response.Status.CREATED.getStatusCode()) {
378                                 throw new CSWebApplicationException(response);
379                         }
380                 }
381
382                 if (status == Response.Status.OK.getStatusCode()) {
383                         logger.debug("Authority of type '{}' with the short ID of '{}' existed already.",
384                                         serviceName, authorityInstance.getTitleRef());
385                 } else if (status == Response.Status.CREATED.getStatusCode()) {
386                         logger.debug("Created a new authority of type '{}' with the short ID of '{}'.",
387                                         serviceName, authorityInstance.getTitleRef());
388                 } else {
389                         logger.warn("Unknown status '{}' encountered when creating or fetching authority of type '{}' with the short ID of '{}'.",
390                                         status, serviceName, authorityInstance.getTitleRef());
391                 }
392
393                 //
394                 // Next, try to create or verify the authority terms.
395                 //
396                 initializeAuthorityInstanceTerms(authorityResource, client, authoritySpecifier, resourceMap, authorityInstance, serviceName, cspaceTenant);
397         }
398
399     private void initializeAuthorityInstanceTerms(
400                 AuthorityResource authorityResource,
401                 AuthorityClient client,
402                 String authoritySpecifier,
403                 ResourceMap resourceMap,
404                 AuthorityInstanceType authorityInstance,
405                 String serviceName,
406                 CSpaceTenant tenant) throws Exception {
407
408         int status = -1;
409         Response response = null;
410
411         TermList termListElement = authorityInstance.getTermList();
412         if (termListElement == null) {
413                 return;
414         }
415
416         for (Term term : termListElement.getTerm()) {
417                 //
418                 // Check to see if the term already exists
419                 //
420                 try {
421                         String termSpecifier = RefName.shortIdToPath(term.getId());
422                         authorityResource.getAuthorityItem(null, null, resourceMap, authoritySpecifier, termSpecifier);
423                         status = Response.Status.OK.getStatusCode();
424                 } catch (CSWebApplicationException e) {
425                         response = e.getResponse();  // If the authority doesn't exist, we expect a 404 error
426                         status = response.getStatus();
427                 }
428
429                 //
430                 // If the term doesn't exist, create it.
431                 //
432                 if (status != Response.Status.OK.getStatusCode()) {
433                         String termShortId = term.getId();
434                         String termDisplayName = term.getContent().trim();
435                         String xmlPayload = client.createAuthorityItemInstance(termShortId, termDisplayName);
436                         try {
437                                 authorityResource.createAuthorityItem(resourceMap, null, authoritySpecifier, xmlPayload);
438                                 logger.debug("Tenant:{}:Created a new term '{}:{}' in the authority of type '{}' with the short ID of '{}'.",
439                                                 tenant.getName(), termDisplayName, termShortId, serviceName, authorityInstance.getTitleRef());
440                         } catch (CSWebApplicationException e) {
441                                 response = e.getResponse();
442                                 status = response.getStatus();
443                                 if (status != Response.Status.CREATED.getStatusCode()) {
444                                         throw new CSWebApplicationException(response);
445                                 }
446                         }
447                 }
448         }
449     }
450 }