--- /dev/null 2015-04-26 17:31:22.381138994 -0700 +++ new/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java 2015-10-26 15:21:48.574814190 -0700 @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.catalog; + +import jdk.xml.internal.SecuritySupport; + +/** + * The CatalogFeatures holds a collection of features and properties. + *
+ * + *
Feature | + *Description | + *Property Name | + *System Property [1] | + *jaxp.properties [1] | + *Value [2] | + *Action | + *|
---|---|---|---|---|---|---|---|
Type | + *Value | + *||||||
FILES | + *A semicolon-delimited list of catalog files. Relative file paths are + * considered relative to ${user.dir}. + * | + *javax.xml.catalog.files | + *javax.xml.catalog.files | + *javax.xml.catalog.files | + *String | + *File paths | + *+ * Reads the first catalog as the current catalog; Loads others if no match + * is found in the current catalog including delegate catalogs if any. + * | + *
PREFER | + *Indicates the preference between the public and system + * identifiers. The default value is public [3]. | + *javax.xml.catalog.prefer | + *N/A | + *N/A | + *String | + *{@code system} | + *Searches system entries for a match; Searches public entries when + * external identifier specifies only a public identifier | + *
{@code public} | + *Searches system entries for a match; Searches public entries when + * there is no matching system entry. | + *||||||
DEFER | + *Indicates that the alternative catalogs including those + * specified in delegate entries or nextCatalog are not read until they are + * needed. The default value is true. | + *javax.xml.catalog.defer [4] | + *javax.xml.catalog.defer | + *javax.xml.catalog.defer | + *String | + *{@code true} | + *Loads alternative catalogs as needed. + * | + *
{@code false} | + *Loads all catalogs[5]. | + *||||||
RESOLVE | + *Determines the action if there is no matching entry found after + * all of the specified catalogs are exhausted. The default is strict. | + *javax.xml.catalog.resolve [4] | + *javax.xml.catalog.resolve | + *javax.xml.catalog.resolve | + *String | + *{@code strict} | + *Throws CatalogException if there is no match. + * | + *
{@code continue} | + *Allows the XML parser to continue as if there is no match. + * | + *||||||
{@code ignore} | + *Tells the XML parser to skip the external references if there no match. + * | + *
+ * [1] There is no System property for the features that marked as "N/A". + * + *
+ * [2] The value shall be exactly as listed in this table, case-sensitive. + * Any unspecified value will result in {@link IllegalArgumentException}. + *
+ * [3] The Catalog specification defined complex rules on + * + * the prefer attribute. Although the prefer can be public or system, the + * specification actually made system the preferred option, that is, no matter + * the option, a system entry is always used if found. Public entries are only + * considered if the prefer is public and system entries are not found. It is + * therefore recommended that the prefer attribute be set as public + * (which is the default). + *
+ * [4] Although non-standard attributes in the OASIS Catalog specification, + * {@code defer} and {@code resolve} are recognized by the Java Catalog API the + * same as the {@code prefer} as being an attribute in the catalog entry of the + * main catalog. Note that only the attributes specified for the catalog entry + * of the main Catalog file will be used. + *
+ * [5] If the intention is to share an entire catalog store, it may be desirable to + * set the property {@code javax.xml.catalog.defer} to false to allow the entire + * catalog to be pre-loaded. + *
+ *
+ * Properties that are specified as attributes in the catalog file for the
+ * catalog and group entries shall take preference over any of the other settings.
+ * For example, if a {@code prefer} attribute is set in the catalog file as in
+ * {@code
+ * Properties set through the Catalog API override those that may have been set
+ * by system properties and/or in {@code jaxp.properties}. In case of multiple
+ * interfaces, the latest in a procedure shall take preference. For
+ * {@link Feature#FILES}, this means that the path(s) specified through the methods
+ * of the {@link CatalogManager} will override any that may have been entered
+ * through the {@link Builder}.
+ *
+ *
+ * System properties when set shall override those in {@code jaxp.properties}.
+ *
+ * The {@code jaxp.properties} file is typically in the conf directory of the Java
+ * installation. The file is read only once by the JAXP implementation and
+ * its values are then cached for future use. If the file does not exist
+ * when the first attempt is made to read from it, no further attempts are
+ * made to check for its existence. It is not possible to change the value
+ * of any properties in {@code jaxp.properties} after it has been read.
+ *
+ * A CatalogFeatures instance can be created through its builder as illustrated
+ * in the following sample code:
+ * {@code
+ CatalogFeatures f = CatalogFeatures.builder()
+ .with(Feature.FILES, "catalog.xml")
+ .with(Feature.PREFER, "public")
+ .with(Feature.DEFER, "true")
+ .with(Feature.RESOLVE, "ignore")
+ .build();
+ * }
+ *
+ * @since 9
+ */
+public class CatalogFeatures {
+
+ /**
+ * The constant name of the javax.xml.catalog.files property. See the property table for more details.
+ */
+ static final String CATALOG_FILES = "javax.xml.catalog.files";
+
+ /**
+ * The javax.xml.catalog.prefer property. See the property table for more details.
+ */
+ static final String CATALOG_PREFER = "javax.xml.catalog.prefer";
+
+ /**
+ * Determines whether or not delegated catalogs and nextCatalog will be read
+ * when the current catalog is loaded.
+ */
+ static final String CATALOG_DEFER = "javax.xml.catalog.defer";
+
+ /**
+ * Determines the action if there is no matching entry found after
+ * all of the specified catalogs are exhausted.
+ */
+ static final String CATALOG_RESOLVE = "javax.xml.catalog.resolve";
+
+ //values for the prefer property
+ static final String PREFER_SYSTEM = "system";
+ static final String PREFER_PUBLIC = "public";
+
+ //values for the defer property
+ static final String DEFER_TRUE = "true";
+ static final String DEFER_FALSE = "false";
+
+ //values for the Resolve property
+ static final String RESOLVE_STRICT = "strict";
+ static final String RESOLVE_CONTINUE = "continue";
+ static final String RESOLVE_IGNORE = "ignore";
+
+ /**
+ * A Feature type as defined in the
+ * Catalog Features table.
+ */
+ public static enum Feature {
+ /**
+ * The {@code javax.xml.catalog.files} property as described in
+ * item FILES of the
+ * Catalog Features table.
+ */
+ FILES(CATALOG_FILES, null, true),
+ /**
+ * The {@code javax.xml.catalog.prefer} property as described in
+ * item PREFER of the
+ * Catalog Features table.
+ */
+ PREFER(CATALOG_PREFER, PREFER_PUBLIC, false),
+ /**
+ * The {@code javax.xml.catalog.defer} property as described in
+ * item DEFER of the
+ * Catalog Features table.
+ */
+ DEFER(CATALOG_DEFER, DEFER_TRUE, true),
+ /**
+ * The {@code javax.xml.catalog.resolve} property as described in
+ * item RESOLVE of the
+ * Catalog Features table.
+ */
+ RESOLVE(CATALOG_RESOLVE, RESOLVE_STRICT, true);
+
+ private final String name;
+ private final String defaultValue;
+ private String value;
+ private final boolean hasSystem;
+
+ /**
+ * Constructs a CatalogFeature instance.
+ * @param name the name of the feature
+ * @param value the value of the feature
+ * @param hasSystem a flag to indicate whether the feature is supported
+ * with a System property
+ */
+ Feature(String name, String value, boolean hasSystem) {
+ this.name = name;
+ this.defaultValue = value;
+ this.hasSystem = hasSystem;
+ }
+
+ /**
+ * Checks whether the specified property is equal to the current property.
+ * @param propertyName the name of a property
+ * @return true if the specified property is the current property, false
+ * otherwise
+ */
+ boolean equalsPropertyName(String propertyName) {
+ return name.equals(propertyName);
+ }
+
+ /**
+ * Returns the name of the corresponding System Property.
+ *
+ * @return the name of the System Property
+ */
+ public String getPropertyName() {
+ return name;
+ }
+
+ /**
+ * Returns the default value of the property.
+ * @return the default value of the property
+ */
+ String defaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * Returns the value of the property.
+ * @return the value of the property
+ */
+ String getValue() {
+ return value;
+ }
+
+ /**
+ * Checks whether System property is supported for the feature.
+ * @return true it is supported, false otherwise
+ */
+ boolean hasSystemProperty() {
+ return hasSystem;
+ }
+ }
+
+ /**
+ * States of the settings of a property, in the order: default value,
+ * jaxp.properties file, jaxp system properties, and jaxp api properties
+ */
+ static enum State {
+ /** represents the default state of a feature. */
+ DEFAULT("default"),
+ /** indicates the value of the feature is read from jaxp.properties. */
+ JAXPDOTPROPERTIES("jaxp.properties"),
+ /** indicates the value of the feature is read from its System property. */
+ SYSTEMPROPERTY("system property"),
+ /** indicates the value of the feature is specified through the API. */
+ APIPROPERTY("property"),
+ /** indicates the value of the feature is specified as a catalog attribute. */
+ CATALOGATTRIBUTE("catalog attribute");
+
+ final String literal;
+
+ State(String literal) {
+ this.literal = literal;
+ }
+
+ String literal() {
+ return literal;
+ }
+ }
+
+ /**
+ * Values of the properties
+ */
+ private String[] values;
+
+ /**
+ * States of the settings for each property
+ */
+ private State[] states;
+
+ /**
+ * Private class constructor
+ */
+ private CatalogFeatures() {
+ }
+
+ /**
+ * Returns a CatalogFeatures instance with default settings.
+ * @return a default CatalogFeatures instance
+ */
+ public static CatalogFeatures defaults() {
+ return CatalogFeatures.builder().build();
+ }
+
+ /**
+ * Constructs a new CatalogFeatures instance with the builder.
+ *
+ * @param builder the builder to build the CatalogFeatures
+ */
+ CatalogFeatures(Builder builder) {
+ init();
+ setProperty(Feature.FILES.ordinal(), State.APIPROPERTY, builder.files);
+ setProperty(Feature.PREFER.ordinal(), State.APIPROPERTY, builder.prefer);
+ setProperty(Feature.DEFER.ordinal(), State.APIPROPERTY, builder.defer);
+ setProperty(Feature.RESOLVE.ordinal(), State.APIPROPERTY, builder.resolve);
+ }
+
+ /**
+ * Returns the value of the specified feature.
+ *
+ * @param cf the type of the Catalog feature
+ * @return the value of the feature
+ */
+ public String get(Feature cf) {
+ return values[cf.ordinal()];
+ }
+
+ /**
+ * Initializes the supported properties
+ */
+ private void init() {
+ values = new String[Feature.values().length];
+ states = new State[Feature.values().length];
+ for (Feature cf : Feature.values()) {
+ setProperty(cf.ordinal(), State.DEFAULT, cf.defaultValue());
+ }
+ //read system properties or jaxp.properties
+ readSystemProperties();
+ }
+
+ /**
+ * Sets the value of a property by its index, updates only if it shall override.
+ *
+ * @param index the index of the property
+ * @param state the state of the property
+ * @param value the value of the property
+ * @throws IllegalArgumentException if the value is invalid
+ */
+ private void setProperty(int index, State state, String value) {
+ if (value != null && value.length() != 0) {
+ if (index == Feature.PREFER.ordinal()) {
+ if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) {
+ CatalogMessages.reportIAE(new Object[]{value, Feature.PREFER.name()}, null);
+ }
+ } else if (index == Feature.DEFER.ordinal()) {
+ if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) {
+ CatalogMessages.reportIAE(new Object[]{value, Feature.DEFER.name()}, null);
+ }
+ } else if (index == Feature.RESOLVE.ordinal()) {
+ if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE)
+ && !value.equals(RESOLVE_IGNORE)) {
+ CatalogMessages.reportIAE(new Object[]{value, Feature.RESOLVE.name()}, null);
+ }
+ }
+ if (states[index] == null || state.compareTo(states[index]) >= 0) {
+ values[index] = value;
+ states[index] = state;
+ }
+ }
+ }
+
+ /**
+ * Reads from system properties, or those in jaxp.properties
+ */
+ private void readSystemProperties() {
+ for (Feature cf : Feature.values()) {
+ getSystemProperty(cf, cf.getPropertyName());
+ }
+ }
+
+ /**
+ * Reads from system properties, or those in jaxp.properties
+ *
+ * @param cf the type of the property
+ * @param sysPropertyName the name of system property
+ */
+ private boolean getSystemProperty(Feature cf, String sysPropertyName) {
+ if (cf.hasSystemProperty()) {
+ String value = SecuritySupport.getSystemProperty(sysPropertyName);
+ if (value != null && !value.equals("")) {
+ setProperty(cf.ordinal(), State.SYSTEMPROPERTY, value);
+ return true;
+ }
+
+ value = SecuritySupport.readJAXPProperty(sysPropertyName);
+ if (value != null && !value.equals("")) {
+ setProperty(cf.ordinal(), State.JAXPDOTPROPERTIES, value);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an instance of the builder for creating the CatalogFeatures object.
+ *
+ * @return an instance of the builder
+ */
+ public static Builder builder() {
+ return new CatalogFeatures.Builder();
+ }
+
+ /**
+ * The Builder class for building the CatalogFeatures object.
+ */
+ public static class Builder {
+ /**
+ * Variables for the features supported by CatalogFeatures.
+ */
+ String files, prefer, defer, resolve;
+
+ /**
+ * Instantiation of Builder is not allowed.
+ */
+ private Builder() {}
+
+ /**
+ * Sets the value to a specified Feature.
+ * @param feature the Feature to be set
+ * @param value the value to be set for the Feature
+ * @return this Builder instance
+ * @throws IllegalArgumentException if the value is not valid for the
+ * Feature or has the wrong syntax for the {@code javax.xml.catalog.files}
+ * property
+ */
+ public Builder with(Feature feature, String value) {
+ switch (feature) {
+ case FILES :
+ files = value;
+ break;
+ case PREFER :
+ prefer = value;
+ break;
+ case DEFER :
+ defer = value;
+ break;
+ case RESOLVE :
+ resolve = value;
+ break;
+ }
+ return this;
+ }
+
+ /**
+ * Returns a CatalogFeatures object built by this builder.
+ *
+ * @return an instance of CatalogFeatures
+ */
+ public CatalogFeatures build() {
+ return new CatalogFeatures(this);
+ }
+ }
+}