org.apache.jk.config.WebXml2Jk.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.jk.config.WebXml2Jk.java

Source

/*
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */
package org.apache.jk.config;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.Hashtable;
import java.util.Vector;

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

import org.apache.tomcat.util.IntrospectionUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/* Naming conventions:
    
JK_CONF_DIR == serverRoot/work  ( XXX /jkConfig ? )
    
- Each vhost has a sub-dir named after the canonycal name
    
- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
    
- In httpd.conf ( or equivalent servers ), in each virtual host you
should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
file will contain the Alias declarations and other rules required
for apache operation. Same for other servers. 
    
- WebXml2Jk will be invoked by a config tool or automatically for each
webapp - it'll generate the WEBAPP.jkmap files and config fragments.
    
WebXml2Jk will _not_ generate anything else but mappings.
It should _not_ try to guess locations or anything else - that's
another components' job.
    
*/

/**
 * Read a web.xml file and generate the mappings for jk2.
 * It can be used from the command line or ant.
 * 
 * In order for the web server to serve static pages, all webapps
 * must be deployed on the computer that runs Apache, IIS, etc.
 *
 * Dynamic pages can be executed on that computer or other servers
 * in a pool, but even if the main server doesn't run tomcat,
 * it must have all the static files and WEB-INF/web.xml.
 * ( you could have a script remove everything else, including jsps - if
 *  security paranoia is present ).
 *
 * XXX We could have this in WEB-INF/urimap.properties.
 *
 * @author Costin Manolache
 */
public class WebXml2Jk {
    String vhost = "";
    String cpath = "";
    String docBase;
    String file;
    String worker = "lb";

    // -------------------- Settings -------------------- 

    // XXX We can also generate location-independent mappings.

    /** Set the canonycal name of the virtual host.
     */
    public void setHost(String vhost) {
        this.vhost = vhost;
    }

    /** Set the canonical name of the virtual host.
     */
    public void setContext(String contextPath) {
        this.cpath = contextPath;
    }

    /** Set the base directory where the application is
     *  deployed ( on the web server ).
     */
    public void setDocBase(String docBase) {
        this.docBase = docBase;
    }

    // Automatically generated.
    //     /** The file where the jk2 mapping will be generated
    //      */
    //     public void setJk2Conf( String outFile ) {
    //         file=outFile;
    //         type=CONFIG_JK2_URIMAP;
    //     }

    //     /** Backward compat: generate JkMounts for mod_jk1
    //      */
    //     public void setJkmountFile( String outFile ) {
    //         file=outFile;
    //         type=CONFIG_JK_MOUNT;
    //     }

    /* By default we map to the lb - in jk2 this is automatically
     * created and includes all  tomcat instances.
     *
     * This is equivalent to the worker in jk1.
     */
    public void setGroup(String route) {
        worker = route;
    }

    // -------------------- Generators --------------------
    public static interface MappingGenerator {
        void setWebXmlReader(WebXml2Jk wxml);

        /** Start section( vhost declarations, etc )
         */
        void generateStart() throws IOException;

        void generateEnd() throws IOException;

        void generateServletMapping(String servlet, String url) throws IOException;

        void generateFilterMapping(String servlet, String url) throws IOException;

        void generateLoginConfig(String loginPage, String errPage, String authM) throws IOException;

        void generateErrorPage(int err, String location) throws IOException;

        void generateConstraints(Vector urls, Vector methods, Vector roles, boolean isSSL) throws IOException;
    }

    // -------------------- Implementation --------------------
    Node webN;
    File jkDir;

    /** Return the top level node
     */
    public Node getWebXmlNode() {
        return webN;
    }

    public File getJkDir() {
        return jkDir;
    }

    /** Extract the wellcome files from the web.xml
     */
    public Vector getWellcomeFiles() {
        Node n0 = getChild(webN, "welcome-file-list");
        Vector wF = new Vector();
        if (n0 != null) {
            for (Node mapN = getChild(webN, "welcome-file"); mapN != null; mapN = getNext(mapN)) {
                wF.addElement(getContent(mapN));
            }
        }
        // XXX Add index.html, index.jsp
        return wF;
    }

    void generate(MappingGenerator gen) throws IOException {
        gen.generateStart();
        log.info("Generating mappings for servlets ");
        for (Node mapN = getChild(webN, "servlet-mapping"); mapN != null; mapN = getNext(mapN)) {

            String serv = getChildContent(mapN, "servlet-name");
            String url = getChildContent(mapN, "url-pattern");

            gen.generateServletMapping(serv, url);
        }

        log.info("Generating mappings for filters ");
        for (Node mapN = getChild(webN, "filter-mapping"); mapN != null; mapN = getNext(mapN)) {

            String filter = getChildContent(mapN, "filter-name");
            String url = getChildContent(mapN, "url-pattern");

            gen.generateFilterMapping(filter, url);
        }

        for (Node mapN = getChild(webN, "error-page"); mapN != null; mapN = getNext(mapN)) {
            String errorCode = getChildContent(mapN, "error-code");
            String location = getChildContent(mapN, "location");

            if (errorCode != null && !"".equals(errorCode)) {
                try {
                    int err = new Integer(errorCode).intValue();
                    gen.generateErrorPage(err, location);
                } catch (Exception ex) {
                    log.error("Format error " + location, ex);
                }
            }
        }

        Node lcN = getChild(webN, "login-config");
        if (lcN != null) {
            log.info("Generating mapping for login-config ");

            String authMeth = getContent(getChild(lcN, "auth-method"));
            String realm = getContent(getChild(lcN, "realm-name"));
            if (authMeth == null)
                authMeth = "BASIC";

            Node n1 = getChild(lcN, "form-login-config");
            String loginPage = getChildContent(n1, "form-login-page");
            String errPage = getChildContent(n1, "form-error-page");

            if (loginPage != null) {
                int lpos = loginPage.lastIndexOf("/");
                String jscurl = loginPage.substring(0, lpos + 1) + "j_security_check";
                gen.generateLoginConfig(jscurl, errPage, authMeth);
            }
        }

        log.info("Generating mappings for security constraints ");
        for (Node mapN = getChild(webN, "security-constraint"); mapN != null; mapN = getNext(mapN)) {

            Vector methods = new Vector();
            Vector urls = new Vector();
            Vector roles = new Vector();
            boolean isSSL = false;

            Node wrcN = getChild(mapN, "web-resource-collection");
            for (Node uN = getChild(wrcN, "http-method"); uN != null; uN = getNext(uN)) {
                methods.addElement(getContent(uN));
            }
            for (Node uN = getChild(wrcN, "url-pattern"); uN != null; uN = getNext(uN)) {
                urls.addElement(getContent(uN));
            }

            // Not used at the moment
            Node acN = getChild(mapN, "auth-constraint");
            for (Node rN = getChild(acN, "role-name"); rN != null; rN = getNext(rN)) {
                roles.addElement(getContent(rN));
            }

            Node ucN = getChild(mapN, "user-data-constraint");
            String transp = getContent(getChild(ucN, "transport-guarantee"));
            if (transp != null) {
                if ("INTEGRAL".equalsIgnoreCase(transp) || "CONFIDENTIAL".equalsIgnoreCase(transp)) {
                    isSSL = true;
                }
            }

            gen.generateConstraints(urls, methods, roles, isSSL);
        }
        gen.generateEnd();
    }

    // -------------------- Main and ant wrapper --------------------

    public void execute() {
        try {
            if (docBase == null) {
                log.error(
                        "No docbase - please specify the base directory of you web application ( -docBase PATH )");
                return;
            }
            if (cpath == null) {
                log.error("No context - please specify the mount ( -context PATH )");
                return;
            }
            File docbF = new File(docBase);
            File wXmlF = new File(docBase, "WEB-INF/web.xml");

            Document wXmlN = readXml(wXmlF);
            if (wXmlN == null)
                return;

            webN = wXmlN.getDocumentElement();
            if (webN == null) {
                log.error("Can't find web-app");
                return;
            }

            jkDir = new File(docbF, "WEB-INF/jk2");
            jkDir.mkdirs();

            MappingGenerator generator = new GeneratorJk2();
            generator.setWebXmlReader(this);
            generate(generator);

            generator = new GeneratorJk1();
            generator.setWebXmlReader(this);
            generate(generator);

            generator = new GeneratorApache2();
            generator.setWebXmlReader(this);
            generate(generator);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String args[]) {
        try {
            if (args.length == 1 && ("-?".equals(args[0]) || "-h".equals(args[0]))) {
                System.out.println("Usage: ");
                System.out.println("  WebXml2Jk [OPTIONS]");
                System.out.println();
                System.out.println("  -docBase DIR        The location of the webapp. Required");
                System.out.println(
                        "  -group GROUP        Group, if you have multiple tomcats with diffrent content. ");
                System.out.println("                      The default is 'lb', and should be used in most cases");
                System.out.println("  -host HOSTNAME      Canonical hostname - for virtual hosts");
                System.out.println("  -context /CPATH     Context path where the app will be mounted");
                return;
            }

            WebXml2Jk w2jk = new WebXml2Jk();

            /* do ant-style property setting */
            IntrospectionUtils.processArgs(w2jk, args, new String[] {}, null, new Hashtable());
            w2jk.execute();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
            .getLog(WebXml2Jk.class);

    // -------------------- DOM utils --------------------

    /** Get the content of a node
     */
    public static String getContent(Node n) {
        if (n == null)
            return null;
        Node n1 = n.getFirstChild();
        // XXX Check if it's a text node

        String s1 = n1.getNodeValue();
        return s1.trim();
    }

    /** Get the first child
     */
    public static Node getChild(Node parent, String name) {
        if (parent == null)
            return null;
        Node first = parent.getFirstChild();
        if (first == null)
            return null;
        for (Node node = first; node != null; node = node.getNextSibling()) {
            //System.out.println("getNode: " + name + " " + node.getNodeName());
            if (name.equals(node.getNodeName())) {
                return node;
            }
        }
        return null;
    }

    /** Get the first child's content ( i.e. it's included TEXT node )
     */
    public static String getChildContent(Node parent, String name) {
        Node first = parent.getFirstChild();
        if (first == null)
            return null;
        for (Node node = first; node != null; node = node.getNextSibling()) {
            //System.out.println("getNode: " + name + " " + node.getNodeName());
            if (name.equals(node.getNodeName())) {
                return getContent(node);
            }
        }
        return null;
    }

    /** Get the node in the list of siblings
     */
    public static Node getNext(Node current) {
        Node first = current.getNextSibling();
        String name = current.getNodeName();
        if (first == null)
            return null;
        for (Node node = first; node != null; node = node.getNextSibling()) {
            //System.out.println("getNode: " + name + " " + node.getNodeName());
            if (name.equals(node.getNodeName())) {
                return node;
            }
        }
        return null;
    }

    public static class NullResolver implements EntityResolver {
        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            System.out.println("ResolveEntity: " + publicId + " " + systemId);
            return new InputSource(new StringReader(""));
        }
    }

    public static Document readXml(File xmlF) throws SAXException, IOException, ParserConfigurationException {
        if (!xmlF.exists()) {
            log.error("No xml file " + xmlF);
            return null;
        }
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        dbf.setValidating(false);
        dbf.setIgnoringComments(false);
        dbf.setIgnoringElementContentWhitespace(true);
        //dbf.setCoalescing(true);
        //dbf.setExpandEntityReferences(true);

        DocumentBuilder db = null;
        db = dbf.newDocumentBuilder();
        db.setEntityResolver(new NullResolver());

        // db.setErrorHandler( new MyErrorHandler());

        Document doc = db.parse(xmlF);
        return doc;
    }

}