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