1 /* 2 * Copyright (c) 2015, 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 jdk.xml.internal.SecuritySupport; 28 29 /** 30 * The CatalogFeatures holds a collection of features and properties. 31 * <p> 32 * 33 * <center><h2><a name="CatalogFeatures">Catalog Features</a></h2></center></p> 34 * 35 * <table border="1"> 36 * <thead> 37 * <tr> 38 * <th rowspan="2">Feature</th> 39 * <th rowspan="2">Description</th> 40 * <th rowspan="2">Property Name</th> 41 * <th rowspan="2">System Property [1]</th> 42 * <th rowspan="2">jaxp.properties [1]</th> 43 * <th colspan="2" align="center">Value [2]</th> 44 * <th rowspan="2">Action</th> 45 * </tr> 46 * <tr> 47 * <th>Type</th> 48 * <th>Value</th> 49 * </tr> 50 * </thead> 51 * <tbody> 52 * 53 * <tr> 54 * <td><a name="FILES">FILES</a></td> 55 * <td>A semicolon-delimited list of catalog files. Relative file paths are 56 * considered relative to ${user.dir}. 57 * </td> 58 * <td>javax.xml.catalog.files</td> 59 * <td>javax.xml.catalog.files</td> 60 * <td>javax.xml.catalog.files</td> 61 * <td>String</td> 62 * <td>File paths</td> 63 * <td> 64 * Reads the first catalog as the current catalog; Loads others if no match 65 * is found in the current catalog including delegate catalogs if any. 66 * </td> 67 * </tr> 68 * 69 * <tr> 70 * <td rowspan="2"><a name="PREFER">PREFER</a></td> 71 * <td rowspan="2">Indicates the preference between the public and system 72 * identifiers. The default value is public [3].</td> 73 * <td rowspan="2">javax.xml.catalog.prefer</td> 74 * <td rowspan="2">N/A</td> 75 * <td rowspan="2">N/A</td> 76 * <td rowspan="2">String</td> 77 * <td>{@code system}</td> 78 * <td>Searches system entries for a match; Searches public entries when 79 * external identifier specifies only a public identifier</td> 80 * </tr> 81 * <tr> 82 * <td>{@code public}</td> 83 * <td>Searches system entries for a match; Searches public entries when 84 * there is no matching system entry.</td> 85 * </tr> 86 * 87 * <tr> 88 * <td rowspan="2"><a name="DEFER">DEFER</a></td> 89 * <td rowspan="2">Indicates that the alternative catalogs including those 90 * specified in delegate entries or nextCatalog are not read until they are 91 * needed. The default value is true.</td> 92 * <td rowspan="2">javax.xml.catalog.defer [4]</td> 93 * <td rowspan="2">javax.xml.catalog.defer</td> 94 * <td rowspan="2">javax.xml.catalog.defer</td> 95 * <td rowspan="2">String</td> 96 * <td>{@code true}</td> 97 * <td>Loads alternative catalogs as needed. 98 * </td> 99 * </tr> 100 * <tr> 101 * <td>{@code false}</td> 102 * <td>Loads all catalogs[5]. </td> 103 * </tr> 104 * 105 * <tr> 106 * <td rowspan="3"><a name="RESOLVE">RESOLVE</a></td> 107 * <td rowspan="3">Determines the action if there is no matching entry found after 108 * all of the specified catalogs are exhausted. The default is strict.</td> 109 * <td rowspan="3">javax.xml.catalog.resolve [4]</td> 110 * <td rowspan="3">javax.xml.catalog.resolve</td> 111 * <td rowspan="3">javax.xml.catalog.resolve</td> 112 * <td rowspan="3">String</td> 113 * <td>{@code strict}</td> 114 * <td>Throws CatalogException if there is no match. 115 * </td> 116 * </tr> 117 * <tr> 118 * <td>{@code continue}</td> 119 * <td>Allows the XML parser to continue as if there is no match. 120 * </td> 121 * </tr> 122 * <tr> 123 * <td>{@code ignore}</td> 124 * <td>Tells the XML parser to skip the external references if there no match. 125 * </td> 126 * </tr> 127 * 128 * </tbody> 129 * </table> 130 * <p> 131 * <b>[1]</b> There is no System property for the features that marked as "N/A". 132 * 133 * <p> 134 * <b>[2]</b> The value shall be exactly as listed in this table, case-sensitive. 135 * Any unspecified value will result in {@link IllegalArgumentException}. 136 * <p> 137 * <b>[3]</b> The Catalog specification defined complex rules on 138 * <a href="https://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html#attrib.prefer"> 139 * the prefer attribute</a>. Although the prefer can be public or system, the 140 * specification actually made system the preferred option, that is, no matter 141 * the option, a system entry is always used if found. Public entries are only 142 * considered if the prefer is public and system entries are not found. It is 143 * therefore recommended that the prefer attribute be set as public 144 * (which is the default). 145 * <p> 146 * <b>[4]</b> Although non-standard attributes in the OASIS Catalog specification, 147 * {@code defer} and {@code resolve} are recognized by the Java Catalog API the 148 * same as the {@code prefer} as being an attribute in the catalog entry of the 149 * main catalog. Note that only the attributes specified for the catalog entry 150 * of the main Catalog file will be used. 151 * <p> 152 * <b>[5]</b> If the intention is to share an entire catalog store, it may be desirable to 153 * set the property {@code javax.xml.catalog.defer} to false to allow the entire 154 * catalog to be pre-loaded. 155 * <p> 156 * <h3>Scope and Order</h3> 157 * Features and properties can be set through the catalog file, the Catalog API, 158 * system properties, and {@code jaxp.properties}, with a preference in the same order. 159 * <p> 160 * Properties that are specified as attributes in the catalog file for the 161 * catalog and group entries shall take preference over any of the other settings. 162 * For example, if a {@code prefer} attribute is set in the catalog file as in 163 * {@code <catalog prefer="public">}, any other input for the "prefer" property 164 * is not necessary or will be ignored. 165 * <p> 166 * Properties set through the Catalog API override those that may have been set 167 * by system properties and/or in {@code jaxp.properties}. In case of multiple 168 * interfaces, the latest in a procedure shall take preference. For 169 * {@link Feature#FILES}, this means that the path(s) specified through the methods 170 * of the {@link CatalogManager} will override any that may have been entered 171 * through the {@link Builder}. 172 * 173 * <p> 174 * System properties when set shall override those in {@code jaxp.properties}. 175 * <p> 176 * The {@code jaxp.properties} file is typically in the conf directory of the Java 177 * installation. The file is read only once by the JAXP implementation and 178 * its values are then cached for future use. If the file does not exist 179 * when the first attempt is made to read from it, no further attempts are 180 * made to check for its existence. It is not possible to change the value 181 * of any properties in {@code jaxp.properties} after it has been read. 182 * <p> 183 * A CatalogFeatures instance can be created through its builder as illustrated 184 * in the following sample code: 185 * <pre>{@code 186 CatalogFeatures f = CatalogFeatures.builder() 187 .with(Feature.FILES, "catalog.xml") 188 .with(Feature.PREFER, "public") 189 .with(Feature.DEFER, "true") 190 .with(Feature.RESOLVE, "ignore") 191 .build(); 192 * }</pre> 193 * 194 * @since 9 195 */ 196 public class CatalogFeatures { 197 198 /** 199 * The constant name of the javax.xml.catalog.files property. See the property table for more details. 200 */ 201 static final String CATALOG_FILES = "javax.xml.catalog.files"; 202 203 /** 204 * The javax.xml.catalog.prefer property. See the property table for more details. 205 */ 206 static final String CATALOG_PREFER = "javax.xml.catalog.prefer"; 207 208 /** 209 * Determines whether or not delegated catalogs and nextCatalog will be read 210 * when the current catalog is loaded. 211 */ 212 static final String CATALOG_DEFER = "javax.xml.catalog.defer"; 213 214 /** 215 * Determines the action if there is no matching entry found after 216 * all of the specified catalogs are exhausted. 217 */ 218 static final String CATALOG_RESOLVE = "javax.xml.catalog.resolve"; 219 220 //values for the prefer property 221 static final String PREFER_SYSTEM = "system"; 222 static final String PREFER_PUBLIC = "public"; 223 224 //values for the defer property 225 static final String DEFER_TRUE = "true"; 226 static final String DEFER_FALSE = "false"; 227 228 //values for the Resolve property 229 static final String RESOLVE_STRICT = "strict"; 230 static final String RESOLVE_CONTINUE = "continue"; 231 static final String RESOLVE_IGNORE = "ignore"; 232 233 /** 234 * A Feature type as defined in the 235 * <a href="CatalogFeatures.html#CatalogFeatures">Catalog Features table</a>. 236 */ 237 public static enum Feature { 238 /** 239 * The {@code javax.xml.catalog.files} property as described in 240 * item <a href="CatalogFeatures.html#FILES">FILES</a> of the 241 * Catalog Features table. 242 */ 243 FILES(CATALOG_FILES, null, true), 244 /** 245 * The {@code javax.xml.catalog.prefer} property as described in 246 * item <a href="CatalogFeatures.html#PREFER">PREFER</a> of the 247 * Catalog Features table. 248 */ 249 PREFER(CATALOG_PREFER, PREFER_PUBLIC, false), 250 /** 251 * The {@code javax.xml.catalog.defer} property as described in 252 * item <a href="CatalogFeatures.html#DEFER">DEFER</a> of the 253 * Catalog Features table. 254 */ 255 DEFER(CATALOG_DEFER, DEFER_TRUE, true), 256 /** 257 * The {@code javax.xml.catalog.resolve} property as described in 258 * item <a href="CatalogFeatures.html#RESOLVE">RESOLVE</a> of the 259 * Catalog Features table. 260 */ 261 RESOLVE(CATALOG_RESOLVE, RESOLVE_STRICT, true); 262 263 private final String name; 264 private final String defaultValue; 265 private String value; 266 private final boolean hasSystem; 267 268 /** 269 * Constructs a CatalogFeature instance. 270 * @param name the name of the feature 271 * @param value the value of the feature 272 * @param hasSystem a flag to indicate whether the feature is supported 273 * with a System property 274 */ 275 Feature(String name, String value, boolean hasSystem) { 276 this.name = name; 277 this.defaultValue = value; 278 this.hasSystem = hasSystem; 279 } 280 281 /** 282 * Checks whether the specified property is equal to the current property. 283 * @param propertyName the name of a property 284 * @return true if the specified property is the current property, false 285 * otherwise 286 */ 287 boolean equalsPropertyName(String propertyName) { 288 return name.equals(propertyName); 289 } 290 291 /** 292 * Returns the name of the corresponding System Property. 293 * 294 * @return the name of the System Property 295 */ 296 public String getPropertyName() { 297 return name; 298 } 299 300 /** 301 * Returns the default value of the property. 302 * @return the default value of the property 303 */ 304 String defaultValue() { 305 return defaultValue; 306 } 307 308 /** 309 * Returns the value of the property. 310 * @return the value of the property 311 */ 312 String getValue() { 313 return value; 314 } 315 316 /** 317 * Checks whether System property is supported for the feature. 318 * @return true it is supported, false otherwise 319 */ 320 boolean hasSystemProperty() { 321 return hasSystem; 322 } 323 } 324 325 /** 326 * States of the settings of a property, in the order: default value, 327 * jaxp.properties file, jaxp system properties, and jaxp api properties 328 */ 329 static enum State { 330 /** represents the default state of a feature. */ 331 DEFAULT("default"), 332 /** indicates the value of the feature is read from jaxp.properties. */ 333 JAXPDOTPROPERTIES("jaxp.properties"), 334 /** indicates the value of the feature is read from its System property. */ 335 SYSTEMPROPERTY("system property"), 336 /** indicates the value of the feature is specified through the API. */ 337 APIPROPERTY("property"), 338 /** indicates the value of the feature is specified as a catalog attribute. */ 339 CATALOGATTRIBUTE("catalog attribute"); 340 341 final String literal; 342 343 State(String literal) { 344 this.literal = literal; 345 } 346 347 String literal() { 348 return literal; 349 } 350 } 351 352 /** 353 * Values of the properties 354 */ 355 private String[] values; 356 357 /** 358 * States of the settings for each property 359 */ 360 private State[] states; 361 362 /** 363 * Private class constructor 364 */ 365 private CatalogFeatures() { 366 } 367 368 /** 369 * Returns a CatalogFeatures instance with default settings. 370 * @return a default CatalogFeatures instance 371 */ 372 public static CatalogFeatures defaults() { 373 return CatalogFeatures.builder().build(); 374 } 375 376 /** 377 * Constructs a new CatalogFeatures instance with the builder. 378 * 379 * @param builder the builder to build the CatalogFeatures 380 */ 381 CatalogFeatures(Builder builder) { 382 init(); 383 setProperty(Feature.FILES.ordinal(), State.APIPROPERTY, builder.files); 384 setProperty(Feature.PREFER.ordinal(), State.APIPROPERTY, builder.prefer); 385 setProperty(Feature.DEFER.ordinal(), State.APIPROPERTY, builder.defer); 386 setProperty(Feature.RESOLVE.ordinal(), State.APIPROPERTY, builder.resolve); 387 } 388 389 /** 390 * Returns the value of the specified feature. 391 * 392 * @param cf the type of the Catalog feature 393 * @return the value of the feature 394 */ 395 public String get(Feature cf) { 396 return values[cf.ordinal()]; 397 } 398 399 /** 400 * Initializes the supported properties 401 */ 402 private void init() { 403 values = new String[Feature.values().length]; 404 states = new State[Feature.values().length]; 405 for (Feature cf : Feature.values()) { 406 setProperty(cf.ordinal(), State.DEFAULT, cf.defaultValue()); 407 } 408 //read system properties or jaxp.properties 409 readSystemProperties(); 410 } 411 412 /** 413 * Sets the value of a property by its index, updates only if it shall override. 414 * 415 * @param index the index of the property 416 * @param state the state of the property 417 * @param value the value of the property 418 * @throws IllegalArgumentException if the value is invalid 419 */ 420 private void setProperty(int index, State state, String value) { 421 if (value != null && value.length() != 0) { 422 if (index == Feature.PREFER.ordinal()) { 423 if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) { 424 CatalogMessages.reportIAE(new Object[]{value, Feature.PREFER.name()}, null); 425 } 426 } else if (index == Feature.DEFER.ordinal()) { 427 if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) { 428 CatalogMessages.reportIAE(new Object[]{value, Feature.DEFER.name()}, null); 429 } 430 } else if (index == Feature.RESOLVE.ordinal()) { 431 if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE) 432 && !value.equals(RESOLVE_IGNORE)) { 433 CatalogMessages.reportIAE(new Object[]{value, Feature.RESOLVE.name()}, null); 434 } 435 } 436 if (states[index] == null || state.compareTo(states[index]) >= 0) { 437 values[index] = value; 438 states[index] = state; 439 } 440 } 441 } 442 443 /** 444 * Reads from system properties, or those in jaxp.properties 445 */ 446 private void readSystemProperties() { 447 for (Feature cf : Feature.values()) { 448 getSystemProperty(cf, cf.getPropertyName()); 449 } 450 } 451 452 /** 453 * Reads from system properties, or those in jaxp.properties 454 * 455 * @param cf the type of the property 456 * @param sysPropertyName the name of system property 457 */ 458 private boolean getSystemProperty(Feature cf, String sysPropertyName) { 459 if (cf.hasSystemProperty()) { 460 String value = SecuritySupport.getSystemProperty(sysPropertyName); 461 if (value != null && !value.equals("")) { 462 setProperty(cf.ordinal(), State.SYSTEMPROPERTY, value); 463 return true; 464 } 465 466 value = SecuritySupport.readJAXPProperty(sysPropertyName); 467 if (value != null && !value.equals("")) { 468 setProperty(cf.ordinal(), State.JAXPDOTPROPERTIES, value); 469 return true; 470 } 471 } 472 return false; 473 } 474 475 /** 476 * Returns an instance of the builder for creating the CatalogFeatures object. 477 * 478 * @return an instance of the builder 479 */ 480 public static Builder builder() { 481 return new CatalogFeatures.Builder(); 482 } 483 484 /** 485 * The Builder class for building the CatalogFeatures object. 486 */ 487 public static class Builder { 488 /** 489 * Variables for the features supported by CatalogFeatures. 490 */ 491 String files, prefer, defer, resolve; 492 493 /** 494 * Instantiation of Builder is not allowed. 495 */ 496 private Builder() {} 497 498 /** 499 * Sets the value to a specified Feature. 500 * @param feature the Feature to be set 501 * @param value the value to be set for the Feature 502 * @return this Builder instance 503 * @throws IllegalArgumentException if the value is not valid for the 504 * Feature or has the wrong syntax for the {@code javax.xml.catalog.files} 505 * property 506 */ 507 public Builder with(Feature feature, String value) { 508 switch (feature) { 509 case FILES : 510 files = value; 511 break; 512 case PREFER : 513 prefer = value; 514 break; 515 case DEFER : 516 defer = value; 517 break; 518 case RESOLVE : 519 resolve = value; 520 break; 521 } 522 return this; 523 } 524 525 /** 526 * Returns a CatalogFeatures object built by this builder. 527 * 528 * @return an instance of CatalogFeatures 529 */ 530 public CatalogFeatures build() { 531 return new CatalogFeatures(this); 532 } 533 } 534 } --- EOF ---