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