Package org.fcrepo.server

Source Code of org.fcrepo.server.Server

/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;

import org.fcrepo.common.Constants;
import org.fcrepo.common.FaultException;
import org.fcrepo.common.MalformedPIDException;
import org.fcrepo.common.PID;
import org.fcrepo.common.http.WebClientConfiguration;
import org.fcrepo.server.config.DatastoreConfiguration;
import org.fcrepo.server.config.ModuleConfiguration;
import org.fcrepo.server.config.Parameter;
import org.fcrepo.server.config.ServerConfiguration;
import org.fcrepo.server.config.ServerConfigurationParser;
import org.fcrepo.server.errors.GeneralException;
import org.fcrepo.server.errors.MalformedPidException;
import org.fcrepo.server.errors.ModuleInitializationException;
import org.fcrepo.server.errors.ModuleShutdownException;
import org.fcrepo.server.errors.ServerInitializationException;
import org.fcrepo.server.errors.ServerShutdownException;
import org.fcrepo.server.errors.authorization.AuthzException;
import org.fcrepo.server.resourceIndex.ModelBasedTripleGenerator;
import org.fcrepo.server.security.Authorization;
import org.fcrepo.server.utilities.status.ServerState;
import org.fcrepo.server.utilities.status.ServerStatusFile;
import org.fcrepo.utilities.DateUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

/**
* The starting point for working with a Fedora repository. This class handles
* loading, starting, and stopping modules (the module lifecycle), and provides
* access to core constants.
*
* @author Chris Wilper
*/
public abstract class Server
        extends Pluggable implements ApplicationContextAware, BeanDefinitionRegistry, ListableBeanFactory {

    public static final boolean USE_CACHE = true;

    public static final boolean USE_DEFINITIVE_STORE = false;

    public static final boolean GLOBAL_CHOICE = false;

    private static final Logger logger =
            LoggerFactory.getLogger(Server.class);

    /**
     * The ResourceBundle that provides access to constants from
     * fedora/server/resources/Server.properties.
     */
    private static ResourceBundle s_const =
            ResourceBundle.getBundle("org.fcrepo.server.resources.Server");

    private static MetadataReaderFactory s_readerFactory = new SimpleMetadataReaderFactory();

    /** The version of this release. */
    public static String VERSION = s_const.getString("version");

    /** The build date of this release. */
    public static String BUILD_DATE = s_const.getString("buildDate");

    /** The name of the property that tells the server where it's based. */
    public static String HOME_PROPERTY = s_const.getString("home.property");

    /** The internal XML storage format for digital objects */
    public static String STORAGE_FORMAT = s_const.getString("format.storage");

    /** The directory where server configuration is stored, relative to home. */
    public static String CONFIG_DIR = s_const.getString("config.dir");

    /** The directory where Spring configurations are stored, relative to CONFIG_DIR. */
    public static String SPRING_DIR = s_const.getString("spring.dir");
    /**
     * The startup log file. This file will include all log messages regardless
     * of their <code>Level</code>.
     */
    public static String LOG_STARTUP_FILE =
            s_const.getString("log.startup.file");

    /** The configuration filename. */
    public static String CONFIG_FILE = s_const.getString("config.file");

    /** The directory where server extensions are stored, relative to home. */
    public static String EXTENSION_DIR = s_const.getString("extension.dir");

    /** The directory where server executables are stored, relative to home. */
    public static String BIN_DIR = s_const.getString("bin.dir");

    /**
     * The prefix to all fedora-defined namespaces for this version.
     * 0={version.major}, 1={version.minor}
     */
    public static String NAMESPACE_PREFIX =
            MessageFormat.format(s_const.getString("namespace.prefix"),
                                 new Object[] {"1", "0"}); // so config namespace uses 1/0/

    /** The configuration file elements' namespace. 0={namespace.prefix} */
    public static String CONFIG_NAMESPACE =
            MessageFormat.format(s_const.getString("config.namespace"),
                                 new Object[] {NAMESPACE_PREFIX});

    /** The configuration file root element's name. */
    public static String CONFIG_ELEMENT_ROOT =
            s_const.getString("config.element.root");

    /** The configuration file comment element's name. */
    public static String CONFIG_ELEMENT_COMMENT =
            s_const.getString("config.element.comment");

    /** The configuration file datastore element's name. */
    public static String CONFIG_ELEMENT_DATASTORE =
            s_const.getString("config.element.datastore");

    /** The configuration file module element's name. */
    public static String CONFIG_ELEMENT_MODULE =
            s_const.getString("config.element.module");

    /** The configuration file param element's name. */
    public static String CONFIG_ELEMENT_PARAM =
            s_const.getString("config.element.param");

    /**
     * The configuration file's class-specifying attribute for server and module
     * elements.
     */
    public static String CONFIG_ATTRIBUTE_CLASS =
            s_const.getString("config.attribute.class");

    /**
     * The configuration file's role-specifying attribute for module elements.
     */
    public static String CONFIG_ATTRIBUTE_ROLE =
            s_const.getString("config.attribute.role");

    /** The configuration file param element's name attribute. */
    public static String CONFIG_ATTRIBUTE_NAME =
            s_const.getString("config.attribute.name");

    /** The configuration file param element's value attribute. */
    public static String CONFIG_ATTRIBUTE_VALUE =
            s_const.getString("config.attribute.value");

    /** The configuration file datastore element's id attribute. */
    public static String CONFIG_ATTRIBUTE_ID =
            s_const.getString("config.attribute.id");

    /** The required server constructor's first parameter's class. */
    public static String SERVER_CONSTRUCTOR_PARAM1_CLASS =
            s_const.getString("server.constructor.param1.class");

    /** The required server constructor's second parameter's class. */
    public static String SERVER_CONSTRUCTOR_PARAM2_CLASS =
            s_const.getString("server.constructor.param2.class");

    /** The required module constructor's first parameter's class. */
    public static String MODULE_CONSTRUCTOR_PARAM1_CLASS =
            s_const.getString("module.constructor.param1.class");

    /** The required module constructor's second parameter's class. */
    public static String MODULE_CONSTRUCTOR_PARAM2_CLASS =
            s_const.getString("module.constructor.param2.class");

    /** The required module constructor's third parameter's class. */
    public static String MODULE_CONSTRUCTOR_PARAM3_CLASS =
            s_const.getString("module.constructor.param3.class");

    /** The name of the default Server implementation class */
    public static String DEFAULT_SERVER_CLASS =
            s_const.getString("default.server.class");

    /** Indicates that an XML parser could not be found. */
    public static String INIT_XMLPARSER_SEVERE_MISSING =
            s_const.getString("init.xmlparser.severe.missing");

    /**
     * Indicates that the config file could not be read. 0=config file full
     * path, 1=additional info from underlying exception
     */
    public static String INIT_CONFIG_SEVERE_UNREADABLE =
            s_const.getString("init.config.severe.unreadable");

    /**
     * Indicates that the config file has malformed XML. 0=config file full
     * path, 1=additional info from underlying exception
     */
    public static String INIT_CONFIG_SEVERE_MALFORMEDXML =
            s_const.getString("init.config.severe.malformedxml");

    /**
     * Indicates that the config file has a mis-named root element. 0=config
     * file full path, 1={config.element.root}, 2=actual root element name
     */
    public static String INIT_CONFIG_SEVERE_BADROOTELEMENT =
            s_const.getString("init.config.severe.badrootelement");

    /**
     * Indicates that an invalid element was found in the configuration xml.
     * 1=the invalid element's name
     */
    public static String INIT_CONFIG_SEVERE_BADELEMENT =
            s_const.getString("init.config.severe.badelement");

    /**
     * Indicates that a CONFIG_ELEMENT_DATASTORE didn't specify the required
     * CONFIG_ATTRIBUTE_ID. 0={config.element.datastore},
     * 1={config.attribute.id}
     */
    public static String INIT_CONFIG_SEVERE_NOIDGIVEN =
            MessageFormat.format(s_const
                    .getString("init.config.severe.noidgiven"), new Object[] {
                    CONFIG_ELEMENT_DATASTORE, CONFIG_ATTRIBUTE_ID});

    /**
     * Indicates that the config file's element's namespace does not match
     * {config.namespace}. 0=config file full path, 1={config.namespace}
     */
    public static String INIT_CONFIG_SEVERE_BADNAMESPACE =
            s_const.getString("init.config.severe.badnamespace");

    /**
     * Indicates that a module element in the server configuration did not
     * specify a role, but should. 0={config.element.module},
     * 1={config.attribute.role}
     */
    public static String INIT_CONFIG_SEVERE_NOROLEGIVEN =
            MessageFormat.format(s_const
                    .getString("init.config.severe.norolegiven"), new Object[] {
                    CONFIG_ELEMENT_MODULE, CONFIG_ATTRIBUTE_ROLE});

    /**
     * Indicates that a module element in the server configuration did not
     * specify an implementing class, but should. 0={config.element.module},
     * 1={config.attribute.class}
     */
    public static String INIT_CONFIG_SEVERE_NOCLASSGIVEN =
            MessageFormat
                    .format(s_const
                                    .getString("init.config.severe.noclassgiven"),
                            new Object[] {CONFIG_ELEMENT_MODULE,
                                    CONFIG_ATTRIBUTE_CLASS});

    /**
     * Indicates that an attribute of an element was assigned the same value as
     * a previously specified element's attribute, and that this constitutes a
     * disallowed reassignment. 0=the common element, 1=the common attribute's
     * name, 2=the common attribute's value.
     */
    public static String INIT_CONFIG_SEVERE_REASSIGNMENT =
            s_const.getString("init.config.severe.reassignment");

    /**
     * Indicates that a parameter element in the config file is missing a
     * required element. 0={config.element.param}, 1={config.attribute.name},
     * 2={config.attribute.value}
     */
    public static String INIT_CONFIG_SEVERE_INCOMPLETEPARAM =
            MessageFormat
                    .format(s_const
                                    .getString("init.config.severe.incompleteparam"),
                            new Object[] {CONFIG_ELEMENT_PARAM,
                                    CONFIG_ATTRIBUTE_NAME,
                                    CONFIG_ATTRIBUTE_VALUE});

    /**
     * Tells which config element is being looked at in order to load its
     * parameters into memory. 0=name of element being examined,
     * 1=distinguishing attribute (name=&quot;value&quot;), or empty string if
     * no distinguishing attribute.
     */
    public static String INIT_CONFIG_CONFIG_EXAMININGELEMENT =
            s_const.getString("init.config.config.examiningelement");

    /**
     * Tells the name and value of a parameter loaded from the config file.
     * 0=param name, 1=param value
     */
    public static String INIT_CONFIG_CONFIG_PARAMETERIS =
            s_const.getString("init.config.config.parameteris");

    /**
     * Indicates that the server class could not be found. 0=server class
     * specified in config root element
     */
    public static String INIT_SERVER_SEVERE_CLASSNOTFOUND =
            s_const.getString("init.server.severe.classnotfound");

    /**
     * Indicates that the server class couldn't be accessed due to security
     * misconfiguration. 0=server class specified in config root element
     */
    public static String INIT_SERVER_SEVERE_ILLEGALACCESS =
            s_const.getString("init.server.severe.illegalaccess");

    /**
     * Indicates that the server class constructor was invoked improperly due to
     * programmer error. 0=server class specified in config root element
     */
    public static String INIT_SERVER_SEVERE_BADARGS =
            s_const.getString("init.server.severe.badargs");

    /**
     * Indicates that the server class doesn't have a constructor matching
     * Server(NodeList, File), but needs one. 0=server class specified in config
     * root element.
     */
    public static String INIT_SERVER_SEVERE_MISSINGCONSTRUCTOR =
            s_const.getString("init.server.severe.missingconstructor");

    /**
     * Indicates that a module role required to be fulfilled by this server was
     * not fulfilled because the configuration did not specify a module with
     * that role. 0=the role
     */
    public static String INIT_SERVER_SEVERE_UNFULFILLEDROLE =
            s_const.getString("init.server.severe.unfulfilledrole");

    public static String INIT_MODULE_SEVERE_UNFULFILLEDROLE =
            s_const.getString("init.module.severe.unfulfilledrole");

    /**
     * Indicates that the server class was abstract, but shouldn't be. 0=server
     * class specified in config root element
     */
    public static String INIT_SERVER_SEVERE_ISABSTRACT =
            s_const.getString("init.server.severe.isabstract");

    /**
     * Indicates that the module class could not be found. 0=module class
     * specified in config
     */
    public static String INIT_MODULE_SEVERE_CLASSNOTFOUND =
            s_const.getString("init.module.severe.classnotfound");

    /**
     * Indicates that the module class couldn't be accessed due to security
     * misconfiguration. 0=module class specified in config
     */
    public static String INIT_MODULE_SEVERE_ILLEGALACCESS =
            s_const.getString("init.module.severe.illegalaccess");

    /**
     * Indicates that the module class constructor was invoked improperly due to
     * programmer error. 0=module class specified in config
     */
    public static String INIT_MODULE_SEVERE_BADARGS =
            s_const.getString("init.module.severe.badargs");

    /**
     * Indicates that the module class doesn't have a constructor matching
     * Module(Map, Server, String), but needs one. 0=module class specified in
     * config
     */
    public static String INIT_MODULE_SEVERE_MISSINGCONSTRUCTOR =
            s_const.getString("init.module.severe.missingconstructor");

    /**
     * Indicates that the module class was abstract, but shouldn't be. 0=module
     * class specified in config
     */
    public static String INIT_MODULE_SEVERE_ISABSTRACT =
            s_const.getString("init.module.severe.isabstract");

    /**
     * Indicates that the startup log could not be written to its usual place
     * for some reason, and that we're falling back to stderr. 0=usual place,
     * 1=exception message
     */
    public static String INIT_LOG_WARNING_CANTWRITESTARTUPLOG =
            s_const.getString("init.log.warning.cantwritestartuplog");

    /**
     * The server-wide default locale, obtained via <code>getLocale()</code>.
     */
    private static Locale s_locale;

    /**
     * Holds an instance of a <code>Server</code> for each distinct
     * <code>File</code> given as a parameter to <code>getInstance(...)</code>
     */
    protected static Map<File, Server> s_instances = new HashMap<File, Server>();

    /**
     * The server's home directory; this is typically the 'server' subdirectory under $FEDORA_HOME.
     */
    private final File m_serverDir;

    private AbstractApplicationContext m_serverContext;
    private GenericApplicationContext m_moduleContext;

    /**
     * The server's directory for (temp) uploaded files
     */
    private final File m_uploadDir;

    /**
     * Datastore configurations initialized from the server config file.
     * Should now be handled by application context
     */
//    private Map<String, DatastoreConfig> m_datastoreConfigs;

    /**
     * Modules that have been loaded.
     */
    @Deprecated
    protected Map<String, Module> m_loadedModules;
    @Deprecated
    protected Set<String> m_loadedModuleRoles;

    /**
     * The server's configuration file
     */
    private final File m_configFile;
    /**
     * Is the server running?
     */
    private boolean m_initialized;

    /**
     * The server status File.
     */
    private final ServerStatusFile m_statusFile;

    /**
     * What server profile should be used?
     */
    private static String s_serverProfile =
            System.getProperty("fedora.serverProfile");

    /**
     * Web Client http connection configuration object
     */
    private WebClientConfiguration m_webClientConfig;

    /**
     * Initializes the Server from a Map of Strings (as per Module)
     */

    protected Server(Map<String,String> params, File homeDir)
        throws ServerInitializationException, ModuleInitializationException {

        setParameters(params);
        m_initialized = false;
        m_loadedModuleRoles = new HashSet<String>();
        m_serverDir = new File(homeDir, "server");
        m_uploadDir = new File(m_serverDir, "management/upload");
        try{
            m_statusFile = new ServerStatusFile(m_serverDir);
        } catch (Exception e) {
            throw new ServerInitializationException(e.toString());
        }
        File logDir = new File(m_serverDir, "logs");
        if (!logDir.exists()) {
            logDir.mkdir(); // try to create dir if doesn't exist
        }
        m_configFile = new File(m_serverDir + File.separator + CONFIG_DIR
                                + File.separator + CONFIG_FILE);
        Server.s_instances.put(homeDir, this);
    }

    /**
     * Initializes the Server based on configuration.
     * <p>
     * </p>
     * Reads and schema-validates the configuration items in the given DOM
     * <code>NodeList</code>, validates required server params, initializes
     * the <code>Server</code>, then initializes each module, validating its
     * required params, then verifies that the server's required module roles
     * have been met.
     *
     * @param rootConfigElement
     *        The root <code>Element</code> of configuration.
     * @param homeDir
     *        The home directory of fedora, used to interpret relative paths
     *        used in configuration.
     * @throws ServerInitializationException
     *         If there was an error starting the server.
     * @throws ModuleInitializationException
     *         If there was an error starting a module.
     */
    protected Server(Element rootConfigElement, File homeDir)
            throws ServerInitializationException, ModuleInitializationException {
        this(Server.loadParameters(rootConfigElement, ""), homeDir);
    }

    public void init()  throws ServerInitializationException, ModuleInitializationException {
        logger.info("Registered server at " + getHomeDir().getPath());
        try {
            if (m_serverContext == null) {
                m_serverContext = getDefaultContext();
            }
            m_moduleContext = new GenericApplicationContext(m_serverContext);
            registerBeanDefinition(CommonAnnotationBeanPostProcessor.class.getName(),
                                                   getScannedBeanDefinition(CommonAnnotationBeanPostProcessor.class.getName()));
            // Load bean definitions that should be override-able (ie, are new)

            loadSpringModules();

            // Default definition for ModelBasedTripleGenerator
            if (!knownBeanDefinition(ModelBasedTripleGenerator.class.getName())){
                ScannedGenericBeanDefinition tripleGen = getScannedBeanDefinition(ModelBasedTripleGenerator.class.getName());
                tripleGen.setScope(AbstractBeanDefinition.SCOPE_PROTOTYPE);
                registerBeanDefinition(ModelBasedTripleGenerator.class.getName(), tripleGen);
            }

            logger.info("Server home is " + m_serverDir.toString());
            if (s_serverProfile == null) {
                logger.debug("fedora.serverProfile property not set... will always "
                        + "use param 'value' attributes from configuration for param values.");
            } else {
                logger.debug("fedora.serverProfile property was '"
                        + s_serverProfile + "'... will use param '"
                        + s_serverProfile + "value' attributes from "
                        + "configuration for param values, falling back to "
                        + "'value' attributes where unspecified.");
            }
            logger.debug("Loading and validating configuration file \""
                    + m_configFile + "\"");

            // do the parsing and validation of configuration
            ServerConfiguration serverConfig = getConfig();
            List<DatastoreConfiguration> dsConfigs = serverConfig.getDatastoreConfigurations();
            List<ModuleConfiguration> moduleConfigs = serverConfig.getModuleConfigurations();

            // ensure server's module roles are met
            String[] reqRoles = getRequiredModuleRoles();
            for (String element : reqRoles) {
                if (!knownBeanDefinition(element) && serverConfig.getModuleConfiguration(element) == null) {
                    throw new ServerInitializationException(MessageFormat
                            .format(INIT_SERVER_SEVERE_UNFULFILLEDROLE,
                                    new Object[] {element}));
                }
            }

            // initialize the server
            m_statusFile.append(ServerState.STARTING, "Initializing Server");
            initServer();

            // create the datastore configs and set the instance variable
            // so they can be seen with getDatastoreConfig(...)
            m_statusFile.append(ServerState.STARTING, "Initializing datastore definitions");

            for (DatastoreConfiguration ds:dsConfigs) {
                String id = ds.getId();
//                m_datastoreConfigs
//                        .put(id, new DatastoreConfig((HashMap) datastoreParams
//                                .get(id)));
                logger.info("Loading fcfg datastore definitions for " + id);
                registerBeanDefinition(id, createDatastoreConfigurationBeanDefinition(id));
            }

            // Initialize the web client configuration
            initWebClientConfig();

            // initialize each module
            m_statusFile.append(ServerState.STARTING, "Loading Module Definitions");

            for (ModuleConfiguration mconfig:moduleConfigs) {
                String role = mconfig.getRole();
                String className = mconfig.getClassName();
                if (!knownBeanDefinition(role)){
                    logger.info("Loading bean definitions for {} impl class={}", className, role);
                    registerBeanDefinition(role,
                                           createModuleBeanDefinition(className, mconfig.getParameters(), role));
                } else {
                    logger.info("FCFG bean definitions for {} superceded by existing Spring bean definition", className);
                }
                if (!knownBeanDefinition(role+"Configuration")){
                    registerBeanDefinition(role+"Configuration",
                                           createModuleConfigurationBeanDefinition(role));
                }
            }
            registerBeanDefinitions();
            // initialize each module by getting Spring bean
            m_statusFile.append(ServerState.STARTING, "Initializing Modules");
            m_moduleContext.refresh(); // attach postprocessors to bean definitions
            String [] moduleNames = getBeanNamesForType(Module.class,false,true);
            for (String moduleName:moduleNames){
                getBean(moduleName);
            }


            // Do postInitModule for all Modules, verifying beforehand that
            // the required module roles (dependencies) have been fulfilled
            // for that module.
            m_statusFile.append(ServerState.STARTING,
                                "Post-Initializing Modules");
            for (String moduleName:moduleNames){
                Module m = getModule(moduleName);
                logger.info("Post-Initializing " + m.getClass().getName());
                reqRoles = m.getRequiredModuleRoles();
                logger.debug("verifying dependencies have been loaded...");
                for (String element : reqRoles) {
                    if (getModule(element) == null) {
                        throw new ModuleInitializationException(MessageFormat
                                .format(INIT_MODULE_SEVERE_UNFULFILLEDROLE,
                                        new Object[] {element}), moduleName);
                    }
                }
                logger.debug(reqRoles.length + " dependencies, all loaded, ok.");
                m.postInitModule();
            }

            // Do postInitServer for the Server instance
            logger.debug("Post-initializing server");
            postInitServer();

            // flag that we're done initting
            logger.info("Server startup complete");
            m_initialized = true;
        } catch (ServerInitializationException sie) {
            // these are caught and rethrown for two reasons:
            // 1) so they can be logged in the startup log, and
            // 2) so an attempt can be made to free resources tied up thus far
            //    via shutdown()
            logger.error("Server failed to initialize", sie);
            try {
                shutdown(null);
            } catch (Throwable th) {
                logger.warn("Error shutting down server after failed startup", th);
            }
            throw sie;
        } catch (ModuleInitializationException mie) {
            logger.error("Module (" + mie.getRole() + ") failed to initialize",
                      mie);
            try {
                shutdown(null);
            } catch (Throwable th) {
                logger.warn("Error shutting down server after failed startup", th);
            }
            throw mie;
        } catch (Throwable th) {
            String msg = "Fatal error while starting server";
            logger.error(msg, th);
            try {
                shutdown(null);
            } catch (Throwable oth) {
                logger.warn("Error shutting down server after failed startup",
                              oth);
            }
            throw new RuntimeException(msg, th);
        }
    }

    protected AbstractApplicationContext getDefaultContext() throws IOException {
        GenericApplicationContext appContext = new GenericApplicationContext();
        appContext.refresh(); // init event multicaster to avoid synch issue
        appContext.registerBeanDefinition(MODULE_CONSTRUCTOR_PARAM2_CLASS, getServerBeanDefinition());
        appContext.getBeanFactory().registerSingleton(MODULE_CONSTRUCTOR_PARAM2_CLASS, this);
        appContext.registerBeanDefinition(ServerConfiguration.class.getName(), getServerConfigurationBeanDefinition());
        ScannedGenericBeanDefinition moduleDef = getScannedBeanDefinition(Module.class.getName());
        moduleDef.setAbstract(true);
        moduleDef.setInitMethodName("initModule");
        moduleDef.setDestroyMethodName("shutdownModule");
        appContext.registerBeanDefinition(Module.class.getName(), moduleDef);
        return appContext;
    }

    /**
     * This constructor is a compatibility bridge to allow
     *  the getInstance factory method to be used by Spring contexts
     * @param homeDir
     * @throws ServerInitializationException
     * @throws ModuleInitializationException
     */
    protected Server(File homeDir)
            throws ServerInitializationException, ModuleInitializationException {
        this(getConfigElement(homeDir),homeDir);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        m_serverContext = (AbstractApplicationContext)applicationContext;
    }

    protected BeanDefinition getServerBeanDefinition(){
        GenericBeanDefinition result = new GenericBeanDefinition();
        result.setAutowireCandidate(true);
        result.setScope(BeanDefinition.SCOPE_SINGLETON);
        result.setBeanClass(this.getClass());
        result.setAttribute("id", MODULE_CONSTRUCTOR_PARAM2_CLASS);
        result.setAttribute("name", MODULE_CONSTRUCTOR_PARAM2_CLASS);
        return result;
    }

    /**
     * Provide a generic bean definition if the Server was not created by Spring
     * @return
     */
    protected static BeanDefinition getServerConfigurationBeanDefinition(){
        String className = ServerConfiguration.class.getName();
        GenericBeanDefinition result = new GenericBeanDefinition();
        result.setAutowireCandidate(true);
        result.setScope(BeanDefinition.SCOPE_SINGLETON);
        result.setBeanClass(Server.class);
        result.setFactoryMethodName("getConfig");
        result.setAttribute("id", className);
        result.setAttribute("name", className);
        return result;
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        String beanClassName = overrideModuleClass(beanDefinition.getBeanClassName());
        if (beanClassName != null) beanDefinition.setBeanClassName(beanClassName);
        if (overrideModuleRole(beanName)){
            beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
            if (beanDefinition instanceof GenericBeanDefinition){
                ((GenericBeanDefinition)beanDefinition).setAbstract(true);
            }
        }
        m_moduleContext.registerBeanDefinition(beanName, beanDefinition);
    }

    /**
     * Register any implementation-specific bean definitions before the context is refreshed.
     * @throws ServerInitializationException
     */
    protected void registerBeanDefinitions() throws ServerInitializationException {
        if (1 == 2) {
            throw new ServerInitializationException(null);
        }
    }

    protected static ScannedGenericBeanDefinition getScannedBeanDefinition(String className)
        throws IOException {
        MetadataReader reader = s_readerFactory.getMetadataReader(className);
        ScannedGenericBeanDefinition beanDefinition = new ScannedGenericBeanDefinition(reader);
        return beanDefinition;
    }

    /**
     * Generates Spring Bean definitions for Fedora Modules.
     * Server param should be unnecessary if autowired.
     * @param className
     * @param server
     * @param params
     * @param role
     * @return
     */
    protected static GenericBeanDefinition createModuleBeanDefinition(String className, Map<String,String> params, String role)
        throws IOException {
        ScannedGenericBeanDefinition result = getScannedBeanDefinition(className);
        result.setParentName(Module.class.getName());
        result.setScope(BeanDefinition.SCOPE_SINGLETON);
        result.setAttribute("id", role);
        result.setAttribute("name", role);
        result.setAttribute("init-method", "initModule");
        result.setEnforceInitMethod(true);
        result.setAttribute("destroy-method", "shutdownModule");
        result.setEnforceDestroyMethod(true);

        ConstructorArgumentValues cArgs = new ConstructorArgumentValues();
        cArgs.addIndexedArgumentValue(0, params,MODULE_CONSTRUCTOR_PARAM1_CLASS);
        // one server bean in context
        BeanReference serverRef = new RuntimeBeanReference(MODULE_CONSTRUCTOR_PARAM2_CLASS);
        cArgs.addIndexedArgumentValue(1, serverRef);
        cArgs.addIndexedArgumentValue(2, role,MODULE_CONSTRUCTOR_PARAM3_CLASS);
        result.setConstructorArgumentValues(cArgs);
        return result;
    }

    protected static GenericBeanDefinition createModuleConfigurationBeanDefinition(String role){
        GenericBeanDefinition result = new GenericBeanDefinition();
        result.setScope(BeanDefinition.SCOPE_SINGLETON);
        result.setBeanClassName(ModuleConfiguration.class.getName());
        String name = role+"Configuration";
        result.setAttribute("id", name);
        result.setAttribute("name", name);
        result.setFactoryBeanName(ServerConfiguration.class.getName());
        result.setFactoryMethodName("getModuleConfiguration");
        ConstructorArgumentValues cArgs = new ConstructorArgumentValues();
        cArgs.addGenericArgumentValue(role);
        result.setConstructorArgumentValues(cArgs);
        return result;
    }

    protected static GenericBeanDefinition createDatastoreConfigurationBeanDefinition(String id){
        GenericBeanDefinition result = new GenericBeanDefinition();
        result.setScope(BeanDefinition.SCOPE_SINGLETON);
        result.setBeanClassName(DatastoreConfiguration.class.getName());
        result.setAttribute("id", id);
        result.setAttribute("name", id);
        result.setFactoryBeanName(ServerConfiguration.class.getName());
        result.setFactoryMethodName("getDatastoreConfiguration");
        ConstructorArgumentValues cArgs = new ConstructorArgumentValues();
        cArgs.addGenericArgumentValue(id);
        result.setConstructorArgumentValues(cArgs);
        return result;
    }

    /**
     *
     * @param DatastoreConfiguration tsDC : the datastore configuration intended for the triplestore connector
     * @return GenericBeanDefinition for the TriplestoreConnector
     * @throws ClassNotFoundException
     * @throws IOException
     */
    protected static GenericBeanDefinition getTriplestoreConnectorBeanDefinition(DatastoreConfiguration tsDC)
        throws IOException {
        String tsConnector = tsDC.getParameter("connectorClassName",Parameter.class).getValue();
        ScannedGenericBeanDefinition beanDefinition = getScannedBeanDefinition(tsConnector);
        beanDefinition.setAutowireCandidate(true);

        Iterator<Parameter> it;
        Parameter p;

        Map<String, String> tsTC = new HashMap<String, String>();
        it = tsDC.getParameters(Parameter.class).iterator();
        while (it.hasNext()) {
            p = it.next();
            tsTC.put(p.getName(), p.getValue(p.getIsFilePath()));
        }
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.addPropertyValue("configuration", tsTC);
        beanDefinition.setPropertyValues(propertyValues);
        return beanDefinition;
    }


    private void loadSpringModules(){
        File springDir =
            new File(m_serverDir + File.separator + CONFIG_DIR
                     + File.separator + SPRING_DIR);
        if (springDir.exists() && springDir.isDirectory()){

            // load some Spring configs with an XmlBeanDefinitionReader
            XmlBeanDefinitionReader beanReader = new XmlBeanDefinitionReader(this);
            for(String path:springDir.list()){
                if (path.endsWith(".xml")){
                    File springConfig = new File(springDir,path);
                    logger.info("loading spring beans from " + springConfig.getAbsolutePath());
                    FileSystemResource beanConfig = new FileSystemResource(springConfig);
                    int count = beanReader.loadBeanDefinitions(beanConfig);
                    if (count < 1){
                        logger.warn("Loaded " + Integer.toString(count) + " beans from " + springConfig.getAbsolutePath());
                    }
                }
            }
        }
    }

    @Override
    public Object getBean(String name)
        throws BeansException {
        return m_moduleContext.getBean(name);
    }

    @Override
    public boolean containsBean(String name)
    throws BeansException {
        return m_moduleContext.containsBean(name);
    }

    /**
     * Gets a loaded <code>Module</code>.
     *
     * @param role
     *        The role of the <code>Module</code> to get.
     * @return The <code>Module</code>, <code>null</code> if not found.
     */
    public Module getModule(String role) {
        if(m_moduleContext.containsBean(role)){
            try{
                return m_moduleContext.getBean(role,Module.class);
            }
            catch(Throwable e){
                logger.warn(e.toString());
            }
        }
        return null;
    }

    protected boolean overrideModuleRole(String moduleRole) {
        return false;
    }

    protected String overrideModuleClass(String moduleClass) {
        return null;
    }

    /**
     * Builds and returns a <code>Map</code> of parameter name-value pairs
     * defined as children of the given <code>Element</code>, according to
     * the server configuration schema.
     * <p>
     * </p>
     * If the given element is a CONFIG_ELEMENT_ROOT, this method will return
     * (along with the server's parameter name-value pairs) a <code>null</code>-keyed
     * value, which is an <code>ArrayList</code> of three <code>HashMap</code>
     * objects. The first will contain the name-value pair HashMaps of each of
     * the CONFIG_ELEMENT_MODULE elements found (in a <code>HashMap</code>
     * keyed by <i>role</i>), the second will contain a <code>HashMap</code>
     * mapping module <i>role</i>s to implementation classnames, and the third
     * will contain the the name-value pair <code>HashMaps</code> of each of
     * the CONFIG_ELEMENT_DATASTORE elements found (keyed by
     * CONFIG_ATTRIBUTE_ID).
     *
     * @param element
     *        The element containing the name-value pair definitions.
     * @param dAttribute
     *        The name of the attribute of the <code>Element</code> whose
     *        value will distinguish this element from others that may occur in
     *        the <code>Document</code>. If there is no distinguishing
     *        attribute, this should be an empty string.
     */
    private static final Map<String,String> loadParameters(Element element, String dAttribute)
            throws ServerInitializationException {
        Map<String,String> params = new HashMap<String,String>();

        logger.debug(MessageFormat.format(INIT_CONFIG_CONFIG_EXAMININGELEMENT,
                                       new Object[] {element.getLocalName(),
                                               dAttribute}));
        for (int i = 0; i < element.getChildNodes().getLength(); i++) {
            Node n = element.getChildNodes().item(i);
            if (n.getNodeType() == Node.ELEMENT_NODE) {
                if (n.getLocalName().equals(CONFIG_ELEMENT_PARAM)) {
                    // if name-value pair, save in the HashMap
                    NamedNodeMap attrs = n.getAttributes();
                    Node nameNode =
                            attrs.getNamedItemNS(CONFIG_NAMESPACE,
                                                 CONFIG_ATTRIBUTE_NAME);
                    if (nameNode == null) {
                        nameNode = attrs.getNamedItem(CONFIG_ATTRIBUTE_NAME);
                    }
                    Node valueNode = null;
                    if (s_serverProfile != null) {
                        valueNode =
                                attrs.getNamedItemNS(CONFIG_NAMESPACE,
                                                     s_serverProfile + "value");
                        if (valueNode == null) {
                            valueNode =
                                    attrs.getNamedItem(s_serverProfile
                                            + "value");
                        }
                    }
                    if (valueNode == null) {
                        valueNode =
                                attrs.getNamedItemNS(CONFIG_NAMESPACE,
                                                     CONFIG_ATTRIBUTE_VALUE);
                        if (valueNode == null) {
                            valueNode =
                                    attrs.getNamedItem(CONFIG_ATTRIBUTE_VALUE);
                        }
                        if (nameNode == null || valueNode == null) {
                            throw new ServerInitializationException(INIT_CONFIG_SEVERE_INCOMPLETEPARAM);
                        }
                    }
                    if (nameNode.getNodeValue().equals("")
                            || valueNode.getNodeValue().equals("")) {
                        throw new ServerInitializationException(MessageFormat
                                .format(INIT_CONFIG_SEVERE_INCOMPLETEPARAM,
                                        new Object[] {CONFIG_ELEMENT_PARAM,
                                                CONFIG_ATTRIBUTE_NAME,
                                                CONFIG_ATTRIBUTE_VALUE}));
                    }
                    if (params.get(nameNode.getNodeValue()) != null) {
                        throw new ServerInitializationException(MessageFormat
                                .format(INIT_CONFIG_SEVERE_REASSIGNMENT,
                                        new Object[] {CONFIG_ELEMENT_PARAM,
                                                CONFIG_ATTRIBUTE_NAME,
                                                nameNode.getNodeValue()}));
                    }
                    params.put(nameNode.getNodeValue(), valueNode
                            .getNodeValue());
                    logger.debug(MessageFormat
                            .format(INIT_CONFIG_CONFIG_PARAMETERIS,
                                    new Object[] {nameNode.getNodeValue(),
                                            valueNode.getNodeValue()}));

                } else if (!n.getLocalName().equals(CONFIG_ELEMENT_COMMENT)) {
                }

            }
        }
        params.remove(null);
        return params;
    }

    /**
     * Tells whether the server (and loaded modules) have initialized.
     * <p>
     * </p>
     * This is useful for threaded <code>Modules</code> that need to wait
     * until all initialization has occurred before doing something.
     *
     * @return whether initialization has completed.
     */
    public final boolean hasInitialized() {
        return m_initialized;
    }

    /**
     * Get the status file for the server. Important messages pertaining to
     * startup and shutdown go here.
     */
    public ServerStatusFile getStatusFile() {
        return m_statusFile;
    }

    public final static boolean hasInstance(File homeDir) {
        return s_instances.get(homeDir) != null;
    }

    public final String status(Context context) throws AuthzException {
        (getBean("org.fcrepo.server.security.Authorization", Authorization.class))
                .enforceServerStatus(context);
        return "RUNNING";
    }

    public final static Server getInstance(File homeDir, boolean okToStart)
            throws ServerInitializationException, ModuleInitializationException {
        if (okToStart) {
            return getInstance(homeDir);
        } else {
            Server instance = s_instances.get(homeDir);
            if (instance == null) {
                throw new ServerInitializationException("The Fedora server is not yet running.");
            } else {
                return instance;
            }
        }

    }

    public final static Element getConfigElement(File homeDir)
            throws ServerInitializationException {
        File configFile = null;
        try {
            DocumentBuilderFactory factory =
                    DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            configFile =
                    new File(homeDir + File.separator + "server"
                            + File.separator + CONFIG_DIR + File.separator
                            + CONFIG_FILE);
            // suck it in
            Element rootElement =
                    builder.parse(configFile).getDocumentElement();
            // ensure root element name ok
            if (!rootElement.getLocalName().equals(CONFIG_ELEMENT_ROOT)) {
                throw new ServerInitializationException(MessageFormat
                        .format(INIT_CONFIG_SEVERE_BADROOTELEMENT,
                                new Object[] {configFile, CONFIG_ELEMENT_ROOT,
                                        rootElement.getLocalName()}));
            }
            // ensure namespace specified properly
            if (!rootElement.getNamespaceURI().equals(CONFIG_NAMESPACE)) {
                throw new ServerInitializationException(MessageFormat
                        .format(INIT_CONFIG_SEVERE_BADNAMESPACE, new Object[] {
                                configFile, CONFIG_NAMESPACE}));
            }
            return rootElement;
        } catch (IOException ioe) {
            throw new ServerInitializationException(MessageFormat
                    .format(INIT_CONFIG_SEVERE_UNREADABLE, new Object[] {
                            configFile, ioe.getMessage()}));
        } catch (ParserConfigurationException pce) {
            throw new ServerInitializationException(INIT_XMLPARSER_SEVERE_MISSING);
        } catch (SAXException saxe) {
            throw new ServerInitializationException(MessageFormat
                    .format(INIT_CONFIG_SEVERE_MALFORMEDXML, new Object[] {
                            configFile, saxe.getMessage()}));
        }
    }

    /**
     * Provides an instance of the server specified in the configuration file at
     * homeDir/CONFIG_DIR/CONFIG_FILE, or DEFAULT_SERVER_CLASS if unspecified.
     *
     * @param homeDir
     *        The base directory for the server.
     * @return The instance.
     * @throws ServerInitializationException
     *         If there was an error starting the server.
     * @throws ModuleInitializationException
     *         If there was an error starting a module.
     */
    public final static synchronized Server getInstance(File homeDir)
            throws ServerInitializationException, ModuleInitializationException {
        // return an instance if already in memory
        Server instance = s_instances.get(homeDir);
        if (instance != null) {
            return instance;
        }

        logger.info("Starting up server");

        // else instantiate a new one given the class provided in the
        // root element in the config file and return it
        File configFile = null;
        try {
            Element rootElement = getConfigElement(homeDir);
            // select <server class="THIS_PART"> .. </server>
            String className = rootElement.getAttribute(CONFIG_ATTRIBUTE_CLASS);
            if (className.equals("")) {
                className =
                        rootElement.getAttributeNS(CONFIG_NAMESPACE,
                                                   CONFIG_ATTRIBUTE_CLASS);
                if (className.equals("")) {
                    className = DEFAULT_SERVER_CLASS;
                }
            }
            try {
                Class serverClass = Class.forName(className);
                Class param1Class =
                        Class.forName(SERVER_CONSTRUCTOR_PARAM1_CLASS);
                Class param2Class =
                        Class.forName(SERVER_CONSTRUCTOR_PARAM2_CLASS);
                Constructor serverConstructor =
                        serverClass.getConstructor(new Class[] {param1Class,
                                param2Class});
                Server inst =
                        (Server) serverConstructor.newInstance(new Object[] {
                                rootElement, homeDir});
                inst.init();
                return inst;
            } catch (ClassNotFoundException cnfe) {
                throw new ServerInitializationException(MessageFormat
                        .format(INIT_SERVER_SEVERE_CLASSNOTFOUND,
                                new Object[] {className}));
            } catch (IllegalAccessException iae) {
                // improbable
                throw new ServerInitializationException(MessageFormat
                        .format(INIT_SERVER_SEVERE_ILLEGALACCESS,
                                new Object[] {className}));
            } catch (IllegalArgumentException iae) {
                // improbable
                throw new ServerInitializationException(MessageFormat
                        .format(INIT_SERVER_SEVERE_BADARGS,
                                new Object[] {className}));
            } catch (InstantiationException ie) {
                throw new ServerInitializationException(MessageFormat
                        .format(INIT_SERVER_SEVERE_MISSINGCONSTRUCTOR,
                                new Object[] {className}));
            } catch (NoSuchMethodException nsme) {
                throw new ServerInitializationException(MessageFormat
                        .format(INIT_SERVER_SEVERE_ISABSTRACT,
                                new Object[] {className}));
            } catch (InvocationTargetException ite) {
                // throw the constructor's thrown exception, if any
                try {
                    throw ite.getCause(); // as of java 1.4
                } catch (ServerInitializationException sie) {
                    throw sie;
                } catch (ModuleInitializationException mie) {
                    throw mie;
                } catch (Throwable t) {
                    // a runtime error..shouldn't happen, but if it does...
                    StringBuffer s = new StringBuffer();
                    s.append(t.getClass().getName());
                    s.append(": ");
                    for (int i = 0; i < t.getStackTrace().length; i++) {
                        s.append(t.getStackTrace()[i] + "\n");
                    }
                    throw new ServerInitializationException(s.toString());
                }
            }
        } catch (FactoryConfigurationError fce) {
            throw new ServerInitializationException(INIT_XMLPARSER_SEVERE_MISSING);
        } catch (IllegalArgumentException iae) {
            throw new ServerInitializationException(MessageFormat
                    .format(INIT_CONFIG_SEVERE_UNREADABLE, new Object[] {
                            configFile, iae.getMessage()}));
        }
    }

    /**
     * Gets the server's home directory; this is typically the 'server' subdirectory under $FEDORA_HOME.
     *
     * @return The directory.
     */
    public final File getHomeDir() {
        return m_serverDir;
    }

    /**
    * Gets the server's temp file upload directory.
    *
    * @return The directory.
    */
    public File getUploadDir() {
       return m_uploadDir;
   }

    /**
     * Gets a <code>DatastoreConfig</code>.
     *
     * @param id
     *        The id as given in the server configuration.
     * @return The <code>DatastoreConfig</code>, <code>null</code> if not
     *         found.
     */
    public final DatastoreConfig getDatastoreConfig(String id) {
        try{
            return m_moduleContext.getBean(id,DatastoreConfiguration.class);
        }
        catch (Throwable t){
            logger.info(t.getMessage(),t);
            return null;
        }
    }

    public Iterator<String> datastoreConfigIds() {
        String [] dsNames = m_moduleContext.getBeanNamesForType(DatastoreConfiguration.class,false,true);
        return Arrays.asList(dsNames).iterator();
    }

    /**
     * Gets an <code>Iterator</code> over the roles that have been loaded.
     *
     * @return (<code>String</code>s) The roles.
     */
    public final Iterator<String> loadedModuleRoles() {
        String [] names = m_moduleContext.getBeanNamesForType(Module.class,false,true);
        return Arrays.asList(names).iterator();
    }

    /**
     * Performs any server start-up tasks particular to this type of Server.
     * <p>
     * </p>
     * This is guaranteed to be run before any modules are loaded. The default
     * implementation does nothing.
     *
     * @throws ServerInitializationException
     *         If a severe server startup-related error occurred.
     */
    protected void initServer() throws ServerInitializationException {
        if (1 == 2) {
            throw new ServerInitializationException(null);
        }
    }

    /**
     * Second stage of Server initialization.
     * <p>
     * </p>
     * This is guaranteed to be run after all Modules have been loaded and all
     * module initialization (initModule() and postInitModule()) has taken
     * place. The default implementation does nothing.
     *
     * @throws ServerInitializationException
     *         If a severe server startup-related error occurred.
     */
    protected void postInitServer() throws ServerInitializationException {
        if (1 == 2) {
            throw new ServerInitializationException(null);
        }
    }

    /**
     * Performs shutdown tasks for the modules and the server.
     * <p>
     * </p>
     * All loaded modules' shutdownModule() methods are called, then
     * shutdownServer is called.
     * <p>
     * </p>
     * <h3>How to Ensure Clean Server Shutdown</h3>
     * <p>
     * </p>
     * After having used a <code>Server</code> instance, if you know your
     * program is the only client of the <code>Server</code> in the VM
     * instance, you should make an explicit call to this method so that you can
     * catch and handle its exceptions properly. If you are usure or know that
     * there may be at least one other client of the <code>Server</code> in
     * the VM instance, you should call <code>System.runFinalization()</code>
     * after ensuring you no longer have a reference. In this case, if there is
     * no other reference to the object in the VM, finalization will be called
     * (but you will be unable to catch <code>ShutdownException</code>
     * variants, if thrown).
     * <p>
     * </p>
     * Right before this is finished, the instance is removed from the server
     * instances map.
     *
     * @throws ServerShutdownException
     *         If a severe server shutdown-related error occurred.
     *         USER_REPRESENTED = addName(new XacmlName(this,
     *         "subjectRepresented"));
     * @throws ModuleShutdownException
     *         If a severe module shutdown-related error occurred.
     */
    public final void shutdown(Context context) throws ServerShutdownException,
            ModuleShutdownException, AuthzException {

        logger.info("Shutting down server");
        Throwable mse = null;
        try{
            m_moduleContext.close();
            m_moduleContext.destroy();
        }
        catch(Throwable e){
            logger.error("Shutdown error: " + e.toString(),e);
            mse = e;
        }

        shutdownServer();
        logger.info("Server shutdown complete");
        s_instances.remove(getHomeDir());

        if (mse != null) {
            throw new ServerShutdownException(mse.toString());
        }
    }

    /**
     * Performs shutdown tasks for the server itself. This should be written so
     * that system resources are always freed, regardless of whether there is an
     * error. If an error occurs, it should be thrown as a
     * <code>ServerShutdownException</code> after attempts to free every
     * resource have been made.
     *
     * @throws ServerShutdownException
     *         If a severe server shutdown-related error occurred.
     */
    protected void shutdownServer() throws ServerShutdownException {
        if (1 == 2) {
            throw new ServerShutdownException(null);
        }
    }

    /**
     * Calls <code>shutdown()</code> when finalization occurs.
     *
     * @throws ServerShutdownException
     *         If a severe server shutdown-related error occurred.
     * @throws ModuleShutdownException
     *         If a severe module shutdown-related error occurred.
     */
    @Override
    public final void finalize() throws ServerShutdownException,
            ModuleShutdownException {
        shutdownServer();
    }

    public final static Locale getLocale() {
        if (s_locale == null) {
            String language = System.getProperty("locale.language");
            String country = System.getProperty("locale.country");
            String variant = System.getProperty("locale.variant");
            if (language != null && country != null) {
                if (variant != null) {
                    s_locale = new Locale(language, country, variant);
                } else {
                    s_locale = new Locale(language, country);
                }
            } else {
                s_locale = Locale.getDefault();
            }
        }
        return s_locale;
    }

    public String getConfigSummary() {
        int i;
        StringBuffer out = new StringBuffer();
        out.append("[ Fedora Server Configuration Summary ]\n\n");
        out.append("Server class     : " + this.getClass().getName() + "\n");
        out.append("Required modules : ");
        String padding = "                   ";
        String[] roles = getRequiredModuleRoles();
        if (roles.length == 0) {
            out.append("<none>\n");
        } else {
            for (i = 0; i < roles.length; i++) {
                if (i > 0) {
                    out.append(padding);
                }
                out.append(roles[i] + "\n");
            }
        }
        out.append("Parameters       : ");
        Iterator<String> iter = parameterNames();
        i = 0;
        while (iter.hasNext()) {
            String name = iter.next();
            String value = getParameter(name);
            if (i > 0) {
                out.append(padding);
            }
            out.append(name + "=" + value + "\n");
            i++;
        }
        if (i == 0) {
            out.append("<none>\n");
        }

        iter = loadedModuleRoles();
        while (iter.hasNext()) {
            String role = iter.next();
            out.append("\nLoaded Module : " + role + "\n");
            Module module = getModule(role);
            out.append("Class         : " + module.getClass().getName() + "\n");
            out.append("Dependencies  : "
                    + module.getRequiredModuleRoles().length + "\n");
            for (i = 0; i < module.getRequiredModuleRoles().length; i++) {
                out.append("Dependency    : "
                        + module.getRequiredModuleRoles()[i] + "\n");
            }
            out.append("Parameters    : ");
            padding = "                ";
            i = 0;
            Iterator<String> iter2 = module.parameterNames();
            while (iter2.hasNext()) {
                String name = iter2.next();
                String value = module.getParameter(name);
                if (i > 0) {
                    out.append(padding);
                }
                out.append(name + "=" + value + "\n");
                i++;
            }
            if (i == 0) {
                out.append("<none>\n");
            }
        }

        iter = datastoreConfigIds();
        while (iter.hasNext()) {
            String id = iter.next();
            out.append("\nDatastore Cfg : " + id + "\n");
            out.append("Parameters    : ");
            padding = "                ";
            i = 0;
            Iterator<String> iter2 =
                    (getDatastoreConfig(id)).parameterNames();
            while (iter2.hasNext()) {
                String name = iter2.next();
                String value =
                        (getDatastoreConfig(id))
                                .getParameter(name);
                if (i > 0) {
                    out.append(padding);
                }
                out.append(name + "=" + value + "\n");
                i++;
            }
            if (i == 0) {
                out.append("<none>\n");
            }
        }

        return out.toString();
    }


    // Wraps PID constructor, throwing a ServerException instead
    public static PID getPID(String pidString) throws MalformedPidException {
        try {
            return new PID(pidString);
        } catch (MalformedPIDException e) {
            throw new MalformedPidException(e.getMessage());
        }
    }

    // Wraps PID.fromFilename, throwing a ServerException instead
    public static PID pidFromFilename(String filename)
            throws MalformedPidException {
        try {
            return PID.fromFilename(filename);
        } catch (MalformedPIDException e) {
            throw new MalformedPidException(e.getMessage());
        }
    }

    /**
     * Get the current date from the context. If the context doesn't specify a
     * value for the current date, or the specified value cannot be parsed as an
     * ISO8601 date string, a GeneralException will be thrown.
     */
    public static Date getCurrentDate(Context context) throws GeneralException {

        String propName = Constants.ENVIRONMENT.CURRENT_DATE_TIME.uri;
        String dateTimeValue = context.getEnvironmentValue(propName);
        if (dateTimeValue == null) {
            throw new GeneralException("Missing value for environment "
                    + "context attribute: " + propName);
        }

        try {
            return DateUtility.parseDateStrict(dateTimeValue);
        } catch (ParseException e) {
            throw new GeneralException(e.getMessage());
        }
    }

    /**
     * Gets the server configuration.
     *
     * @return the server configuration.
     */
    public static ServerConfiguration getConfig() {
        try {
            InputStream fcfg = new FileInputStream(
                    new File(Constants.FEDORA_HOME,
                             "server/config/fedora.fcfg"));
            ServerConfigurationParser parser =
                new ServerConfigurationParser(fcfg);
            return parser.parse();
        } catch (IOException e) {
            throw new FaultException("Error loading server configuration",
                                     e);
        }
    }

    /**
     * Initializes the web client http connection settings.
     */
    private void initWebClientConfig() {
        m_webClientConfig = new WebClientConfiguration();

        if (getParameter("httpClientTimeoutSecs") != null)
            m_webClientConfig.setTimeoutSecs(Integer.parseInt(getParameter("httpClientTimeoutSecs")));

        if (getParameter("httpClientSocketTimeoutSecs") != null)
            m_webClientConfig.setSockTimeoutSecs(Integer.parseInt(getParameter("httpClientSocketTimeoutSecs")));

        if (getParameter("httpClientMaxConnectionsPerHost") != null)
            m_webClientConfig.setMaxConnPerHost(Integer.parseInt(getParameter("httpClientMaxConnectionsPerHost")));

        if (getParameter("httpClientMaxTotalConnections") != null)
            m_webClientConfig.setMaxTotalConn(Integer.parseInt(getParameter("httpClientMaxTotalConnections")));

        if (getParameter("httpClientFollowRedirects") != null)
            m_webClientConfig.setFollowRedirects(Boolean.parseBoolean(getParameter("httpClientFollowRedirects")));

        if (getParameter("httpClientMaxFollowRedirects") != null)
            m_webClientConfig.setMaxRedirects(Integer.parseInt(getParameter("httpClientMaxFollowRedirects")));

        if (getParameter("httpClientUserAgent") != null)
            m_webClientConfig.setUserAgent(getParameter("httpClientUserAgent"));
    }

    /**
     * Gets the web client http connection configuration object.
     * @return the web client http connection configuration
     */
    public WebClientConfiguration getWebClientConfig() {
        return m_webClientConfig;
    }
   
    protected boolean knownBeanDefinition(String beanName) {
        return m_moduleContext.containsBeanDefinition(beanName)
               || m_moduleContext.getParent().containsBeanDefinition(beanName);
    }

    // Spring methods
    @Override
    public boolean containsBeanDefinition(String beanName) {
        return m_moduleContext.containsBeanDefinition(beanName);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName)
            throws NoSuchBeanDefinitionException {
        return m_moduleContext.getBeanDefinition(beanName);
    }

    @Override
    public int getBeanDefinitionCount() {
        return m_moduleContext.getBeanDefinitionCount();
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return m_moduleContext.getBeanDefinitionNames();
    }

    @Override
    public boolean isBeanNameInUse(String beanName) {
        return m_moduleContext.isBeanNameInUse(beanName);
    }

    @Override
    public void removeBeanDefinition(String beanName)
            throws NoSuchBeanDefinitionException {
        m_moduleContext.removeBeanDefinition(beanName);
    }

    @Override
    public String[] getAliases(String name) {
        return m_moduleContext.getAliases(name);
    }

    @Override
    public boolean isAlias(String beanName) {
        return m_moduleContext.isAlias(beanName);
    }

    @Override
    public void registerAlias(String beanName, String alias) {
        m_moduleContext.registerAlias(beanName, alias);
    }

    @Override
    public void removeAlias(String alias) {
        m_moduleContext.removeAlias(alias);
    }

    @Override
    public String[] getBeanNamesForType(Class type) {
        return m_moduleContext.getBeanNamesForType(type);
    }

    @Override
    public String[] getBeanNamesForType(Class type,
                                        boolean includeNonSingletons,
                                        boolean allowEagerInit) {
        return m_moduleContext.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    }

    @Override
    public <T> Map<String,T> getBeansOfType(Class<T> type) throws BeansException {
        return m_moduleContext.getBeansOfType(type);
    }

    @Override
    public <T> Map<String,T> getBeansOfType(Class<T> type,
                              boolean includeNonSingletons,
                              boolean allowEagerInit) throws BeansException {
        return m_moduleContext.getBeansOfType(type, includeNonSingletons, allowEagerInit);
    }

    @Override
    public <T>T getBean(String name, Class <T> type)
            throws BeansException {
        return m_moduleContext.getBean(name, type);
    }

    @Override
    public <T>T getBean(Class <T> requiredType)
        throws BeansException {
        return m_moduleContext.getBean(requiredType);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return m_moduleContext.getBean(name, args);
    }

    @Override
    public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return m_moduleContext.getType(name);
    }

    @Override
    public boolean isPrototype(String name)
            throws NoSuchBeanDefinitionException {
        return m_moduleContext.isPrototype(name);
    }

    @Override
    public boolean isSingleton(String name)
            throws NoSuchBeanDefinitionException {
        return m_moduleContext.isSingleton(name);
    }

    @Override
    public boolean isTypeMatch(String name, Class targetType)
            throws NoSuchBeanDefinitionException {
        return m_moduleContext.isTypeMatch(name, targetType);
    }

    @Override
    public Map<String,Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
            throws BeansException {
        return m_moduleContext.getBeansWithAnnotation(annotationType);
    }

    @Override
    public <T extends Annotation> T findAnnotationOnBean(String beanName, Class<T> annotationType)
        {
        return m_moduleContext.findAnnotationOnBean(beanName, annotationType);
        }
}
TOP

Related Classes of org.fcrepo.server.Server

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.