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