Java tutorial
/** * Copyright (C) 2014 Karlsruhe Institute of Technology * * Licensed 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 edu.kit.dama.mdm.core; import edu.kit.dama.commons.exceptions.InitializationError; import edu.kit.dama.util.DataManagerSettings; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SubnodeConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Interface for the MetaDataManagement. Implementation as abstract factory. * Class is implemented as a singleton. * * @author hartmann-v */ public final class MetaDataManagement { // <editor-fold defaultstate="collapsed" desc="Declaration of attributes"> /** * For logging purposes. */ private static final Logger LOGGER = LoggerFactory.getLogger(MetaDataManagement.class); /** * Implementation of the MetaDataManagement. There should be only one * instance available (singleton). */ private final static MetaDataManagement SINGLETON = new MetaDataManagement(); /** * Constants for the config files: filename. */ //private static final String CONFIG_FILE = "datamanager.xml"; /** * Constants for the config files: root of MDM configuration. */ private static final String CONFIG_ROOT = DataManagerSettings.METADATA_MANAGEMENT_CONFIG_ROOT; /** * Constants for the config files: subpath to persistence implementations. */ private static final String CONFIG_PERSISTENCE_IMPL = "persistenceImplementations.persistenceImplementation"; /** * Constants for the config files: subpath to persistence units. */ private static final String CONFIG_PERSISTENCE_UNIT = "persistenceUnits.persistenceUnit"; /** * Constants for the config files: key for name of persistence * implementation. */ private static final String CONFIG_PERSISTENCE_NAME = "name"; /** * Constants for the config files: key for class of persistence * implementation. */ private static final String CONFIG_PERSISTENCE_CLASS = "class"; /** * Constants for the config files: key for default persistence * implementation. */ private static final String CONFIG_DEFAULT_PERSISTENCE = "default"; /** * Map of the persistenceImplementation names and their persistence units. */ private volatile Map<String, List<String>> persistenceUnitMap = null; /** * Map of the persistenceImplementation names and their default persistence * units. */ private volatile Map<String, String> persistenceUnitDefaultMap = null; /** * Map of the persistenceImplementation names and their implementation * classes. */ private volatile Map<String, IPersistenceFactory> persistenceClassMap = null; /** * Name of the default implementation. */ private volatile String defaultImplementation = null; // </editor-fold> /** * Private Constructor. */ private MetaDataManagement() { LOGGER.info("Initializing MetaDataManagement"); loadConfiguration(); if (getDefaultImplementation() == null) { throw new InitializationError( "Failed to configure metdatata management. Default persistence implementation is not provided. Please check datamanger.xml"); } if (getDefaultPersistenceUnit() == null) { throw new InitializationError( "Failed to configure metdatata management. Default persistence unit is not provided. Please check datamanger.xml"); } } /** * Get single instance of MetaDataManagement (singleton). * * @return instance of MetaDataManagement (singleton). */ public static MetaDataManagement getMetaDataManagement() { return SINGLETON; } /** * Get single instance for manage queries of meta data. throws * IllegalArgumentException if implementation/unit is not defined in * configuration. * * @param persistenceImplementation Label of the implementation which should * be used * @return Instance for managing the associated objects. */ private synchronized IPersistenceFactory getPersistenceFactory(final String persistenceImplementation) { IPersistenceFactory returnValue; // Test for existence of implementation if (!persistenceUnitMap.containsKey(persistenceImplementation)) { throw new IllegalArgumentException( "Persistence implementation '" + persistenceImplementation + "' doesn't exist!"); } // Create instance of IPersistenceFactory returnValue = persistenceClassMap.get(persistenceImplementation); return returnValue; } /** * Get single instance for manage queries of meta data. Throws an * IllegalArgumentException if implementation/unit is not defined in * configuration. * * @param persistenceUnit Label of the persistence unit to use. * @return Instance for managing the associated objects. */ public synchronized IMetaDataManager getMetaDataManager(final String persistenceUnit) { return getMetaDataManager(getDefaultImplementation(), persistenceUnit); } /** * Get a single instance for manage queries of meta data. Throws an * IllegalArgumentException if implementation/unit is not defined in * configuration. * * @return Instance for managing the associated objects. */ public synchronized IMetaDataManager getMetaDataManager() { return getMetaDataManager(getDefaultImplementation(), getDefaultPersistenceUnit()); } /** * Get single instance for manage queries of meta data. Throws an * IllegalArgumentException if implementation/unit is not defined in * configuration. * * @param persistenceImplementation Label of the implementation which should * be used * @param persistenceUnit Label of the persistence unit to use. * @return Instance for managing the associated objects. */ public synchronized IMetaDataManager getMetaDataManager(final String persistenceImplementation, final String persistenceUnit) { IPersistenceFactory persistenceFactory; // Test for existence of persistence unit if (!persistenceUnitMap.get(persistenceImplementation).contains(persistenceUnit)) { throw new IllegalArgumentException("Persistence unit '" + persistenceUnit + "' for implementation '" + persistenceImplementation + "' doesn't exist!"); } persistenceFactory = getPersistenceFactory(persistenceImplementation); return persistenceFactory.getMetaDataManager(persistenceUnit); } /** * Get labels of all configured implementations. * * @return list with all implementation labels. */ public List<String> getAllImplementations() { return new ArrayList<>(persistenceClassMap.keySet()); } /** * Get labels of all configured persistence units for the given * implementation. Return 'null' if implementation doesn't exist. * * @param persistenceImplementation label of the persistence implementation. * @return list with all persistence units. */ public List<String> getAllPersistenceUnits(final String persistenceImplementation) { return persistenceUnitMap.get(persistenceImplementation); } /** * Get label of the persistence unit defined as default for the given * implementation. Return 'null' if implementation doesn't exist. * * @param persistenceImplementation label of the persistence implementation. * @return default persistence unit. */ public String getDefaultPersistenceUnit(final String persistenceImplementation) { return persistenceUnitDefaultMap.get(persistenceImplementation); } /** * Get labels of all configured persistence units for the default * implementation. * * @return list with all persistence units. */ public List<String> getAllPersistenceUnits() { return persistenceUnitMap.get(getDefaultImplementation()); } /** * Get label of the persistence unit defined as default of the default * implementation. Return 'null' if implementation doesn't exist. * * @return default persistence unit. */ public String getDefaultPersistenceUnit() { return persistenceUnitDefaultMap.get(getDefaultImplementation()); } /** * Warning: This method is only for testing purposes. Reseting during run * time will possibly loss data base informations. */ static void reset() { LOGGER.warn("Resetting configuration. This is intended to be done only in TEST MODE!"); SINGLETON.defaultImplementation = null; SINGLETON.loadConfiguration(); } /** * Get default implementation. * * @return default implementation. */ public String getDefaultImplementation() { return defaultImplementation; } /** * Load configuration from XML-File */ private void loadConfiguration() { String firstImplementation = null; String firstPersistenceUnit = null; HierarchicalConfiguration hc = null; List<String> persistenceUnits = null; URL configURL = null; try { configURL = DataManagerSettings.getConfigurationURL(); LOGGER.debug("Loading configuration from {}", configURL); hc = new HierarchicalConfiguration(new XMLConfiguration(configURL)); LOGGER.debug("Configuration successfully loaded"); } catch (ConfigurationException ex) { // error in configuration // reason see debug log message: LOGGER.error("Failed to load configuration.", ex); throw new RuntimeException(ex); } SubnodeConfiguration configurationAt = hc.configurationAt(CONFIG_ROOT); List fields = configurationAt.configurationsAt(CONFIG_PERSISTENCE_IMPL); LOGGER.debug("Found {} configured persistence implementations", fields.size()); persistenceUnitMap = new HashMap<>(); persistenceClassMap = new HashMap<>(); persistenceUnitDefaultMap = new HashMap<>(); String implementationName; IPersistenceFactory iPersistenceFactory = null; for (Iterator it = fields.iterator(); it.hasNext();) { HierarchicalConfiguration sub = (HierarchicalConfiguration) it.next(); LOGGER.debug("Reading sub-configuration"); // First get all persistence units. persistenceUnits = new ArrayList<>(); try { List<HierarchicalConfiguration> persistenceUnitsList = sub .configurationsAt(CONFIG_PERSISTENCE_UNIT); if (persistenceUnitsList == null) { persistenceUnitsList = new LinkedList<>(); } LOGGER.debug("Configuration contains {} persistence units.", persistenceUnitsList.size()); firstPersistenceUnit = null; for (HierarchicalConfiguration item : persistenceUnitsList) { String value = item.getString("."); String defaultAttribute = item.getString("[@default]"); LOGGER.debug("PersistenceUnit found: " + value); LOGGER.debug("@default = {}", defaultAttribute); if (Boolean.parseBoolean(defaultAttribute)) { if (firstPersistenceUnit == null) { LOGGER.debug("{} is used as default persistence unit.", value); firstPersistenceUnit = value; } else { LOGGER.warn( "{} is an additional persistence unit defined as default. We'll ignore this.", value); } } LOGGER.debug("Adding persistence unit to list of units."); persistenceUnits.add(value); } } catch (Exception any) { LOGGER.error("Failed to read persistence units.", any); } LOGGER.debug("firstPersistenceUnit: " + firstPersistenceUnit); if ((persistenceUnits.size() > 0) && (firstPersistenceUnit == null)) { LOGGER.debug("No default persistence unit defined. Using first entry ({})", persistenceUnits.get(0)); firstPersistenceUnit = persistenceUnits.get(0); } LOGGER.debug("Getting implementation name."); implementationName = sub.getString(CONFIG_PERSISTENCE_NAME); LOGGER.debug("Implementation name '{}' found.", implementationName); if (firstImplementation == null) { LOGGER.debug("Using implementation '{}' as first implementation.", implementationName); firstImplementation = implementationName; } LOGGER.debug("Testing implementation '{}'", implementationName); if (sub.containsKey(CONFIG_DEFAULT_PERSISTENCE)) { LOGGER.debug("'{}' is configured as default implementation.", implementationName); if (defaultImplementation != null) { LOGGER.warn("{} is an additional implementation defined as default. We'll ignore this.", implementationName); } else { defaultImplementation = implementationName; } } Class<?> loadClass; boolean success = false; String persistenceClass = sub.getString(CONFIG_PERSISTENCE_CLASS); try { LOGGER.debug("Loading class '{}': ", persistenceClass); loadClass = getClass().getClassLoader().loadClass(persistenceClass); LOGGER.debug("Checking IPersistenceFactory.class.assignableFrom({})", persistenceClass); success = IPersistenceFactory.class.isAssignableFrom(loadClass); iPersistenceFactory = null; if (success) { LOGGER.debug("Creating instance of class {}", persistenceClass); iPersistenceFactory = (IPersistenceFactory) loadClass.newInstance(); LOGGER.debug("Persistence factory successfully instantiated."); } else { LOGGER.error("IPersistenceFactory seems not to be assignable from class {}", persistenceClass); } } catch (InstantiationException | IllegalAccessException | ClassNotFoundException ex) { LOGGER.error("Failed to create instance of persistence implementation " + persistenceClass, ex); success = false; } if (success) { persistenceUnitMap.put(implementationName, persistenceUnits); persistenceClassMap.put(implementationName, iPersistenceFactory); persistenceUnitDefaultMap.put(implementationName, firstPersistenceUnit); } else { throw new edu.kit.dama.mdm.core.exception.ConfigurationException( "Failed to initialize persistence factory from URL '" + configURL + "'. See logfile for details."); } } if (defaultImplementation == null) { LOGGER.debug("Default implementation not set, yet. Using first one ({}) as default.", firstImplementation); defaultImplementation = firstImplementation; } } /** * Destroy all persistence factories. This method is intended to be used in * situations, e.g. redeploying a web application, where the runtime is * terminated without terminating the actual virtual machine. In order to * avoid stale connections, it is recommended to destroy the * MetaDataManagement as soon as the web application context is destroyed. * * This method should not be called automatically, e.g. in a finalize block, * as this would influence situations where the MetaDataManagement is used * by multiple threads, e.g. during testing. */ public final void destroy() { Set<Entry<String, IPersistenceFactory>> entries = persistenceClassMap.entrySet(); for (Entry<String, IPersistenceFactory> e : entries) { e.getValue().destroy(); } persistenceClassMap.clear(); } }