Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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.apache.geode.distributed.internal; import static org.apache.geode.distributed.ConfigurationProperties.*; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.xpath.XPathExpressionException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.logging.log4j.Logger; import org.w3c.dom.Document; import org.xml.sax.SAXException; import org.apache.geode.CancelException; import org.apache.geode.cache.AttributesFactory; import org.apache.geode.cache.Cache; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.DiskStore; import org.apache.geode.cache.Region; import org.apache.geode.cache.Scope; import org.apache.geode.cache.execute.ResultCollector; import org.apache.geode.distributed.DistributedLockService; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.distributed.internal.locks.DLockService; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.InternalRegionArguments; import org.apache.geode.internal.cache.persistence.PersistentMemberID; import org.apache.geode.internal.cache.persistence.PersistentMemberManager; import org.apache.geode.internal.cache.persistence.PersistentMemberPattern; import org.apache.geode.internal.cache.xmlcache.CacheXml; import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator; import org.apache.geode.internal.lang.StringUtils; import org.apache.geode.internal.logging.LogService; import org.apache.geode.management.internal.cli.CliUtil; import org.apache.geode.management.internal.cli.functions.ImportSharedConfigurationArtifactsFunction; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.configuration.callbacks.ConfigurationChangeListener; import org.apache.geode.management.internal.configuration.domain.Configuration; import org.apache.geode.management.internal.configuration.domain.SharedConfigurationStatus; import org.apache.geode.management.internal.configuration.domain.XmlEntity; import org.apache.geode.management.internal.configuration.functions.GetAllJarsFunction; import org.apache.geode.management.internal.configuration.messages.ConfigurationRequest; import org.apache.geode.management.internal.configuration.messages.ConfigurationResponse; import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusResponse; import org.apache.geode.management.internal.configuration.utils.XmlUtils; import org.apache.geode.management.internal.configuration.utils.ZipUtils; @SuppressWarnings({ "deprecation", "unchecked" }) public class SharedConfiguration { private static final Logger logger = LogService.getLogger(); /** * Name of the directory where the shared configuration artifacts are stored */ public static final String CLUSTER_CONFIG_ARTIFACTS_DIR_NAME = "cluster_config"; private static final String CLUSTER_CONFIG_DISK_STORE_NAME = "cluster_config"; public static final String CLUSTER_CONFIG_DISK_DIR_PREFIX = "ConfigDiskDir_"; public static final String CLUSTER_CONFIG = "cluster"; /** * Name of the lock service used for shared configuration */ private static final String SHARED_CONFIG_LOCK_SERVICE_NAME = "__CLUSTER_CONFIG_LS"; /** * Name of the lock for locking the shared configuration */ public static final String SHARED_CONFIG_LOCK_NAME = "__CLUSTER_CONFIG_LOCK"; /** * Name of the region which is used to store the configuration information */ private static final String CONFIG_REGION_NAME = "_ConfigurationRegion"; private final String configDirPath; private final String configDiskDirName; private final String configDiskDirPath;; private final Set<PersistentMemberPattern> newerSharedConfigurationLocatorInfo = new HashSet<PersistentMemberPattern>(); private final AtomicReference<SharedConfigurationStatus> status = new AtomicReference<SharedConfigurationStatus>(); private static final GetAllJarsFunction getAllJarsFunction = new GetAllJarsFunction(); private static final JarFileFilter jarFileFilter = new JarFileFilter(); private GemFireCacheImpl cache; private final DistributedLockService sharedConfigLockingService; /** * Gets or creates (if not created) shared configuration lock service */ public static DistributedLockService getSharedConfigLockService(DistributedSystem ds) { DistributedLockService sharedConfigDls = DLockService.getServiceNamed(SHARED_CONFIG_LOCK_SERVICE_NAME); try { if (sharedConfigDls == null) { sharedConfigDls = DLockService.create(SHARED_CONFIG_LOCK_SERVICE_NAME, (InternalDistributedSystem) ds, true, true); } } catch (IllegalArgumentException e) { return DLockService.getServiceNamed(SHARED_CONFIG_LOCK_SERVICE_NAME); } return sharedConfigDls; } public SharedConfiguration(Cache cache) throws IOException { this.cache = (GemFireCacheImpl) cache; this.configDiskDirName = CLUSTER_CONFIG_DISK_DIR_PREFIX + cache.getDistributedSystem().getName(); String clusterConfigDir = cache.getDistributedSystem().getProperties() .getProperty(CLUSTER_CONFIGURATION_DIR); if (StringUtils.isBlank(clusterConfigDir)) { clusterConfigDir = System.getProperty("user.dir"); } else { File diskDir = new File(clusterConfigDir); if (!diskDir.exists() && !diskDir.mkdirs()) { throw new IOException("Cannot create directory : " + clusterConfigDir); } clusterConfigDir = diskDir.getCanonicalPath(); } this.configDiskDirPath = FilenameUtils.concat(clusterConfigDir, this.configDiskDirName); configDirPath = FilenameUtils.concat(clusterConfigDir, CLUSTER_CONFIG_ARTIFACTS_DIR_NAME); sharedConfigLockingService = getSharedConfigLockService(cache.getDistributedSystem()); status.set(SharedConfigurationStatus.NOT_STARTED); } /** * Add jar information into the shared configuration and save the jars in the file system * @return true on success */ public boolean addJars(String[] jarNames, byte[][] jarBytes, String[] groups) { boolean success = true; try { if (groups == null) { groups = new String[] { SharedConfiguration.CLUSTER_CONFIG }; } Region<String, Configuration> configRegion = getConfigurationRegion(); for (String group : groups) { Configuration configuration = configRegion.get(group); if (configuration == null) { configuration = new Configuration(group); writeConfig(configuration); } configuration.addJarNames(jarNames); configRegion.put(group, configuration); String groupDir = FilenameUtils.concat(configDirPath, group); writeJarFiles(groupDir, jarNames, jarBytes); } } catch (Exception e) { success = false; logger.info(e.getMessage(), e); } return success; } /** * Adds/replaces the xml entity in the shared configuration */ public void addXmlEntity(XmlEntity xmlEntity, String[] groups) throws Exception { Region<String, Configuration> configRegion = getConfigurationRegion(); if (groups == null || groups.length == 0) { groups = new String[] { SharedConfiguration.CLUSTER_CONFIG }; } for (String group : groups) { Configuration configuration = (Configuration) configRegion.get(group); if (configuration == null) { configuration = new Configuration(group); } String xmlContent = configuration.getCacheXmlContent(); if (xmlContent == null || xmlContent.isEmpty()) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); CacheXmlGenerator.generateDefault(pw); xmlContent = sw.toString(); } final Document doc = createAndUpgradeDocumentFromXml(xmlContent); XmlUtils.addNewNode(doc, xmlEntity); configuration.setCacheXmlContent(XmlUtils.prettyXml(doc)); configRegion.put(group, configuration); writeConfig(configuration); } } public void clearSharedConfiguration() throws Exception { Region<String, Configuration> configRegion = getConfigurationRegion(); if (configRegion != null) { configRegion.clear(); } } /** * Creates the shared configuration service * @param loadSharedConfigFromDir when set to true, loads the configuration from the share_config directory */ public void initSharedConfiguration(boolean loadSharedConfigFromDir) throws Exception { status.set(SharedConfigurationStatus.STARTED); Region<String, Configuration> configRegion = this.getConfigurationRegion(); if (loadSharedConfigFromDir) { lockSharedConfiguration(); try { logger.info("Reading cluster configuration from '{}' directory", SharedConfiguration.CLUSTER_CONFIG_ARTIFACTS_DIR_NAME); Map<String, Configuration> sharedConfigMap = this.readSharedConfigurationFromDisk(); final DM dm = cache.getDistributedSystem().getDistributionManager(); if (dm.getNormalDistributionManagerIds().isEmpty()) { Set<DistributedMember> locatorsWithSC = new HashSet<DistributedMember>( dm.getAllHostedLocatorsWithSharedConfiguration().keySet()); //Send the config to other locators which host the shared configuration. if (!locatorsWithSC.isEmpty()) { final ImportSharedConfigurationArtifactsFunction fn = new ImportSharedConfigurationArtifactsFunction(); final Date date = new Date(); String zipFileName = CliStrings.format(CliStrings.EXPORT_SHARED_CONFIG__FILE__NAME, new Timestamp(date.getTime()).toString()); try { ZipUtils.zip(getSharedConfigurationDirPath(), zipFileName); File zipFile = new File(zipFileName); byte[] zipBytes = FileUtils.readFileToByteArray(zipFile); Object[] args = new Object[] { zipFileName, zipBytes }; // Make sure we wait for the result. The fn also does a clear on the config // region so there is a race with the clear below. CliUtil.executeFunction(fn, args, locatorsWithSC).getResult(); } catch (Exception e) { logger.error(e.getMessage(), e); } } } //Clear the configuration region and load the configuration read from the 'shared_config' directory configRegion.clear(); configRegion.putAll(sharedConfigMap); } finally { unlockSharedConfiguration(); } } else { //Write out the existing configuration into the 'shared_config' directory //And get deployed jars from other locators. lockSharedConfiguration(); putSecurityPropsIntoClusterConfig(configRegion); try { Set<Entry<String, Configuration>> configEntries = configRegion.entrySet(); for (Entry<String, Configuration> configEntry : configEntries) { Configuration configuration = configEntry.getValue(); try { this.writeConfig(configuration); } catch (Exception e) { logger.info(e.getMessage(), e); } } logger.info("Completed writing the shared configuration to 'cluster_config' directory"); this.getAllJarsFromOtherLocators(); } finally { unlockSharedConfiguration(); } } status.set(SharedConfigurationStatus.RUNNING); } private void putSecurityPropsIntoClusterConfig(final Region<String, Configuration> configRegion) { Properties securityProps = cache.getDistributedSystem().getSecurityProperties(); Configuration clusterPropertiesConfig = configRegion.get(SharedConfiguration.CLUSTER_CONFIG); if (clusterPropertiesConfig == null) { clusterPropertiesConfig = new Configuration(SharedConfiguration.CLUSTER_CONFIG); configRegion.put(SharedConfiguration.CLUSTER_CONFIG, clusterPropertiesConfig); } // put security-manager and security-post-processor in the cluster config Properties clusterProperties = clusterPropertiesConfig.getGemfireProperties(); if (securityProps.containsKey(SECURITY_MANAGER)) { clusterProperties.setProperty(SECURITY_MANAGER, securityProps.getProperty(SECURITY_MANAGER)); } if (securityProps.containsKey(SECURITY_POST_PROCESSOR)) { clusterProperties.setProperty(SECURITY_POST_PROCESSOR, securityProps.getProperty(SECURITY_POST_PROCESSOR)); } } /** * Creates a ConfigurationResponse based on the configRequest, configuration response contains the requested shared configuration * This method locks the SharedConfiguration */ public ConfigurationResponse createConfigurationReponse(final ConfigurationRequest configRequest) throws Exception { ConfigurationResponse configResponse = new ConfigurationResponse(); for (int i = 0; i < configRequest.getNumAttempts(); i++) { boolean isLocked = sharedConfigLockingService.lock(SHARED_CONFIG_LOCK_NAME, 5000, 5000); try { if (isLocked) { Set<String> groups = configRequest.getGroups(); groups.add(SharedConfiguration.CLUSTER_CONFIG); logger.info("Building up configuration response with following configurations: {}", groups); for (String group : groups) { Configuration configuration = getConfiguration(group); configResponse.addConfiguration(configuration); } Object[] jars = getAllJars(groups); if (jars != null) { String[] jarNames = (String[]) jars[0]; byte[][] jarBytes = (byte[][]) jars[1]; configResponse.addJarsToBeDeployed(jarNames, jarBytes); } configResponse.setFailedToGetSharedConfig(false); return configResponse; } } finally { sharedConfigLockingService.unlock(SHARED_CONFIG_LOCK_NAME); } } configResponse.setFailedToGetSharedConfig(true); return configResponse; } /** * Create a response containing the status of the Shared configuration and information about other locators containing newer * shared configuration data (if at all) * @return {@link SharedConfigurationStatusResponse} containing the {@link SharedConfigurationStatus} */ public SharedConfigurationStatusResponse createStatusResponse() { SharedConfigurationStatusResponse response = new SharedConfigurationStatusResponse(); response.setStatus(getStatus()); response.addWaitingLocatorInfo(newerSharedConfigurationLocatorInfo); return response; } /** * Deletes the xml entity from the shared configuration. */ public void deleteXmlEntity(final XmlEntity xmlEntity, String[] groups) throws Exception { Region<String, Configuration> configRegion = getConfigurationRegion(); //No group is specified, so delete in every single group if it exists. if (groups == null) { Set<String> groupSet = configRegion.keySet(); groups = groupSet.toArray(new String[groupSet.size()]); } for (String group : groups) { Configuration configuration = (Configuration) configRegion.get(group); if (configuration != null) { String xmlContent = configuration.getCacheXmlContent(); if (xmlContent != null && !xmlContent.isEmpty()) { Document doc = createAndUpgradeDocumentFromXml(xmlContent); XmlUtils.deleteNode(doc, xmlEntity); configuration.setCacheXmlContent(XmlUtils.prettyXml(doc)); configRegion.put(group, configuration); writeConfig(configuration); } } } } public void modifyCacheAttributes(final XmlEntity xmlEntity, String[] groups) throws Exception { Region<String, Configuration> configRegion = getConfigurationRegion(); //No group is specified, so modify the cache attributes for a in every single group if it exists. if (groups == null) { Set<String> groupSet = configRegion.keySet(); groups = groupSet.toArray(new String[groupSet.size()]); } for (String group : groups) { Configuration configuration = (Configuration) configRegion.get(group); if (configuration == null) { configuration = new Configuration(group); } String xmlContent = configuration.getCacheXmlContent(); if (xmlContent == null || xmlContent.isEmpty()) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); CacheXmlGenerator.generateDefault(pw); xmlContent = sw.toString(); } Document doc = createAndUpgradeDocumentFromXml(xmlContent); //Modify the cache attributes XmlUtils.modifyRootAttributes(doc, xmlEntity); //Change the xml content of the configuration and put it the config region configuration.setCacheXmlContent(XmlUtils.prettyXml(doc)); configRegion.put(group, configuration); writeConfig(configuration); } } /** * For tests only. TODO: clean this up and remove from production code * <p/> * Throws {@code AssertionError} wrapping any exception thrown by operation. */ public void destroySharedConfiguration() { try { Region<String, Configuration> configRegion = getConfigurationRegion(); if (configRegion != null) { configRegion.destroyRegion(); } DiskStore configDiskStore = this.cache.findDiskStore(CLUSTER_CONFIG_ARTIFACTS_DIR_NAME); if (configDiskStore != null) { configDiskStore.destroy(); File file = new File(configDiskDirPath); FileUtils.deleteDirectory(file); } FileUtils.deleteDirectory(new File(configDirPath)); } catch (Exception exception) { throw new AssertionError(exception); } } public Object[] getAllJars(Set<String> groups) throws Exception { Set<String> jarsAdded = new HashSet<String>(); Object[] jars = new Object[2]; for (String group : groups) { Configuration configuration = getConfiguration(group); if (configuration != null) { jarsAdded.addAll(configuration.getJarNames()); } } int numJars = jarsAdded.size(); jarsAdded.clear(); if (numJars > 0) { String[] jarNames = new String[numJars]; byte[][] jarBytes = new byte[numJars][]; int ctr = 0; for (String group : groups) { Configuration configuration = getConfiguration(group); if (configuration != null) { Set<String> jarNameSet = configuration.getJarNames(); for (String jarName : jarNameSet) { String groupDirPath = FilenameUtils.concat(configDirPath, group); if (!jarsAdded.contains(jarName)) { String jarFilePath = FilenameUtils.concat(groupDirPath, jarName); jarNames[ctr] = jarName; jarBytes[ctr] = FileUtils.readFileToByteArray(new File(jarFilePath)); ctr++; } } } } jars[0] = jarNames; jars[1] = jarBytes; } return jars; } public Configuration getConfiguration(String groupName) throws Exception { Configuration configuration = getConfigurationRegion().get(groupName); return configuration; } public Map<String, Configuration> getEntireConfiguration() throws Exception { Set<String> keys = getConfigurationRegion().keySet(); return getConfigurationRegion().getAll(keys); } /** * Returns the path of Shared configuration directory * @return {@link String} path of the shared configuration directory */ public String getSharedConfigurationDirPath() { return configDirPath; } /** * Gets the current status of the SharedConfiguration * If the status is started , it determines if the shared configuration is waiting for new configuration on * other locators * @return {@link SharedConfigurationStatus} */ public SharedConfigurationStatus getStatus() { SharedConfigurationStatus scStatus = this.status.get(); if (scStatus == SharedConfigurationStatus.STARTED) { PersistentMemberManager pmm = cache.getPersistentMemberManager(); Map<String, Set<PersistentMemberID>> waitingRegions = pmm.getWaitingRegions(); if (!waitingRegions.isEmpty()) { this.status.compareAndSet(SharedConfigurationStatus.STARTED, SharedConfigurationStatus.WAITING); Set<PersistentMemberID> persMemIds = waitingRegions.get(Region.SEPARATOR_CHAR + CONFIG_REGION_NAME); for (PersistentMemberID persMemId : persMemIds) { newerSharedConfigurationLocatorInfo.add(new PersistentMemberPattern(persMemId)); } } } return this.status.get(); } /** * Loads the * @throws Exception */ public void loadSharedConfigurationFromDisk() throws Exception { Map<String, Configuration> sharedConfigurationMap = readSharedConfigurationFromDisk(); getConfigurationRegion().clear(); getConfigurationRegion().putAll(sharedConfigurationMap); } public void modifyProperties(final Properties properties, String[] groups) throws Exception { if (groups == null) { groups = new String[] { SharedConfiguration.CLUSTER_CONFIG }; } Region<String, Configuration> configRegion = getConfigurationRegion(); for (String group : groups) { Configuration configuration = configRegion.get(group); if (configuration == null) { configuration = new Configuration(group); } configuration.getGemfireProperties().putAll(properties); configRegion.put(group, configuration); writeConfig(configuration); } } /** * Removes the jar files from the shared configuration. * @param jarNames Names of the jar files. * @param groups Names of the groups which had the jar file deployed. * @return true on success. */ public boolean removeJars(final String[] jarNames, String[] groups) { boolean success = true; try { Region<String, Configuration> configRegion = getConfigurationRegion(); if (groups == null) { Set<String> groupSet = configRegion.keySet(); groups = groupSet.toArray(new String[groupSet.size()]); } for (String group : groups) { Configuration configuration = (Configuration) configRegion.get(group); if (configuration != null) { String dirPath = FilenameUtils.concat(getSharedConfigurationDirPath(), configuration.getConfigName()); removeJarFiles(dirPath, jarNames); } } for (String group : groups) { Configuration configuration = (Configuration) configRegion.get(group); if (configuration != null) { if (!configuration.getJarNames().isEmpty()) { configuration.removeJarNames(jarNames); configRegion.put(group, configuration); } } } } catch (Exception e) { logger.info("Exception occurred while deleting the jar files", e); success = false; } return success; } public void renameExistingSharedConfigDirectory() { File configDirFile = new File(configDirPath); if (configDirFile.exists()) { String configDirFileName2 = CLUSTER_CONFIG_ARTIFACTS_DIR_NAME + new SimpleDateFormat("yyyyMMddhhmm").format(new Date()) + "." + System.nanoTime(); File configDirFile2 = new File(FilenameUtils.concat(configDirFileName2, configDirFileName2)); try { FileUtils.moveDirectoryToDirectory(configDirFile, configDirFile2, true); } catch (IOException e) { logger.info(e); } } } /** * Writes the contents of the {@link Configuration} to the file system */ public void writeConfig(final Configuration configuration) throws Exception { File configDir = new File(getSharedConfigurationDirPath()); if (!configDir.exists()) { if (!configDir.mkdirs()) { throw new IOException("Cannot create directory : " + getSharedConfigurationDirPath()); } } String dirPath = FilenameUtils.concat(getSharedConfigurationDirPath(), configuration.getConfigName()); File file = new File(dirPath); if (!file.exists()) { if (!file.mkdir()) { throw new IOException("Cannot create directory : " + dirPath); } } writeProperties(dirPath, configuration); writeCacheXml(dirPath, configuration); } private boolean lockSharedConfiguration() { return sharedConfigLockingService.lock(SHARED_CONFIG_LOCK_NAME, -1, -1); } private void unlockSharedConfiguration() { sharedConfigLockingService.unlock(SHARED_CONFIG_LOCK_NAME); } /** * Gets the Jar from existing locators in the system */ private void getAllJarsFromOtherLocators() throws Exception { logger.info("Getting Jar files from other locators"); DM dm = cache.getDistributionManager(); DistributedMember me = cache.getMyId(); Set<DistributedMember> locators = new HashSet<DistributedMember>( dm.getAllHostedLocatorsWithSharedConfiguration().keySet()); locators.remove(me); String[] jarNames = null; byte[][] jarBytes = null; if (locators.isEmpty()) { logger.info("No other locators present"); return; } ResultCollector<?, List<Object>> rc = (ResultCollector<?, List<Object>>) CliUtil .executeFunction(getAllJarsFunction, null, locators); List<Object> results = rc.getResult(); for (Object result : results) { if (result != null) { if (!(result instanceof Exception)) { Object[] jars = (Object[]) result; jarNames = (String[]) jars[0]; jarBytes = (byte[][]) jars[1]; break; } } } if (jarNames != null && jarBytes != null) { Map<String, Integer> jarIndex = new HashMap<String, Integer>(); for (int i = 0; i < jarNames.length; i++) { String jarName = jarNames[i]; jarIndex.put(jarName, i); } Map<String, Configuration> entireConfiguration = getEntireConfiguration(); Set<String> groups = entireConfiguration.keySet(); for (String group : groups) { Configuration config = entireConfiguration.get(group); Set<String> groupJarNames = config.getJarNames(); String groupDirPath = FilenameUtils.concat(configDirPath, group); for (String groupJarName : groupJarNames) { Integer index = jarIndex.get(groupJarName); if (index != null) { String jarFilePath = FilenameUtils.concat(groupDirPath, groupJarName); byte[] jarData = jarBytes[index.intValue()]; try { FileUtils.writeByteArrayToFile(new File(jarFilePath), jarData); } catch (IOException e) { logger.info(e.getMessage(), e); } } else { //This should NEVER happen logger.error("JarFile {} not delivered.", groupJarName); } } } } else { logger.info("No deployed jars found on other locators."); } } /** * Gets the region containing the shared configuration data. * The region is created , if it does not exist already. * Note : this could block if this locator contains stale persistent configuration data. * @return {@link Region} ConfigurationRegion */ private Region<String, Configuration> getConfigurationRegion() throws Exception { Region<String, Configuration> configRegion = cache.getRegion(CONFIG_REGION_NAME); try { if (configRegion == null) { File diskDir = new File(configDiskDirPath); if (!diskDir.exists()) { if (!diskDir.mkdirs()) { throw new IOException("Cannot create directory at " + configDiskDirPath); } } File[] diskDirs = { diskDir }; cache.createDiskStoreFactory().setDiskDirs(diskDirs).setAutoCompact(true).setMaxOplogSize(10) .create(CLUSTER_CONFIG_DISK_STORE_NAME); AttributesFactory<String, Configuration> regionAttrsFactory = new AttributesFactory<String, Configuration>(); regionAttrsFactory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); regionAttrsFactory.setCacheListener(new ConfigurationChangeListener(this)); regionAttrsFactory.setDiskStoreName(CLUSTER_CONFIG_DISK_STORE_NAME); regionAttrsFactory.setScope(Scope.DISTRIBUTED_ACK); InternalRegionArguments internalArgs = new InternalRegionArguments(); internalArgs.setIsUsedForMetaRegion(true); internalArgs.setMetaRegionWithTransactions(false); configRegion = cache.createVMRegion(CONFIG_REGION_NAME, regionAttrsFactory.create(), internalArgs); } } catch (CancelException e) { if (configRegion == null) { this.status.set(SharedConfigurationStatus.STOPPED); } throw e; // CONFIG: don't rethrow as Exception, keep it a subclass of CancelException } catch (Exception e) { if (configRegion == null) { this.status.set(SharedConfigurationStatus.STOPPED); } throw new Exception("Error occurred while initializing cluster configuration", e); } return configRegion; } /** * Reads the configuration information from the shared configuration directory and returns a {@link Configuration} object * @param configName * @param configDirectory * @return {@link Configuration} * @throws TransformerException * @throws TransformerFactoryConfigurationError * @throws ParserConfigurationException * @throws SAXException */ private Configuration readConfiguration(final String configName, final String configDirectory) throws SAXException, ParserConfigurationException, TransformerFactoryConfigurationError, TransformerException { Configuration configuration = new Configuration(configName); String cacheXmlFullPath = FilenameUtils.concat(configDirectory, configuration.getCacheXmlFileName()); String propertiesFullPath = FilenameUtils.concat(configDirectory, configuration.getPropertiesFileName()); File file = new File(configDirectory); String[] jarFileNames = file.list(jarFileFilter); if (jarFileNames != null && jarFileNames.length != 0) { configuration.addJarNames(jarFileNames); } try { configuration.setCacheXmlContent(XmlUtils.readXmlAsStringFromFile(cacheXmlFullPath)); configuration.setGemfireProperties(readProperties(propertiesFullPath)); } catch (IOException e) { logger.info(e); } return configuration; } /** * Reads the properties from the properties file. * @param propertiesFilePath * @return {@link Properties} * @throws IOException */ private Properties readProperties(final String propertiesFilePath) throws IOException { Properties properties = new Properties(); File propsFile = new File(propertiesFilePath); FileInputStream fis = null; if (propsFile.exists()) { try { fis = new FileInputStream(propsFile); properties.load(fis); } finally { if (fis != null) { fis.close(); } } } return properties; } /** * Reads the "shared_config" directory and loads all the cache.xml, gemfire.properties and deployed jars information * @return {@link Map} * @throws TransformerException * @throws TransformerFactoryConfigurationError * @throws ParserConfigurationException * @throws SAXException */ private Map<String, Configuration> readSharedConfigurationFromDisk() throws SAXException, ParserConfigurationException, TransformerFactoryConfigurationError, TransformerException { String[] subdirectoryNames = getSubdirectories(configDirPath); Map<String, Configuration> sharedConfiguration = new HashMap<String, Configuration>(); if (subdirectoryNames != null) { for (String subdirectoryName : subdirectoryNames) { String fullpath = FilenameUtils.concat(configDirPath, subdirectoryName); Configuration configuration = readConfiguration(subdirectoryName, fullpath); sharedConfiguration.put(subdirectoryName, configuration); } } return sharedConfiguration; } /** * Removes the jar files from the given directory * @param dirPath Path of the configuration directory * @param jarNames Names of the jar files * @throws IOException */ private void removeJarFiles(final String dirPath, final String[] jarNames) throws IOException { if (jarNames != null) { for (int i = 0; i < jarNames.length; i++) { File jarFile = new File(FilenameUtils.concat(dirPath, jarNames[i])); if (jarFile.exists()) { FileUtils.forceDelete(jarFile); } } } else { File dir = new File(dirPath); String[] jarFileNames = dir.list(jarFileFilter); if (jarFileNames.length != 0) { File jarFileToBeDeleted; for (String jarFileName : jarFileNames) { String fullPath = FilenameUtils.concat(dirPath, jarFileName); jarFileToBeDeleted = new File(fullPath); FileUtils.forceDelete(jarFileToBeDeleted); } } } } /** * Writes the cache.xml to the file , based on Configuration */ private void writeCacheXml(final String dirPath, final Configuration configuration) throws IOException { String fullPath = FilenameUtils.concat(dirPath, configuration.getCacheXmlFileName()); FileUtils.writeStringToFile(new File(fullPath), configuration.getCacheXmlContent(), "UTF-8"); } /** * Writes the * @param dirPath target directory , where the jar files are to be written * @param jarNames Array containing the name of the jar files. * @param jarBytes Array of byte arrays for the jar files. */ private void writeJarFiles(final String dirPath, final String[] jarNames, final byte[][] jarBytes) { for (int i = 0; i < jarNames.length; i++) { String filePath = FilenameUtils.concat(dirPath, jarNames[i]); File jarFile = new File(filePath); try { FileUtils.writeByteArrayToFile(jarFile, jarBytes[i]); } catch (IOException e) { logger.info(e); } } } /** * Writes the properties to the file based on the {@link Configuration} */ private void writeProperties(final String dirPath, final Configuration configuration) throws IOException { String fullPath = FilenameUtils.concat(dirPath, configuration.getPropertiesFileName()); BufferedWriter bw = new BufferedWriter(new FileWriter(fullPath)); configuration.getGemfireProperties().store(bw, ""); bw.close(); } /** * Create a {@link Document} using * {@link XmlUtils#createDocumentFromXml(String)} and if the version attribute * is not equal to the current version then update the XML to the current * schema and return the document. * * @param xmlContent XML content to load and upgrade. * @return {@link Document} from xmlContent. * @since GemFire 8.1 */ // UnitTest SharedConfigurationJUnitTest.testCreateAndUpgradeDocumentFromXml static Document createAndUpgradeDocumentFromXml(final String xmlContent) throws SAXException, ParserConfigurationException, IOException, XPathExpressionException { Document doc = XmlUtils.createDocumentFromXml(xmlContent); if (!CacheXml.VERSION_LATEST.equals( XmlUtils.getAttribute(doc.getDocumentElement(), CacheXml.VERSION, CacheXml.GEODE_NAMESPACE))) { doc = XmlUtils.upgradeSchema(doc, CacheXml.GEODE_NAMESPACE, CacheXml.LATEST_SCHEMA_LOCATION, CacheXml.VERSION_LATEST); } return doc; } /** * Returns an array containing the names of the subdirectories in a given directory * @param path Path of the directory whose subdirectories are listed * @return String[] names of first level subdirectories, null if no subdirectories are found or if the path is incorrect */ private static String[] getSubdirectories(String path) { File directory = new File(path); return directory.list(DirectoryFileFilter.INSTANCE); } private static class JarFileFilter implements FilenameFilter { @Override public boolean accept(File dir, String name) { return name.endsWith(".jar"); } } }