]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
6f1e41f200bd6ded6f099eaeae8c72ba7c5853c2
[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);
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 protoBindingsFile, List<File> tenantDirList) throws IOException {
241                 List<TenantBindingType> result = new ArrayList<TenantBindingType>();            
242                 //
243                 // Iterate through a list of directories.
244                 //
245                 for (File tenantDir : tenantDirList) {
246                         boolean found = false;
247                         String errMessage = null;
248                         File configFile = new File(tenantDir.getAbsoluteFile() + File.separator + getFileName());
249                         if (configFile.exists() == true) {
250                         InputStream tenantBindingsStream = this.merge(protoBindingsFile, configFile);
251                         TenantBindingConfig tenantBindingConfig = null;
252                         try {
253                                         tenantBindingConfig = (TenantBindingConfig) parse(tenantBindingsStream,
254                                                         TenantBindingConfig.class);
255                         } catch (Exception e) {
256                                 logger.error("Could not parse the merged tenant bindings.", e);
257                         }
258                                 if (tenantBindingConfig != null) {
259                                         TenantBindingType binding = tenantBindingConfig.getTenantBinding();
260                                         if (binding != null) {
261                                                 result.add(binding);
262                                                 found = true;
263                                                 if (logger.isInfoEnabled() == true) {
264                                                         logger.info("Parsed tenant configureation for: " + binding.getDisplayName());
265                                                 }
266                                         } else {
267                                                 errMessage = "Cound not parse the tentant bindings in: ";
268                                         }
269                                 } else {
270                                         errMessage = "Could not parse the tenant bindings file: ";                              
271                                 }
272                         } else {
273                                 errMessage = "Cound not find a tenant configuration file: ";
274                         }
275                         if (found == false) {
276                                 if (logger.isErrorEnabled() == true) {
277                                         errMessage = errMessage != null ? errMessage : TENANT_BINDINGS_ERROR;
278                                         logger.error(errMessage + configFile.getAbsolutePath());
279                                 }
280                         }
281                 } // else-for
282                 
283                 return result;
284         }
285     
286     private void readDomains(TenantBindingType tenantBinding) throws Exception {
287         for (RepositoryDomainType domain : tenantBinding.getRepositoryDomain()) {
288                 String key = getTenantQualifiedIdentifier(tenantBinding.getId(),
289                                 domain.getName());
290             domains.put(key, domain);
291         }
292     }
293
294     private void readServiceBindings(TenantBindingType tenantBinding) throws Exception {
295         for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
296             String key = getTenantQualifiedServiceName(tenantBinding.getId(),
297                     serviceBinding.getName());
298             serviceBindings.put(key, serviceBinding);
299
300             if (serviceBinding!=null){
301                 ServiceObjectType objectType = serviceBinding.getObject();
302                 if (objectType!=null){
303                     String docType = objectType.getName();
304                     String docTypeKey = getTenantQualifiedIdentifier(tenantBinding.getId(), docType);
305                     docTypes.put(docTypeKey, serviceBinding);
306                 }
307             }
308             if (logger.isTraceEnabled()) {
309                 logger.trace("readServiceBindings() added service "
310                         + " name=" + key
311                         + " workspace=" + serviceBinding.getName());
312             }
313         }
314     }
315
316     @Override
317     public List<TenantBindingType> getConfiguration() {
318         return tenantBindingTypeList;
319     }
320
321     /**
322      * getTenantBindings returns all the tenant bindings read from configuration
323      * @return
324      */
325     public Hashtable<String, TenantBindingType> getTenantBindings() {
326         return tenantBindings;
327     }
328
329     /**
330      * getTenantBinding gets tenant binding for given tenant
331      * @param tenantId
332      * @return
333      */
334     public TenantBindingType getTenantBinding(
335             String tenantId) {
336         return tenantBindings.get(tenantId);
337     }
338
339     /**
340      * getRepositoryDomain gets repository domain configuration for the given name
341      * @param domainName
342      * @return
343      */
344     public RepositoryDomainType getRepositoryDomain(String domainName) {
345         return domains.get(domainName.trim());
346     }
347
348     /**
349      * getRepositoryDomain gets repository domain configuration for the given service
350      * and given tenant id
351      * @param tenantId
352      * @param serviceName
353      * @return
354      */
355     public RepositoryDomainType getRepositoryDomain(String tenantId, String serviceName) {
356         ServiceBindingType serviceBinding = getServiceBinding(tenantId, serviceName);
357         if (serviceBinding == null) {
358             throw new IllegalArgumentException("no service binding found for " + serviceName
359                     + " of tenant with id=" + tenantId);
360         }
361         String repoDomain = serviceBinding.getRepositoryDomain(); 
362         if (repoDomain == null) {
363             if (logger.isTraceEnabled()) {
364                 logger.trace("No repository domain configured for " + serviceName
365                         + " of tenant with id=" + tenantId);
366             }
367             return null;
368         }
369         String key = this.getTenantQualifiedIdentifier(tenantId, repoDomain.trim());
370         return domains.get(key);
371     }
372
373     /**
374      * getServiceBinding gets service binding for given tenant for a given service
375      * @param tenantId
376      * @param serviceName
377      * @return
378      */
379     public ServiceBindingType getServiceBinding(
380             String tenantId, String serviceName) {
381         String key = getTenantQualifiedServiceName(tenantId, serviceName);
382         return serviceBindings.get(key);
383     }
384
385     /**
386      * getServiceBinding gets service binding for given tenant for a given service
387      * @param tenantId
388      * @param docType
389      * @return
390      */
391     public ServiceBindingType getServiceBindingForDocType (String tenantId, String docType) {
392         String key = getTenantQualifiedIdentifier(tenantId, docType);
393         return docTypes.get(key);
394     }
395
396     /**
397      * getServiceBinding gets service binding for given tenant for a given service
398      * @param tenantId
399      * @param serviceName
400      * @return
401      */
402     public List<ServiceBindingType> getServiceBindingsByType(
403             String tenantId, String serviceType) {
404         List<String> serviceTypes = new ArrayList<String>(1);
405         serviceTypes.add(serviceType);
406         return getServiceBindingsByType(tenantId, serviceTypes);
407     }
408     /**
409      * getServiceBindingsByType gets service bindings for a given tenant
410      * for the services that fall within a supplied set of service type(s)
411      * @param tenantId
412      * @param serviceTypes
413      * @return
414      */
415     public List<ServiceBindingType> getServiceBindingsByType(
416             String tenantId, List<String> serviceTypes) {
417         ArrayList<ServiceBindingType> list = null;
418         TenantBindingType tenant = tenantBindings.get(tenantId);
419         if (tenant != null) {
420             for (ServiceBindingType sb : tenant.getServiceBindings()) {
421                 if (serviceTypes.contains(sb.getType())) {
422                     if (list == null) {
423                         list = new ArrayList<ServiceBindingType>();
424                     }
425                     list.add(sb);
426                 }
427             }
428         }
429         return list;
430     }
431
432     /**
433      * @param tenantId
434      * @param serviceName
435      * @return the properly qualified service name
436      */
437     public static String getTenantQualifiedServiceName(
438             String tenantId, String serviceName) {
439 //        return tenantId + "." + serviceName.toLowerCase();
440         return getTenantQualifiedIdentifier(tenantId, serviceName.toLowerCase());
441     }
442
443     public static String getTenantQualifiedIdentifier(String tenantId, String identifier) {
444         return tenantId + "." + identifier;
445     }
446     /**
447      * Sets properties in the passed list on the local properties for this TenantBinding.
448      * Note: will only set properties not already set on the TenantBinding.
449      * 
450      * @param propList
451      * @param propagateToServices If true, recurses to set set properties 
452      *                  on the associated services.
453      */
454     public void setDefaultPropertiesOnTenants(List<PropertyItemType> propList,
455             boolean propagateToServices) {
456         // For each tenant, set properties in list that are not already set
457         if (propList == null || propList.isEmpty()) {
458             return;
459         }
460         for (TenantBindingType tenant : tenantBindings.values()) {
461             for (PropertyItemType prop : propList) {
462                 TenantBindingUtils.setPropertyValue(tenant,
463                         prop, TenantBindingUtils.SET_PROP_IF_MISSING);
464             }
465             if (propagateToServices) {
466                 TenantBindingUtils.propagatePropertiesToServices(tenant,
467                         TenantBindingUtils.SET_PROP_IF_MISSING);
468             }
469         }
470     }
471
472     public String getResourcesDir(){
473         return getConfigRootDir() + File.separator + RESOURCES_DIR_NAME;
474     }
475     
476     
477     /**
478      * Returns a list of tenant identifiers (tenant IDs).
479      * 
480      * @return a list of tenant IDs
481      */
482     public List<String> getTenantIds() {
483         List<String> tenantIds = new ArrayList<String>();
484         String tenantId;
485         Hashtable<String, TenantBindingType> tenantBindings = getTenantBindings();
486         if (tenantBindings != null && !tenantBindings.isEmpty()) {
487             Enumeration keys = tenantBindings.keys();
488             while (keys.hasMoreElements()) {
489                 tenantId = (String) keys.nextElement();
490                 if (Tools.notBlank(tenantId)) {
491                     tenantIds.add(tenantId);
492                 }
493             }
494         }
495         return tenantIds;
496     }
497 }