com.icesoft.faces.webapp.parser.ComponentRuleSet.java Source code

Java tutorial

Introduction

Here is the source code for com.icesoft.faces.webapp.parser.ComponentRuleSet.java

Source

/*
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * "The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * The Original Code is ICEfaces 1.5 open source software code, released
 * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
 * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
 * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 *
 * Contributor(s): _____________________.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
 * License), in which case the provisions of the LGPL License are
 * applicable instead of those above. If you wish to allow use of your
 * version of this file only under the terms of the LGPL License and not to
 * allow others to use your version of this file under the MPL, indicate
 * your decision by deleting the provisions above and replace them with
 * the notice and other provisions required by the LGPL License. If you do
 * not delete the provisions above, a recipient may use your version of
 * this file under either the MPL or the LGPL License."
 *
 */

package com.icesoft.faces.webapp.parser;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.commons.digester.RuleSetBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;

import javax.servlet.jsp.tagext.Tag;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * This class provides a ruleset for the Apache Digester, that supports parsing
 * of a JSFX page into a tree of JSP tag processing classes.  This tree is then
 * used in the parser to mimick the JSP lifecycle in order to produce the JSF
 * component tree.
 *
 * @author Steve Maryka
 */
public class ComponentRuleSet extends RuleSetBase {

    /**
     * The tag to tag processing class map.
     */
    private TagToComponentMap map;
    private String viewTagClass;
    private String ruleNamespace;
    private static String TAG_NEST = "*/";
    private static Class setPropertiesRuleClass = null;
    private static boolean isJSF12 = false;

    private static final Log log = LogFactory.getLog(ComponentRuleSet.class);

    static {
        try {
            setPropertiesRuleClass = Class.forName("org.apache.commons.digester.SetPropertiesRule");
            //Test for JSF 1.2
            Class.forName("javax.faces.webapp.UIComponentELTag");
            setPropertiesRuleClass = Class.forName("com.icesoft.faces.webapp.parser.ELSetPropertiesRule");
            if (log.isDebugEnabled()) {
                log.debug("ICEfaces using JSF 1.2 JSP tags.");
            }
            isJSF12 = true;
        } catch (Throwable t) {
            //many different throwables besides ClassNotFoundException
            if (log.isDebugEnabled()) {
                log.debug("No JSF 1.2 classes found. Running in JSF 1.1 environment");
            }
        }
    }

    /**
     * Constructor
     *
     * @param mp  The map from tags to tag processing classes
     * @param namespaceURI 
     */
    public ComponentRuleSet(TagToComponentMap mp, String namespaceURI) {
        super();
        map = mp;
        ruleNamespace = namespaceURI;
    }

    /**
     * Detect JSF 1.2 for special cases
     *
     * @return true if JSF 1.2 is being used
     */
    public static boolean isJSF12() {
        return isJSF12;
    }

    /**
     * Adds rules for each tag in the map.
     *
     * @param digester The digester to which rules are added.
     */
    public void addRuleInstances(Digester digester) {

        Hashtable table = map.getTagToComponentMap();
        Enumeration keys = table.keys();
        TagRule tagRule = new TagRule();
        XhtmlTagRule xhtmlTagRule = new XhtmlTagRule();
        ViewTagRule viewTagRule = new ViewTagRule();

        digester.setRuleNamespaceURI(ruleNamespace);

        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            String tagType = (String) table.get(key);

            if (!key.equals("view")) {

                // Want to create tag object regardless of type;
                digester.addObjectCreate(TAG_NEST + key, tagType);

                if (tagType.equals(XhtmlTag.class.getName())) {
                    // Rules for Xhtml Tags;
                    digester.addObjectCreate(TAG_NEST + key, "com.icesoft.faces.webapp.parser.TagWire");
                    digester.addRule(TAG_NEST + key, xhtmlTagRule);
                } else {
                    // Rules for JSF Tags;
                    try {
                        digester.addRule(TAG_NEST + key, (Rule) setPropertiesRuleClass.newInstance());
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(e.getMessage(), e);
                        }
                    }
                    digester.addObjectCreate(TAG_NEST + key, "com.icesoft.faces.webapp.parser.TagWire");
                    digester.addRule(TAG_NEST + key, tagRule);
                }
            } else {

                // #2551 we do want to create the tag and wire for the viewTag
                digester.addObjectCreate(TAG_NEST + key, tagType);
                try {
                    digester.addRule(TAG_NEST + key, (Rule) setPropertiesRuleClass.newInstance());
                } catch (Exception e) {
                    if (log.isDebugEnabled()) {
                        log.debug(e.getMessage(), e);
                    }
                }
                digester.addObjectCreate(TAG_NEST + key, "com.icesoft.faces.webapp.parser.TagWire");
                digester.addRule(TAG_NEST + key, viewTagRule);

                // Capture the view tag class;
                ((JsfJspDigester) digester).setViewTagClassName(tagType);
                viewTagClass = tagType;
            }
        }
    }

    public String getViewTagClass() {
        return viewTagClass;
    }
}

/**
 * Contains base functionality for all rules.
 */
abstract class BaseRule extends Rule {

    /**
     * Constructor
     */
    public BaseRule() {
        super();
    }

    /**
     * Body processing for the rule.  The body text for this tag gets trimmed
     * up, and an outputTextTag is created to hold the body text.
     *
     * @param namespace Namespace provided by digester.
     * @param name      Name provided by digester.
     * @param text      The body text.
     */
    public void body(String namespace, String name, String text) {

        String bodyText = text.trim();
        //        System.out.println("Base Rule handles body: " + name);
        if (bodyText.length() > 0) {
            TagWire wire = (TagWire) digester.peek();
            Tag child = (Tag) digester.peek(1);
            //            System.out.println("TagWire: " + wire + " child: " + child);
            IceOutputTextTag bodyTextTag = new IceOutputTextTag();
            TagWire newWire = new TagWire();
            bodyTextTag.setValue(bodyText);
            wireUpTheTag((Tag) bodyTextTag, child, newWire, wire);
        }
    }

    /**
     * Because Tag processing classes themselves don't support a tree structure,
     * a wiring class is used to hold the tree together.  This member wires up
     * the tree appropriately.
     *
     * @param child      The child Tag
     * @param parent     The parent Tag
     * @param childWire  The child Wire
     * @param parentWire The parent Wire
     */
    protected void wireUpTheTag(Tag child, Tag parent, TagWire childWire, TagWire parentWire) {

        child.setParent(parent);
        childWire.setTag(child);
        parentWire.addChild(childWire);
    }

    /**
     * This function peeks into the digester to see if there is body text
     * assiciated with the parent.  If there is, an Output Text tag is created
     * to hold that body text.
     *
     * @param parent     The parent Tag.
     * @param parentWire The parent Wire.
     */
    protected void dealWithPreceedingBodyText(Tag parent, TagWire parentWire) {
        /* This function peeks into the digester to see if there is body text
           associated with the parent.  If there is, an OutputText component is
           created to hold that body text */

        // In this version we create an IceOutputTextTag and wire it in;

        String bodyText = ((JsfJspDigester) digester).stealParentBodyText();
        if (bodyText != null) {
            IceOutputTextTag bodyTextTag = new IceOutputTextTag();
            TagWire wire = new TagWire();
            bodyTextTag.setValue(bodyText);
            wireUpTheTag((Tag) bodyTextTag, parent, wire, parentWire);
        }
    }
}

/**
 * This class provides the rule for processing JSF tags.  The tag attributes are
 * saved and the tag is wired into the tag processing tree.
 */
final class TagRule extends BaseRule {

    /**
     * Constructor.
     */
    public TagRule() {
        super();
    }

    /**
     * The begin processing for the rule.  Saves attributes, deals with parent
     * body text, and wires up tag processing tree.
     *
     * @param attributes Attributes for the Tag.
     * @throws Exception No exception is thrown.
     */
    public void begin(Attributes attributes) throws Exception {

        // Get all the important bits off the digester stack;
        TagWire wire = (TagWire) digester.peek();
        Tag child = (Tag) digester.peek(1);
        TagWire parentWire = (TagWire) digester.peek(2);
        Tag parent = (Tag) digester.peek(3);

        Attributes cloned = clone(attributes);
        wire.setAttributes(cloned);

        // Deal with preceeding body text;
        dealWithPreceedingBodyText(parent, parentWire);

        // Wire up the tree;
        wireUpTheTag(child, parent, wire, parentWire);
    }

    /**
     * Create clone of attributes.
     *
     * @param attributes Attributes to clone.
     * @return Cloned attributes.
     */
    private Attributes clone(Attributes attributes) {
        Attributes clone = new AttributesImpl(attributes);
        for (int i = 0; i < clone.getLength(); i++) {
            String name = attributes.getQName(i);
            String value = attributes.getValue(name);
            ((AttributesImpl) clone).setLocalName(i, name);
            ((AttributesImpl) clone).setValue(i, value);
        }
        return clone;
    }
}

/**
 * A rule for processing Xhtml Tags.  Need to save the tag name for future
 * processing.
 */
final class XhtmlTagRule extends BaseRule {

    /**
     * Constructor.
     */
    public XhtmlTagRule() {
        super();
    }

    /**
     * Begin processing for the rule.  Saves attributes, saves tag name, deals
     * with parent's preceeding body text, and wires up the tag processing
     * tree.
     *
     * @param attributes Attributes for the tag.
     * @throws Exception No exception is thrown.
     */
    public void begin(Attributes attributes) throws Exception {

        // Get all the important bits off the digester stack;
        TagWire wire = (TagWire) digester.peek();
        XhtmlTag child = (XhtmlTag) digester.peek(1);
        TagWire parentWire = (TagWire) digester.peek(2);
        Tag parent = (Tag) digester.peek(3);

        // Save attributes;
        child.setAttributes((Attributes) (new AttributesImpl(attributes)));

        // Save the tag;
        child.setTagName(new String(digester.getCurrentElementName()));

        // Deal with preceeding body text;
        dealWithPreceedingBodyText(parent, parentWire);

        // Wire up the tree;
        wireUpTheTag((Tag) child, parent, wire, parentWire);
    }
}

/**
 * A rule for processing the View Tag.  Need to save the viewTag
 */
final class ViewTagRule extends BaseRule {

    /**
     * Constructor.
     */
    public ViewTagRule() {
        super();
    }

    /**
     * Begin processing for the rule.  Saves attributes, saves tag name, deals
     * with parent's preceeding body text, and wires up the tag processing
     * tree.
     *
     * @param attributes Attributes for the tag.
     * @throws Exception No exception is thrown.
     */
    public void begin(Attributes attributes) throws Exception {

        // Get all the important bits off the digester stack;
        TagWire wire = (TagWire) digester.peek();
        Tag child = (Tag) digester.peek(1);

        JsfJspDigester jsdig = (JsfJspDigester) digester;
        jsdig.setViewWire(wire);

        TagWire parentWire = (TagWire) digester.peek(2);
        Tag parent = (Tag) digester.peek(3);

        // the attributes haven't been set up yet? !
        Attributes cloned = clone(attributes);
        wire.setAttributes(cloned);

        //        dealWithPreceedingBodyText(parent, parentWire, true);

        // Wire up the tree;
        wireUpTheTag(child, parent, wire, parentWire);
    }

    private Attributes clone(Attributes attributes) {
        Attributes clone = new AttributesImpl(attributes);
        for (int i = 0; i < clone.getLength(); i++) {
            String name = attributes.getQName(i);
            String value = attributes.getValue(name);
            ((AttributesImpl) clone).setLocalName(i, name);
            ((AttributesImpl) clone).setValue(i, value);
        }
        return clone;
    }
}