1 /* 2 * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jnlp.converter.parser; 25 26 import java.net.URL; 27 import java.net.MalformedURLException; 28 29 import jnlp.converter.parser.exception.BadFieldException; 30 import jnlp.converter.parser.exception.MissingFieldException; 31 import jnlp.converter.parser.xml.XMLNode; 32 33 /** Contains handy methods for looking up information 34 * stored in XMLNodes. 35 */ 36 public class XMLUtils { 37 38 /** Returns the value of an integer attribute */ 39 public static int getIntAttribute(String source, XMLNode root, String path, String name, int defaultvalue) 40 throws BadFieldException { 41 String value = getAttribute(root, path, name); 42 if (value == null) { 43 return defaultvalue; 44 } 45 46 try { 47 return Integer.parseInt(value); 48 } catch (NumberFormatException nfe) { 49 throw new BadFieldException(source, getPathString(root) + path + name, value); 50 } 51 } 52 53 /** Returns the value of a given attribute, or null if not set */ 54 public static String getAttribute(XMLNode root, String path, String name) 55 throws BadFieldException { 56 return getAttribute(root, path, name, null); 57 } 58 59 /** Returns the value of a given attribute */ 60 public static String getRequiredAttributeEmptyOK(String source, 61 XMLNode root, String path, String name) throws MissingFieldException { 62 String value = null; 63 XMLNode elem = findElementPath(root, path); 64 if (elem != null) { 65 value = elem.getAttribute(name); 66 } 67 if (value == null) { 68 throw new MissingFieldException(source, 69 getPathString(root)+ path + name); 70 } 71 return value; 72 } 73 74 /*** Returns the value of an attribute, which must be a valid class name */ 75 public static String getClassName(String source, XMLNode root, 76 String path, String name, boolean required) 77 throws BadFieldException, MissingFieldException { 78 79 String className; 80 if (required) { 81 className = getRequiredAttribute(source, root, path, name); 82 } else { 83 className = getAttribute(root, path, name); 84 } 85 if (className != null && className.endsWith(".class")) { 86 int i = className.lastIndexOf(".class"); 87 String cname = className.substring(0, i); 88 return cname; 89 } 90 return className; 91 } 92 93 /** Returns the value of a given attribute, or null if not set */ 94 public static String getRequiredAttribute(String source, XMLNode root, 95 String path, String name) throws MissingFieldException, BadFieldException { 96 String s = getAttribute(root, path, name, null); 97 if (s == null) { 98 throw new MissingFieldException(source, getPathString(root) + path + name); 99 } 100 s = s.trim(); 101 return (s.length() == 0) ? null : s; 102 } 103 104 /** Returns the value of a given attribute, or the default value 'def' if not set */ 105 public static String getAttribute(XMLNode root, String path, String name, 106 String def) throws BadFieldException { 107 XMLNode elem = findElementPath(root, path); 108 if (elem == null) { 109 return def; 110 } 111 String value = elem.getAttribute(name); 112 return (value == null || value.length() == 0) ? def : value; 113 } 114 115 /** Expands a URL into an absolute URL from a relative URL */ 116 public static URL getAttributeURL(String source, URL base, XMLNode root, String path, String name) throws BadFieldException { 117 String value = getAttribute(root, path, name); 118 if (value == null) return null; 119 try { 120 if (value.startsWith("jar:")) { 121 int bang = value.indexOf("!/"); 122 if (bang > 0) { 123 String entry = value.substring(bang); 124 String urlString = value.substring(4, bang); 125 URL url = (base == null) ? 126 new URL(urlString) : new URL(base, urlString); 127 return new URL("jar:" + url.toString() + entry); 128 } 129 } 130 return (base == null) ? new URL(value) : new URL(base, value); 131 } catch(MalformedURLException mue) { 132 if (mue.getMessage().contains("https")) { 133 throw new BadFieldException(source, "<jnlp>", "https"); 134 } 135 throw new BadFieldException(source, getPathString(root) + path + name, value); 136 } 137 } 138 139 /** Returns the value of an attribute as a URL or null if not set */ 140 public static URL getAttributeURL(String source, XMLNode root, String path, String name) throws BadFieldException { 141 return getAttributeURL(source, null, root, path, name); 142 } 143 144 public static URL getRequiredURL(String source, URL base, XMLNode root, String path, String name) throws BadFieldException, MissingFieldException { 145 URL url = getAttributeURL(source, base, root, path, name); 146 if (url == null) { 147 throw new MissingFieldException(source, getPathString(root) + path + name); 148 } 149 return url; 150 } 151 152 /** Returns the value of an attribute as a URL. Throws a MissingFieldException if the 153 * attribute is not defined 154 */ 155 public static URL getRequiredURL(String source, XMLNode root, String path, String name) throws BadFieldException, MissingFieldException { 156 return getRequiredURL(source, null, root, path, name); 157 } 158 159 /** Returns true if the path exists in the document, otherwise false */ 160 public static boolean isElementPath(XMLNode root, String path) { 161 return findElementPath(root, path) != null; 162 } 163 164 public static URL getElementURL(String source, XMLNode root, String path) throws BadFieldException { 165 String value = getElementContents(root, path); 166 try { 167 return new URL(value); 168 } catch(MalformedURLException mue) { 169 throw new BadFieldException(source, getPathString(root) + path, value); 170 } 171 } 172 173 /** Returns a string describing the current location in the DOM */ 174 public static String getPathString(XMLNode e) { 175 return (e == null || !(e.isElement())) ? "" : getPathString(e.getParent()) + "<" + e.getName() + ">"; 176 } 177 178 /** Returns the contents of an element with the given path and an attribute matching a specific value. Returns 179 * NULL if not found 180 */ 181 public static String getElementContentsWithAttribute(XMLNode root, String path, String attr, String val, String defaultvalue) 182 throws BadFieldException, MissingFieldException { 183 XMLNode e = getElementWithAttribute(root, path, attr, val); 184 if (e == null) { 185 return defaultvalue; 186 } 187 return getElementContents(e, "", defaultvalue); 188 } 189 190 public static URL getAttributeURLWithAttribute(String source, XMLNode root, String path, String attrcond, String val, 191 String name, URL defaultvalue) 192 throws BadFieldException, MissingFieldException { 193 XMLNode e = getElementWithAttribute(root, path, attrcond, val); 194 if (e == null) { 195 return defaultvalue; 196 } 197 URL url = getAttributeURL(source, e, "", name); 198 if (url == null) { 199 return defaultvalue; 200 } 201 return url; 202 } 203 204 /** Returns an element with the given path and an attribute matching a specific value. Returns 205 * NULL if not found 206 */ 207 public static XMLNode getElementWithAttribute(XMLNode root, String path, final String attr, final String val) 208 throws BadFieldException, MissingFieldException { 209 final XMLNode[] result = {null}; 210 visitElements(root, path, new ElementVisitor() { 211 public void visitElement(XMLNode e) throws BadFieldException, MissingFieldException { 212 if (result[0] == null && e.getAttribute(attr).equals(val)) { 213 result[0] = e; 214 } 215 } 216 }); 217 return result[0]; 218 } 219 220 /** Like getElementContents(...) but with a defaultValue of null */ 221 public static String getElementContents(XMLNode root, String path) { 222 return getElementContents(root, path, null); 223 } 224 225 /** Returns the value of the last element tag in the path, e.g., <..><tag>value</tag>. The DOM is assumes 226 * to be normalized. If no value is found, the defaultvalue is returned 227 */ 228 public static String getElementContents(XMLNode root, String path, String defaultvalue) { 229 XMLNode e = findElementPath(root, path); 230 if (e == null) { 231 return defaultvalue; 232 } 233 XMLNode n = e.getNested(); 234 if (n != null && !n.isElement()) { 235 return n.getName(); 236 } 237 return defaultvalue; 238 } 239 240 /** Parses a path string of the form <tag1><tag2><tag3> and returns the specific Element 241 * node for that tag, or null if it does not exist. If multiple elements exists with same 242 * path the first is returned 243 */ 244 public static XMLNode findElementPath(XMLNode elem, String path) { 245 // End condition. Root null -> path does not exist 246 if (elem == null) { 247 return null; 248 } 249 250 // End condition. String empty, return current root 251 if (path == null || path.length() == 0) { 252 return elem; 253 } 254 255 // Strip of first tag 256 int idx = path.indexOf('>'); 257 if (!(path.charAt(0) == '<')) { 258 throw new IllegalArgumentException("bad path. Missing begin tag"); 259 } 260 if (idx == -1) { 261 throw new IllegalArgumentException("bad path. Missing end tag"); 262 } 263 String head = path.substring(1, idx); 264 String tail = path.substring(idx + 1); 265 return findElementPath(findChildElement(elem, head), tail); 266 } 267 268 /** Returns an child element with the current tag name or null. */ 269 public static XMLNode findChildElement(XMLNode elem, String tag) { 270 XMLNode n = elem.getNested(); 271 while (n != null) { 272 if (n.isElement() && n.getName().equals(tag)) { 273 return n; 274 } 275 n = n.getNext(); 276 } 277 return null; 278 } 279 280 /** Iterator class */ 281 public abstract static class ElementVisitor { 282 abstract public void visitElement(XMLNode e) throws BadFieldException, MissingFieldException; 283 } 284 285 /** Visits all elements which matches the <path>. The iteration is only 286 * done on the last element in the path. 287 */ 288 public static void visitElements(XMLNode root, String path, ElementVisitor ev) 289 throws BadFieldException, MissingFieldException { 290 // Get last element in path 291 int idx = path.lastIndexOf('<'); 292 if (idx == -1) { 293 throw new IllegalArgumentException( 294 "bad path. Must contain atleast one tag"); 295 } 296 if (path.length() == 0 || path.charAt(path.length() - 1) != '>') { 297 throw new IllegalArgumentException("bad path. Must end with a >"); 298 } 299 String head = path.substring(0, idx); 300 String tag = path.substring(idx + 1, path.length() - 1); 301 302 XMLNode elem = findElementPath(root, head); 303 if (elem == null) { 304 return; 305 } 306 307 // Iterate through all child nodes 308 XMLNode n = elem.getNested(); 309 while (n != null) { 310 if (n.isElement() && n.getName().equals(tag)) { 311 ev.visitElement(n); 312 } 313 n = n.getNext(); 314 } 315 } 316 317 public static void visitChildrenElements(XMLNode elem, ElementVisitor ev) 318 throws BadFieldException, MissingFieldException { 319 // Iterate through all child nodes 320 XMLNode n = elem.getNested(); 321 while (n != null) { 322 if (n.isElement()) { 323 ev.visitElement(n); 324 } 325 n = n.getNext(); 326 } 327 } 328 }