/* * Copyright (c) 2015, 2016, 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 java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; 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();
setProperties(builder);
}
/**
* 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 properties by the Builder.
* @param builder the CatalogFeatures builder
*/
private void setProperties(Builder builder) {
builder.values.entrySet().stream().forEach((entry) -> {
setProperty(entry.getKey().ordinal(), State.APIPROPERTY, entry.getValue());
});
}
/**
* 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);
}
} else if (index == Feature.FILES.ordinal()) {
try {
String[] catalogFile = value.split(";[ ]*");
for (String temp : catalogFile) {
if (Util.verifyAndGetURI(temp, null) == null) {
CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, null);
}
}
}catch (MalformedURLException | URISyntaxException | IllegalArgumentException ex) {
CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, ex);
}
}
if (states[index] == null || state.compareTo(states[index]) >= 0) {
values[index] = value;
states[index] = state;
}
} else {
if (state == State.SYSTEMPROPERTY || state == State.JAXPDOTPROPERTIES) {
CatalogMessages.reportIAE(new Object[]{value, Feature.values()[index].name()}, null);
}
}
}
/**
* 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 {
/**
* Values of the features supported by CatalogFeatures.
*/
Map