jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java
changeset 43121 e73af7b6ce47
parent 39907 db51759e3695
child 45261 8a151bf73222
equal deleted inserted replaced
43040:ab2c8b03c328 43121:e73af7b6ce47
     1 /*
     1 /*
     2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
     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.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    54  * </thead>
    54  * </thead>
    55  * <tbody>
    55  * <tbody>
    56  *
    56  *
    57  * <tr>
    57  * <tr>
    58  * <td><a name="FILES">FILES</a></td>
    58  * <td><a name="FILES">FILES</a></td>
    59  * <td>A semicolon-delimited list of catalog files. Relative file paths are
    59  * <td>A semicolon-delimited list of URIs to locate the catalog files.
    60  * considered relative to ${user.dir}.
    60  * The URIs must be absolute and have a URL protocol handler for the URI scheme.
    61  * </td>
    61  * </td>
    62  * <td>javax.xml.catalog.files</td>
    62  * <td>javax.xml.catalog.files</td>
    63  * <td>javax.xml.catalog.files</td>
    63  * <td>javax.xml.catalog.files</td>
    64  * <td>javax.xml.catalog.files</td>
    64  * <td>javax.xml.catalog.files</td>
    65  * <td>String</td>
    65  * <td>String</td>
    66  * <td>File paths</td>
    66  * <td>URIs</td>
    67  * <td>
    67  * <td>
    68  * Reads the first catalog as the current catalog; Loads others if no match
    68  * Reads the first catalog as the current catalog; Loads others if no match
    69  * is found in the current catalog including delegate catalogs if any.
    69  * is found in the current catalog including delegate catalogs if any.
    70  * </td>
    70  * </td>
    71  * </tr>
    71  * </tr>
   168  * is not necessary or will be ignored.
   168  * is not necessary or will be ignored.
   169  * <p>
   169  * <p>
   170  * Properties set through the Catalog API override those that may have been set
   170  * Properties set through the Catalog API override those that may have been set
   171  * by system properties and/or in {@code jaxp.properties}. In case of multiple
   171  * by system properties and/or in {@code jaxp.properties}. In case of multiple
   172  * interfaces, the latest in a procedure shall take preference. For
   172  * interfaces, the latest in a procedure shall take preference. For
   173  * {@link Feature#FILES}, this means that the path(s) specified through the methods
   173  * {@link Feature#FILES}, this means that the URI(s) specified through the methods
   174  * of the {@link CatalogManager} will override any that may have been entered
   174  * of the {@link CatalogManager} will override any that may have been entered
   175  * through the {@link Builder}.
   175  * through the {@link Builder}.
   176  *
   176  *
   177  * <p>
   177  * <p>
   178  * System properties when set shall override those in {@code jaxp.properties}.
   178  * System properties when set shall override those in {@code jaxp.properties}.
   186  * <p>
   186  * <p>
   187  * A CatalogFeatures instance can be created through its builder as illustrated
   187  * A CatalogFeatures instance can be created through its builder as illustrated
   188  * in the following sample code:
   188  * in the following sample code:
   189  * <pre>{@code
   189  * <pre>{@code
   190                 CatalogFeatures f = CatalogFeatures.builder()
   190                 CatalogFeatures f = CatalogFeatures.builder()
   191                         .with(Feature.FILES, "catalog.xml")
   191                         .with(Feature.FILES, "file:///etc/xml/catalog")
   192                         .with(Feature.PREFER, "public")
   192                         .with(Feature.PREFER, "public")
   193                         .with(Feature.DEFER, "true")
   193                         .with(Feature.DEFER, "true")
   194                         .with(Feature.RESOLVE, "ignore")
   194                         .with(Feature.RESOLVE, "ignore")
   195                         .build();
   195                         .build();
   196  * }</pre>
   196  * }</pre>
   200  * The Catalog Features are supported throughout the JAXP processors, including
   200  * The Catalog Features are supported throughout the JAXP processors, including
   201  * SAX and DOM ({@link javax.xml.parsers}), and StAX parsers ({@link javax.xml.stream}),
   201  * SAX and DOM ({@link javax.xml.parsers}), and StAX parsers ({@link javax.xml.stream}),
   202  * Schema Validation ({@link javax.xml.validation}), and XML Transformation
   202  * Schema Validation ({@link javax.xml.validation}), and XML Transformation
   203  * ({@link javax.xml.transform}). The features described above can be set through JAXP
   203  * ({@link javax.xml.transform}). The features described above can be set through JAXP
   204  * factories or processors that define a setProperty or setAttribute interface.
   204  * factories or processors that define a setProperty or setAttribute interface.
   205  * For example, the following code snippet sets a path to a catalog file on a SAX
   205  * For example, the following code snippet sets a URI to a catalog file on a SAX
   206  * parser through the {@code javax.xml.catalog.files} property:
   206  * parser through the {@code javax.xml.catalog.files} property:
   207  * <p>
   207  * <p>
   208  * <pre>{@code
   208  * <pre>{@code
   209  *      SAXParserFactory spf = SAXParserFactory.newInstance();
   209  *      SAXParserFactory spf = SAXParserFactory.newInstance();
   210  *      spf.setFeature(XMLConstants.USE_CATALOG, true); [1]
   210  *      spf.setFeature(XMLConstants.USE_CATALOG, true); [1]
   211  *      SAXParser parser = spf.newSAXParser();
   211  *      SAXParser parser = spf.newSAXParser();
   212  *      parser.setProperty(CatalogFeatures.Feature.FILES.getPropertyName(), "catalog.xml");
   212  *      parser.setProperty(CatalogFeatures.Feature.FILES.getPropertyName(), "file:///etc/xml/catalog");
   213  * }</pre>
   213  * }</pre>
   214  * <p>
   214  * <p>
   215  * [1] Note that this statement is not required since the default value of
   215  * [1] Note that this statement is not required since the default value of
   216  * {@link javax.xml.XMLConstants#USE_CATALOG USE_CATALOG} is true.
   216  * {@link javax.xml.XMLConstants#USE_CATALOG USE_CATALOG} is true.
   217  *
   217  *
   273  * <td>
   273  * <td>
   274  * <pre>{@literal
   274  * <pre>{@literal
   275    The following XInclude element:
   275    The following XInclude element:
   276    <xi:include href="http://openjdk.java.net/xml/disclaimer.xml"/>
   276    <xi:include href="http://openjdk.java.net/xml/disclaimer.xml"/>
   277 
   277 
   278    can be resolved using an uri entry:
   278    can be resolved using a URI entry:
   279    <uri name="http://openjdk.java.net/xml/disclaimer.xml" uri="file:///pathto/local/disclaimer.xml"/>
   279    <uri name="http://openjdk.java.net/xml/disclaimer.xml" uri="file:///pathto/local/disclaimer.xml"/>
   280    or
   280    or
   281    <uriSuffix uriSuffix="disclaimer.xml" uri="file:///pathto/local/disclaimer.xml"/>
   281    <uriSuffix uriSuffix="disclaimer.xml" uri="file:///pathto/local/disclaimer.xml"/>
   282  * }</pre>
   282  * }</pre>
   283  * </td>
   283  * </td>
   289  * <pre>{@literal
   289  * <pre>{@literal
   290    The following import element:
   290    The following import element:
   291     <xsd:import namespace="http://openjdk.java.net/xsd/XSDImport_person"
   291     <xsd:import namespace="http://openjdk.java.net/xsd/XSDImport_person"
   292                 schemaLocation="http://openjdk.java.net/xsd/XSDImport_person.xsd"/>
   292                 schemaLocation="http://openjdk.java.net/xsd/XSDImport_person.xsd"/>
   293 
   293 
   294    can be resolved using an uri entry:
   294    can be resolved using a URI entry:
   295    <uri name="http://openjdk.java.net/xsd/XSDImport_person.xsd" uri="file:///pathto/local/XSDImport_person.xsd"/>
   295    <uri name="http://openjdk.java.net/xsd/XSDImport_person.xsd" uri="file:///pathto/local/XSDImport_person.xsd"/>
   296    or
   296    or
   297    <uriSuffix uriSuffix="XSDImport_person.xsd" uri="file:///pathto/local/XSDImport_person.xsd"/>
   297    <uriSuffix uriSuffix="XSDImport_person.xsd" uri="file:///pathto/local/XSDImport_person.xsd"/>
   298    or
   298    or
   299    <uriSuffix uriSuffix="http://openjdk.java.net/xsd/XSDImport_person" uri="file:///pathto/local/XSDImport_person.xsd"/>
   299    <uriSuffix uriSuffix="http://openjdk.java.net/xsd/XSDImport_person" uri="file:///pathto/local/XSDImport_person.xsd"/>
   306  * <td>
   306  * <td>
   307  * <pre>{@literal
   307  * <pre>{@literal
   308    The following include element:
   308    The following include element:
   309    <xsd:include schemaLocation="http://openjdk.java.net/xsd/XSDInclude_person.xsd"/>
   309    <xsd:include schemaLocation="http://openjdk.java.net/xsd/XSDInclude_person.xsd"/>
   310 
   310 
   311    can be resolved using an uri entry:
   311    can be resolved using a URI entry:
   312    <uri name="http://openjdk.java.net/xsd/XSDInclude_person.xsd" uri="file:///pathto/local/XSDInclude_person.xsd"/>
   312    <uri name="http://openjdk.java.net/xsd/XSDInclude_person.xsd" uri="file:///pathto/local/XSDInclude_person.xsd"/>
   313    or
   313    or
   314    <uriSuffix uriSuffix="XSDInclude_person.xsd" uri="file:///pathto/local/XSDInclude_person.xsd"/>
   314    <uriSuffix uriSuffix="XSDInclude_person.xsd" uri="file:///pathto/local/XSDInclude_person.xsd"/>
   315  * }</pre>
   315  * }</pre>
   316  * </td>
   316  * </td>
   321  * <td>
   321  * <td>
   322  * <pre>{@literal
   322  * <pre>{@literal
   323    The following include element:
   323    The following include element:
   324    <xsl:include href="http://openjdk.java.net/xsl/include.xsl"/>
   324    <xsl:include href="http://openjdk.java.net/xsl/include.xsl"/>
   325 
   325 
   326    can be resolved using an uri entry:
   326    can be resolved using a URI entry:
   327    <uri name="http://openjdk.java.net/xsl/include.xsl" uri="file:///pathto/local/include.xsl"/>
   327    <uri name="http://openjdk.java.net/xsl/include.xsl" uri="file:///pathto/local/include.xsl"/>
   328    or
   328    or
   329    <uriSuffix uriSuffix="include.xsl" uri="file:///pathto/local/include.xsl"/>
   329    <uriSuffix uriSuffix="include.xsl" uri="file:///pathto/local/include.xsl"/>
   330  * }</pre>
   330  * }</pre>
   331  * </td>
   331  * </td>
   336  * <td>
   336  * <td>
   337  * <pre>{@literal
   337  * <pre>{@literal
   338    The document in the following element:
   338    The document in the following element:
   339    <xsl:variable name="dummy" select="document('http://openjdk.java.net/xsl/list.xml')"/>
   339    <xsl:variable name="dummy" select="document('http://openjdk.java.net/xsl/list.xml')"/>
   340 
   340 
   341    can be resolved using an uri entry:
   341    can be resolved using a URI entry:
   342    <uri name="http://openjdk.java.net/xsl/list.xml" uri="file:///pathto/local/list.xml"/>
   342    <uri name="http://openjdk.java.net/xsl/list.xml" uri="file:///pathto/local/list.xml"/>
   343    or
   343    or
   344    <uriSuffix uriSuffix="list.xml" uri="file:///pathto/local/list.xml"/>
   344    <uriSuffix uriSuffix="list.xml" uri="file:///pathto/local/list.xml"/>
   345  * }</pre>
   345  * }</pre>
   346  * </td>
   346  * </td>
   557      */
   557      */
   558     private void init() {
   558     private void init() {
   559         values = new String[Feature.values().length];
   559         values = new String[Feature.values().length];
   560         states = new State[Feature.values().length];
   560         states = new State[Feature.values().length];
   561         for (Feature cf : Feature.values()) {
   561         for (Feature cf : Feature.values()) {
   562             setProperty(cf.ordinal(), State.DEFAULT, cf.defaultValue());
   562             setProperty(cf, State.DEFAULT, cf.defaultValue());
   563         }
   563         }
   564         //read system properties or jaxp.properties
   564         //read system properties or jaxp.properties
   565         readSystemProperties();
   565         readSystemProperties();
   566     }
   566     }
   567 
   567 
   569      * Sets properties by the Builder.
   569      * Sets properties by the Builder.
   570      * @param builder the CatalogFeatures builder
   570      * @param builder the CatalogFeatures builder
   571      */
   571      */
   572     private void setProperties(Builder builder) {
   572     private void setProperties(Builder builder) {
   573         builder.values.entrySet().stream().forEach((entry) -> {
   573         builder.values.entrySet().stream().forEach((entry) -> {
   574             setProperty(entry.getKey().ordinal(), State.APIPROPERTY, entry.getValue());
   574             setProperty(entry.getKey(), State.APIPROPERTY, entry.getValue());
   575         });
   575         });
   576     }
   576     }
   577     /**
   577     /**
   578      * Sets the value of a property by its index, updates only if it shall override.
   578      * Sets the value of a property, updates only if it shall override.
   579      *
   579      *
   580      * @param index the index of the property
   580      * @param index the index of the property
   581      * @param state the state of the property
   581      * @param state the state of the property
   582      * @param value the value of the property
   582      * @param value the value of the property
   583      * @throws IllegalArgumentException if the value is invalid
   583      * @throws IllegalArgumentException if the value is invalid
   584      */
   584      */
   585     private void setProperty(int index, State state, String value) {
   585     private void setProperty(Feature feature, State state, String value) {
       
   586         int index = feature.ordinal();
   586         if (value != null && value.length() != 0) {
   587         if (value != null && value.length() != 0) {
   587             if (index == Feature.PREFER.ordinal()) {
   588             if (state != State.APIPROPERTY) {
   588                 if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) {
   589                 Util.validateFeatureInput(feature, value);
   589                     CatalogMessages.reportIAE(new Object[]{value, Feature.PREFER.name()}, null);
       
   590                 }
       
   591             } else if (index == Feature.DEFER.ordinal()) {
       
   592                 if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) {
       
   593                     CatalogMessages.reportIAE(new Object[]{value, Feature.DEFER.name()}, null);
       
   594                 }
       
   595             } else if (index == Feature.RESOLVE.ordinal()) {
       
   596                 if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE)
       
   597                          && !value.equals(RESOLVE_IGNORE)) {
       
   598                     CatalogMessages.reportIAE(new Object[]{value, Feature.RESOLVE.name()}, null);
       
   599                 }
       
   600             } else if (index == Feature.FILES.ordinal()) {
       
   601                 try {
       
   602                     String[] catalogFile = value.split(";[ ]*");
       
   603                     for (String temp : catalogFile) {
       
   604                         if (Util.verifyAndGetURI(temp, null) == null) {
       
   605                             CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, null);
       
   606                         }
       
   607                     }
       
   608                 }catch (MalformedURLException | URISyntaxException | IllegalArgumentException ex) {
       
   609                     CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, ex);
       
   610                 }
       
   611             }
   590             }
   612             if (states[index] == null || state.compareTo(states[index]) >= 0) {
   591             if (states[index] == null || state.compareTo(states[index]) >= 0) {
   613                 values[index] = value;
   592                 values[index] = value;
   614                 states[index] = state;
   593                 states[index] = state;
   615             }
   594             }
   616         } else {
       
   617             if (state == State.SYSTEMPROPERTY || state == State.JAXPDOTPROPERTIES) {
       
   618                 CatalogMessages.reportIAE(new Object[]{value, Feature.values()[index].name()}, null);
       
   619             }
       
   620         }
   595         }
   621     }
   596     }
   622 
   597 
   623     /**
   598     /**
   624      * Reads from system properties, or those in jaxp.properties
   599      * Reads from system properties, or those in jaxp.properties
   637      */
   612      */
   638     private boolean getSystemProperty(Feature cf, String sysPropertyName) {
   613     private boolean getSystemProperty(Feature cf, String sysPropertyName) {
   639         if (cf.hasSystemProperty()) {
   614         if (cf.hasSystemProperty()) {
   640             String value = SecuritySupport.getSystemProperty(sysPropertyName);
   615             String value = SecuritySupport.getSystemProperty(sysPropertyName);
   641             if (value != null && !value.equals("")) {
   616             if (value != null && !value.equals("")) {
   642                 setProperty(cf.ordinal(), State.SYSTEMPROPERTY, value);
   617                 setProperty(cf, State.SYSTEMPROPERTY, value);
   643                 return true;
   618                 return true;
   644             }
   619             }
   645 
   620 
   646             value = SecuritySupport.readJAXPProperty(sysPropertyName);
   621             value = SecuritySupport.readJAXPProperty(sysPropertyName);
   647             if (value != null && !value.equals("")) {
   622             if (value != null && !value.equals("")) {
   648                 setProperty(cf.ordinal(), State.JAXPDOTPROPERTIES, value);
   623                 setProperty(cf, State.JAXPDOTPROPERTIES, value);
   649                 return true;
   624                 return true;
   650             }
   625             }
   651         }
   626         }
   652         return false;
   627         return false;
   653     }
   628     }
   683          * @throws IllegalArgumentException if the value is not valid for the
   658          * @throws IllegalArgumentException if the value is not valid for the
   684          * Feature or has the wrong syntax for the {@code javax.xml.catalog.files}
   659          * Feature or has the wrong syntax for the {@code javax.xml.catalog.files}
   685          * property
   660          * property
   686          */
   661          */
   687         public Builder with(Feature feature, String value) {
   662         public Builder with(Feature feature, String value) {
   688             if (value == null || value.length() == 0) {
   663             Util.validateFeatureInput(feature, value);
   689                 CatalogMessages.reportIAE(new Object[]{value, feature.name()}, null);
       
   690             }
       
   691             values.put(feature, value);
   664             values.put(feature, value);
   692             return this;
   665             return this;
   693         }
   666         }
   694 
   667 
   695         /**
   668         /**