ingo@100: /*
ingo@100:  * Copyright (c) 2010 by Intevation GmbH
ingo@100:  *
ingo@100:  * This program is free software under the LGPL (>=v2.1)
ingo@100:  * Read the file LGPL.txt coming with the software for details
ingo@100:  * or visit http://www.gnu.org/licenses/ if it does not exist.
ingo@100:  */
ingo@100: 
sascha@5: package de.intevation.artifactdatabase;
sascha@5: 
ingo@155: import de.intevation.artifacts.ArtifactCollectionFactory;
sascha@70: import de.intevation.artifacts.ArtifactContextFactory;
sascha@70: import de.intevation.artifacts.ArtifactFactory;
sascha@70: import de.intevation.artifacts.ServiceFactory;
ingo@125: import de.intevation.artifacts.UserFactory;
sascha@70: 
sascha@70: import java.util.ArrayList;
sascha@70: 
sascha@70: import org.apache.log4j.Logger;
sascha@70: 
sascha@5: import org.w3c.dom.Document;
ingo@130: import org.w3c.dom.Node;
sascha@5: import org.w3c.dom.NodeList;
ingo@79: 
sascha@5: /**
sascha@5:  * Bootstrap facility for the global context and the artifact factories.
sascha@5:  *
sascha@77:  * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
sascha@5:  */
sascha@5: public class FactoryBootstrap
sascha@5: {
sascha@17:     private static Logger logger = Logger.getLogger(FactoryBootstrap.class);
sascha@17: 
sascha@89:     /**
sascha@89:      * XPath to figure out the class name of the context factory from
sascha@89:      * the global configuration.
sascha@89:      */
sascha@5:     public static final String CONTEXT_FACTORY =
sascha@5:         "/artifact-database/factories/context-factory/text()";
sascha@5: 
sascha@89:     /**
sascha@89:      * The name of the default context factory.
sascha@89:      */
sascha@5:     public static final String DEFAULT_CONTEXT_FACTORY =
sascha@5:         "de.intevation.artifactdatabase.DefaultArtifactContextFactory";
sascha@5: 
sascha@89:     /**
sascha@89:      * XPath to figure out the names of the artifact factories from
sascha@89:      * the global configuration to be exposed by the artifact database.
sascha@89:      */
sascha@5:     public static final String ARTIFACT_FACTORIES =
tim@16:         "/artifact-database/factories/artifact-factories/artifact-factory";
sascha@5: 
sascha@89:     /**
sascha@89:      * XPath to figure out the names of the service factories from
sascha@89:      * the global configuration to build the services offered by the
sascha@89:      * artifact database.
sascha@89:      */
sascha@71:     public static final String SERVICE_FACTORIES =
sascha@71:         "/artifact-database/factories/service-factories/service-factory";
sascha@71: 
sascha@89:     /**
ingo@125:      * XPath to figure out the class name of the user factory from global
ingo@125:      * configuration.
ingo@125:      */
ingo@125:     public static final String USER_FACTORY =
ingo@155:         "/artifact-database/factories/user-factory";
ingo@125: 
ingo@125:     /**
ingo@125:      * The name of the default user factory.
ingo@125:      */
ingo@125:     public static final String DEFAULT_USER_FACTORY =
ingo@125:         "de.intevation.artifactdatabase.DefaultUserFactory";
ingo@125: 
ingo@125:     /**
ingo@155:      * XPath to figure out the class name of the collection factory from global
ingo@155:      * configuration.
ingo@155:      */
ingo@155:     public static final String COLLECTION_FACTORY =
ingo@155:         "/artifact-database/factories/collection-factory";
ingo@155: 
ingo@155:     /**
ingo@155:      * The name of the default user factory.
ingo@155:      */
ingo@155:     public static final String DEFAULT_COLLECTION_FACTORY =
ingo@155:         "de.intevation.artifactdatabase.DefaultArtifactCollectionFactory";
ingo@155: 
ingo@155:     /**
sascha@89:      * XPath to figure out the secret used to sign the artifact exports
sascha@89:      * made by the artfifact database server.
sascha@89:      */
ingo@79:     public static final String EXPORT_SECRET =
ingo@79:         "/artifact-database/export-secret/text()";
ingo@79: 
sascha@89:     /**
sascha@89:      * Default export signing secret.
sascha@89:      * <strong>PLEASE CHANGE THE SECRET VIA THE XPATH EXPORT_SECRET
sascha@89:      * IN THE CONFIGURATION.</strong>.
sascha@89:      */
sascha@89:     public static final String DEFAULT_EXPORT_SECRET =
ingo@79:         "!!!CHANGE ME! I'M NO SECRET!!!";
ingo@79: 
sascha@89:     /**
sascha@89:      * Reference to the global context build by the global context factory.
sascha@89:      */
sascha@5:     protected Object context;
sascha@5: 
sascha@89:     /**
sascha@89:      * List of the artifact factories to be exposed by the
sascha@89:      * artifact database.
sascha@89:      */
sascha@5:     protected ArtifactFactory [] artifactFactories;
sascha@5: 
sascha@89:     /**
sascha@89:      * List of service factories which creates services that are
sascha@89:      * exposed by the artifact database.
sascha@89:      */
sascha@71:     protected ServiceFactory [] serviceFactories;
sascha@71: 
sascha@89:     /**
ingo@125:      * The factory that is used to create and list users.
ingo@125:      */
ingo@125:     protected UserFactory userFactory;
ingo@125: 
ingo@125:     /**
ingo@155:      * The factory that is used to create new artifact collections.
ingo@155:      */
ingo@155:     protected ArtifactCollectionFactory collectionFactory;
ingo@155: 
ingo@155:     /**
sascha@89:      * byte array holding the export signing secret.
sascha@89:      */
ingo@79:     protected byte [] exportSecret;
ingo@79: 
ingo@79: 
sascha@89:     /**
sascha@89:      * Default constructor
sascha@89:      */
sascha@5:     public FactoryBootstrap() {
sascha@5:     }
sascha@5: 
sascha@5:     void buildContext() {
sascha@5:         String className = Config.getStringXPath(
sascha@5:             CONTEXT_FACTORY, DEFAULT_CONTEXT_FACTORY);
sascha@5: 
sascha@5:         ArtifactContextFactory factory = null;
sascha@5: 
sascha@5:         try {
sascha@5:             Class clazz = Class.forName(className);
sascha@5:             factory = (ArtifactContextFactory)clazz.newInstance();
sascha@5:         }
sascha@5:         catch (ClassNotFoundException cnfe) {
sascha@17:             logger.error(cnfe.getLocalizedMessage(), cnfe);
sascha@5:         }
sascha@5:         catch (InstantiationException ie) {
sascha@17:             logger.error(ie.getLocalizedMessage(), ie);
sascha@5:         }
sascha@5:         catch (ClassCastException cce) {
sascha@17:             logger.error(cce.getLocalizedMessage(), cce);
sascha@5:         }
sascha@5:         catch (IllegalAccessException iae) {
sascha@17:             logger.error(iae.getLocalizedMessage(), iae);
sascha@5:         }
sascha@5: 
sascha@5:         if (factory == null) {
sascha@5:             factory = new DefaultArtifactContextFactory();
sascha@5:         }
sascha@5: 
sascha@19:         logger.info("Using class '" + factory.getClass().getName()
sascha@19:             + "' for context creation.");
sascha@19: 
sascha@5:         context = factory.createArtifactContext(Config.getConfig());
sascha@5:     }
sascha@5: 
ingo@155: 
ingo@155:     /**
ingo@155:      * Scans the global configuration to load the configured collection factory
ingo@155:      * and sets it up.
ingo@155:      */
ingo@155:     protected void loadCollectionFactory() {
ingo@155: 
ingo@155:         logger.info("loading collection factory.");
ingo@155: 
ingo@155:         Node factory = Config.getNodeXPath(COLLECTION_FACTORY);
ingo@155: 
ingo@155:         String className = Config.getStringXPath(
ingo@155:             factory, "text()", DEFAULT_COLLECTION_FACTORY);
ingo@155: 
ingo@155:         try {
ingo@155:             Class clazz       = Class.forName(className);
ingo@155:             collectionFactory = (ArtifactCollectionFactory) clazz.newInstance();
ingo@155: 
ingo@155:             collectionFactory.setup(Config.getConfig(), factory);
ingo@155:         }
ingo@155:         catch (ClassNotFoundException cnfe) {
ingo@155:             logger.error(cnfe.getLocalizedMessage(), cnfe);
ingo@155:         }
ingo@155:         catch (InstantiationException ie) {
ingo@155:             logger.error(ie.getLocalizedMessage(), ie);
ingo@155:         }
ingo@155:         catch (ClassCastException cce) {
ingo@155:             logger.error(cce.getLocalizedMessage(), cce);
ingo@155:         }
ingo@155:         catch (IllegalAccessException iae) {
ingo@155:             logger.error(iae.getLocalizedMessage(), iae);
ingo@155:         }
ingo@155:     }
ingo@155: 
sascha@89:     /**
sascha@89:      * Scans the global configuration to load the configured
sascha@89:      * artifact factories and sets them up.
sascha@89:      */
sascha@5:     protected void loadArtifactFactories() {
sascha@71: 
sascha@71:         logger.info("loading artifact factories");
sascha@71: 
sascha@5:         ArrayList loadedFactories = new ArrayList();
sascha@5: 
sascha@5:         NodeList nodes = Config.getNodeSetXPath(ARTIFACT_FACTORIES);
sascha@5: 
sascha@10:         if (nodes == null) {
sascha@17:             logger.warn("No factories found");
sascha@10:         }
sascha@10: 
sascha@5:         Document config = Config.getConfig();
sascha@5: 
sascha@19:         for (int i = 0, N = nodes != null ? nodes.getLength() : 0; i < N; ++i) {
sascha@71:             String className = nodes.item(i).getTextContent().trim();
sascha@5: 
sascha@5:             ArtifactFactory factory = null;
sascha@5: 
sascha@5:             try {
sascha@5:                 Class clazz = Class.forName(className);
sascha@5:                 factory = (ArtifactFactory)clazz.newInstance();
sascha@5:             }
sascha@5:             catch (ClassNotFoundException cnfe) {
sascha@17:                 logger.error(cnfe.getLocalizedMessage(), cnfe);
sascha@5:             }
sascha@5:             catch (InstantiationException ie) {
sascha@17:                 logger.error(ie.getLocalizedMessage(), ie);
sascha@5:             }
sascha@5:             catch (ClassCastException cce) {
sascha@17:                 logger.error(cce.getLocalizedMessage(), cce);
sascha@5:             }
sascha@5:             catch (IllegalAccessException iae) {
sascha@17:                 logger.error(iae.getLocalizedMessage(), iae);
sascha@5:             }
sascha@5: 
sascha@5:             if (factory != null) {
sascha@19:                 factory.setup(config, nodes.item(i));
sascha@5:                 loadedFactories.add(factory);
sascha@89:                 logger.info("Registering '"
sascha@89:                     + factory.getName() + "' as artifact factory.");
sascha@5:             }
sascha@5:         }
sascha@5: 
sascha@5:         artifactFactories = (ArtifactFactory [])loadedFactories.toArray(
sascha@5:             new ArtifactFactory[loadedFactories.size()]);
sascha@5:     }
sascha@5: 
sascha@89:     /**
sascha@89:      * Scans the global configuration for the configured service factories
sascha@89:      * and sets them up.
sascha@89:      */
sascha@71:     protected void loadServiceFactories() {
sascha@71: 
sascha@71:         logger.info("loading service factories");
sascha@71: 
sascha@71:         ArrayList loadedFactories = new ArrayList();
sascha@71: 
sascha@71:         NodeList nodes = Config.getNodeSetXPath(SERVICE_FACTORIES);
sascha@71: 
sascha@71:         if (nodes == null) {
sascha@71:             logger.warn("No factories found");
sascha@71:         }
sascha@71: 
sascha@71:         Document config = Config.getConfig();
sascha@71: 
sascha@71:         for (int i = 0, N = nodes != null ? nodes.getLength() : 0; i < N; ++i) {
sascha@71:             String className = nodes.item(i).getTextContent().trim();
sascha@71: 
sascha@71:             ServiceFactory factory = null;
sascha@71: 
sascha@71:             try {
sascha@71:                 Class clazz = Class.forName(className);
sascha@71:                 factory = (ServiceFactory)clazz.newInstance();
sascha@71:             }
sascha@71:             catch (ClassNotFoundException cnfe) {
sascha@71:                 logger.error(cnfe.getLocalizedMessage(), cnfe);
sascha@71:             }
sascha@71:             catch (InstantiationException ie) {
sascha@71:                 logger.error(ie.getLocalizedMessage(), ie);
sascha@71:             }
sascha@71:             catch (ClassCastException cce) {
sascha@71:                 logger.error(cce.getLocalizedMessage(), cce);
sascha@71:             }
sascha@71:             catch (IllegalAccessException iae) {
sascha@71:                 logger.error(iae.getLocalizedMessage(), iae);
sascha@71:             }
sascha@71: 
sascha@71:             if (factory != null) {
sascha@71:                 factory.setup(config, nodes.item(i));
sascha@71:                 loadedFactories.add(factory);
sascha@94:                 logger.info( "Registering '" + factory.getName()
sascha@94:                     + "' as service factory.");
sascha@71:             }
sascha@71:         }
sascha@71: 
sascha@71:         serviceFactories = (ServiceFactory [])loadedFactories.toArray(
sascha@71:             new ServiceFactory[loadedFactories.size()]);
sascha@71:     }
sascha@71: 
ingo@125: 
ingo@125:     /**
ingo@125:      * Scans the global configuration for the configured user factory.
ingo@125:      */
ingo@125:     protected void loadUserFactory() {
ingo@125:         logger.info("loading user factory");
ingo@125: 
ingo@130:         Node factory = Config.getNodeXPath(USER_FACTORY);
ingo@130: 
ingo@125:         String className = Config.getStringXPath(
ingo@130:             factory, "text()", DEFAULT_USER_FACTORY);
ingo@125: 
ingo@125:         try {
ingo@125:             Class clazz = Class.forName(className);
ingo@125:             userFactory = (UserFactory) clazz.newInstance();
ingo@130: 
ingo@130:             userFactory.setup(Config.getConfig(), factory);
ingo@125:         }
ingo@125:         catch (ClassNotFoundException cnfe) {
ingo@125:                 logger.error(cnfe.getLocalizedMessage(), cnfe);
ingo@125:         }
ingo@125:         catch (InstantiationException ie) {
ingo@125:             logger.error(ie.getLocalizedMessage(), ie);
ingo@125:         }
ingo@125:         catch (ClassCastException cce) {
ingo@125:             logger.error(cce.getLocalizedMessage(), cce);
ingo@125:         }
ingo@125:         catch (IllegalAccessException iae) {
ingo@125:             logger.error(iae.getLocalizedMessage(), iae);
ingo@125:         }
ingo@125:     }
ingo@125: 
sascha@89:     /**
sascha@89:      * Fetches the export signing secret from the global configuration.
sascha@89:      * If none is found if defaults to the DEFAULT_EXORT_SECRET which
sascha@89:      * is insecure.
sascha@89:      */
ingo@79:     protected void setupExportSecret() {
ingo@79:         String secret = Config.getStringXPath(EXPORT_SECRET);
ingo@79: 
ingo@79:         if (secret == null) {
ingo@79:             logger.warn("NO EXPORT SECRET SET! USING INSECURE DEFAULT!");
sascha@89:             secret = DEFAULT_EXPORT_SECRET;
ingo@79:         }
ingo@79: 
ingo@79:         exportSecret = StringUtils.getUTF8Bytes(secret);
ingo@79:     }
ingo@79: 
sascha@89:     /**
sascha@89:      * Loads all the dynamic classes configured by the global configuration.
sascha@89:      */
sascha@5:     public void boot() {
ingo@79:         setupExportSecret();
sascha@5:         buildContext();
ingo@155:         loadCollectionFactory();
sascha@5:         loadArtifactFactories();
sascha@71:         loadServiceFactories();
ingo@125:         loadUserFactory();
sascha@5:     }
sascha@5: 
sascha@89:     /**
ingo@155:      * Returns the artifact collection factory.
ingo@155:      *
ingo@155:      * @return the artifact collection factory.
ingo@155:      */
ingo@155:     public ArtifactCollectionFactory getArtifactCollectionFactory() {
ingo@155:         return collectionFactory;
ingo@155:     }
ingo@155: 
ingo@155:     /**
sascha@89:      * Returns the list of ready to use artifact factories.
sascha@89:      * @return The list of artifact factories.
sascha@89:      */
sascha@5:     public ArtifactFactory [] getArtifactFactories() {
sascha@5:         return artifactFactories;
sascha@5:     }
sascha@5: 
sascha@89:     /**
sascha@89:      * Returns the ready to use service factories.
sascha@89:      * @return The list of service factories.
sascha@89:      */
sascha@70:     public ServiceFactory [] getServiceFactories() {
sascha@71:         return serviceFactories;
sascha@70:     }
sascha@70: 
sascha@89:     /**
ingo@127:      * Returns the user factory.
ingo@127:      *
ingo@127:      * @return the user factory.
ingo@127:      */
ingo@127:     public UserFactory getUserFactory() {
ingo@127:         return userFactory;
ingo@127:     }
ingo@127: 
ingo@127:     /**
sascha@89:      * Returns the global context created by the global context factory.
sascha@89:      * @return The global context.
sascha@89:      */
sascha@5:     public Object getContext() {
sascha@5:         return context;
sascha@5:     }
ingo@79: 
sascha@89:     /**
sascha@89:      * Returns the signing secret to be used when ex- and importing
sascha@89:      * artifacts from and into the artifact database.
sascha@89:      * @return the byte array containg the signing secret.
sascha@89:      */
ingo@79:     public byte [] getExportSecret() {
ingo@79:         return exportSecret;
ingo@79:     }
sascha@5: }
ingo@79: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :