1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /** 6 * Licensed to the Apache Software Foundation (ASF) under one 7 * or more contributor license agreements. See the NOTICE file 8 * distributed with this work for additional information 9 * regarding copyright ownership. The ASF licenses this file 10 * to you under the Apache License, Version 2.0 (the 11 * "License"); you may not use this file except in compliance 12 * with the License. You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, 17 * software distributed under the License is distributed on an 18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 * KIND, either express or implied. See the License for the 20 * specific language governing permissions and limitations 21 * under the License. 22 */ 23 package com.sun.org.apache.xml.internal.security.utils; 24 25 import java.lang.reflect.Constructor; 26 import java.lang.reflect.Method; 27 import java.lang.reflect.Modifier; 28 29 import javax.xml.transform.ErrorListener; 30 import javax.xml.transform.SourceLocator; 31 import javax.xml.transform.TransformerException; 32 33 import com.sun.org.apache.xml.internal.security.transforms.implementations.FuncHere; 34 import com.sun.org.apache.xml.internal.utils.PrefixResolver; 35 import com.sun.org.apache.xml.internal.utils.PrefixResolverDefault; 36 import com.sun.org.apache.xpath.internal.Expression; 37 import com.sun.org.apache.xpath.internal.XPath; 38 import com.sun.org.apache.xpath.internal.XPathContext; 39 import com.sun.org.apache.xpath.internal.compiler.FunctionTable; 40 import com.sun.org.apache.xpath.internal.objects.XObject; 41 import org.w3c.dom.Document; 42 import org.w3c.dom.Node; 43 import org.w3c.dom.NodeList; 44 45 /** 46 * An implementation of XPathAPI using Xalan. This supports the "here()" function defined in the digital 47 * signature spec. 48 */ 49 public class XalanXPathAPI implements XPathAPI { 50 51 private static java.util.logging.Logger log = 52 java.util.logging.Logger.getLogger(XalanXPathAPI.class.getName()); 53 54 private String xpathStr = null; 55 56 private XPath xpath = null; 57 58 private static FunctionTable funcTable = null; 59 60 private static boolean installed; 61 62 private XPathContext context; 63 64 static { 65 fixupFunctionTable(); 66 } 67 68 69 /** 70 * Use an XPath string to select a nodelist. 71 * XPath namespace prefixes are resolved from the namespaceNode. 72 * 73 * @param contextNode The node to start searching from. 74 * @param xpathnode 75 * @param str 76 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces. 77 * @return A NodeIterator, should never be null. 78 * 79 * @throws TransformerException 80 */ 81 public NodeList selectNodeList( 82 Node contextNode, Node xpathnode, String str, Node namespaceNode 83 ) throws TransformerException { 84 85 // Execute the XPath, and have it return the result 86 XObject list = eval(contextNode, xpathnode, str, namespaceNode); 87 88 // Return a NodeList. 89 return list.nodelist(); 90 } 91 92 /** 93 * Evaluate an XPath string and return true if the output is to be included or not. 94 * @param contextNode The node to start searching from. 95 * @param xpathnode The XPath node 96 * @param str The XPath expression 97 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces. 98 */ 99 public boolean evaluate(Node contextNode, Node xpathnode, String str, Node namespaceNode) 100 throws TransformerException { 101 XObject object = eval(contextNode, xpathnode, str, namespaceNode); 102 return object.bool(); 103 } 104 105 /** 106 * Clear any context information from this object 107 */ 108 public void clear() { 109 xpathStr = null; 110 xpath = null; 111 context = null; 112 } 113 114 public synchronized static boolean isInstalled() { 115 return installed; 116 } 117 118 private XObject eval(Node contextNode, Node xpathnode, String str, Node namespaceNode) 119 throws TransformerException { 120 if (context == null) { 121 context = new XPathContext(xpathnode); 122 context.setSecureProcessing(true); 123 } 124 125 // Create an object to resolve namespace prefixes. 126 // XPath namespaces are resolved from the input context node's document element 127 // if it is a root node, or else the current context node (for lack of a better 128 // resolution space, given the simplicity of this sample code). 129 Node resolverNode = 130 (namespaceNode.getNodeType() == Node.DOCUMENT_NODE) 131 ? ((Document) namespaceNode).getDocumentElement() : namespaceNode; 132 PrefixResolverDefault prefixResolver = new PrefixResolverDefault(resolverNode); 133 134 if (!str.equals(xpathStr)) { 135 if (str.indexOf("here()") > 0) { 136 context.reset(); 137 } 138 xpath = createXPath(str, prefixResolver); 139 xpathStr = str; 140 } 141 142 // Execute the XPath, and have it return the result 143 int ctxtNode = context.getDTMHandleFromNode(contextNode); 144 145 return xpath.execute(context, ctxtNode, prefixResolver); 146 } 147 148 private XPath createXPath(String str, PrefixResolver prefixResolver) throws TransformerException { 149 XPath xpath = null; 150 Class<?>[] classes = new Class<?>[]{String.class, SourceLocator.class, PrefixResolver.class, int.class, 151 ErrorListener.class, FunctionTable.class}; 152 Object[] objects = 153 new Object[]{str, null, prefixResolver, Integer.valueOf(XPath.SELECT), null, funcTable}; 154 try { 155 Constructor<?> constructor = XPath.class.getConstructor(classes); 156 xpath = (XPath) constructor.newInstance(objects); 157 } catch (Exception ex) { 158 if (log.isLoggable(java.util.logging.Level.FINE)) { 159 log.log(java.util.logging.Level.FINE, ex.getMessage(), ex); 160 } 161 } 162 if (xpath == null) { 163 xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null); 164 } 165 return xpath; 166 } 167 168 private synchronized static void fixupFunctionTable() { 169 installed = false; 170 if (log.isLoggable(java.util.logging.Level.FINE)) { 171 log.log(java.util.logging.Level.FINE, "Registering Here function"); 172 } 173 /** 174 * Try to register our here() implementation as internal function. 175 */ 176 try { 177 Class<?>[] args = {String.class, Expression.class}; 178 Method installFunction = FunctionTable.class.getMethod("installFunction", args); 179 if ((installFunction.getModifiers() & Modifier.STATIC) != 0) { 180 Object[] params = {"here", new FuncHere()}; 181 installFunction.invoke(null, params); 182 installed = true; 183 } 184 } catch (Exception ex) { 185 log.log(java.util.logging.Level.FINE, "Error installing function using the static installFunction method", ex); 186 } 187 if (!installed) { 188 try { 189 funcTable = new FunctionTable(); 190 Class<?>[] args = {String.class, Class.class}; 191 Method installFunction = FunctionTable.class.getMethod("installFunction", args); 192 Object[] params = {"here", FuncHere.class}; 193 installFunction.invoke(funcTable, params); 194 installed = true; 195 } catch (Exception ex) { 196 log.log(java.util.logging.Level.FINE, "Error installing function using the static installFunction method", ex); 197 } 198 } 199 if (log.isLoggable(java.util.logging.Level.FINE)) { 200 if (installed) { 201 log.log(java.util.logging.Level.FINE, "Registered class " + FuncHere.class.getName() 202 + " for XPath function 'here()' function in internal table"); 203 } else { 204 log.log(java.util.logging.Level.FINE, "Unable to register class " + FuncHere.class.getName() 205 + " for XPath function 'here()' function in internal table"); 206 } 207 } 208 } 209 210 }