All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.deployment.node.DeploymentDescriptorNode Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation.
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.enterprise.deployment.node;

import com.sun.enterprise.deployment.AdministeredObjectDefinitionDescriptor;
import com.sun.enterprise.deployment.ConnectionFactoryDefinitionDescriptor;
import com.sun.enterprise.deployment.DataSourceDefinitionDescriptor;
import com.sun.enterprise.deployment.EjbReferenceDescriptor;
import com.sun.enterprise.deployment.EntityManagerFactoryReferenceDescriptor;
import com.sun.enterprise.deployment.EntityManagerReferenceDescriptor;
import com.sun.enterprise.deployment.EnvironmentProperty;
import com.sun.enterprise.deployment.JMSConnectionFactoryDefinitionDescriptor;
import com.sun.enterprise.deployment.JMSDestinationDefinitionDescriptor;
import com.sun.enterprise.deployment.JndiNameEnvironment;
import com.sun.enterprise.deployment.LifecycleCallbackDescriptor;
import com.sun.enterprise.deployment.MailSessionDescriptor;
import com.sun.enterprise.deployment.MessageDestinationReferenceDescriptor;
import com.sun.enterprise.deployment.ResourceDescriptor;
import com.sun.enterprise.deployment.ResourceEnvReferenceDescriptor;
import com.sun.enterprise.deployment.ResourceReferenceDescriptor;
import com.sun.enterprise.deployment.ServiceReferenceDescriptor;
import com.sun.enterprise.deployment.node.runtime.RuntimeBundleNode;
import com.sun.enterprise.deployment.util.DOLUtils;
import com.sun.enterprise.deployment.xml.TagNames;
import com.sun.enterprise.deployment.xml.WebServicesTagNames;

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.function.Function;

import org.glassfish.api.naming.SimpleJndiName;
import org.glassfish.deployment.common.Descriptor;
import org.glassfish.deployment.common.JavaEEResourceType;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.Globals;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;

import static com.sun.enterprise.deployment.util.DOLUtils.ADD_DESCRIPTOR_FAILURE;
import static com.sun.enterprise.deployment.util.DOLUtils.INVALID_DESC_MAPPING;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.ERROR;
import static java.lang.System.Logger.Level.WARNING;

/**
 * Superclass of all Nodes implementation
 * XMLNode implementation represents all the DOL classes responsible for
 * handling  the XML deployment descriptors. These nodes are called by the
 * SAX parser when reading and are constructed to build the DOM tree for
 * saving the XML files.
 *
 * XMLNode are organized like a tree with one root XMLNode (which
 * implement the RootXMLNode interface) and sub XMLNodes responsible
 * for handling subparts of the XML documents. Sub XMLNodes register
 * themselves to their parent XMLNode as handlers for a particular XML
 * subtag of the tag handled by the parent XMLNode
 *
 * Each XMLNode is therefore associated with a xml tag (located anywhere
 * in the tree of tags as defined by the DTD). It owns the responsibility for
 * reading and writing the tag, its attributes and all subtags (by using
 * delegation to sub XMLNode if necessary).
 *
 * @param  Deployment {@link Descriptor} type.
 * @author Jerome Dochez
 */
public abstract class DeploymentDescriptorNode implements XMLNode  {

    private static final Logger LOG = DOLUtils.getLogger();
    private static final String QNAME_SEPARATOR = ":";

    private static final Map, Function> ALLOWED_DESCRIPTOR_INFO_CONVERSIONS = Map.of(
        String.class, String::valueOf, SimpleJndiName.class, SimpleJndiName::of, int.class, Integer::valueOf,
        long.class, Long::valueOf, boolean.class, Boolean::valueOf);

    protected final ServiceLocator serviceLocator = Globals.getDefaultHabitat();

    /***
     * The handlers is the map of XMLNodes registered for handling sub xml tags of the current
     * XMLNode
     */
    protected Hashtable> handlers;

    /**
     * Map of add methods declared on the descriptor class to add sub descriptors extracted
     * by the handlers registered above. The key for the table is the xml root tag for the
     * descriptor to be added, the value is the method name to add such descriptor to the
     * current descriptor.
     */
    private Hashtable addMethods;

    /** Each node is associated with a XML tag it is handling */
    private XMLElement xmlTag;

    /**
     * Parent node in the XML Nodes implementation tree we create to map to the XML
     * tags of the XML document
     */
    private XMLNode parentNode;

    /**
     * Default descriptor associated with this node, some sub nodes which
     * relies on the dispatch table don't really need to know the actual
     * type of the descriptor they deal with since they are populated through
     * reflection method calls
     */
    protected T abstractDescriptor;

    /** Creates new DeploymentDescriptorNode */
    public DeploymentDescriptorNode() {
        registerElementHandler(new XMLElement(TagNames.DESCRIPTION), LocalizedInfoNode.class);
    }


    /**
     * @return the descriptor instance to associate with this XMLNode
     */
    @Override
    public T getDescriptor() {
        if (abstractDescriptor == null) {
            abstractDescriptor = createDescriptor();
        }
        return abstractDescriptor;
    }


    protected T createDescriptor() {
        return DescriptorFactory.getDescriptor(getXMLPath());
    }


    /**
     * Adds  a new DOL descriptor instance to the descriptor instance associated with
     * this XMLNode
     *
     * @param descriptor the new descriptor
     */
    @Override
    public void addDescriptor(Object descriptor) {
        if (getParentNode() == null) {
            throw new RuntimeException("Cannot add " + descriptor + " to " + toString());
        }
        getParentNode().addDescriptor(descriptor);
    }

    /**
     * Adds a new DOL descriptor instance to the descriptor associated with this XMLNode
     *
     * @param node the sub-node adding the descriptor;
     */
    protected void addNodeDescriptor(DeploymentDescriptorNode node) {
        // if there is no descriptor associated with this class, the addDescriptor should implement
        // the fate of this new descriptor.
        if (getDescriptor() == null) {
            addDescriptor(node.getDescriptor());
            return;
        }
        String xmlRootTag = node.getXMLRootTag().getQName();
        if (addMethods == null || !addMethods.containsKey(xmlRootTag)) {
            addDescriptor(node.getDescriptor());
            return;
        }
        try {
            String methodName = addMethods.get(xmlRootTag);
            final Class parameterType = node.getDescriptor().getClass();
            Method toInvoke = getCompatibleMethod(getDescriptor().getClass(), methodName, parameterType);
            toInvoke.invoke(getDescriptor(), node.getDescriptor());
        } catch (Exception t) {
            // We report the error but we continue loading, this will allow the verifier to
            // catch these errors or to register an error handler for notification
            LOG.log(ERROR, ADD_DESCRIPTOR_FAILURE, node.getDescriptor().getClass(), getDescriptor().getClass());
            LOG.log(ERROR, "Cause:", t);
        }
    }

    /**
     * set the parent node for the current instance.
     */
    public void setParentNode(XMLNode parentNode) {
        this.parentNode = parentNode;
    }

    /**
     * @return the parent node of the current instance
     */
    @Override
    public XMLNode getParentNode() {
        return parentNode;
    }


    /**
     * @return the root node of the current instance
     */
    @Override
    public XMLNode getRootNode() {
        XMLNode parent = this;
        while (parent.getParentNode() != null) {
            parent = parent.getParentNode();
        }
        return parent;
    }


    /**
     * register a new XMLNode handler for a particular XML tag.
     *
     * @param element XMLElement is the XML tag this XMLNode will handle
     * @param handler the class implemenenting the XMLNode interface
     */
    protected final void registerElementHandler(XMLElement element, Class handler) {
        if (handlers == null) {
            handlers = new Hashtable<>();
        }
        handlers.put(element.getQName(), handler);
    }

    /**
     * register a new XMLNode handler for a particular XML tag.
     *
     * @param element XMLElement is the XML tag this XMLNode will handle
     * @param handler the class implemenenting the XMLNode interface
     * @param addMethodName is the method name for adding the descriptor
     * extracted by the handler node to the current descriptor
     */
    public final void registerElementHandler(XMLElement element, Class handler, String addMethodName) {
        registerElementHandler(element, handler);
        if (addMethods == null) {
            addMethods = new Hashtable<>();
        }
        addMethods.put(element.getQName(), addMethodName);
    }

    /**
     * @return the XML tag associated with this XMLNode
     */
    protected XMLElement getXMLRootTag() {
        return xmlTag;
    }

    /**
     * sets the XML tag associated with this XMLNode
     */
    protected void setXMLRootTag(XMLElement element) {
        xmlTag = element;
    }

    /**
     * @return the handler registered for the subtag element of the curent  XMLNode
     */
    @Override
    public XMLNode getHandlerFor(XMLElement element) {
        if (handlers == null) {
            LOG.log(WARNING, "No handler registered in " + this);
            return null;
        }
        Class c = handlers.get(element.getQName());
        if (c == null) {
            LOG.log(WARNING, "No class registered for " + element.getQName() + " in " + this);
            return null;
        }
        LOG.log(DEBUG, "New Handler requested for {0}", c);
        DeploymentDescriptorNode node;
        try {
            node = (DeploymentDescriptorNode) c.getDeclaredConstructor().newInstance();
            node.setParentNode(this);
            node.setXMLRootTag(element);
            // enforces descriptor initialization for some nodes.
            node.getDescriptor();
        } catch(Exception e) {
            LOG.log(WARNING, "Error occurred", e);
            return null;
        }
        return node;
    }

    private Class getExtensionHandler(final XMLElement element) {
        DeploymentDescriptorNode extNode = (DeploymentDescriptorNode) serviceLocator.getService(XMLNode.class,
            element.getQName());
        if (extNode == null) {
            return null;
        }
        return extNode.getClass();
    }


    @Override
    public void startElement(XMLElement element, Attributes attributes) {
        if (!this.getXMLRootTag().equals(element)) {
            return;
        }

        if (attributes.getLength() > 0) {
            for (int i = 0; i < attributes.getLength(); i++) {
                String attrName = attributes.getQName(i);
                String attrValue = attributes.getValue(i);
                LOG.log(DEBUG, "With attribute {0} and value {1}", attrName, attrValue);
                // we try the setAttributeValue first, if not processed then the setElement
                if (!setAttributeValue(element, new XMLElement(attrName), attrValue)) {
                    setElementValue(new XMLElement(attrName), attrValue);
                }
            }
        }
    }


    /**
     * parsed an attribute of an element
     *
     * @param elementName the element name
     * @param attributeName the attribute name
     * @param value the attribute value
     * @return true if the attribute was processed
     */
    protected boolean setAttributeValue(XMLElement elementName, XMLElement attributeName, String value) {
        // we do not support id attribute for the moment
        return attributeName.getQName().equals(TagNames.ID);
    }

    /**
     * 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
     */
    @Override
    public boolean endElement(XMLElement element) {
        boolean allDone = element.equals(getXMLRootTag());
        if (allDone) {
            postParsing();
            if (getParentNode() != null && getDescriptor() != null) {
                ((DeploymentDescriptorNode) getParentNode()).addNodeDescriptor(this);
            }
        }
        return allDone;
    }

    /**
     * notification of the end of XML parsing for this node
     */
    public void postParsing() {
    }

    /**
     *  @return true if the element tag can be handled by any registered sub nodes of the
     * current XMLNode
     */
    @Override
    public boolean handlesElement(XMLElement element) {
        // Let's iterator over all the statically registered handlers to
        // find one which is responsible for handling the XML tag.
        if (handlers != null) {
            for (Enumeration handlersIterator = handlers.keys();handlersIterator.hasMoreElements();) {
                String subElement = handlersIterator.nextElement();
                if (element.getQName().equals(subElement)) {
                    // record element to node mapping for runtime nodes
                    recordNodeMapping(element.getQName(), handlers.get(subElement));
                    return false;
                }
            }
        }

        // let's now find if there is any dynamically registered handler
        // to handle this XML tag
        Class extHandler = getExtensionHandler(element);
        if (extHandler != null) {
            // if yes, we should add this handler to the table so
            // we don't need to look it up again later and also return
            // false
            registerElementHandler(new XMLElement(element.getQName()), extHandler);
            // record element to node mapping for runtime nodes
            recordNodeMapping(element.getQName(), extHandler);
            return false;
        }

        recordNodeMapping(element.getQName(), this.getClass());
        return true;
    }

    // record element to node mapping
    private void recordNodeMapping(String subElementName, Class handler) {
        XMLNode rootNode = getRootNode();
        if (rootNode instanceof RuntimeBundleNode) {
            ((RuntimeBundleNode) rootNode).recordNodeMapping(getXMLRootTag().getQName(), subElementName, handler);
        }
    }

    /**
     * receives notification of the value for a particular tag
     *
     * @param element the xml element
     * @param value it's associated value
     */
    @Override
    public void setElementValue(XMLElement element, String value) {
        LOG.log(DEBUG, "setElementValue(element={0}, value={1})", element, value);
        T descriptor = getDescriptor();
        if (descriptor == null) {
            throw new IllegalStateException("Descriptor not available in " + this);
        }
        Map dispatchTable = getDispatchTable();
        if (dispatchTable == null) {
            throw new IllegalStateException("Method dispatch table not available in " + this);
        }
        String qName = element.getQName();
        String methodName = dispatchTable.get(qName);
        if (methodName == null) {
            // we just ignore these values from the DDs
            LOG.log(WARNING, "Deprecated element {0} with value {1} is ignored for descriptor {2} of node {3}.",
                element, value, descriptor.getClass(), getClass());
            LOG.log(DEBUG, "Helpful stacktrace for the previous warning.", new RuntimeException());
            return;
        }
        try {
            setDescriptorInfo(descriptor, methodName, value);
        } catch (InvocationTargetException e) {
            LOG.log(WARNING, INVALID_DESC_MAPPING, qName, value, descriptor.getClass());
            Throwable t = e.getCause();
            if (t instanceof IllegalArgumentException) {
                // We report the error but we continue loading, this will allow the verifier
                // to catch these errors or to register an error handler for notification
                LOG.log(WARNING, INVALID_DESC_MAPPING, qName, value, descriptor.getClass());
            } else {
                throw new IllegalArgumentException(
                    "Failed " + methodName + " when tried to set '" + value + "' to the descriptor " + descriptor, e);
            }
        } catch (ReflectiveOperationException e) {
            throw new IllegalArgumentException(
                "Failed " + methodName + " when tried to set '" + value + "' to the descriptor " + descriptor, e);
        }
    }

    /**
     * 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() {
        // no need to be synchronized for now
        Map table =  new HashMap<>();
        table.put(TagNames.DESCRIPTION, "setDescription");
        return table;
    }


    /**
     * Call a setter method on a descriptor with a new value converted automatically
     * to a compatible type.
     *
     * @param target the descriptor to use
     * @param methodName the setter method to invoke
     * @param value the new value for the field in the descriptor
     * @throws ReflectiveOperationException if method failed because of number formatting or method
     *             doesn't exist.
     * @throws InvocationTargetException if the invocation failed for other reason.
     * @deprecated guessing element type
     */
    @Deprecated
    private void setDescriptorInfo(Object target, String methodName, String value) throws ReflectiveOperationException {
        LOG.log(Level.DEBUG, "setDescriptorInfo(target.class={0}, methodName={1}, value={2})", target.getClass(),
            methodName, value);

        ReflectiveOperationException e = new ReflectiveOperationException("Could not find compatible setter.");
        for (Entry, Function> entry : ALLOWED_DESCRIPTOR_INFO_CONVERSIONS.entrySet()) {
            try {
                Method toInvoke = target.getClass().getMethod(methodName, entry.getKey());
                toInvoke.invoke(target, entry.getValue().apply(value));
                // If the call succeeded, we are done.
                return;
            } catch (NumberFormatException nfe) {
                e.addSuppressed(nfe);
            } catch (NoSuchMethodException nsme) {
                e.addSuppressed(nsme);
            }
        }
        throw e;
    }

    /**
     * @return the XPath this XML Node is handling
     */
    @Override
    public String getXMLPath() {
        if (getParentNode() == null) {
            return getXMLRootTag().getQName();
        }
        return getParentNode().getXMLPath() + "/" + getXMLRootTag().getQName();
    }

    /**
     * write the descriptor class to a DOM tree and return it
     *
     * @param parent node in the DOM tree
     * @param descriptor the descriptor to write
     * @return the DOM tree top node
     */
    @Override
    public Node writeDescriptor(Node parent, T descriptor) {
        return writeDescriptor(parent, getXMLRootTag().getQName(), descriptor);
    }


    /**
     * write the descriptor class to a DOM tree and return it
     *
     * @param parent node in the DOM tree
     * @param nodeName name for the root element for this DOM tree fragment
     * @param descriptor the descriptor to write
     * @return the DOM tree top node
     */
    public Node writeDescriptor(Node parent, String nodeName, T descriptor) {
        return appendChild(parent, nodeName);
    }

    /**
     * write all occurrences of the descriptor corresponding to the current
     * node from the parent descriptor to an JAXP DOM node and return it
     *
     * This API will be invoked by the parent node when the parent node
     * writes out a mix of statically and dynamically registered sub nodes.
     *
     * This method should be overriden by the sub classes if it
     * needs to be called by the parent node.
     *
     * @param parent node in the DOM tree
     * @param nodeName the name of the node
     * @param parentDesc parent descriptor of the descriptor to be written
     * @return the JAXP DOM node
     */
    public Node writeDescriptors(Node parent, String nodeName, Descriptor parentDesc) {
        return parent;
    }

    /**
     * write out simple text element based on the node name
     * to an JAXP DOM node and return it
     *
     * This API will be invoked by the parent node when the parent node
     * writes out a mix of statically and dynamically registered sub nodes.
     * And this API is to write out the simple text sub element that the
     * parent node handles itself.
     *
     * This method should be overriden by the sub classes if it
     * needs to be called by the parent node.
     *
     * @param parent node in the DOM tree
     * @param nodeName node name of the node
     * @param parentDesc parent descriptor of the descriptor to be written
     * @return the JAXP DOM node
     */
    public Node writeSimpleTextDescriptor(Node parent, String nodeName, Descriptor parentDesc) {
        return parent;
    }

    /**
     * write out descriptor in a generic way to an JAXP DOM
     * node and return it
     *
     * This API will generally be invoked when the parent node needs to
     * write out a mix of statically and dynamically registered sub nodes.
     *
     * @param node current node in the DOM tree
     * @param nodeName node name of the node
     * @param descriptor the descriptor to be written
     * @return the JAXP DOM node for this descriptor
     */
    public Node writeSubDescriptors(Node node, String nodeName, Descriptor descriptor) {
        XMLNode rootNode = getRootNode();
        if (rootNode instanceof RuntimeBundleNode) {
            // we only support this for runtime xml
            LinkedHashMap> elementToNodeMappings = ((RuntimeBundleNode) rootNode)
                .getNodeMappings(nodeName);
            if (elementToNodeMappings != null) {
                Set>> entrySet = elementToNodeMappings.entrySet();
                for (Entry> entry : entrySet) {
                    String subElementName = entry.getKey();
                    // skip if it's the element itself and not the subelement
                    if (subElementName.equals(nodeName)) {
                        continue;
                    }
                    Class handlerClass = entry.getValue();
                    if (handlerClass.getName().equals(this.getClass().getName())) {
                        // if this sublement is handled by the current node
                        // it is a simple text element, just append the text
                        // element based on the node name
                        writeSimpleTextDescriptor(node, subElementName, descriptor);
                    } else {
                        // if this sublement is handled by a sub node
                        // write all occurences of this sub node under
                        // the parent node
                        try {
                            DeploymentDescriptorNode subNode = (DeploymentDescriptorNode) handlerClass
                                .getDeclaredConstructor().newInstance();
                            subNode.setParentNode(this);
                            subNode.writeDescriptors(node, subElementName, descriptor);
                        } catch (Exception e) {
                            LOG.log(WARNING, e.getMessage(), e);
                        }
                    }
                }
            }
        }
        return node;
    }

    /**
     * @return the Document for the given node
     */
    static protected Document getOwnerDocument(Node node) {

        if (node instanceof Document) {
            return (Document) node;
        }
        return node.getOwnerDocument();
    }

    /**
     * Append a new element child to the current node
     *
     * @param parent is the parent node for the new child element
     * @param elementName is new element tag name
     * @return the newly created child node
     */
    public static Element appendChild(Node parent, String elementName) {
        Element child = getOwnerDocument(parent).createElement(elementName);
        parent.appendChild(child);
        return child;
    }


    /**
     * Append a new text child
     *
     * @param parent for the new child element
     * @param elementName is the new element tag name
     * @param content object to be printed via {@link String#toString()} to the text content of
     *            the new element
     * @return the newly create child node
     */
    public static Node appendTextChild(Node parent, String elementName, Object content) {
        if (content == null) {
            return null;
        }
        Node child = appendChild(parent, elementName);
        child.appendChild(getOwnerDocument(child).createTextNode(content.toString()));
        return child;
    }


    /**
     * Append a new text child
     *
     * @param parent for the new child element
     * @param elementName is the new element tag name
     * @param text the text for the new element
     * @return the newly create child node
     */
    public static Node appendTextChild(Node parent, String elementName, String text) {
        if (text == null || text.isEmpty()) {
            return null;
        }
        Node child = appendChild(parent, elementName);
        child.appendChild(getOwnerDocument(child).createTextNode(text));
        return child;
    }


    /**
     * Append a new text child
     *
     * @param parent for the new child element
     * @param elementName is the new element tag name
     * @param value the int value for the new element
     * @return the newly create child node
     */
    public static Node appendTextChild(Node parent, String elementName, int value) {
        return appendTextChild(parent, elementName, String.valueOf(value));
    }


    /**
     * Append a new text child even if text is empty
     *
     * @param parent for the new child element
     * @param elementName is the new element tag name
     * @param text the text for the new element
     * @return the newly create child node
     */
    public static Node forceAppendTextChild(Node parent, String elementName, String text) {
        Node child = appendChild(parent, elementName);
        if (text != null && !text.isEmpty()) {
            child.appendChild(getOwnerDocument(child).createTextNode(text));
        }
        return child;
    }

    /**
     * Append a new attribute to an element
     *
     * @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 static void setAttribute(Element parent, String elementName, String text) {
        if (text == null || text.length()==0) {
            return;
        }
        parent.setAttribute(elementName, text);
    }

    /**
     * Set a namespace attribute on an element.
     *
     * @param element on which to set attribute
     * @param prefix raw prefix (without "xmlns:")
     * @param namespaceURI namespace URI to which prefix is mapped.
     */
    public static void setAttributeNS(Element element, String prefix, String namespaceURI) {
        String nsPrefix = prefix.isEmpty() ? "xmlns" : ("xmlns" + QNAME_SEPARATOR + prefix);
        element.setAttributeNS("http://www.w3.org/2000/xmlns/", nsPrefix, namespaceURI);
    }

    /**
     * write a list of env entry descriptors to a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param envEntries the iterator over the descriptors to write
     */
    protected  void writeEnvEntryDescriptors(Node parentNode, Iterator envEntries) {
        if (envEntries == null || !envEntries.hasNext()) {
            return;
        }
        EnvEntryNode subNode = new EnvEntryNode();
        while (envEntries.hasNext()) {
            EnvironmentProperty envProp = (EnvironmentProperty) envEntries.next();
            subNode.writeDescriptor(parentNode, TagNames.ENVIRONMENT_PROPERTY, envProp);
        }
    }

    /**
     * write  the ejb references (local or remote) to the DOM tree
     *
     * @param parentNode parent node for the DOM tree
     * @param refs the set of EjbReferenceDescriptor to write
     */
    protected void writeEjbReferenceDescriptors(Node parentNode, Iterator refs) {
        if (refs == null || !refs.hasNext()) {
            return;
        }

        EjbReferenceNode subNode = new EjbReferenceNode();
        // ejb-ref*
        Set localRefDescs = new HashSet<>();
        while (refs.hasNext()) {
            EjbReferenceDescriptor ejbRef = refs.next();
            if (ejbRef.isLocal()) {
                localRefDescs.add(ejbRef);
            } else {
                subNode.writeDescriptor(parentNode, TagNames.EJB_REFERENCE, ejbRef);
            }
        }
        // ejb-local-ref*
        for (EjbReferenceDescriptor ejbRef : localRefDescs) {
            subNode.writeDescriptor(parentNode, TagNames.EJB_LOCAL_REFERENCE,ejbRef);
        }
    }


    protected void writeServiceReferenceDescriptors(Node parentNode, Iterator refs) {
        if (refs == null || !refs.hasNext()) {
            return;
        }

        JndiEnvRefNode serviceRefNode = serviceLocator.getService(JndiEnvRefNode.class,
            WebServicesTagNames.SERVICE_REF);
        if (serviceRefNode != null) {
            while (refs.hasNext()) {
                ServiceReferenceDescriptor next = refs.next();
                serviceRefNode.writeDeploymentDescriptor(parentNode, next);
            }
        }
    }

    /**
     * write a list of resource reference descriptors to a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param resRefs the iterator over the descriptors to write
     */
    protected  void writeResourceRefDescriptors(Node parentNode, Iterator resRefs) {
        if (resRefs == null || !resRefs.hasNext()) {
            return;
        }
        ResourceRefNode subNode = new ResourceRefNode();
        while (resRefs.hasNext()) {
            ResourceReferenceDescriptor aResRef = (ResourceReferenceDescriptor) resRefs.next();
            subNode.writeDescriptor(parentNode, TagNames.RESOURCE_REFERENCE, aResRef);
        }
    }

    /**
     * write a list of resource env reference descriptors to a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param resRefs the iterator over the descriptors to write
     */
    protected  void writeResourceEnvRefDescriptors(Node parentNode, Iterator resRefs) {
        if (resRefs == null || !resRefs.hasNext()) {
            return;
        }
        ResourceEnvRefNode subNode = new ResourceEnvRefNode();
        while (resRefs.hasNext()) {
            ResourceEnvReferenceDescriptor aResRef = resRefs.next();
            subNode.writeDescriptor(parentNode, TagNames.RESOURCE_ENV_REFERENCE, aResRef);
        }
    }


    /**
     * write a list of message destination reference descriptors to a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param msgDestRefs the iterator over the descriptors to write
     */
    protected void writeMessageDestinationRefDescriptors(Node parentNode, Iterator msgDestRefs) {
        if (msgDestRefs == null || !msgDestRefs.hasNext()) {
            return;
        }
        MessageDestinationRefNode subNode = new MessageDestinationRefNode();
        while (msgDestRefs.hasNext()) {
            MessageDestinationReferenceDescriptor next = (MessageDestinationReferenceDescriptor) msgDestRefs.next();
            subNode.writeDescriptor(parentNode, TagNames.MESSAGE_DESTINATION_REFERENCE, next);
        }
    }

    /**
     * write a list of entity manager reference descriptors to a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param entityMgrRefs the iterator over the descriptors to write
     */
    protected void writeEntityManagerReferenceDescriptors(Node parentNode, Iterator entityMgrRefs) {
        if (entityMgrRefs == null || !entityMgrRefs.hasNext()) {
            return;
        }
        EntityManagerReferenceNode subNode = new EntityManagerReferenceNode();
        while (entityMgrRefs.hasNext()) {
            EntityManagerReferenceDescriptor aEntityMgrRef = (EntityManagerReferenceDescriptor)entityMgrRefs.next();
            subNode.writeDescriptor(parentNode, TagNames.PERSISTENCE_CONTEXT_REF, aEntityMgrRef);
        }
    }

    /**
     * write a list of entity manager factory reference descriptors to
     * a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param entityMgrFactoryRefs the iterator over the descriptors to write
     */
    protected void writeEntityManagerFactoryReferenceDescriptors(Node parentNode,
        Iterator entityMgrFactoryRefs) {
        if (entityMgrFactoryRefs == null || !entityMgrFactoryRefs.hasNext()) {
            return;
        }
        EntityManagerFactoryReferenceNode subNode = new EntityManagerFactoryReferenceNode();
        while (entityMgrFactoryRefs.hasNext()) {
            EntityManagerFactoryReferenceDescriptor aEntityMgrFactoryRef = entityMgrFactoryRefs.next();
            subNode.writeDescriptor(parentNode, TagNames.PERSISTENCE_UNIT_REF, aEntityMgrFactoryRef);
        }
    }

    /**
     * write a list of life-cycle-callback descriptors to a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param tagName the tag name for the descriptors
     * @param lifecycleCallbacks the iterator over the descriptors to write
     */
    protected void writeLifeCycleCallbackDescriptors(Node parentNode, String tagName,
        Collection lifecycleCallbacks) {
        if (lifecycleCallbacks == null || lifecycleCallbacks.isEmpty()) {
            return;
        }
        LifecycleCallbackNode subNode = new LifecycleCallbackNode();
        for (LifecycleCallbackDescriptor lcd : lifecycleCallbacks) {
            subNode.writeDescriptor(parentNode, tagName, lcd);
        }
    }

    /**
     * write a list of all descriptors to a DOM Tree
     *
     * @param parentNode parent node for the DOM tree
     * @param descriptorIterator the iterator over the descriptors to write
     */
    protected void writeResourceDescriptors(Node parentNode, Iterator descriptorIterator) {
        if (descriptorIterator == null || !descriptorIterator.hasNext()) {
            return;
        }

        DataSourceDefinitionNode dataSourceDefinitionNode = new DataSourceDefinitionNode();
        MailSessionNode mailSessionNode = new MailSessionNode();
        ConnectionFactoryDefinitionNode connectionFactoryDefinitionNode = new ConnectionFactoryDefinitionNode();
        AdministeredObjectDefinitionNode administeredObjectDefinitionNode = new AdministeredObjectDefinitionNode();
        JMSConnectionFactoryDefinitionNode jmsConnectionFactoryDefinitionNode = new JMSConnectionFactoryDefinitionNode();
        JMSDestinationDefinitionNode jmsDestinationDefinitionNode = new JMSDestinationDefinitionNode();

        while (descriptorIterator.hasNext()) {
            ResourceDescriptor descriptor = descriptorIterator.next();

            if (descriptor.getResourceType().equals(JavaEEResourceType.DSD)) {
                DataSourceDefinitionDescriptor next = (DataSourceDefinitionDescriptor) descriptor;
                dataSourceDefinitionNode.writeDescriptor(parentNode, TagNames.DATA_SOURCE, next);
            } else if (descriptor.getResourceType().equals(JavaEEResourceType.MSD)) {
                MailSessionDescriptor next = (MailSessionDescriptor) descriptor;
                mailSessionNode.writeDescriptor(parentNode, TagNames.MAIL_SESSION, next);
            } else if (descriptor.getResourceType().equals(JavaEEResourceType.CFD)) {
                ConnectionFactoryDefinitionDescriptor next = (ConnectionFactoryDefinitionDescriptor) descriptor;
                connectionFactoryDefinitionNode.writeDescriptor(parentNode, TagNames.CONNECTION_FACTORY, next);
            } else if (descriptor.getResourceType().equals(JavaEEResourceType.AODD)) {
                AdministeredObjectDefinitionDescriptor next = (AdministeredObjectDefinitionDescriptor) descriptor;
                administeredObjectDefinitionNode.writeDescriptor(parentNode, TagNames.ADMINISTERED_OBJECT, next);
            } else if (descriptor.getResourceType().equals(JavaEEResourceType.JMSCFDD)) {
                JMSConnectionFactoryDefinitionDescriptor next = (JMSConnectionFactoryDefinitionDescriptor) descriptor;
                jmsConnectionFactoryDefinitionNode.writeDescriptor(parentNode, TagNames.JMS_CONNECTION_FACTORY, next);
            } else if (descriptor.getResourceType().equals(JavaEEResourceType.JMSDD)) {
                JMSDestinationDefinitionDescriptor next = (JMSDestinationDefinitionDescriptor) descriptor;
                jmsDestinationDefinitionNode.writeDescriptor(parentNode, TagNames.JMS_DESTINATION, next);
            }
        }
    }

    /**
     * writes iocalized descriptions (if any) to the DOM node
     */
    protected static void writeLocalizedDescriptions(Node node, Descriptor desc) {
        LocalizedInfoNode localizedNode = new LocalizedInfoNode();
        localizedNode.writeLocalizedMap(node, TagNames.DESCRIPTION, desc.getLocalizedDescriptions());
    }

    /**
     * writes jndi environment references group nodes
     */
    protected void writeJNDIEnvironmentRefs(Node node, JndiNameEnvironment descriptor) {

        /*      
         */
        writeEnvEntryDescriptors(node, descriptor.getEnvironmentProperties().iterator());

        /*      
         */
        /*      
         */
        writeEjbReferenceDescriptors(node, descriptor.getEjbReferenceDescriptors().iterator());

        /*      
         */
        writeServiceReferenceDescriptors(node, descriptor.getServiceReferenceDescriptors().iterator());

        /*  
         */
        writeResourceRefDescriptors(node, descriptor.getResourceReferenceDescriptors().iterator());

        /*  
         */
        writeResourceEnvRefDescriptors(node, descriptor.getResourceEnvReferenceDescriptors().iterator());

        /*      
         */
        writeMessageDestinationRefDescriptors(node, descriptor.getMessageDestinationReferenceDescriptors().iterator());

        /*      
         */
        writeEntityManagerReferenceDescriptors(node, descriptor.getEntityManagerReferenceDescriptors().iterator());

        /*      
         */
        writeEntityManagerFactoryReferenceDescriptors(node, descriptor.getEntityManagerFactoryReferenceDescriptors().iterator());

        /*      
         */
        writeLifeCycleCallbackDescriptors(node, TagNames.POST_CONSTRUCT, descriptor.getPostConstructDescriptors());


        /*      
         */
        writeLifeCycleCallbackDescriptors(node, TagNames.PRE_DESTROY, descriptor.getPreDestroyDescriptors());
    }

    /**
     * Any node can now declare its own namespace. this apply to DDs only
     * when dealing with deployment extensions. Write any declared
     * namespace declaration
     *
     * @param node from which this namespace is declared
     * @param descriptor containing the namespace declaration if any
     */
    protected void addNamespaceDeclaration(Element node, Descriptor descriptor) {

        // declare now all remaining namepace...
        Map prefixMapping = descriptor == null ? null : descriptor.getPrefixMapping();
        if (prefixMapping != null) {
            Set> entrySet = prefixMapping.entrySet();
            for (Entry entry : entrySet) {
                String prefix = entry.getKey();
                String namespaceURI = entry.getValue();
                setAttributeNS(node, prefix, namespaceURI);
            }
        }
    }

    /**
     * notify of a new prefix mapping used in this document
     */
    @Override
    public void addPrefixMapping(String prefix, String uri) {
        Descriptor descriptor = getDescriptor();
        // FIXME: two LocalizedNode children return null!!!
        if (descriptor != null) {
            descriptor.addPrefixMapping(prefix, uri);
        }
    }

    /**
     * Resolve a QName prefix to its corresponding Namespace URI by
     * searching up node chain starting with child.
     */
    @Override
    public String resolvePrefix(XMLElement element, String prefix) {
        // If prefix is empty string, returned namespace URI
        // is the default namespace.
        return element.getPrefixURIMapping(prefix);
    }

    /**
     * @return namespace URI prefix from qname, where qname is
     * an xsd:QName, or the empty string if there is no prefix.
     *
     * QName ::= (Prefix ':')? LocalPart
     */
    public String getPrefixFromQName(String qname) {
        StringTokenizer tokenizer = new StringTokenizer(qname, QNAME_SEPARATOR);
        return tokenizer.countTokens() == 2 ? tokenizer.nextToken() : "";
    }

    /**
     * @return local part from qname, where qname is an xsd:QName.
     * QName ::= (Prefix ':')? LocalPart
     */
    public String getLocalPartFromQName(String qname) {
        StringTokenizer tokenizer = new StringTokenizer(qname, QNAME_SEPARATOR);
        String localPart = qname;
        if (tokenizer.countTokens() == 2) {
            // skip namespace prefix.
            tokenizer.nextToken();
            localPart = tokenizer.nextToken();
        }
        return localPart;
    }

    public String composeQNameValue(String prefix, String localPart) {
        return prefix == null || prefix.isEmpty() ? localPart : (prefix + QNAME_SEPARATOR + localPart);
    }


    public void appendQNameChild(String elementName, Node parent, String namespaceUri, String localPart, String prefix) {
        if (prefix == null) {
            prefix = elementName + "_ns__";
        }

        String elementValue = composeQNameValue(prefix, localPart);
        Element element = (Element) appendTextChild(parent, elementName, elementValue);

        // Always set prefix mapping on leaf node.  If the DOL was
        // populated from an existing deployment descriptor it does
        // not preserve the original node structure of the XML document,
        // so we can't reliably know what level to place mapping.
        // Alternatively, if we're writing out a descriptor that was created
        // by the deploytool, there is no prefix->namespace information in
        // the first place.
        setAttributeNS(element, prefix, namespaceUri);
    }


    /**
     * First tries the exact match, when no such method exists it tries to find any compatible
     * method of the same name.
     *
     * @return never null, throws runtime exceptions if it is not possible to find the method for
     *         any reason.
     */
    private Method getCompatibleMethod(Class descriptor, String methodName, Class parameter) {
        LOG.log(DEBUG, "getCompatibleMethod(descriptor={0}, methodName={1}, parameter={2})",
            descriptor, methodName, parameter);
        try {
            return descriptor.getMethod(methodName, parameter);
        } catch (NoSuchMethodException e) {
            // ignore
        } catch (SecurityException e) {
            throw new IllegalStateException("Reflection failed - SecurityException", e);
        }

        Method[] methods = descriptor.getMethods();
        for (Method method : methods) {
            Class[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length != 1) {
                continue;
            }
            if (!method.getName().equals(methodName)) {
                continue;
            }
            Class parameterOfMethod = parameterTypes[0];
            if (parameterOfMethod.isAssignableFrom(parameter)) {
                return method;
            }
        }
        throw new IllegalArgumentException("Reflection failed for descriptor " + descriptor + ", it's method named "
            + methodName + " and parameter " + parameter);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy