23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 package javax.xml.catalog; |
25 package javax.xml.catalog; |
26 |
26 |
27 import java.io.File; |
27 import java.io.File; |
|
28 import java.io.IOException; |
28 import java.net.MalformedURLException; |
29 import java.net.MalformedURLException; |
29 import java.net.URI; |
30 import java.net.URI; |
30 import java.net.URISyntaxException; |
|
31 import java.net.URL; |
|
32 import java.nio.file.Path; |
|
33 import java.nio.file.Paths; |
|
34 import java.util.Iterator; |
31 import java.util.Iterator; |
|
32 import java.util.jar.JarEntry; |
|
33 import java.util.jar.JarFile; |
|
34 import static javax.xml.catalog.CatalogFeatures.DEFER_FALSE; |
|
35 import static javax.xml.catalog.CatalogFeatures.DEFER_TRUE; |
|
36 import javax.xml.catalog.CatalogFeatures.Feature; |
|
37 import static javax.xml.catalog.CatalogFeatures.PREFER_PUBLIC; |
|
38 import static javax.xml.catalog.CatalogFeatures.PREFER_SYSTEM; |
|
39 import static javax.xml.catalog.CatalogFeatures.RESOLVE_CONTINUE; |
|
40 import static javax.xml.catalog.CatalogFeatures.RESOLVE_IGNORE; |
|
41 import static javax.xml.catalog.CatalogFeatures.RESOLVE_STRICT; |
35 import jdk.xml.internal.SecuritySupport; |
42 import jdk.xml.internal.SecuritySupport; |
36 |
43 |
37 /** |
44 /** |
38 * |
45 * |
39 * @since 9 |
46 * @since 9 |
40 */ |
47 */ |
41 class Util { |
48 class Util { |
|
49 |
42 final static String URN = "urn:publicid:"; |
50 final static String URN = "urn:publicid:"; |
43 final static String PUBLICID_PREFIX = "-//"; |
51 final static String PUBLICID_PREFIX = "-//"; |
44 final static String PUBLICID_PREFIX_ALT = "+//"; |
52 final static String PUBLICID_PREFIX_ALT = "+//"; |
|
53 final static String SCHEME_FILE = "file"; |
|
54 final static String SCHEME_JAR = "jar"; |
|
55 final static String SCHEME_JARFILE = "jar:file:"; |
45 |
56 |
46 /** |
57 /** |
47 * Finds an entry in the catalog that matches with the publicId or systemId. |
58 * Finds an entry in the catalog that matches with the publicId or systemId. |
48 * |
59 * |
49 * The resolution follows the following rules determined by the prefer setting: |
60 * The resolution follows the following rules determined by the prefer |
50 * |
61 * setting: |
51 * prefer "system": attempts to resolve with a system entry; |
62 * |
52 * attempts to resolve with a public entry when only |
63 * prefer "system": attempts to resolve with a system entry; attempts to |
53 * publicId is specified. |
64 * resolve with a public entry when only publicId is specified. |
54 * |
65 * |
55 * prefer "public": attempts to resolve with a system entry; |
66 * prefer "public": attempts to resolve with a system entry; attempts to |
56 * attempts to resolve with a public entry if no matching |
67 * resolve with a public entry if no matching system entry is found. |
57 * system entry is found. |
|
58 * |
68 * |
59 * If no match is found, continue searching uri entries |
69 * If no match is found, continue searching uri entries |
60 * |
70 * |
61 * @param catalog the catalog |
71 * @param catalog the catalog |
62 * @param publicId the publicId |
72 * @param publicId the publicId |
89 |
99 |
90 //search alternative catalogs |
100 //search alternative catalogs |
91 if (resolvedSystemId == null) { |
101 if (resolvedSystemId == null) { |
92 Iterator<Catalog> iter = catalog.catalogs().iterator(); |
102 Iterator<Catalog> iter = catalog.catalogs().iterator(); |
93 while (iter.hasNext()) { |
103 while (iter.hasNext()) { |
94 resolvedSystemId = resolve((CatalogImpl)iter.next(), publicId, systemId); |
104 resolvedSystemId = resolve((CatalogImpl) iter.next(), publicId, systemId); |
95 if (resolvedSystemId != null) { |
105 if (resolvedSystemId != null) { |
96 break; |
106 break; |
97 } |
107 } |
98 |
108 |
99 } |
109 } |
100 } |
110 } |
101 |
111 |
102 return resolvedSystemId; |
112 return resolvedSystemId; |
103 } |
113 } |
104 |
114 |
105 /** |
115 static void validateUrisSyntax(URI... uris) { |
106 * Resolves the specified file path to an absolute systemId. If it is |
116 for (URI uri : uris) { |
107 * relative, it shall be resolved using the base or user.dir property if |
117 validateUriSyntax(uri); |
108 * base is not specified. |
118 } |
109 * |
119 } |
110 * @param file The specified file path |
120 |
111 * @param baseURI the base URI |
121 static void validateUrisSyntax(String... uris) { |
112 * @return The URI |
122 for (String uri : uris) { |
113 * @throws CatalogException if the specified file path can not be converted |
123 validateUriSyntax(URI.create(uri)); |
114 * to a system id |
124 } |
115 */ |
125 } |
116 static URI verifyAndGetURI(String file, URL baseURI) |
126 |
117 throws MalformedURLException, URISyntaxException, IllegalArgumentException { |
127 /** |
118 URL filepath; |
128 * Validate that the URI must be absolute and a valid URL. |
119 URI temp; |
129 * |
120 if (file != null && file.length() > 0) { |
130 * Note that this method does not verify the existence of the resource. The |
121 File f = new File(file); |
131 * Catalog standard requires that such resources be ignored. |
122 |
132 * |
123 if (baseURI != null && !f.isAbsolute()) { |
133 * @param uri |
124 filepath = new URL(baseURI, fixSlashes(file)); |
134 * @throws IllegalArgumentException if the uri is not absolute and a valid |
125 temp = filepath.toURI(); |
135 * URL |
126 } else { |
136 */ |
127 temp = resolveURI(file); |
137 static void validateUriSyntax(URI uri) { |
128 } |
138 CatalogMessages.reportNPEOnNull("URI input", uri); |
129 //Paths.get may throw IllegalArgumentException |
139 |
130 Path path = Paths.get(temp); |
140 if (!uri.isAbsolute()) { |
131 if (path.toFile().isFile()) { |
141 CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTABSOLUTE, |
132 return temp; |
142 new Object[]{uri}, null); |
133 } |
143 } |
134 } |
144 |
135 return null; |
|
136 } |
|
137 |
|
138 /** |
|
139 * Resolves the specified uri. If the uri is relative, makes it absolute by |
|
140 * the user.dir directory. |
|
141 * |
|
142 * @param uri The specified URI. |
|
143 * @return The resolved URI |
|
144 */ |
|
145 static URI resolveURI(String uri) throws MalformedURLException { |
|
146 if (uri == null) { |
|
147 uri = ""; |
|
148 } |
|
149 |
|
150 URI temp = null; |
|
151 try { |
145 try { |
152 URL url = new URL(uri); |
146 // check if the scheme was valid |
153 temp = url.toURI(); |
147 uri.toURL(); |
154 } catch (MalformedURLException | URISyntaxException mue) { |
148 } catch (MalformedURLException ex) { |
155 File file = new File(uri); |
149 CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTVALIDURL, |
156 temp = file.toURI(); |
150 new Object[]{uri}, null); |
157 } |
151 } |
158 |
152 |
159 return temp; |
153 // verify the resource exists where possible |
160 } |
154 if (isFileUri(uri)) { |
161 |
155 if (!isFileUriExist(uri, false)) { |
162 /** |
156 CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTVALIDURL, |
163 * Replace backslashes with forward slashes. (URLs always use forward |
157 new Object[]{uri}, null); |
164 * slashes.) |
158 } |
165 * |
159 } |
166 * @param sysid The input system identifier. |
160 } |
167 * @return The same system identifier with backslashes turned into forward |
161 |
168 * slashes. |
162 /** |
169 */ |
163 * Checks whether the URI is a file URI, including JAR file. |
170 static String fixSlashes(String sysid) { |
164 * |
171 return sysid.replace('\\', '/'); |
165 * @param uri the specified URI. |
|
166 * @return true if it is a file or JAR file URI, false otherwise |
|
167 */ |
|
168 static boolean isFileUri(URI uri) { |
|
169 if (SCHEME_FILE.equals(uri.getScheme()) |
|
170 || SCHEME_JAR.equals(uri.getScheme())) { |
|
171 return true; |
|
172 } |
|
173 return false; |
|
174 } |
|
175 |
|
176 /** |
|
177 * Verifies whether the file resource exists. |
|
178 * |
|
179 * @param uri the URI to locate the resource |
|
180 * @param openJarFile a flag to indicate whether a JAR file should be |
|
181 * opened. This operation may be expensive. |
|
182 * @return true if the resource exists, false otherwise. |
|
183 */ |
|
184 static boolean isFileUriExist(URI uri, boolean openJarFile) { |
|
185 if (uri != null && uri.isAbsolute()) { |
|
186 if (null != uri.getScheme()) { |
|
187 switch (uri.getScheme()) { |
|
188 case SCHEME_FILE: |
|
189 String path = uri.getPath(); |
|
190 File f1 = new File(path); |
|
191 if (f1.isFile()) { |
|
192 return true; |
|
193 } |
|
194 break; |
|
195 case SCHEME_JAR: |
|
196 String tempUri = uri.toString(); |
|
197 int pos = tempUri.indexOf("!"); |
|
198 if (pos < 0) { |
|
199 return false; |
|
200 } |
|
201 if (openJarFile) { |
|
202 String jarFile = tempUri.substring(SCHEME_JARFILE.length(), pos); |
|
203 String entryName = tempUri.substring(pos + 2); |
|
204 try { |
|
205 JarFile jf = new JarFile(jarFile); |
|
206 JarEntry je = jf.getJarEntry(entryName); |
|
207 if (je != null) { |
|
208 return true; |
|
209 } |
|
210 } catch (IOException ex) { |
|
211 return false; |
|
212 } |
|
213 } else { |
|
214 return true; |
|
215 } |
|
216 break; |
|
217 } |
|
218 } |
|
219 } |
|
220 return false; |
172 } |
221 } |
173 |
222 |
174 /** |
223 /** |
175 * Find catalog file paths by reading the system property, and then |
224 * Find catalog file paths by reading the system property, and then |
176 * jaxp.properties if the system property is not specified. |
225 * jaxp.properties if the system property is not specified. |
204 } else { |
254 } else { |
205 return temp; |
255 return temp; |
206 } |
256 } |
207 } |
257 } |
208 } |
258 } |
|
259 |
|
260 /** |
|
261 * Validates the input for features. |
|
262 * |
|
263 * @param f the feature |
|
264 * @param value the value |
|
265 * @throws IllegalArgumentException if the value is invalid for the feature |
|
266 */ |
|
267 static void validateFeatureInput(Feature f, String value) { |
|
268 CatalogMessages.reportNPEOnNull(f.name(), value); |
|
269 if (value.length() == 0) { |
|
270 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, |
|
271 new Object[]{value, f.name()}, null); |
|
272 } |
|
273 |
|
274 if (f == Feature.PREFER) { |
|
275 if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) { |
|
276 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, |
|
277 new Object[]{value, Feature.PREFER.name()}, null); |
|
278 } |
|
279 } else if (f == Feature.DEFER) { |
|
280 if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) { |
|
281 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, |
|
282 new Object[]{value, Feature.DEFER.name()}, null); |
|
283 } |
|
284 } else if (f == Feature.RESOLVE) { |
|
285 if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE) |
|
286 && !value.equals(RESOLVE_IGNORE)) { |
|
287 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, |
|
288 new Object[]{value, Feature.RESOLVE.name()}, null); |
|
289 } |
|
290 } else if (f == Feature.FILES) { |
|
291 Util.validateUrisSyntax(value.split(";")); |
|
292 } |
|
293 } |
209 } |
294 } |