package org.wyona.yarep.core; import java.io.File; import java.net.URL; import java.net.URI; import java.net.URLDecoder; import java.util.Properties; import java.util.Vector; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.wyona.commons.io.FileUtil; /** * Repository factory, which returns the various repository implementations */ public class RepositoryFactory { private static Logger log = LogManager.getLogger(RepositoryFactory.class); public static final String DEFAULT_CONFIGURATION_FILE = "yarep.properties"; public static String CONFIGURATION_FILE = DEFAULT_CONFIGURATION_FILE; private static String DEFAULT_REPOSITORY_IMPL = "org.wyona.yarep.impl.DefaultRepository"; private Vector repositories; private URL propertiesURL; /** * */ public RepositoryFactory() throws RepositoryException { this(DEFAULT_CONFIGURATION_FILE); } /** * TODO: Make CONFIGURATION_FILE loadable from absolute path */ public RepositoryFactory(String configurationFile) throws RepositoryException { CONFIGURATION_FILE = configurationFile; propertiesURL = RepositoryFactory.class.getClassLoader().getResource(CONFIGURATION_FILE); if (propertiesURL == null) { log.warn("No such resource: " + CONFIGURATION_FILE); repositories = new Vector(0); return; } Properties props = new Properties(); log.debug("Properties URL: " + propertiesURL); // use URLDecoder to avoid problems when the filename contains spaces File propsFile = new File(URLDecoder.decode(propertiesURL.getFile())); try { props.load(propertiesURL.openStream()); repositories = new Vector(); if (props.getProperty("configurations").equals("")) { log.warn("There seems to be no repositories configured within " + CONFIGURATION_FILE); return; } String separator = ","; String[] tokens = props.getProperty("configurations").split(separator); if (tokens.length % 2 != 0) { // NOTE: An exception is being trown and hence the repo factory instance will be null anyway //repositories = new Vector(0); throw new Exception("Wrong number of config parameters: " + CONFIGURATION_FILE); } for (int i = 0;i < tokens.length / 2; i++) { String repoID = tokens[2 * i]; String configFilename = tokens[2 * i + 1]; log.debug("Property File: " + propsFile.getAbsolutePath()); log.debug("PARENT: " + propsFile.getParentFile()); log.debug("Filename: " + configFilename); File configFile; if (new File(configFilename).isAbsolute()) { configFile = new File(configFilename); } else { configFile = FileUtil.file(propsFile.getParentFile().getAbsolutePath(), new File(configFilename).toString()); } if (log.isDebugEnabled()) log.debug("Configuration File: " + configFile.getAbsolutePath()); Repository rt = newRepository(repoID, configFile); } // see src/java/org/wyona/meguni/parser/Parser.java } catch (Exception e) { log.error(e.toString(), e); throw new RepositoryException("Could not create RepositoryFactory with file " + configurationFile + ": " + e.getMessage(), e); } } /** * Resets the repository factory and removes all registered repositories. */ public void reset() { this.repositories = new Vector(); } /** * Get properties URL */ public URL getPropertiesURL() { return propertiesURL; } /** * Get repository IDs */ public String[] getRepositoryIDs() { String[] ids = new String[repositories.size()]; for (int i = 0;i < repositories.size(); i++) { ids[i] = ((Repository) repositories.elementAt(i)).getID(); } return ids; } /** * List all registered repositories */ public String toString() { String s = "\n\nShow all (" + repositories.size() + ") repositories listed within " + CONFIGURATION_FILE + " respectively set during runtime:"; for (int i = 0;i < repositories.size(); i++) { Repository repo = (Repository) repositories.elementAt(i); s = s + "\nRepository (id=" + repo.getID() + "): " + (Repository) repositories.elementAt(i); } return s; } /** * Get repository for a specific ID (historically this method created a new repository based on a properties file, hence the name newRepository, but today it should rather be renamed to getRepository(String)) * * @param rid Repository ID */ public Repository newRepository(String rid) throws RepositoryException { for (int i = 0;i < repositories.size(); i++) { if (((Repository) repositories.elementAt(i)).getID().equals(rid)) return (Repository) repositories.elementAt(i); } log.warn("No such repository: " + rid + " (" + getPropertiesURL() + ")"); if (repositories.size() == 0) { log.error("No repositories (" + getPropertiesURL() + ")! Maybe no repositories set yet or/and properties file is misconfigured!"); } return null; } /** * Get first repository from yarep.properties * */ public Repository firstRepository() throws RepositoryException { if (repositories.size() > 0) return (Repository) repositories.elementAt(0); log.error("No repositories (" + getPropertiesURL() + ")! Maybe properties file is misconfigured!"); return null; } /** * Get repository from specified config, whereas config is being resolved relative to classpath if path is not absolute * @param rid Repository ID * @param configFile Repository configuration file (either absolute or relative path, whereas if relative path, then it is resolved relative to classpath) */ public Repository newRepository(String rid, File configFile) throws RepositoryException { if (exists(rid)) { log.warn("Repository ID already exists: " + rid + " Repository will not be added to list of Repository Factory!"); return null; } try { if (!configFile.isAbsolute()) { URL configURL = RepositoryFactory.class.getClassLoader().getResource(configFile.toString()); configFile = new File(configURL.getFile()); } log.debug("Config file: " + configFile); DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); Configuration config; config = builder.buildFromFile(configFile); String className = config.getAttribute("class", null); Repository repository; if (className != null) { log.debug("create repository instance: " + className); Class repoClass = Class.forName(className); repository = (Repository) repoClass.newInstance(); } else { log.warn("No implementation class specified within '" + configFile + "' and hence '" + DEFAULT_REPOSITORY_IMPL + "' will be used!"); repository = (Repository) Class.forName(DEFAULT_REPOSITORY_IMPL).newInstance(); } repository.setID(rid); repository.readConfiguration(configFile); repositories.addElement(repository); return repository; } catch (Exception e) { log.error(e); throw new RepositoryException("Could not create repository: " + rid + " " + configFile + " " + e.getMessage(), e); } } /** * Check if repository exists * * @param rid Repository ID */ public boolean exists(String rid) { for (int i = 0;i < repositories.size(); i++) { if (((Repository) repositories.elementAt(i)).getID().equals(rid)) return true; } log.debug("No such repository: " + rid + " (" + getPropertiesURL() + ")"); return false; } }