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