alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (CombinedXPath.java)

This example Glassfish source code file (CombinedXPath.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

attr, combinedxpath, document, document, dom, element, io, log, node, node, nodelist, nodelist, string, string, util, xml, xpath, xpath, xpathexpression, xpathexpressionexception

The Glassfish CombinedXPath.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. 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_1_1.html
 * or packager/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 packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [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 org.glassfish.appclient.server.core.jws;

import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;

/**
 * XPath-based logic to combine generated JNLP elements with the developer-
 * provided JNLP.
 * <p>
 * Three types of combinations:
 * <ul>
 * <li>owned - the generated content overrides the developer's (we "own" the content)
 * <li>merged - the generated content is merged in with the developer's content
 * <li>defaulted - the generated content is used only if no corresponding developer content exists
 * </ul>
 * <p>
 * This is the abstract superclass for the various types of combinations of
 * generated and developer-provided elements.
 * <p>
 * The client-jnlp-config.properties file contains properties which define
 * which JNLP elements will be combined, one property for each of the types of
 * combinations supported.  Each property's value is a comma-separated list of
 * this form:
 * <p>
 * <code>parent-path:path-within-parent
 * <p>
 * Both the parent-path and the path-within-parent are valid XPath expressions.
 * We need to separate them like this because if the node is not present we
 * need to insert it into the parent, so we need the parent piece separate.
 * For example, the setting
 * <p>
 * <code>/jnlp:/@codebase
 * <p>
 * refers to the codebase attribute within the jnlp element, while
 * <p>/jnlp/resources:/property

* refers to the property element within the resources element within the * jnlp element. * * @author tjquinn */ abstract class CombinedXPath { private static final Logger logger = Logger.getLogger(CombinedXPath.class.getName()); /** property names for the types of combined JNLP content */ private static final String OWNED_PROPERTY_NAME = "owned"; private static final String DEFAULTED_PROPERTY_NAME = "defaulted"; private static final String MERGED_PROPERTY_NAME = "merged"; private final static XPathFactory xPathFactory = XPathFactory.newInstance(); private final static XPath xPath = xPathFactory.newXPath(); private static LSSerializer lsSerializer = null; private static LSOutput lsOutput = null; private final String parentPath; private final String targetRelativePath; /** xpath expression for the target node in the DOM for the developer's XML */ private final XPathExpression targetExpr; /** if developer didn't provide the target, this is the parent where we'll * create a new child. */ private final XPathExpression parentExpr; private static enum Type { OWNED(OWNED_PROPERTY_NAME), DEFAULTED(DEFAULTED_PROPERTY_NAME), MERGED(MERGED_PROPERTY_NAME); private String propertyName; Type(final String propName) { propertyName = propName; } } static List<CombinedXPath> parse(final Properties p) { List<CombinedXPath> result = new ArrayList(); // result.addAll(CombinedXPath.parse(p, CombinedXPath.Type.OWNED)); result.addAll(CombinedXPath.parse(p, CombinedXPath.Type.DEFAULTED)); result.addAll(CombinedXPath.parse(p, CombinedXPath.Type.MERGED)); return result; } /** * For the given combination type fetch the corresponding property value * from the config properties and then parse it into the separate * parent:with-parent pairs, creating for each pair the correct type of * CombinedXPath object and returning a List of them. * @param p * @param type * @return */ private static List<CombinedXPath> parse( final Properties p, Type type) { final List<CombinedXPath> result = new ArrayList<CombinedXPath>(); final String refs = p.getProperty(type.propertyName); for (String ref : refs.split(",")) { final String paths[] = ref.split(":"); if (paths.length != 2) { throw new IllegalArgumentException(ref); } switch (type) { case OWNED: result.add(new OwnedXPath(xPath, paths[0], paths[1])); break; case MERGED: result.add(new MergedXPath(xPath, paths[0], paths[1])); break; case DEFAULTED: result.add(new DefaultedXPath(xPath, paths[0], paths[1])); break; } } return result; } /** * Creates a new combined XPath. * * @param xPath XPath available for searching * @param parentPath path to parent for new child (if developer's document lacks the target) * @param targetRelativePath path relative to the parent for the target node in the developer DOM */ CombinedXPath( final XPath xPath, final String parentPath, final String targetRelativePath) { this.parentPath = parentPath; this.targetRelativePath = targetRelativePath; try { parentExpr = xPath.compile(parentPath); targetExpr = xPath.compile(parentPath + targetRelativePath); } catch (Exception e) { throw new RuntimeException(e); } } String parentPath() { return parentPath; } String targetRelativePath() { return targetRelativePath; } XPathExpression targetExpr() { return targetExpr; } XPathExpression parentExpr() { return parentExpr; } /** * Processes the given combination: replaces, defaults, or merges. * <p> * Note that the template - which takes the form at this point of the * generatedDOM - contains some text nodes that are important. So we * start with the generatedDOM as the "master" and then combine the * developer content into it. * * @param developerDOM * @param generatedDOM * @throws XPathExpressionException */ abstract void process(final Document developerDOM, final Document generatedDOM) throws XPathExpressionException; protected void insert( final Document originalDOM, final Node insertionPoint, final Node newNode) throws XPathExpressionException { if (newNode instanceof Attr) { setAttr(originalDOM, insertionPoint, (Attr) newNode); } else { insertNode(originalDOM, insertionPoint, newNode); } } private void setAttr( final Document originalDOM, final Node insertionPoint, final Attr newAttr) throws XPathExpressionException { final Element parent = (insertionPoint == null) ? (Element) parentExpr().evaluate(originalDOM, XPathConstants.NODE) : ((Attr) insertionPoint).getOwnerElement(); parent.setAttribute(newAttr.getName(), newAttr.getValue()); } private void insertNode( final Document originalDOM, final Node insertionPoint, final Node newNode) throws XPathExpressionException { final Node parentNode = (insertionPoint == null) ? (Node) parentExpr().evaluate(originalDOM, XPathConstants.NODE) : insertionPoint.getParentNode(); parentNode.insertBefore(originalDOM.adoptNode(newNode), insertionPoint); } /** * Represents a node in the document which we completely determine, * overriding any corresponding node from the developer's DOM. */ static class OwnedXPath extends CombinedXPath { OwnedXPath( final XPath xPath, final String parentPath, final String targetRelativePath) { super(xPath, parentPath, targetRelativePath); } @Override void process(Document developerDOM, Document generatedDOM) throws XPathExpressionException { } } /** * Represents a combination of the two XML documents resulting from * merging the two input documents. */ static class MergedXPath extends CombinedXPath { MergedXPath( final XPath xPath, final String parentPath, final String targetRelativePath) { super(xPath, parentPath, targetRelativePath); } @Override void process(Document developerDOM, Document generatedDOM) throws XPathExpressionException { NodeList developerNodes = (NodeList) targetExpr().evaluate(developerDOM, XPathConstants.NODESET); NodeList generatedNodes = (NodeList) targetExpr().evaluate(generatedDOM, XPathConstants.NODESET); final Node insertionPoint = (generatedNodes.getLength() > 0) ? generatedNodes.item(0) : null; final boolean isDetailed = logger.isLoggable(Level.FINER); for (int i = 0; i < developerNodes.getLength(); i++) { if (isDetailed) { logger.log(Level.FINER, "Inserting new node due to {0}:{1}", new Object[]{parentPath(), targetRelativePath()}); } insert(generatedDOM, insertionPoint, developerNodes.item(i)); if (isDetailed) { logger.log(Level.FINER, toXML(generatedDOM)); } } } } /** * Represents a combination in which the developer's setting is used if * present; otherwise the generated document's setting is used. */ static class DefaultedXPath extends CombinedXPath { DefaultedXPath( final XPath xPath, final String parentPath, final String targetRelativePath) { super(xPath, parentPath, targetRelativePath); } @Override void process(Document developerDOM, Document generatedDOM) throws XPathExpressionException { /* * The developer provided content for this XPath. So remove the * generated node(s) for this XPath and replace them with the * ones from the developer's content. */ final NodeList replacementNodes = (NodeList) targetExpr().evaluate(developerDOM, XPathConstants.NODESET); if (replacementNodes.getLength() == 0) { return; } final NodeList originalNodes = (NodeList) targetExpr().evaluate(generatedDOM, XPathConstants.NODESET); /* * Replace all the matching original children (if any) with the * replacement ones. */ final Node insertionPoint = (originalNodes.getLength() > 0) ? originalNodes.item(0).getPreviousSibling() : null; /* * Remove the old node first. They could be attributes and, if so, * we need to remove them first before setting them with the * replacement values. Otherwise, if we removed the old nodes * after setting the new ones, we could accidentally erase new * settings that were intended to replace old settings. */ final boolean isDetailed = logger.isLoggable(Level.FINER); for (int i = 0; i < originalNodes.getLength(); i++) { if (isDetailed) { logger.log(Level.FINER, "Removing generated node to make way for developer node based on {0}:{1}", new Object[] {parentPath(), targetRelativePath()}); } remove(originalNodes.item(i)); if (isDetailed) { logger.log(Level.FINER, toXML(generatedDOM)); } } for (int i = 0; i < replacementNodes.getLength(); i++) { insert(generatedDOM, insertionPoint, replacementNodes.item(i)); if (isDetailed) { logger.log(Level.FINER, toXML(generatedDOM)); } } } private void remove(final Node originalNode) { if (originalNode instanceof Attr) { removeAttr((Attr) originalNode); } else { removeNode(originalNode); } } private void removeNode(final Node originalNode) { originalNode.getParentNode().removeChild(originalNode); } private void removeAttr(final Attr originalAttr) { final Element parent = originalAttr.getOwnerElement(); parent.removeAttribute(originalAttr.getName()); } } /** * Creates a new node that copies its info from the original node and * has similarly created ancestors. * * @param original the Node for which ancestry will be computed * @return */ private static Node ancestry(Node original) { Node nextAncestor; Node displayAncestor; Attr thisAttr = null; if (original.getNodeType() == Node.ATTRIBUTE_NODE) { thisAttr = (Attr) original; nextAncestor = thisAttr.getOwnerElement(); } else { nextAncestor = original.getParentNode(); } displayAncestor = original.getOwnerDocument().createElement(nextAncestor.getNodeName()); if (thisAttr != null) { ((Element) displayAncestor).setAttribute(thisAttr.getName(), thisAttr.getValue()); } nextAncestor = nextAncestor.getParentNode(); while (nextAncestor != null && nextAncestor instanceof Element) { Element newDisplayAncestor = original.getOwnerDocument().createElement(nextAncestor.getNodeName()); NamedNodeMap attrs = ((Node) nextAncestor).getAttributes(); for (int i = 0; i < attrs.getLength(); i++) { newDisplayAncestor.setAttribute(attrs.item(i).getNodeName(), attrs.item(i).getNodeValue()); } newDisplayAncestor.appendChild(displayAncestor); displayAncestor = newDisplayAncestor; nextAncestor = nextAncestor.getParentNode(); } return displayAncestor; } private static String toXML(final Node node) { Writer writer = new StringWriter(); writeXML(node, writer); return writer.toString(); } private synchronized static void writeXML(final Node node, final Writer writer) { try { if (lsSerializer == null) { final DOMImplementation domImpl = DOMImplementationRegistry.newInstance(). getDOMImplementation(""); final DOMImplementationLS domLS = (DOMImplementationLS) domImpl.getFeature("LS", "3.0"); lsOutput = domLS.createLSOutput(); lsOutput.setEncoding("UTF-8"); lsSerializer = domLS.createLSSerializer(); } lsOutput.setCharacterStream(writer); lsSerializer.write(node, lsOutput); } catch (Exception ex) { throw new RuntimeException(ex); } } }

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish CombinedXPath.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.