⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 configloader.java

📁 OS(OpenSymphony)的SiteMesh是一个用来在JSP中实现页面布局和装饰(layout and decoration)的框架组件
💻 JAVA
字号:
/* * Title:        ConfigLoader * Description: * * This software is published under the terms of the OpenSymphony Software * License version 1.1, of which a copy has been included with this * distribution in the LICENSE.txt file. */package com.opensymphony.module.sitemesh.mapper;import com.opensymphony.module.sitemesh.Config;import com.opensymphony.module.sitemesh.Decorator;import com.opensymphony.module.sitemesh.factory.DefaultFactory;import org.w3c.dom.*;import org.xml.sax.SAXException;import javax.servlet.ServletException;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import java.io.File;import java.io.IOException;import java.util.HashMap;import java.util.Map;/** * The ConfigLoader reads a configuration XML file that contains Decorator definitions * (name, url, init-params) and path-mappings (pattern, name). * * <p>These can then be accessed by the getDecoratorByName() methods and getMappedName() * methods respectively.</p> * * <p>The DTD for the configuration file in old (deprecated) format is located at * <a href="http://www.opensymphony.com/dtds/sitemesh_1_0_decorators.dtd"> *  http://www.opensymphony.com/dtds/sitemesh_1_0_decorators.dtd * </a>.</p> * * <p>The DTD for the configuration file in new format is located at * <a href="http://www.opensymphony.com/dtds/sitemesh_1_5_decorators.dtd"> *  http://www.opensymphony.com/dtds/sitemesh_1_5_decorators.dtd * </a>.</p> * * <p>Editing the config file will cause it to be auto-reloaded.</p> * * <p>This class is used by ConfigDecoratorMapper, and uses PathMapper for pattern matching.</p> * * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a> * @author <a href="mailto:pathos@pandora.be">Mathias Bogaert</a> * @version $Revision: 1.8 $ * * @see com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper * @see com.opensymphony.module.sitemesh.mapper.PathMapper */public class ConfigLoader {    /**     * State visibile across threads stored in a single container so that we     * can efficiently atomically access it with the guarantee that we wont see     * a partially loaded configuration in the face of one thread reloading the     * configuration while others are trying to read it.     */    private static class State {        /**         * Timestamp of the last time we checked for an update to the         * configuration file used to rate limit the frequency at which we check         * for efficiency.         */        long lastModificationCheck = System.currentTimeMillis();        /**         * Timestamp of the modification time of the configuration file when we         * generated the state.         */        long lastModified;        /**         * Whether a thread is currently checking if the configuration file has         * been modified and potentially reloading it and therefore others         * shouldn't attempt the same till it's done.         */        boolean checking = false;        Map decorators = new HashMap();        PathMapper pathMapper = new PathMapper();    }    /**     * Mark volatile so that the installation of new versions is guaranteed to     * be visible across threads.     */    private volatile State state;    private File configFile = null;    private String configFileName = null;    private Config config = null;    /**     * Create new ConfigLoader using supplied File.     */    public ConfigLoader(File configFile) throws ServletException {        this.configFile = configFile;        this.configFileName = configFile.getName();        state = loadConfig();    }    /**     * Create new ConfigLoader using supplied filename and config.     */    public ConfigLoader(String configFileName, Config config) throws ServletException {        this.config = config;        this.configFileName = configFileName;        if (config.getServletContext().getRealPath(configFileName) != null) {            this.configFile = new File(config.getServletContext().getRealPath(configFileName));        }        state = loadConfig();    }    /**     * Retrieve Decorator based on name specified in configuration file.     */    public Decorator getDecoratorByName(String name) throws ServletException {        return (Decorator) refresh().decorators.get(name);    }    /** Get name of Decorator mapped to given path. */    public String getMappedName(String path) throws ServletException {        return refresh().pathMapper.get(path);    }    /**     * Load configuration from file.     */    private State loadConfig() throws ServletException {        // The new state which we build up and atomically replace the old state        // with atomically to avoid other threads seeing partial modifications.        State newState = new State();        try {            // Build a document from the file            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();            DocumentBuilder builder = factory.newDocumentBuilder();            Document document;            if (configFile != null && configFile.canRead()) {                // Keep time we read the file to check if the file was modified                newState.lastModified = configFile.lastModified();                document = builder.parse(configFile);            } else {                document = builder.parse(config.getServletContext().getResourceAsStream(configFileName));            }            // Parse the configuration document            parseConfig(newState, document);            return newState;        }        catch (ParserConfigurationException e) {            throw new ServletException("Could not get XML parser", e);        }        catch (IOException e) {            throw new ServletException("Could not read the config file: " + configFileName, e);        }        catch (SAXException e) {            throw new ServletException("Could not parse the config file: " + configFileName, e);        }        catch (IllegalArgumentException e) {            throw new ServletException("Could not find the config file: " + configFileName, e);        }    }    private void parseConfig(State newState, Document document) {        Element root = document.getDocumentElement();        // get the default directory for the decorators        String defaultDir = getAttribute(root, "defaultdir");        if (defaultDir == null) defaultDir = getAttribute(root, "defaultDir");        // Get decorators        NodeList decoratorNodes = root.getElementsByTagName("decorator");        Element decoratorElement;        for (int i = 0; i < decoratorNodes.getLength(); i++) {            String name, page, uriPath = null, role = null;            // get the current decorator element            decoratorElement = (Element) decoratorNodes.item(i);            if (getAttribute(decoratorElement, "name") != null) {                // The new format is used                name = getAttribute(decoratorElement, "name");                page = getAttribute(decoratorElement, "page");                uriPath = getAttribute(decoratorElement, "webapp");                role = getAttribute(decoratorElement, "role");                // Append the defaultDir                if (defaultDir != null && page != null && page.length() > 0 && !page.startsWith("/")) {                    if (page.charAt(0) == '/') page = defaultDir + page;                    else page = defaultDir + '/' + page;                }                // The uriPath must begin with a slash                if (uriPath != null && uriPath.length() > 0) {                    if (uriPath.charAt(0) != '/') uriPath = '/' + uriPath;                }                // Get all <pattern>...</pattern> and <url-pattern>...</url-pattern> nodes and add a mapping                populatePathMapper(newState, decoratorElement.getElementsByTagName("pattern"), role, name);                populatePathMapper(newState, decoratorElement.getElementsByTagName("url-pattern"), role, name);            } else {                // NOTE: Deprecated format                name = getContainedText(decoratorNodes.item(i), "decorator-name");                page = getContainedText(decoratorNodes.item(i), "resource");                // We have this here because the use of jsp-file is deprecated, but we still want                // it to work.                if (page == null) page = getContainedText(decoratorNodes.item(i), "jsp-file");            }            Map params = new HashMap();            NodeList paramNodes = decoratorElement.getElementsByTagName("init-param");            for (int ii = 0; ii < paramNodes.getLength(); ii++) {                String paramName = getContainedText(paramNodes.item(ii), "param-name");                String paramValue = getContainedText(paramNodes.item(ii), "param-value");                params.put(paramName, paramValue);            }            storeDecorator(newState, new DefaultDecorator(name, page, uriPath, role, params));        }        // Get (deprecated format) decorator-mappings        NodeList mappingNodes = root.getElementsByTagName("decorator-mapping");        for (int i = 0; i < mappingNodes.getLength(); i++) {            Element n = (Element) mappingNodes.item(i);            String name = getContainedText(mappingNodes.item(i), "decorator-name");            // Get all <url-pattern>...</url-pattern> nodes and add a mapping            populatePathMapper(newState, n.getElementsByTagName("url-pattern"), null, name);        }    }    private void populatePathMapper(State newState, NodeList patternNodes, String role, String name) {        for (int j = 0; j < patternNodes.getLength(); j++) {            Element p = (Element) patternNodes.item(j);            Text patternText = (Text) p.getFirstChild();            if (patternText != null) {                String pattern = patternText.getData().trim();                if (pattern != null) {                    if (role != null) {                        // concatenate name and role to allow more                        // than one decorator per role                        newState.pathMapper.put(name + role, pattern);                    } else {                        newState.pathMapper.put(name, pattern);                    }                }            }        }    }    private static String getAttribute(Element element, String name) {        if (element != null && element.getAttribute(name) != null && element.getAttribute(name).trim() != "") {            return element.getAttribute(name).trim();        } else {            return null;        }    }    private static String getContainedText(Node parent, String childTagName) {        try {            Node tag = ((Element) parent).getElementsByTagName(childTagName).item(0);            return ((Text) tag.getFirstChild()).getData();        }        catch (Exception e) {            return null;        }    }    private void storeDecorator(State newState, Decorator d) {        if (d.getRole() != null) {            newState.decorators.put(d.getName() + d.getRole(), d);        } else {            newState.decorators.put(d.getName(), d);        }    }    /**     * Check if configuration file has been updated, and if so, reload.     */    private State refresh() throws ServletException {        // Read the current state just once since another thread can swap        // another version in at any time.        State currentState = state;        if (configFile == null) {            return currentState;        }        // Rate limit the stat'ing of the config file to find its        // modification time to once every five seconds to reduce the        // number of system calls made. We grab the monitor of currentState        // so that we can safely read the values shared across threads and        // so that only one thread is performing the modification check at        // a time.        long current = System.currentTimeMillis();        long oldLastModified;        boolean check = false;        synchronized (currentState) {            oldLastModified = currentState.lastModified;            if (!currentState.checking && current >= currentState.lastModificationCheck + DefaultFactory.configCheckMillis) {                currentState.lastModificationCheck = current;                currentState.checking = true;                check = true;            }        }        if (check) {            // Perform the file stat'ing system call without holding a lock            // on the current state.            State newState = null;            try {                long currentLastModified = configFile.lastModified();                if (currentLastModified != oldLastModified) {                    // The configuration file has been modified since we last                    // read it so reload the configuration without holding a                    // lock on the current state and then slam down the new                    // state for other threads to see. The State.checking flag                    // being set on currentState will prevent other threads                    // from attempting to reload the state while we are and                    // the new state will have the flag cleared so that we can                    // continue checking if the configuration file is modified.                    newState = loadConfig();                    state = newState;                    return newState;                }            } finally {                // In the event of a failure of the modification time check,                // or while reloading the configuration file, mark that we're no                // longer checking if the modification time or reloading so that                // we'll retry.                if (newState == null) {                    synchronized (currentState) {                        currentState.checking = false;                    }                }            }        }        return currentState;    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -