|
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 } |