Package org.apache.shale.remoting.faces

Source Code of org.apache.shale.remoting.faces.MappingsHelper

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shale.remoting.faces;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.context.FacesContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shale.remoting.Constants;
import org.apache.shale.remoting.Mapping;
import org.apache.shale.remoting.Mappings;
import org.apache.shale.remoting.Mechanism;
import org.apache.shale.remoting.Processor;
import org.apache.shale.remoting.impl.FilteringProcessor;
import org.apache.shale.remoting.impl.MappingImpl;
import org.apache.shale.remoting.impl.MappingsImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
* <p>Helper bean for accessing the {@link Mappings} instance for this
* application, creating it the first time if necessary.</p>
*
* @since 1.0.1
*/
public class MappingsHelper {


    // ------------------------------------------------------ Instance Variables


    /**
     * <p><code>ResourceBundle</code> containing our localized messages.</p>
     */
    private ResourceBundle bundle =
            ResourceBundle.getBundle("org.apache.shale.remoting.Bundle");


    /**
     * <p>Log instance for this class.</p>
     */
    private transient Log log = null;


    // ---------------------------------------------------------- Public Methods


    /**
     * <p>Return the {@link Mappings} instance for this web application,
     * creating it if necessary.</p>
     *
     * @param context <code>FacesContext</code> for the current request
     */
    public Mappings getMappings(FacesContext context) {

        Mappings mappings = (Mappings)
            context.getExternalContext().getApplicationMap().
                get(Constants.MAPPINGS_ATTR);
        if (mappings == null) {
            mappings = createMappings(context);
            context.getExternalContext().getApplicationMap().
                    put(Constants.MAPPINGS_ATTR, mappings);
        }
        return mappings;

    }


    // --------------------------------------------------------- Private Methods


    /**
     * <p>Configure {@link Mapping} instances on the specified {@link Mappings}
     * instance, for the specified context initialization parameter.</p>
     *
     * @param context <code>FacesContext</code> for the current request
     * @param mappings {@link Mappings} instance being configured
     * @param paramName Context initialization parameter name to process
     * @param excludesName Context initialization parameter containing our
     *  exclude patterns
     * @param excludesDefault Default exclude patterns if none are configured
     * @param includesName Context initialization parameter containing our
     *  include patterns
     * @param includesDefault Default include patterns if none are configured
     * @param mechanism {@link Mechanism} to configure on created instances
     * @param defaultValue Default value (if any) if not specified
     *
     * @exception FacesException if a new Mapping instance cannot be created
     *  or configured
     */
    private void configureMappings(FacesContext context, Mappings mappings,
                                   String paramName,
                                   String excludesName, String excludesDefault,
                                   String includesName, String includesDefault,
                                   Mechanism mechanism, String defaultValue) {

        // Identify the Mapping implementation class to be used
        Class clazz = MappingImpl.class;
        String mappingClass =
          context.getExternalContext().getInitParameter(Constants.MAPPING_CLASS);
        if (mappingClass != null) {
            try {
                clazz = loadClass(mappingClass);
            } catch (Exception e) {
                throw new FacesException(e);
            }
        }

        // Acquire the context initialization parameter value (or default it)
        String paramValue = context.getExternalContext().getInitParameter(paramName);
        if (paramValue == null) {
            paramValue = defaultValue;
        }
        if (paramValue == null) {
            return;
        }

        // Configure new Mapping instances for each specified pattern:classname pair
        while (true) {
            paramValue = paramValue.trim();
            if (paramValue.length() == 0) {
                break;
            }
            String pair = null;
            int comma = paramValue.indexOf(',');
            if (comma >= 0) {
                pair = paramValue.substring(0, comma).trim();
                paramValue = paramValue.substring(comma + 1);
            } else {
                pair = paramValue.trim();
                paramValue = "";
            }
            int colon = pair.indexOf(':');
            if (colon < 0) {
                throw new IllegalArgumentException(pair);
            }
            String pattern = pair.substring(0, colon).trim();
            String processorClass = pair.substring(colon + 1).trim();
            if (log().isInfoEnabled()) {
                log().info(bundle.getString("mapping.configure"));
                log().info(pattern + ":" + processorClass);
            }
            Class processorClazz = null;
            try {
                processorClazz = loadClass(processorClass);
            } catch (Exception e) {
                throw new FacesException(e);
            }
            try {
                Mapping mapping = (Mapping) clazz.newInstance();
                mapping.setMappings(mappings);
                mapping.setMechanism(mechanism);
                mapping.setPattern(pattern);
                Processor processor = (Processor) processorClazz.newInstance();
                if (processor instanceof FilteringProcessor) {
                    String excludesPatterns =
                      context.getExternalContext().getInitParameter(excludesName);
                    if (excludesPatterns == null) {
                        excludesPatterns = excludesDefault;
                    }
                    ((FilteringProcessor) processor).setExcludes(excludesPatterns);
                    String includesPatterns =
                      context.getExternalContext().getInitParameter(includesName);
                    if (includesPatterns == null) {
                        includesPatterns = includesDefault;
                    }
                    ((FilteringProcessor) processor).setIncludes(includesPatterns);
                }
                mapping.setProcessor(processor);
                mappings.addMapping(mapping);
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new FacesException(e);
            }
        }

    }


    /**
     * <p>Create and configure a {@link Mappings} instance based on the relevant
     * context initialization parameters for this web application.</p>
     *
     * @param context <code>FacesContext</code> for the current request
     *
     * @exception FacesException if a new Mappings instance cannot be created
     *  or configured
     */
    private Mappings createMappings(FacesContext context) {

        // Instantiate a Mappings instance to configure
        Mappings mappings = null;
        String mappingsClass = MappingsImpl.class.getName();
        String mappingsClassParam =
          context.getExternalContext().getInitParameter(Constants.MAPPINGS_CLASS);
        if (mappingsClassParam != null) {
            mappingsClass = mappingsClassParam;
        }
        Class clazz = null;
        try {
            if (log().isInfoEnabled()) {
                log().info(bundle.getString("mappings.configure"));
                log().info(mappingsClass);
            }
            clazz = loadClass(mappingsClass);
        } catch (Exception e) {
            throw new FacesException(e);
        }
        try {
            mappings = (Mappings) clazz.newInstance();
        } catch (Exception e) {
            throw new FacesException(e);
        }

        // Configure the Mapping instances for this Mappings instance
        configureMappings(context, mappings, Constants.CLASS_RESOURCES_PARAM,
                          Constants.CLASS_RESOURCES_EXCLUDES,
                          Constants.CLASS_RESOURCES_EXCLUDES_DEFAULT,
                          Constants.CLASS_RESOURCES_INCLUDES,
                          Constants.CLASS_RESOURCES_INCLUDES_DEFAULT,
                          Mechanism.CLASS_RESOURCE,
                          "/static/*:org.apache.shale.remoting.impl.ClassResourceProcessor");
        configureMappings(context, mappings, Constants.DYNAMIC_RESOURCES_PARAM,
                          Constants.DYNAMIC_RESOURCES_EXCLUDES,
                          Constants.DYNAMIC_RESOURCES_EXCLUDES_DEFAULT,
                          Constants.DYNAMIC_RESOURCES_INCLUDES,
                          Constants.DYNAMIC_RESOURCES_INCLUDES_DEFAULT,
                          Mechanism.DYNAMIC_RESOURCE,
                          "/dynamic/*:org.apache.shale.remoting.impl.MethodBindingProcessor");
        configureMappings(context, mappings, Constants.OTHER_RESOURCES_PARAM,
                          Constants.OTHER_RESOURCES_EXCLUDES,
                          Constants.OTHER_RESOURCES_EXCLUDES_DEFAULT,
                          Constants.OTHER_RESOURCES_INCLUDES,
                          Constants.OTHER_RESOURCES_INCLUDES_DEFAULT,
                          Mechanism.OTHER_RESOURCE,
                          null);
        configureMappings(context, mappings, Constants.WEBAPP_RESOURCES_PARAM,
                          Constants.WEBAPP_RESOURCES_EXCLUDES,
                          Constants.WEBAPP_RESOURCES_EXCLUDES_DEFAULT,
                          Constants.WEBAPP_RESOURCES_INCLUDES,
                          Constants.WEBAPP_RESOURCES_INCLUDES_DEFAULT,
                          Mechanism.WEBAPP_RESOURCE,
                          "/webapp/*:org.apache.shale.remoting.impl.WebResourceProcessor");

        // Calculate and set the replacement extension, to be used
        // if FacesServlet is extension mapped
        String extension = context.getExternalContext().
                getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
        if (extension == null) {
            extension = ViewHandler.DEFAULT_SUFFIX;
        }
        mappings.setExtension(extension);

        // Calculate and set the URL patterns that FacesServlet is mapped with
        // FIXME - hard coded to "*.faces" for now
        String[] patterns = patterns(context);
        if (log().isTraceEnabled()) {
            for (int i = 0; i < patterns.length; i++) {
                log().trace("FacesServlet is mapped with URL pattern '" + patterns[i] + "'");
            }
        }
        mappings.setPatterns(patterns);

        // Calculate the index of the pattern to use by default
        int patternIndex = 0;
        String patternIndexString =
          context.getExternalContext().getInitParameter(Constants.FACES_SERVLET_URL_PARAM);
        if (patternIndexString != null) {
            patternIndex = Integer.parseInt(patternIndexString.trim());
        }
        if (patternIndex >= patterns.length) {
            log.warn("FacesServlet pattern index of " + patternIndex
                     + " does not match any specified pattern");
        }
        mappings.setPatternIndex(patternIndex);

        // Return the configured Mappings instance
        return mappings;

    }


    /**
     * <p>Load the specified class from the web application class loader
     * (if possible).</p>
     *
     * @param name Fully qualified class name
     *
     * @exception ClassNotFoundException if the specified class cannot
     *  be loaded
     */
    private Class loadClass(String name) throws ClassNotFoundException {

        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            cl = this.getClass().getClassLoader();
        }
        return cl.loadClass(name);

    }


    /**
     * <p>Return the <code>Log</code> instance to use, creating one if needed.</p>
     */
    private Log log() {

        if (this.log == null) {
            log = LogFactory.getLog(MappingsHelper.class);
        }
        return log;

    }


    /**
     * <p>Return an array of URL patterns that <code>FacesServlet</code> is
     * mapped to for this application.</p>
     *
     * @param context <code>FacesContext</code> for the current request
     */
    private String[] patterns(FacesContext context) {

        Document document = null;
        InputStream stream = null;

        try {

            // Acquire a URL for /WEB-INF/web.xml (if any)
            Object ctxt = context.getExternalContext().getContext();
            Method method =
                    ctxt.getClass().getMethod("getResource",
                                              new Class[] { String.class });
            URL url = (URL) method.invoke(ctxt, new Object[] { "/WEB-INF/web.xml" });
            if (url == null) {
                if (log().isTraceEnabled()) {
                    log().trace("No /WEB-INF/web.xml resource available, returning empty list");
                }
                return new String[0];
            }

            // Parse this resource into a DOM tree
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            stream = url.openStream();
            document = db.parse(stream);

        } catch (Exception e) {

            if (log().isErrorEnabled()) {
                log().error(bundle.getString("mappings.parseWebXml"), e);
            }
            return new String[0];

        } finally {

            if (stream != null) {
                try { stream.close(); } catch (Exception e) { ; }
            }

        }

        // Identify the servlet name of the JavaServer Faces controller servlet
        String name =
                context.getExternalContext().getInitParameter(Constants.FACES_SERVLET_NAME_PARAM);
        if (null == name) {
            NodeList servletNodes = document.getElementsByTagName("servlet");
            for (int i = 0; i < servletNodes.getLength(); i++) {
                Node servletNode = servletNodes.item(i);
                String servletName = null;
                String servletClass = null;
                NodeList kids = servletNode.getChildNodes();
                for (int j = 0; j < kids.getLength(); j++) {
                    Node kid = kids.item(j);
                    if ("servlet-name".equals(kid.getNodeName())) {
                        servletName = text(kid);
                    } else if ("servlet-class".equals(kid.getNodeName())) {
                        servletClass = text(kid);
                    }
                }
                if ("javax.faces.webapp.FacesServlet".equals(servletClass)) {
                    name = servletName;
                }
            }
        }

        // Identify the URL patterns to which this servlet is mapped
        List list = new ArrayList();
        NodeList mappingNodes = document.getElementsByTagName("servlet-mapping");
        for (int i = 0; i < mappingNodes.getLength(); i++) {
            Node mappingNode = mappingNodes.item(i);
            String servletName = null;
            String urlPattern = null;
            NodeList kids = mappingNode.getChildNodes();
            for (int j = 0; j < kids.getLength(); j++) {
                Node kid = kids.item(j);
                if ("servlet-name".equals(kid.getNodeName())) {
                    servletName = text(kid);
                } else if ("url-pattern".equals(kid.getNodeName())) {
                    urlPattern = text(kid);
                }
            }
            if (name.equals(servletName)) {
                list.add(urlPattern);
            }
        }

        // Return the resulting list
        return (String[]) list.toArray(new String[list.size()]);

    }


    /**
     * <p>Return the text content inside the specified node.</p>
     *
     * @param node Node from which text is to be extracted
     */
    private String text(Node node) {

        NodeList kids = node.getChildNodes();
        for (int k = 0; k < kids.getLength(); k++) {
            Node kid = kids.item(k);
            if ("#text".equals(kid.getNodeName())) {
                return kid.getNodeValue().trim();
            }
        }
        return "";

    }


}
TOP

Related Classes of org.apache.shale.remoting.faces.MappingsHelper

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.