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