]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
b12f43ec1c9614478e4ca6b40cabb2bbb84acf74
[tmp/jakarta-migration.git] /
1 /**
2  *  This document is a part of the source code and related artifacts
3  *  for CollectionSpace, an open source collections management system
4  *  for museums and related institutions:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
18  *  Unless required by applicable law or agreed to in writing, software
19  *  distributed under the License is distributed on an "AS IS" BASIS,
20  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  *  See the License for the specific language governing permissions and
22  *  limitations under the License.
23  */
24 package org.collectionspace.services.common.config;
25
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.util.ArrayList;
31 import java.util.Enumeration;
32 import java.util.Hashtable;
33 import java.util.List;
34
35 import org.apache.commons.io.FileUtils;
36 import org.collectionspace.services.common.ServiceMain;
37 import org.collectionspace.services.common.api.JEEServerDeployment;
38 import org.collectionspace.services.common.api.Tools;
39 import org.collectionspace.services.config.service.ServiceBindingType;
40 import org.collectionspace.services.config.service.ServiceObjectType;
41 import org.collectionspace.services.config.tenant.RepositoryDomainType;
42 import org.collectionspace.services.config.tenant.TenantBindingConfig;
43 import org.collectionspace.services.config.tenant.TenantBindingType;
44 import org.collectionspace.services.config.types.PropertyItemType;
45
46 import ch.elca.el4j.services.xmlmerge.Configurer;
47 import ch.elca.el4j.services.xmlmerge.config.AttributeMergeConfigurer;
48 import ch.elca.el4j.services.xmlmerge.config.ConfigurableXmlMerge;
49
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 /**
54  * ServicesConfigReader reads service layer specific configuration
55  * 
56  * $LastChangedRevision: $ $LastChangedDate: $
57  */
58 public class TenantBindingConfigReaderImpl extends AbstractConfigReaderImpl<List<TenantBindingType>> {
59         final public static boolean INCLUDE_CREATE_DISABLED_TENANTS = true;
60         final public static boolean EXCLUDE_CREATE_DISABLED_TENANTS = false;
61
62         final private static String TENANT_BINDINGS_ERROR = "Tenant bindings error(s) for tenant: ";
63         final private static String TENANT_BINDINGS_DELTA_FILENAME = JEEServerDeployment.TENANT_BINDINGS_FILENAME_PREFIX
64                         + ".delta.xml";
65         final private static String MERGED_SUFFIX = ".merged.xml";
66         private static final String NO_SERVICE_BINDINGS_FOUND_ERR = "No Service bindings found.";
67
68         private static final Logger logger = LoggerFactory.getLogger(TenantBindingConfigReaderImpl.class);
69         private List<TenantBindingType> tenantBindingTypeList;
70         // tenant id, tenant binding, for tenants not marked as createDisabled
71         private Hashtable<String, TenantBindingType> enabledTenantBindings = new Hashtable<String, TenantBindingType>();
72         // tenant id, tenant binding
73         private Hashtable<String, TenantBindingType> allTenantBindings = new Hashtable<String, TenantBindingType>();
74         // repository domains
75         private Hashtable<String, RepositoryDomainType> domains = new Hashtable<String, RepositoryDomainType>();
76         // tenant-qualified servicename, service binding
77         private Hashtable<String, ServiceBindingType> serviceBindings = new Hashtable<String, ServiceBindingType>();
78
79         // tenant-qualified service object name to service name, service binding
80         private Hashtable<String, ServiceBindingType> docTypes = new Hashtable<String, ServiceBindingType>();
81
82         public TenantBindingConfigReaderImpl(String serverRootDir) {
83                 super(serverRootDir);
84         }
85
86         @Override
87         public String getFileName() {
88                 return TENANT_BINDINGS_DELTA_FILENAME;
89         }
90
91         private String getFileName(String tenantName, boolean useAppGeneratedBindings) {
92                 String result = getFileName();
93
94                 if (useAppGeneratedBindings == true) {
95                         result = tenantName + "-" + result;
96                 }
97
98                 return result;
99         }
100
101         protected File getTenantsRootDir() {
102                 File result = null;
103                 String errMessage = null;
104                 try {
105                         String tenantsRootPath = getConfigRootDir() + File.separator
106                                         + JEEServerDeployment.TENANT_BINDINGS_ROOTDIRNAME;
107                         File tenantsRootDir = new File(tenantsRootPath);
108                         if (tenantsRootDir.exists() == true) {
109                                 result = tenantsRootDir;
110                                 if (logger.isDebugEnabled() == true) {
111                                         logger.debug("The home directory for all tenants is at: " + result.getCanonicalPath());
112                                 }
113                         } else {
114                                 errMessage = "The home directory for all tenants is missing or inaccessible: ";
115                                 try {
116                                         errMessage = errMessage + tenantsRootDir.getCanonicalPath();
117                                 } catch (IOException ioException) {
118                                         errMessage = errMessage + tenantsRootDir.getAbsolutePath();
119                                 }
120                         }
121                 } catch (IOException e) {
122                         // Log this exception, but continue anyway. Caller should handle the
123                         // null result gracefully.
124                         logger.equals(e);
125                 }
126
127                 if (errMessage != null) {
128                         logger.error(errMessage);
129                 }
130
131                 return result;
132         }
133
134         /*
135          * Take the directory of the prototype bindings and the directory of the
136          * delta bindings. Merge the two and create (replace) a file named
137          * "tenant-bindings.xml"
138          */
139
140         private InputStream merge(File srcFile, File deltaFile) throws IOException {
141                 InputStream result = null;
142                 try {
143                         FileInputStream srcStream = new FileInputStream(srcFile);
144                         FileInputStream deltaStream = new FileInputStream(deltaFile);
145                         InputStream[] inputStreamArray = { srcStream, deltaStream };
146
147                         Configurer configurer = new AttributeMergeConfigurer();
148                         result = new ConfigurableXmlMerge(configurer).merge(inputStreamArray);
149                 } catch (Exception e) {
150                         logger.error("Could not merge tenant configuration delta file: " + deltaFile.getCanonicalPath(), e);
151                 }
152                 //
153                 // Try to save the merge output to a file that is suffixed with
154                 // ".merged.xml" in the same directory
155                 // as the delta file.
156                 //
157                 if (result != null) {
158                         File outputDir = deltaFile.getParentFile();
159                         String mergedFileName = outputDir.getAbsolutePath() + File.separator
160                                         + JEEServerDeployment.TENANT_BINDINGS_FILENAME_PREFIX + MERGED_SUFFIX;
161                         File mergedOutFile = new File(mergedFileName);
162                         try {
163                                 FileUtils.copyInputStreamToFile(result, mergedOutFile);
164                         } catch (IOException e) {
165                                 logger.warn("Could not create a copy of the merged tenant configuration at: " + mergedFileName, e);
166                         }
167                         result.reset(); // reset the stream even if the file create failed.
168                 }
169
170                 return result;
171         }
172
173         @Override
174         public void read(boolean useAppGeneratedBindings) throws Exception {
175                 String tenantsRootPath = getTenantsRootDir().getAbsolutePath();
176                 read(tenantsRootPath, useAppGeneratedBindings);
177         }
178
179         @Override
180         public void read(String tenantRootDirPath, boolean useAppGeneratedBindings) throws Exception {
181                 File tenantsRootDir = new File(tenantRootDirPath);
182                 if (tenantsRootDir.exists() == false) {
183                         throw new Exception("Cound not find tenant bindings root directory: " + tenantRootDirPath);
184                 }
185
186                 List<File> tenantDirs = getDirectories(tenantsRootDir);
187                 tenantBindingTypeList = readTenantConfigs(new File(tenantRootDirPath), tenantDirs, useAppGeneratedBindings);
188                 if (tenantBindingTypeList == null || tenantBindingTypeList.size() < 1) {
189                         throw new Exception(NO_SERVICE_BINDINGS_FOUND_ERR);
190                 }
191
192                 for (TenantBindingType tenantBinding : tenantBindingTypeList) {
193                         if (allTenantBindings.get(tenantBinding.getId()) != null) {
194                                 TenantBindingType tenantBindingOld = allTenantBindings.get(tenantBinding.getId());
195                                 logger.error("Ignoring duplicate binding definition for tenant id=" + tenantBinding.getId()
196                                                 + " existing name=" + tenantBindingOld.getName() + " conflicting (ignored) name="
197                                                 + tenantBinding.getName());
198                                 continue;
199                         }
200                         allTenantBindings.put(tenantBinding.getId(), tenantBinding);
201                         if (!tenantBinding.isCreateDisabled()) {
202                                 enabledTenantBindings.put(tenantBinding.getId(), tenantBinding);
203                         } else {
204                         }
205                         readDomains(tenantBinding);
206                         readServiceBindings(tenantBinding);
207                         if (logger.isInfoEnabled()) {
208                                 logger.info("Finished reading tenant bindings for tenant id=" + tenantBinding.getId() + " name="
209                                                 + tenantBinding.getName());
210                                 if (tenantBinding.isCreateDisabled())
211                                         logger.info("Tenant tenant id={} is marked createDisabled.", tenantBinding.getId());
212                         }
213                 }
214         }
215
216         /*
217          * Take the directory of the prototype bindings and the directory of the
218          * delta bindings. Merge the two and create (replace) a file named
219          * "tenant-bindings.xml"
220          * 
221          * private static String merge(String original, String patch) { InputStream
222          * result = null; try { Configurer configurer = new
223          * AttributeMergeConfigurer();
224          * 
225          * 
226          * FileInputStream ins1 = new
227          * FileInputStream(".\\src\\main\\resources\\File1.xml"); FileInputStream
228          * ins2 = new FileInputStream(".\\src\\main\\resources\\File2.xml");
229          * InputStream[] inputStreamArray = {ins1, ins2};
230          * 
231          * result = new ConfigurableXmlMerge(configurer).merge(inputStreamArray); //
232          * result = new ConfigurableXmlMerge(configurer).merge(new String[]
233          * {original, patch}); } catch (Exception e) { // TODO Auto-generated catch
234          * block e.printStackTrace(); } File mergedOutFile = new
235          * File(".\\target\\merged.xml"); try {
236          * FileUtils.copyInputStreamToFile(result, mergedOutFile); } catch
237          * (IOException e) { // TODO Auto-generated catch block e.printStackTrace();
238          * }
239          * 
240          * return null; }
241          */
242
243         /**
244          * Merge and read the prototype bindsings with each tenant specific bindings
245          * delta to create the final tenant bindings.
246          * 
247          * @param protoBindingsFile
248          *            - The prototypical bindings file.
249          * @param tenantDirList
250          *            - The list of tenant directories containing tenant specific
251          *            bindings
252          * @return A list of tenant bindings.
253          * @throws IOException
254          *             Signals that an I/O exception has occurred.
255          */
256         List<TenantBindingType> readTenantConfigs(File protoBindingsDir, List<File> tenantDirList,
257                         boolean useAppGeneratedBindings) throws IOException {
258                 List<TenantBindingType> result = new ArrayList<TenantBindingType>();
259
260                 //
261                 // Iterate through a list of directories.
262                 //
263                 for (File tenantDir : tenantDirList) {
264                         boolean found = false;
265                         String errMessage = null;
266
267                         File tenantBindingsProtoFile = null;
268                         String tenantName = tenantDir.getName();        // By convention, the
269                                                                                                                 // directory name should
270                                                                                                                 // be the tenant name
271                         if (useAppGeneratedBindings == true) {
272                                 tenantBindingsProtoFile = new File(protoBindingsDir.getAbsolutePath() + File.separator + tenantName
273                                                 + "-" + JEEServerDeployment.TENANT_BINDINGS_PROTOTYPE_FILENAME);
274                         } else {
275                                 tenantBindingsProtoFile = new File(protoBindingsDir + File.separator
276                                                 + JEEServerDeployment.TENANT_BINDINGS_PROTOTYPE_FILENAME);
277                         }
278
279                         if (tenantBindingsProtoFile.exists() == true) {
280                                 File configFile = new File(tenantDir.getAbsoluteFile() + File.separator
281                                                 + getFileName(tenantName, useAppGeneratedBindings));
282                                 if (configFile.exists() == true) {
283                                         InputStream tenantBindingsStream = this.merge(tenantBindingsProtoFile, configFile);
284                                         TenantBindingConfig tenantBindingConfig = null;
285                                         try {
286                                                 tenantBindingConfig = (TenantBindingConfig) parse(tenantBindingsStream,
287                                                                 TenantBindingConfig.class);
288                                         } catch (Exception e) {
289                                                 logger.error("Could not parse the merged tenant bindings.", e);
290                                         }
291                                         if (tenantBindingConfig != null) {
292                                                 TenantBindingType binding = tenantBindingConfig.getTenantBinding();
293                                                 if (binding != null) {
294                                                         result.add(binding);
295                                                         found = true;
296                                                         if (logger.isInfoEnabled() == true) {
297                                                                 logger.info("Parsed tenant configuration for: " + binding.getDisplayName());
298                                                         }
299                                                 } else {
300                                                         errMessage = "Cound not parse the tentant bindings in: ";
301                                                 }
302                                         } else {
303                                                 errMessage = "Could not parse the tenant bindings file: ";
304                                         }
305                                 } else {
306                                         errMessage = "Expected to, but could not, find the tenant delta configuration file: "
307                                                         + configFile.getAbsolutePath();
308                                 }
309                         } else {
310                                 errMessage = "Expected to, but could not, find the tenant proto configuration file: "
311                                                 + tenantBindingsProtoFile.getAbsolutePath();
312                         }
313
314                         if (found == false) {
315                                 if (logger.isErrorEnabled() == true) {
316                                         errMessage = errMessage != null ? errMessage : TENANT_BINDINGS_ERROR;
317                                         logger.error(errMessage + " - For tenant: " + tenantName);
318                                 }
319                         }
320                 } // else-for
321
322                 return result;
323         }
324
325         private void readDomains(TenantBindingType tenantBinding) throws Exception {
326                 for (RepositoryDomainType domain : tenantBinding.getRepositoryDomain()) {
327                         String key = getTenantQualifiedIdentifier(tenantBinding.getId(), domain.getName());
328                         domains.put(key, domain);
329                 }
330         }
331
332         private void readServiceBindings(TenantBindingType tenantBinding) throws Exception {
333                 for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
334                         String key = getTenantQualifiedServiceName(tenantBinding.getId(), serviceBinding.getName());
335                         if (key == null) {
336                                 continue;
337                         }
338                         serviceBindings.put(key, serviceBinding);
339
340                         if (serviceBinding != null) {
341                                 ServiceObjectType objectType = serviceBinding.getObject();
342                                 if (objectType != null) {
343                                         String docType = objectType.getName();
344                                         String docTypeKey = getTenantQualifiedIdentifier(tenantBinding.getId(), docType);
345                                         docTypes.put(docTypeKey, serviceBinding);
346                                 }
347                         }
348                         if (logger.isTraceEnabled()) {
349                                 logger.trace("readServiceBindings() added service " + " name=" + key + " workspace="
350                                                 + serviceBinding.getName());
351                         }
352                 }
353         }
354
355         @Override
356         public List<TenantBindingType> getConfiguration() {
357                 return tenantBindingTypeList;
358         }
359
360         /**
361          * getTenantBindings returns all the tenant bindings read from configuration
362          * 
363          * @return
364          */
365         public Hashtable<String, TenantBindingType> getTenantBindings() {
366                 return getTenantBindings(EXCLUDE_CREATE_DISABLED_TENANTS);
367         }
368
369         /**
370          * getTenantBindings returns all the tenant bindings read from configuration
371          * 
372          * @return
373          */
374         public Hashtable<String, TenantBindingType> getTenantBindings(boolean includeDisabled) {
375                 return includeDisabled ? allTenantBindings : enabledTenantBindings;
376         }
377
378         /**
379          * getTenantBinding gets tenant binding for given tenant
380          * 
381          * @param tenantId
382          * @return
383          */
384         public TenantBindingType getTenantBinding(String tenantId) {
385                 return allTenantBindings.get(tenantId);
386         }
387
388         /**
389          * getRepositoryDomain gets repository domain configuration for the given
390          * name
391          * 
392          * @param domainName
393          * @return
394          */
395         public RepositoryDomainType getRepositoryDomain(String domainName) {
396                 return domains.get(domainName.trim());
397         }
398
399         /**
400          * getRepositoryDomain gets repository domain configuration for the given
401          * service and given tenant id
402          * 
403          * @param tenantId
404          * @param serviceName
405          * @return
406          */
407         public RepositoryDomainType getRepositoryDomain(String tenantId, String serviceName) {
408                 ServiceBindingType serviceBinding = getServiceBinding(tenantId, serviceName);
409                 if (serviceBinding == null) {
410                         throw new IllegalArgumentException("no service binding found for " + serviceName + " of tenant with id="
411                                         + tenantId);
412                 }
413                 String repoDomain = serviceBinding.getRepositoryDomain();
414                 if (repoDomain == null) {
415                         if (logger.isTraceEnabled()) {
416                                 logger.trace("No repository domain configured for " + serviceName + " of tenant with id=" + tenantId);
417                         }
418                         return null;
419                 }
420                 String key = this.getTenantQualifiedIdentifier(tenantId, repoDomain.trim());
421                 return domains.get(key);
422         }
423
424         /**
425          * getServiceBinding gets service binding for given tenant for a given
426          * service
427          * 
428          * @param tenantId
429          * @param serviceName
430          * @return
431          */
432         public ServiceBindingType getServiceBinding(String tenantId, String serviceName) {
433                 String key = getTenantQualifiedServiceName(tenantId, serviceName);
434                 return serviceBindings.get(key);
435         }
436
437         /**
438          * getServiceBinding gets service binding for given tenant for a given
439          * service
440          * 
441          * @param tenantId
442          * @param docType
443          * @return
444          */
445         public ServiceBindingType getServiceBindingForDocType(String tenantId, String docType) {
446                 String key = getTenantQualifiedIdentifier(tenantId, docType);
447                 return docTypes.get(key);
448         }
449
450         /**
451          * getServiceBinding gets service binding for given tenant for a given
452          * service
453          * 
454          * @param tenantId
455          * @param serviceName
456          * @return
457          */
458         public List<ServiceBindingType> getServiceBindingsByType(String tenantId, String serviceType) {
459                 List<String> serviceTypes = new ArrayList<String>(1);
460                 serviceTypes.add(serviceType);
461                 return getServiceBindingsByType(tenantId, serviceTypes);
462         }
463
464         /**
465          * getServiceBindingsByType gets service bindings for a given tenant for the
466          * services that fall within a supplied set of service type(s)
467          * 
468          * @param tenantId
469          * @param serviceTypes
470          * @return
471          */
472         public List<ServiceBindingType> getServiceBindingsByType(String tenantId, List<String> serviceTypes) {
473                 ArrayList<ServiceBindingType> list = null;
474                 TenantBindingType tenant = allTenantBindings.get(tenantId);
475                 if (tenant != null) {
476                         for (ServiceBindingType sb : tenant.getServiceBindings()) {
477                                 if (serviceTypes.contains(sb.getType())) {
478                                         if (list == null) {
479                                                 list = new ArrayList<ServiceBindingType>();
480                                         }
481                                         list.add(sb);
482                                 }
483                         }
484                 }
485                 return list;
486         }
487
488         /**
489          * @param tenantId
490          * @param serviceName
491          * @return the properly qualified service name
492          */
493         public static String getTenantQualifiedServiceName(String tenantId, String serviceName) {
494                 String result = null;
495
496                 if (serviceName != null) {
497                         if (logger.isDebugEnabled() == true) {
498                                 logger.debug(String.format(" * tenant:serviceBindings '%s'", serviceName));
499                                 System.out.println(String.format(" * tenant:serviceBindings '%s'", serviceName)); // Debug only
500                         }
501                         result = getTenantQualifiedIdentifier(tenantId, serviceName.toLowerCase());
502                 }
503
504                 return result;
505         }
506
507         public static String getTenantQualifiedIdentifier(String tenantId, String identifier) {
508                 return tenantId + "." + identifier;
509         }
510
511         /**
512          * Sets properties in the passed list on the local properties for this
513          * TenantBinding. Note: will only set properties not already set on the
514          * TenantBinding.
515          * 
516          * @param propList
517          * @param propagateToServices
518          *            If true, recurses to set set properties on the associated
519          *            services.
520          */
521         public void setDefaultPropertiesOnTenants(List<PropertyItemType> propList, boolean propagateToServices) {
522                 // For each tenant, set properties in list that are not already set
523                 if (propList == null || propList.isEmpty()) {
524                         return;
525                 }
526                 for (TenantBindingType tenant : allTenantBindings.values()) {
527                         for (PropertyItemType prop : propList) {
528                                 TenantBindingUtils.setPropertyValue(tenant, prop, TenantBindingUtils.SET_PROP_IF_MISSING);
529                         }
530                         if (propagateToServices) {
531                                 TenantBindingUtils.propagatePropertiesToServices(tenant, TenantBindingUtils.SET_PROP_IF_MISSING);
532                         }
533                 }
534         }
535
536         public String getResourcesDir() {
537                 return getConfigRootDir() + File.separator + RESOURCES_DIR_NAME;
538         }
539
540         /**
541          * Returns a list of tenant identifiers (tenant IDs).
542          * 
543          * @return a list of tenant IDs
544          */
545         public List<String> getTenantIds() {
546                 return getTenantIds(EXCLUDE_CREATE_DISABLED_TENANTS);
547         }
548
549         /**
550          * Returns a list of tenant identifiers (tenant IDs).
551          * 
552          * @return a list of tenant IDs
553          */
554         public List<String> getTenantIds(boolean includeDisabled) {
555                 List<String> tenantIds = new ArrayList<String>();
556                 String tenantId;
557                 Hashtable<String, TenantBindingType> tenantBindings = getTenantBindings(includeDisabled);
558                 if (tenantBindings != null && !tenantBindings.isEmpty()) {
559                         Enumeration keys = tenantBindings.keys();
560                         while (keys.hasMoreElements()) {
561                                 tenantId = (String) keys.nextElement();
562                                 if (Tools.notBlank(tenantId)) {
563                                         tenantIds.add(tenantId);
564                                 }
565                         }
566                 }
567                 return tenantIds;
568         }
569 }