1 /* 2 * Copyright (c) 2015, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.xml.catalog; 26 27 import java.io.File; 28 import java.io.IOException; 29 import java.net.MalformedURLException; 30 import java.net.URI; 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; 42 import jdk.xml.internal.SecuritySupport; 43 44 /** 45 * 46 * @since 9 47 */ 48 class Util { 49 50 final static String URN = "urn:publicid:"; 51 final static String PUBLICID_PREFIX = "-//"; 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:"; 56 57 /** 58 * Finds an entry in the catalog that matches with the publicId or systemId. 59 * 60 * The resolution follows the following rules determined by the prefer 61 * setting: 62 * 63 * prefer "system": attempts to resolve with a system entry; attempts to 64 * resolve with a public entry when only publicId is specified. 65 * 66 * prefer "public": attempts to resolve with a system entry; attempts to 67 * resolve with a public entry if no matching system entry is found. 68 * 69 * If no match is found, continue searching uri entries 70 * 71 * @param catalog the catalog 72 * @param publicId the publicId 73 * @param systemId the systemId 74 * @return the resolved systemId if a match is found, null otherwise 75 */ 76 static String resolve(CatalogImpl catalog, String publicId, String systemId) { 77 String resolvedSystemId = null; 78 79 //search the current catalog 80 catalog.reset(); 81 if (systemId != null) { 82 /* 83 If a system identifier is specified, it is used no matter how 84 prefer is set. 85 */ 86 resolvedSystemId = catalog.matchSystem(systemId); 87 } 88 89 if (resolvedSystemId == null && publicId != null) { 90 resolvedSystemId = catalog.matchPublic(publicId); 91 } 92 93 if (resolvedSystemId == null && systemId != null) { 94 resolvedSystemId = catalog.matchURI(systemId); 95 } 96 97 //mark the catalog as having been searched before trying alternatives 98 catalog.markAsSearched(); 99 100 //search alternative catalogs 101 if (resolvedSystemId == null) { 102 Iterator<Catalog> iter = catalog.catalogs().iterator(); 103 while (iter.hasNext()) { 104 resolvedSystemId = resolve((CatalogImpl) iter.next(), publicId, systemId); 105 if (resolvedSystemId != null) { 106 break; 107 } 108 109 } 110 } 111 112 return resolvedSystemId; 113 } 114 115 static void validateUrisSyntax(URI... uris) { 116 for (URI uri : uris) { 117 validateUriSyntax(uri); 118 } 119 } 120 121 static void validateUrisSyntax(String... uris) { 122 for (String uri : uris) { 123 validateUriSyntax(URI.create(uri)); 124 } 125 } 126 127 /** 128 * Validate that the URI must be absolute and a valid URL. 129 * 130 * Note that this method does not verify the existence of the resource. The 131 * Catalog standard requires that such resources be ignored. 132 * 133 * @param uri 134 * @throws IllegalArgumentException if the uri is not absolute and a valid 135 * URL 136 */ 137 static void validateUriSyntax(URI uri) { 138 CatalogMessages.reportNPEOnNull("URI input", uri); 139 140 if (!uri.isAbsolute()) { 141 CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTABSOLUTE, 142 new Object[]{uri}, null); 143 } 144 145 try { 146 // check if the scheme was valid 147 uri.toURL(); 148 } catch (MalformedURLException ex) { 149 CatalogMessages.reportIAE(CatalogMessages.ERR_URI_NOTVALIDURL, 150 new Object[]{uri}, null); 151 } 152 } 153 154 /** 155 * Checks whether the URI is a file URI, including JAR file. 156 * 157 * @param uri the specified URI. 158 * @return true if it is a file or JAR file URI, false otherwise 159 */ 160 static boolean isFileUri(URI uri) { 161 if (SCHEME_FILE.equals(uri.getScheme()) 162 || SCHEME_JAR.equals(uri.getScheme())) { 163 return true; 164 } 165 return false; 166 } 167 168 /** 169 * Verifies whether the file resource exists. 170 * 171 * @param uri the URI to locate the resource 172 * @param openJarFile a flag to indicate whether a JAR file should be 173 * opened. This operation may be expensive. 174 * @return true if the resource exists, false otherwise. 175 */ 176 static boolean isFileUriExist(URI uri, boolean openJarFile) { 177 if (uri != null && uri.isAbsolute()) { 178 if (null != uri.getScheme()) { 179 switch (uri.getScheme()) { 180 case SCHEME_FILE: 181 String path = uri.getPath(); 182 File f1 = new File(path); 183 if (f1.isFile()) { 184 return true; 185 } 186 break; 187 case SCHEME_JAR: 188 String tempUri = uri.toString(); 189 int pos = tempUri.indexOf("!"); 190 if (pos < 0) { 191 return false; 192 } 193 if (openJarFile) { 194 String jarFile = tempUri.substring(SCHEME_JARFILE.length(), pos); 195 String entryName = tempUri.substring(pos + 2); 196 try { 197 JarFile jf = new JarFile(jarFile); 198 JarEntry je = jf.getJarEntry(entryName); 199 if (je != null) { 200 return true; 201 } 202 } catch (IOException ex) { 203 return false; 204 } 205 } else { 206 return true; 207 } 208 break; 209 } 210 } 211 } 212 return false; 213 } 214 215 /** 216 * Find catalog file paths by reading the system property, and then 217 * jaxp.properties if the system property is not specified. 218 * 219 * @param sysPropertyName the name of system property 220 * @return the catalog file paths, or null if not found. 221 */ 222 static String[] getCatalogFiles(String sysPropertyName) { 223 String value = SecuritySupport.getJAXPSystemProperty(sysPropertyName); 224 if (value != null && !value.isEmpty()) { 225 return value.split(";"); 226 } 227 return null; 228 } 229 230 /** 231 * Checks whether the specified string is null or empty, returns the 232 * original string with leading and trailing spaces removed if not. 233 * 234 * @param test the string to be tested 235 * @return the original string with leading and trailing spaces removed, or 236 * null if it is null or empty 237 * 238 */ 239 static String getNotNullOrEmpty(String test) { 240 if (test == null) { 241 return test; 242 } else { 243 String temp = test.trim(); 244 if (temp.length() == 0) { 245 return null; 246 } else { 247 return temp; 248 } 249 } 250 } 251 252 /** 253 * Validates the input for features. 254 * 255 * @param f the feature 256 * @param value the value 257 * @throws IllegalArgumentException if the value is invalid for the feature 258 */ 259 static void validateFeatureInput(Feature f, String value) { 260 CatalogMessages.reportNPEOnNull(f.name(), value); 261 if (value.length() == 0) { 262 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, 263 new Object[]{value, f.name()}, null); 264 } 265 266 if (f == Feature.PREFER) { 267 if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) { 268 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, 269 new Object[]{value, Feature.PREFER.name()}, null); 270 } 271 } else if (f == Feature.DEFER) { 272 if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) { 273 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, 274 new Object[]{value, Feature.DEFER.name()}, null); 275 } 276 } else if (f == Feature.RESOLVE) { 277 if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE) 278 && !value.equals(RESOLVE_IGNORE)) { 279 CatalogMessages.reportIAE(CatalogMessages.ERR_INVALID_ARGUMENT, 280 new Object[]{value, Feature.RESOLVE.name()}, null); 281 } 282 } else if (f == Feature.FILES) { 283 Util.validateUrisSyntax(value.split(";")); 284 } 285 } 286 }