FileDocCategorySizeDatePackage
ExtensionElementNode.javaAPI DocGlassfish v2 API10614Fri May 04 22:31:38 BST 2007com.sun.enterprise.deployment.node

ExtensionElementNode.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.deployment.node;

import java.util.Map;
import java.util.Iterator;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;
import com.sun.enterprise.deployment.Descriptor;
import com.sun.enterprise.deployment.ExtensionElementDescriptor;
import com.sun.enterprise.deployment.DynamicAttributesDescriptor;
import com.sun.enterprise.deployment.xml.TagNames;

/**
 * This node is responsible for loading and saving any type of 
 * xml node and store them in a DeploymentExtensionElement 
 *
 * @author Jerome Dochez
 */
public class ExtensionElementNode extends DeploymentDescriptorNode {
    
    ExtensionElementDescriptor descriptor;
    
    /** Creates a new instance of DynamicDescriptorNode */
    public ExtensionElementNode() {
        descriptor = new ExtensionElementDescriptor();
    }

   /**
     * all sub-implementation of this class can use a dispatch table to map xml element to
     * method name on the descriptor class for setting the element value. 
     *  
     * @return the map with the element name as a key, the setter method as a value
     */    
    protected Map getDispatchTable() {   
        return null;
    }
    
    /**
     * Adds a new DOL descriptor instance to the descriptor associated with this 
     * XMLNode
     * 
     * @param XMLNode the sub-node adding the descriptor;
     * @param descriptor the new descriptor
     */
    protected void addNodeDescriptor(DeploymentDescriptorNode node) {
        // nodes are added upon creation
        ExtensionElementDescriptor dad = (ExtensionElementDescriptor) node.getDescriptor();
        Iterator itr = dad.getElementNames();
        // jump over first element;
        if (itr.hasNext()) itr.next();
        
        if (itr.hasNext() && !dad.hasAttributes()) {
            descriptor.addElement(node.getXMLRootTag().getCompleteName(), dad);
        } else {
            descriptor.addElement(node.getXMLRootTag().getCompleteName(), dad.getElement(node.getXMLRootTag().getCompleteName()));
        }
    }
    
   /**
    * @return the descriptor instance to associate with this XMLNode
    */    
    public Object getDescriptor() {    
        return descriptor;
    }
    
    /**
     *  @return true if the element tag can be handled by any registered sub nodes of the
     * current XMLNode
     */
    public boolean handlesElement(XMLElement element) {
        // we are never handling xml fragment only leaf nodes, we create subnodes for that.
        return false;
    }
    
    /**
     * @return the handler registered for the subtag element of the curent  XMLNode
     */
    public  XMLNode getHandlerFor(XMLElement element) {
        ExtensionElementNode subNode = new ExtensionElementNode();        
        subNode.setParentNode(this);
        subNode.setXMLRootTag(new XMLElement(element.getCompleteName()));
        return subNode;
    }
    
    /**
     * SAX Parser API implementation, we don't really care for now.
     */
    public void startElement(XMLElement element, Attributes attributes) {
        if (attributes.getLength()>0) {
            for (int i=0;i<attributes.getLength();i++) {        
                if (attributes.getLocalName(i).equals("type")) {
                    // type declaration... replace the standard xml declaration with ours...
                    descriptor.getAttributes().addExtraAttribute("xsi:type", attributes.getValue(i));
                } else {
                    descriptor.getAttributes().addExtraAttribute(attributes.getQName(i), attributes.getValue(i));                
                }
            }
        }
    }
    
    /**
     * receives notification of the value for a particular tag
     * 
     * @param element the xml element
     * @param value it's associated value
     */
    public void setElementValue(XMLElement element, String value) {
        descriptor.addElement(element.getCompleteName(), value);
    } 
    
    /** 
     * receives notification of the end of an XML element by the Parser
     * 
     * @param element the xml tag identification
     * @return true if this node is done processing the XML sub tree
     */
    public boolean endElement(XMLElement element) {
        boolean allDone = element.getCompleteName().equals(getXMLRootTag().getCompleteName()) || element.getQName().equals(TagNames.EXTENSION_ELEMENT);        
        if (allDone) {
            postParsing();    
            ((DeploymentDescriptorNode) getParentNode()).addNodeDescriptor(this);            
        }
        return allDone;        
    }
    
    /**
     * write the deployment extensions nodes associated with this node
     * 
     * @param parent node for the DOM tree
     * @param deployment extension element
     */
    protected void writeDescriptor(Node parentNode, String tagName, ExtensionElementDescriptor descriptor) {
        Element node = appendChildNS(parentNode, tagName, descriptor);
        if (descriptor.hasAttributes()) {
            Map attributes = descriptor.getAttributes().getExtraAttributes();
            for (Iterator itr = attributes.keySet().iterator();itr.hasNext();) {
                String key = (String) itr.next();
                String value = (String) attributes.get(key);
                String namespace = "";
                if (key.indexOf(':')!=-1) {
                    String prefix = key.substring(0, key.indexOf(':'));
                    namespace = getNamespaceFor(descriptor, parentNode, prefix);
                }                
                node.setAttributeNS(namespace, key, value);
            }
        }
        addNamespaceDeclaration(node, descriptor);
        for (Iterator itr = descriptor.getElementNames();itr.hasNext();) {
            String elementName = (String) itr.next();
            Object value = descriptor.getElement(elementName);
            if (value instanceof ExtensionElementDescriptor) {
                writeDescriptor(node, elementName, (ExtensionElementDescriptor) value);
            } else 
            if (value instanceof String) {
                appendTextChildNS(node, elementName, (String) value, descriptor);
            }
        }                
    }
    
    /**
     * <p>
     * Append a new element child to the current node 
     * </p>
     * @param parentNode is the parent node for the new child element
     * @param elementName is new element tag name
     * @return the newly created child node
     */
    public Element appendChildNS(Node parent, String elementName, Descriptor descriptor) {
        if (elementName.indexOf(':')!=-1) {
            String prefix = elementName.substring(0, elementName.indexOf(':'));
            elementName = elementName.substring(elementName.indexOf(':')+1);
            
            String namespace = getNamespaceFor(descriptor, parent, prefix);
            
            Element child = getOwnerDocument(parent).createElementNS(namespace, elementName);            
            child.setPrefix(prefix);
            parent.appendChild(child);
            return child;
        }
        return super.appendChild(parent, elementName);
    }

    /**
     * look in the mapping defined in this descriptor and in all parent nodes 
     * for the right namespace for the passed prefix
     */
    private String getNamespaceFor(Descriptor descriptor, Node parent, String prefix) {
        
        Map prefixMapping = descriptor.getPrefixMapping();
        String namespace = null;
        if (prefixMapping!=null) {
            namespace = (String) prefixMapping.get(prefix);
        }
        if (namespace==null) {
            Element currentNode = (Element) parent;
            namespace="";
            while (currentNode!=null && namespace.length()==0) {
                namespace = currentNode.getAttributeNS("http://www.w3.org/2000/xmlns/", prefix);
                if (namespace.length()==0) 
                    currentNode = (Element) currentNode.getParentNode();
            }
        }
        return namespace;
    }

    
    /**
     * <p>
     * Append a new text child
     * </p>
     * @param parent for the new child element
     * @param elementName is the new element tag name
     * @param text the text for the new element
     * @result the newly create child node
     */
    public Node appendTextChildNS(Node parent, String elementName, String text, Descriptor descriptor) {
        
        if (text == null || text.length()==0) 
            return null;
        
        Node child = appendChildNS(parent, elementName, descriptor);
        child.appendChild(getOwnerDocument(child).createTextNode(text));        
        return child;
    }       
    
}