]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
dfbb4fe1fc3850289b7d4ba0b09ac10b069130de
[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                 if(tenantBindings.get(tenantBinding.getId()) != null) {
181                         TenantBindingType tenantBindingOld = tenantBindings.get(tenantBinding.getId());
182                 logger.error("Ignoring duplicate binding definition for tenant id=" 
183                                 + tenantBinding.getId()
184                         + " existing name=" + tenantBindingOld.getName()
185                         + " conflicting (ignored) name=" + tenantBinding.getName());
186                 continue;
187                 }
188             tenantBindings.put(tenantBinding.getId(), tenantBinding);
189             readDomains(tenantBinding);
190             readServiceBindings(tenantBinding);
191             if (logger.isInfoEnabled()) {
192                 logger.info("Finished reading tenant bindings for tenant id=" + tenantBinding.getId()
193                         + " name=" + tenantBinding.getName());
194             }
195         }
196     }
197     
198     /*
199      * Take the directory of the prototype bindings and the directory of the delta bindings.  Merge the two and create (replace) a file
200      * named "tenant-bindings.xml"
201      *
202         private static String merge(String original, String patch) {
203                 InputStream result = null;
204                 try {
205                         Configurer configurer = new AttributeMergeConfigurer();
206                         
207                         
208                         FileInputStream ins1 = new FileInputStream(".\\src\\main\\resources\\File1.xml");
209                         FileInputStream ins2 = new FileInputStream(".\\src\\main\\resources\\File2.xml");
210                         InputStream[] inputStreamArray = {ins1, ins2};                  
211                         
212                         result = new ConfigurableXmlMerge(configurer).merge(inputStreamArray);
213 //                      result = new ConfigurableXmlMerge(configurer).merge(new String[] {original, patch});
214                 } catch (Exception e) {
215                         // TODO Auto-generated catch block
216                         e.printStackTrace();
217                 }
218                 File mergedOutFile = new File(".\\target\\merged.xml");
219                 try {
220                         FileUtils.copyInputStreamToFile(result, mergedOutFile);
221                 } catch (IOException e) {
222                         // TODO Auto-generated catch block
223                         e.printStackTrace();
224                 }
225
226                 return null;
227         }
228         */
229     
230         /**
231      * Merge and read the prototype bindsings with each tenant specific bindings delta to create the final
232      * tenant bindings.
233      *
234      * @param protoBindingsFile - The prototypical bindings file.
235      * @param tenantDirList - The list of tenant directories containing tenant specific bindings
236      * @return A list of tenant bindings.
237      * @throws IOException Signals that an I/O exception has occurred.
238      */
239     List<TenantBindingType> readTenantConfigs(File protoBindingsFile, List<File> tenantDirList) throws IOException {
240                 List<TenantBindingType> result = new ArrayList<TenantBindingType>();            
241                 //
242                 // Iterate through a list of directories.
243                 //
244                 for (File tenantDir : tenantDirList) {
245                         boolean found = false;
246                         String errMessage = null;
247                         File configFile = new File(tenantDir.getAbsoluteFile() + File.separator + getFileName());
248                         if (configFile.exists() == true) {
249                         InputStream tenantBindingsStream = this.merge(protoBindingsFile, configFile);
250                         TenantBindingConfig tenantBindingConfig = null;
251                         try {
252                                         tenantBindingConfig = (TenantBindingConfig) parse(tenantBindingsStream,
253                                                         TenantBindingConfig.class);
254                         } catch (Exception e) {
255                                 logger.error("Could not parse the merged tenant bindings.", e);
256                         }
257                                 if (tenantBindingConfig != null) {
258                                         TenantBindingType binding = tenantBindingConfig.getTenantBinding();
259                                         if (binding != null) {
260                                                 result.add(binding);
261                                                 found = true;
262                                                 if (logger.isInfoEnabled() == true) {
263                                                         logger.info("Parsed tenant configureation for: " + binding.getDisplayName());
264                                                 }
265                                         } else {
266                                                 errMessage = "Cound not parse the tentant bindings in: ";
267                                         }
268                                 } else {
269                                         errMessage = "Could not parse the tenant bindings file: ";                              
270                                 }
271                         } else {
272                                 errMessage = "Cound not find a tenant configuration file: ";
273                         }
274                         if (found == false) {
275                                 if (logger.isErrorEnabled() == true) {
276                                         errMessage = errMessage != null ? errMessage : TENANT_BINDINGS_ERROR;
277                                         logger.error(errMessage + configFile.getAbsolutePath());
278                                 }
279                         }
280                 } // else-for
281                 
282                 return result;
283         }
284     
285     private void readDomains(TenantBindingType tenantBinding) throws Exception {
286         for (RepositoryDomainType domain : tenantBinding.getRepositoryDomain()) {
287                 String key = getTenantQualifiedIdentifier(tenantBinding.getId(),
288                                 domain.getName());
289             domains.put(key, domain);
290         }
291     }
292
293     private void readServiceBindings(TenantBindingType tenantBinding) throws Exception {
294         for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
295             String key = getTenantQualifiedServiceName(tenantBinding.getId(),
296                     serviceBinding.getName());
297             serviceBindings.put(key, serviceBinding);
298
299             if (serviceBinding!=null){
300                 ServiceObjectType objectType = serviceBinding.getObject();
301                 if (objectType!=null){
302                     String docType = objectType.getName();
303                     String docTypeKey = getTenantQualifiedIdentifier(tenantBinding.getId(), docType);
304                     docTypes.put(docTypeKey, serviceBinding);
305                 }
306             }
307             if (logger.isTraceEnabled()) {
308                 logger.trace("readServiceBindings() added service "
309                         + " name=" + key
310                         + " workspace=" + serviceBinding.getName());
311             }
312         }
313     }
314
315     @Override
316     public List<TenantBindingType> getConfiguration() {
317         return tenantBindingTypeList;
318     }
319
320     /**
321      * getTenantBindings returns all the tenant bindings read from configuration
322      * @return
323      */
324     public Hashtable<String, TenantBindingType> getTenantBindings() {
325         return tenantBindings;
326     }
327
328     /**
329      * getTenantBinding gets tenant binding for given tenant
330      * @param tenantId
331      * @return
332      */
333     public TenantBindingType getTenantBinding(
334             String tenantId) {
335         return tenantBindings.get(tenantId);
336     }
337
338     /**
339      * getRepositoryDomain gets repository domain configuration for the given name
340      * @param domainName
341      * @return
342      */
343     public RepositoryDomainType getRepositoryDomain(String domainName) {
344         return domains.get(domainName.trim());
345     }
346
347     /**
348      * getRepositoryDomain gets repository domain configuration for the given service
349      * and given tenant id
350      * @param tenantId
351      * @param serviceName
352      * @return
353      */
354     public RepositoryDomainType getRepositoryDomain(String tenantId, String serviceName) {
355         ServiceBindingType serviceBinding = getServiceBinding(tenantId, serviceName);
356         if (serviceBinding == null) {
357             throw new IllegalArgumentException("no service binding found for " + serviceName
358                     + " of tenant with id=" + tenantId);
359         }
360         String repoDomain = serviceBinding.getRepositoryDomain(); 
361         if (repoDomain == null) {
362                 /* This is excessive - every call to a JPA based service dumps this msg.
363             if (logger.isDebugEnabled()) {
364                 logger.debug("No repository domain configured for " + serviceName
365                         + " of tenant with id=" + tenantId);
366             }
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      * getServiceBinding gets service binding for given tenant for a given service
411      * @param tenantId
412      * @param serviceName
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";
474     }
475 }