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 * |
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"/> |
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 /** |