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