package org.apache.maven.struts;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2002 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 acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *    "Apache Maven" 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",
 *    "Apache Maven", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * 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/>.
 *
 * ====================================================================
 */

import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;

import org.apache.maven.j2ee.WarFile;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * Encapsulates a Struts 1.0 War File. Holds functionality to access Struts
 * specific resources and data in the war.
 * @author  dion
 * @version $Id: Struts10WarFile.java,v 1.1 2003/01/24 03:45:53 jvanzyl Exp $
 */
public class Struts10WarFile extends WarFile
{
    /** Default location of Struts configuration file in the war */
    public static final String DEFAULT_CONFIG = "WEB-INF/struts-config.xml";
    /** property for the location of the Struts configuration file in the war */
    private String config = Struts10WarFile.DEFAULT_CONFIG;
    /** Default name of the action servlet in web.xml */
    public static final String DEFAULT_ACTIONSERVLET_NAME = "action";
    /** name of the action servlet in web.xml */
    private String actionServletName = 
        Struts10WarFile.DEFAULT_ACTIONSERVLET_NAME;
    
    /** 
     * Creates a new instance of Struts10WarFile
     * @param name the {@link File file} name of a war file containing a Struts
     * web application
     * @throws IOException when an I/O error occurs
     */
    public Struts10WarFile(String name) throws IOException
    {
        super(name);
    }
    
    /** 
     * Creates a new instance of Struts10WarFile
     * @param name the {@link File file} name of a war file containing a Struts
     * web application
     * @param verify whether or not to verify the war file if it is signed
     * @throws IOException when an I/O error occurs     */
    public Struts10WarFile(String name, boolean verify) throws IOException
    {
        super(name, verify);
    }
    
    /** 
     * Creates a new instance of Struts10WarFile
     * @param warFile a J2EE .war {@link File file} containing a Struts web
     * application
     * @throws IOException when an I/O error occurs
     */
    public Struts10WarFile(File warFile) throws IOException
    {
        super(warFile);
    }

    /** 
     * Creates a new instance of Struts10WarFile
     * @param warFile a J2EE .war {@link File file} containing a Struts web
     * application
     * @param verify whether or not to verify the war file if it is signed
     * @throws IOException when an I/O error occurs
     */
    public Struts10WarFile(File warFile, boolean verify) throws IOException
    {
        super(warFile, verify);
    }

    /** 
     * Creates a new instance of Struts10WarFile
     * @param warFile a J2EE .war {@link File file} containing a Struts web
     * application
     * @param verify whether or not to verify the war file if it is signed
     * @param mode the mode in which the file is to be opened
     * @throws IOException when an I/O error occurs
     */
    public Struts10WarFile(File warFile, boolean verify, int mode) 
        throws IOException
    {
        super(warFile, verify, mode);
    }
    
    /** Provide the location of the Struts configuration file in the war.
     * @return Value of property config.
     */
    public String getConfig()
    {
        return config;
    }
    
    /** Set the location of the Struts configuration file in the war.
     * @param config New value of property config.
     */
    public void setConfig(String config)
    {
        this.config = config;
    }
    
    /**
     * Retrieves the Struts configuration (as specified by the config property)
     * entry if it exists.
     * @return a {@link JarEntry} for Struts config
     */
    public JarEntry getStrutsConfigEntry()
    {
        return getJarEntry(getConfig());
    }
 
   /** Get the Struts configuration back as a dom4j Document, for easier 
     * processing
     * @return a {@link Document} representing the web.xml
     * @throws IOException if there are any issues reading the web.xml
     * or producing the xml document
     */
    private Document getStrutsConfig() throws IOException
    {
        if (getStrutsConfigEntry() == null)
        {
            throw new IOException("Attempted to get non-existent config");
        }
        try 
        {
            SAXReader xmlReader = new SAXReader(false);
            xmlReader.setEntityResolver(new StrutsEntityResolver());
            InputStream configStream = getInputStream(getStrutsConfigEntry());
            Document configXml = xmlReader.read(configStream);
            return configXml;
        }
        catch (DocumentException de)
        {
            de.printStackTrace();
            throw new IOException(de.getMessage());
        }
    }
    
    /** retrieves the form beans defined in the struts configuration file
     * @return a collection of {@link FormBean form beans}
     * @throws IOException when there are problems reading from the war
     */
    public List getFormBeans() throws IOException
    {
        List formBeans = new ArrayList();
        Document config = getStrutsConfig();
        List formBeanNodes = config.selectNodes(
            "/struts-config/form-beans/form-bean");
        Element formBeanNode = null;
        FormBean formBean = null;
        for (Iterator nodes = formBeanNodes.iterator(); nodes.hasNext();)
        {
            formBeanNode = (Element) nodes.next();
            formBean = new FormBean();
            formBean.setClassName(formBeanNode.attributeValue("className"));
            formBean.setName(formBeanNode.attributeValue("name"));
            formBean.setType(formBeanNode.attributeValue("type"));
            formBeans.add(formBean);
        }
        
        return formBeans;
    }
    
    /** retrieve the actions defined in the struts configuration file
     * @return a {@link List] of {@link Action actions}
     * @throws IOException when there are problems reading from the war
     */
    public List getActions() throws IOException
    {
        List actions = new ArrayList();
        Document config = getStrutsConfig();
        List actionNodes = config.selectNodes(
            "/struts-config/action-mappings/action");
        Element actionNode = null;
        Action action = null;
        for (Iterator nodes = actionNodes.iterator(); nodes.hasNext();)
        {
            actionNode = (Element) nodes.next();
            action = new Action();
            action.setClassName(actionNode.attributeValue("className"));
            action.setName(actionNode.attributeValue("name"));
            action.setPath(actionNode.attributeValue("path"));
            action.setScope(actionNode.attributeValue("scope"));
            action.setType(actionNode.attributeValue("type"));
            action.setUnknown(actionNode.attributeValue("unknown"));
            action.setValidate(actionNode.attributeValue("validate"));
            actions.add(action);
        }
        return actions;
    }
    
    /** retrieves the type attribute of the &lt;form-beans&gt; element if
     * it exists, or null otherwise
     * @return the form-bean type attribute
     * @throws IOException when there are problems reading from the war
     */
    public String getFormBeansType() throws IOException
    {
        String type = null;
        Element formBeans = (Element) getStrutsConfig().selectSingleNode(
            "/struts-config/form-beans");
        if (formBeans != null)
        {
            type = formBeans.attributeValue("type");
        }
        return type;
    }
    
    /** retrieves the type attribute of the &lt;global-forwards&gt; element if
     * it exists, or null otherwise
     * @return the global-forwards type attribute
     * @throws IOException when there are problems reading from the war
     */
    public String getGlobalForwardsType() throws IOException
    {
        String type = null;
        Element forwards = (Element) getStrutsConfig().selectSingleNode(
            "/struts-config/global-forwards");
        if (forwards != null)
        {
            type = forwards.attributeValue("type");
        }
        return type;
    }

    /** retrieve the global forwards defined in the struts configuration
     * @return a {@link List} of {@link Forward forwards}
     * @throws IOException when there are problems reading from the war
     */
    public List getForwards() throws IOException
    {
        List forwards = new ArrayList();
        Document config = getStrutsConfig();
        List nodes = config.selectNodes(
            "/struts-config/global-forwards/forward");
        Element element = null;
        Forward forward = null;
        for (int index = 0; index < nodes.size(); index++)
        {
            element = (Element) nodes.get(index);
            forward = new Forward();
            forward.setName(element.attributeValue("name"));
            forward.setPath(element.attributeValue("path"));
            if (element.attribute("className") != null)
            {
                forward.setClassName(element.attributeValue("className"));
            }
            if (element.attribute("redirect") != null)
            {
                forward.setRedirect(element.attributeValue("redirect"));
            }
            forwards.add(forward);
        }
        
        return forwards;
    }
    
    /** retrieve the url pattern for the action servlet, or null if not found
     * @return the &lt;url-pattern&gt provided for the servlet named by
     *      {@link #getActionServletName}
     * @throws IOException when there are problems reading from the war
     */
    public String getActionServletPattern() throws IOException
    {
        return (String) getServletMappings().get(getActionServletName());
    }
    
    /** Getter for property actionServletName.
     * @return Value of property actionServletName.
     */
    public String getActionServletName()
    {
        return actionServletName;
    }
    
    /** Setter for property actionServletName.
     * @param actionServletName New value of property actionServletName.
     */
    public void setActionServletName(String actionServletName)
    {
        if (actionServletName == null) 
        {
            throw new NullPointerException("action servlet name can't be null");
        }
        this.actionServletName = actionServletName;
    }
    
 }
