Java tutorial
/** * This document is a part of the source code and related artifacts * for CollectionSpace, an open source collections management system * for museums and related institutions: * http://www.collectionspace.org * http://wiki.collectionspace.org * Copyright 2009 University of California at Berkeley * Licensed under the Educational Community License (ECL), Version 2.0. * You may not use this file except in compliance with this License. * You may obtain a copy of the ECL 2.0 License at * https://source.collectionspace.org/collection-space/LICENSE.txt * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.collectionspace.services.common.config; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import org.apache.commons.io.FileUtils; import org.collectionspace.services.common.service.ServiceBindingType; import org.collectionspace.services.common.service.ServiceObjectType; import org.collectionspace.services.common.tenant.RepositoryDomainType; import org.collectionspace.services.common.tenant.TenantBindingType; import org.collectionspace.services.common.tenant.TenantBindingConfig; import org.collectionspace.services.common.types.PropertyItemType; import ch.elca.el4j.util.codingsupport.Reject; import ch.elca.el4j.services.xmlmerge.AbstractXmlMergeException; import ch.elca.el4j.services.xmlmerge.ConfigurationException; import ch.elca.el4j.services.xmlmerge.Configurer; import ch.elca.el4j.services.xmlmerge.XmlMerge; import ch.elca.el4j.services.xmlmerge.config.AttributeMergeConfigurer; import ch.elca.el4j.services.xmlmerge.config.ConfigurableXmlMerge; import ch.elca.el4j.services.xmlmerge.config.PropertyXPathConfigurer; import ch.elca.el4j.services.xmlmerge.merge.DefaultXmlMerge; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.elca.el4j.services.xmlmerge.Configurer; import ch.elca.el4j.services.xmlmerge.config.AttributeMergeConfigurer; import ch.elca.el4j.services.xmlmerge.config.ConfigurableXmlMerge; /** * ServicesConfigReader reads service layer specific configuration * * $LastChangedRevision: $ * $LastChangedDate: $ */ public class TenantBindingConfigReaderImpl extends AbstractConfigReaderImpl<List<TenantBindingType>> { final private static String TENANT_BINDINGS_ERROR = "Tenant bindings error: "; final private static String TENANT_BINDINGS_ROOTDIRNAME = "tenants"; final private static String TENANT_BINDINGS_FILENAME_PREFIX = "tenant-bindings"; final private static String TENANT_BINDINGS_PROTOTYPE_FILENAME = TENANT_BINDINGS_FILENAME_PREFIX + "-proto.xml"; final private static String TENANT_BINDINGS_DELTA_FILENAME = TENANT_BINDINGS_FILENAME_PREFIX + ".delta.xml"; final private static String MERGED_SUFFIX = ".merged.xml"; final Logger logger = LoggerFactory.getLogger(TenantBindingConfigReaderImpl.class); private List<TenantBindingType> tenantBindingTypeList; //tenant id, tenant binding private Hashtable<String, TenantBindingType> tenantBindings = new Hashtable<String, TenantBindingType>(); //repository domains private Hashtable<String, RepositoryDomainType> domains = new Hashtable<String, RepositoryDomainType>(); //tenant-qualified servicename, service binding private Hashtable<String, ServiceBindingType> serviceBindings = new Hashtable<String, ServiceBindingType>(); //tenant-qualified service object name to service name, service binding private Hashtable<String, ServiceBindingType> docTypes = new Hashtable<String, ServiceBindingType>(); public TenantBindingConfigReaderImpl(String serverRootDir) { super(serverRootDir); } @Override public String getFileName() { return TENANT_BINDINGS_DELTA_FILENAME; } protected File getTenantsRootDir() { File result = null; String tenantsRootPath = getConfigRootDir() + File.separator + TENANT_BINDINGS_ROOTDIRNAME; File tenantsRootDir = new File(tenantsRootPath); if (tenantsRootDir.exists() == true) { result = tenantsRootDir; logger.debug("Tenants home directory is: " + tenantsRootDir.getAbsolutePath()); //FIXME: REM - Add proper if (logger.isDebug() == true) check } else { logger.error("Tenants home directory is missing. Can't find: " + tenantsRootDir.getAbsolutePath()); //FIXME: REM - Add proper if (logger.isError() == true) check } return result; } /* * Take the directory of the prototype bindings and the directory of the delta bindings. Merge the two and create (replace) a file * named "tenant-bindings.xml" */ private InputStream merge(File srcFile, File deltaFile) throws IOException { InputStream result = null; try { FileInputStream srcStream = new FileInputStream(srcFile); FileInputStream deltaStream = new FileInputStream(deltaFile); InputStream[] inputStreamArray = { srcStream, deltaStream }; Configurer configurer = new AttributeMergeConfigurer(); result = new ConfigurableXmlMerge(configurer).merge(inputStreamArray); } catch (Exception e) { logger.error("Could not merge tenant configuration delta file: " + deltaFile.getAbsolutePath(), e); } // // Try to save the merge output to a file that is suffixed with ".merged.xml" in the same directory // as the delta file. // if (result != null) { File outputDir = deltaFile.getParentFile(); String mergedFileName = outputDir.getAbsolutePath() + File.separator + this.TENANT_BINDINGS_FILENAME_PREFIX + MERGED_SUFFIX; File mergedOutFile = new File(mergedFileName); try { FileUtils.copyInputStreamToFile(result, mergedOutFile); } catch (IOException e) { logger.warn("Could not create a copy of the merged tenant configuration at: " + mergedFileName, e); } result.reset(); //reset the stream even if the file create failed. } return result; } @Override public void read() throws Exception { String tenantsRootPath = getTenantsRootDir().getAbsolutePath(); read(tenantsRootPath); } @Override public void read(String tenantRootDirPath) throws Exception { File tenantsRootDir = new File(tenantRootDirPath); if (tenantsRootDir.exists() == false) { throw new Exception("Cound not find tenant bindings root directory: " + tenantRootDirPath); } File protoBindingsFile = new File(tenantRootDirPath + File.separator + TENANT_BINDINGS_PROTOTYPE_FILENAME); List<File> tenantDirs = getDirectories(tenantsRootDir); tenantBindingTypeList = readTenantConfigs(protoBindingsFile, tenantDirs); for (TenantBindingType tenantBinding : tenantBindingTypeList) { tenantBindings.put(tenantBinding.getId(), tenantBinding); readDomains(tenantBinding); readServiceBindings(tenantBinding); if (logger.isDebugEnabled()) { logger.debug( "read() added tenant id=" + tenantBinding.getId() + " name=" + tenantBinding.getName()); } } } /* * Take the directory of the prototype bindings and the directory of the delta bindings. Merge the two and create (replace) a file * named "tenant-bindings.xml" * private static String merge(String original, String patch) { InputStream result = null; try { Configurer configurer = new AttributeMergeConfigurer(); FileInputStream ins1 = new FileInputStream(".\\src\\main\\resources\\File1.xml"); FileInputStream ins2 = new FileInputStream(".\\src\\main\\resources\\File2.xml"); InputStream[] inputStreamArray = {ins1, ins2}; result = new ConfigurableXmlMerge(configurer).merge(inputStreamArray); // result = new ConfigurableXmlMerge(configurer).merge(new String[] {original, patch}); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } File mergedOutFile = new File(".\\target\\merged.xml"); try { FileUtils.copyInputStreamToFile(result, mergedOutFile); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } */ /** * Merge and read the prototype bindsings with each tenant specific bindings delta to create the final * tenant bindings. * * @param protoBindingsFile - The prototypical bindings file. * @param tenantDirList - The list of tenant directories containing tenant specific bindings * @return A list of tenant bindings. * @throws IOException Signals that an I/O exception has occurred. */ List<TenantBindingType> readTenantConfigs(File protoBindingsFile, List<File> tenantDirList) throws IOException { List<TenantBindingType> result = new ArrayList<TenantBindingType>(); // // Iterate through a list of directories. // for (File tenantDir : tenantDirList) { boolean found = false; String errMessage = null; File configFile = new File(tenantDir.getAbsoluteFile() + File.separator + getFileName()); if (configFile.exists() == true) { InputStream tenantBindingsStream = this.merge(protoBindingsFile, configFile); TenantBindingConfig tenantBindingConfig = null; try { tenantBindingConfig = (TenantBindingConfig) parse(tenantBindingsStream, TenantBindingConfig.class); } catch (Exception e) { logger.error("Could not parse the merged tenant bindings.", e); } if (tenantBindingConfig != null) { TenantBindingType binding = tenantBindingConfig.getTenantBinding(); if (binding != null) { result.add(binding); found = true; if (logger.isInfoEnabled() == true) { logger.info("Parsed tenant configureation for: " + binding.getDisplayName()); } } else { errMessage = "Cound not parse the tentant bindings in: "; } } else { errMessage = "Could not parse the tenant bindings file: "; } } else { errMessage = "Cound not find a tenant configuration file: "; } if (found == false) { if (logger.isErrorEnabled() == true) { errMessage = errMessage != null ? errMessage : TENANT_BINDINGS_ERROR; logger.error(errMessage + configFile.getAbsolutePath()); } } } // else-for return result; } private void readDomains(TenantBindingType tenantBinding) throws Exception { for (RepositoryDomainType domain : tenantBinding.getRepositoryDomain()) { String key = getTenantQualifiedIdentifier(tenantBinding.getId(), domain.getName()); domains.put(key, domain); } } private void readServiceBindings(TenantBindingType tenantBinding) throws Exception { for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) { String key = getTenantQualifiedServiceName(tenantBinding.getId(), serviceBinding.getName()); serviceBindings.put(key, serviceBinding); if (serviceBinding != null) { ServiceObjectType objectType = serviceBinding.getObject(); if (objectType != null) { String docType = objectType.getName(); String docTypeKey = getTenantQualifiedIdentifier(tenantBinding.getId(), docType); docTypes.put(docTypeKey, serviceBinding); } } if (logger.isDebugEnabled()) { logger.debug("readServiceBindings() added service " + " name=" + key + " workspace=" + serviceBinding.getName()); } } } @Override public List<TenantBindingType> getConfiguration() { return tenantBindingTypeList; } /** * getTenantBindings returns all the tenant bindings read from configuration * @return */ public Hashtable<String, TenantBindingType> getTenantBindings() { return tenantBindings; } /** * getTenantBinding gets tenant binding for given tenant * @param tenantId * @return */ public TenantBindingType getTenantBinding(String tenantId) { return tenantBindings.get(tenantId); } /** * getRepositoryDomain gets repository domain configuration for the given name * @param domainName * @return */ public RepositoryDomainType getRepositoryDomain(String domainName) { return domains.get(domainName.trim()); } /** * getRepositoryDomain gets repository domain configuration for the given service * and given tenant id * @param tenantId * @param serviceName * @return */ public RepositoryDomainType getRepositoryDomain(String tenantId, String serviceName) { ServiceBindingType serviceBinding = getServiceBinding(tenantId, serviceName); if (serviceBinding == null) { throw new IllegalArgumentException( "no service binding found for " + serviceName + " of tenant with id=" + tenantId); } String repoDomain = serviceBinding.getRepositoryDomain(); if (repoDomain == null) { /* This is excessive - every call to a JPA based service dumps this msg. if (logger.isDebugEnabled()) { logger.debug("No repository domain configured for " + serviceName + " of tenant with id=" + tenantId); } */ return null; } String key = this.getTenantQualifiedIdentifier(tenantId, repoDomain.trim()); return domains.get(key); } /** * getServiceBinding gets service binding for given tenant for a given service * @param tenantId * @param serviceName * @return */ public ServiceBindingType getServiceBinding(String tenantId, String serviceName) { String key = getTenantQualifiedServiceName(tenantId, serviceName); return serviceBindings.get(key); } /** * getServiceBinding gets service binding for given tenant for a given service * @param tenantId * @param docType * @return */ public ServiceBindingType getServiceBindingForDocType(String tenantId, String docType) { String key = getTenantQualifiedIdentifier(tenantId, docType); return docTypes.get(key); } /** * getServiceBinding gets service binding for given tenant for a given service * @param tenantId * @param serviceName * @return */ public List<ServiceBindingType> getServiceBindingsByType(String tenantId, String serviceType) { ArrayList<ServiceBindingType> list = null; TenantBindingType tenant = tenantBindings.get(tenantId); if (tenant != null) { for (ServiceBindingType sb : tenant.getServiceBindings()) { if (serviceType.equals(sb.getType())) { if (list == null) { list = new ArrayList<ServiceBindingType>(); } list.add(sb); } } } return list; } /** * @param tenantId * @param serviceName * @return the properly qualified service name */ public static String getTenantQualifiedServiceName(String tenantId, String serviceName) { // return tenantId + "." + serviceName.toLowerCase(); return getTenantQualifiedIdentifier(tenantId, serviceName.toLowerCase()); } public static String getTenantQualifiedIdentifier(String tenantId, String identifier) { return tenantId + "." + identifier; } /** * Sets properties in the passed list on the local properties for this TenantBinding. * Note: will only set properties not already set on the TenantBinding. * * @param propList * @param propagateToServices If true, recurses to set set properties * on the associated services. */ public void setDefaultPropertiesOnTenants(List<PropertyItemType> propList, boolean propagateToServices) { // For each tenant, set properties in list that are not already set if (propList == null || propList.isEmpty()) { return; } for (TenantBindingType tenant : tenantBindings.values()) { for (PropertyItemType prop : propList) { TenantBindingUtils.setPropertyValue(tenant, prop, TenantBindingUtils.SET_PROP_IF_MISSING); } if (propagateToServices) { TenantBindingUtils.propagatePropertiesToServices(tenant, TenantBindingUtils.SET_PROP_IF_MISSING); } } } public String getResourcesDir() { return getConfigRootDir() + File.separator + "resources"; } }