1 /* 2 * Copyright (c) 2016, 2017, 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 26 package jdk.xml.internal; 27 28 import javax.xml.XMLConstants; 29 import static jdk.xml.internal.JdkXmlUtils.OVERRIDE_PARSER; 30 import static jdk.xml.internal.JdkXmlUtils.SP_USE_CATALOG; 31 import static jdk.xml.internal.JdkXmlUtils.RESET_SYMBOL_TABLE; 32 33 /** 34 * This class manages JDK's XML Features. Previously added features and properties 35 * may be gradually moved to this class. 36 */ 37 public class JdkXmlFeatures { 38 public static final String ORACLE_JAXP_PROPERTY_PREFIX = 39 "http://www.oracle.com/xml/jaxp/properties/"; 40 41 public static final String XML_FEATURE_MANAGER = 42 ORACLE_JAXP_PROPERTY_PREFIX + "XmlFeatureManager"; 43 44 public static final String ORACLE_FEATURE_SERVICE_MECHANISM = 45 "http://www.oracle.com/feature/use-service-mechanism"; 46 47 /** 48 * Feature enableExtensionFunctions 49 */ 50 public static final String ORACLE_ENABLE_EXTENSION_FUNCTION = 51 ORACLE_JAXP_PROPERTY_PREFIX + "enableExtensionFunctions"; 52 public static final String SP_ENABLE_EXTENSION_FUNCTION = 53 "javax.xml.enableExtensionFunctions"; 54 // This is the correct name by the spec 55 public static final String SP_ENABLE_EXTENSION_FUNCTION_SPEC = 56 "jdk.xml.enableExtensionFunctions"; 57 public static final String CATALOG_FEATURES = "javax.xml.catalog.catalogFeatures"; 58 59 public final static String PROPERTY_USE_CATALOG = XMLConstants.USE_CATALOG; 60 61 public static enum XmlFeature { 62 /** 63 * Feature enableExtensionFunctions 64 * FSP: extension function is enforced by FSP. When FSP is on, extension 65 * function is disabled. 66 */ 67 ENABLE_EXTENSION_FUNCTION(ORACLE_ENABLE_EXTENSION_FUNCTION, SP_ENABLE_EXTENSION_FUNCTION_SPEC, 68 ORACLE_ENABLE_EXTENSION_FUNCTION, SP_ENABLE_EXTENSION_FUNCTION, 69 true, false, true, true), 70 /** 71 * The {@link javax.xml.XMLConstants.USE_CATALOG} feature. 72 * FSP: USE_CATALOG is not enforced by FSP. 73 */ 74 USE_CATALOG(PROPERTY_USE_CATALOG, SP_USE_CATALOG, 75 null, null, 76 true, false, true, false), 77 78 /** 79 * Feature resetSymbolTable 80 * FSP: RESET_SYMBOL_TABLE_FEATURE is not enforced by FSP. 81 */ 82 RESET_SYMBOL_TABLE_FEATURE(RESET_SYMBOL_TABLE, RESET_SYMBOL_TABLE, 83 null, null, 84 false, false, true, false), 85 86 /** 87 * Feature overrideDefaultParser 88 * FSP: not enforced by FSP. 89 */ 90 JDK_OVERRIDE_PARSER(OVERRIDE_PARSER, OVERRIDE_PARSER, 91 ORACLE_FEATURE_SERVICE_MECHANISM, ORACLE_FEATURE_SERVICE_MECHANISM, 92 false, false, true, false); 93 94 private final String name; 95 private final String nameSP; 96 private final String nameOld; 97 private final String nameOldSP; 98 private final boolean valueDefault; 99 private final boolean valueEnforced; 100 private final boolean hasSystem; 101 private final boolean enforced; 102 103 /** 104 * Constructs an XmlFeature instance. 105 * @param name the name of the feature 106 * @param nameSP the name of the System Property 107 * @param nameOld the name of the corresponding legacy property 108 * @param nameOldSP the system property of the legacy property 109 * @param value the value of the feature 110 * @param hasSystem a flag to indicate whether the feature is supported 111 * @param enforced a flag indicating whether the feature is 112 * FSP (Feature_Secure_Processing) enforced 113 * with a System property 114 */ 115 XmlFeature(String name, String nameSP, String nameOld, String nameOldSP, 116 boolean value, boolean valueEnforced, boolean hasSystem, boolean enforced) { 117 this.name = name; 118 this.nameSP = nameSP; 119 this.nameOld = nameOld; 120 this.nameOldSP = nameOldSP; 121 this.valueDefault = value; 122 this.valueEnforced = valueEnforced; 123 this.hasSystem = hasSystem; 124 this.enforced = enforced; 125 } 126 127 /** 128 * Checks whether the specified property is equal to the current property. 129 * @param propertyName the name of a property 130 * @return true if the specified property is the current property, false 131 * otherwise 132 */ 133 boolean equalsPropertyName(String propertyName) { 134 return name.equals(propertyName) || 135 (nameOld != null && nameOld.equals(propertyName)); 136 } 137 138 /** 139 * Returns the name of the property. 140 * 141 * @return the name of the property 142 */ 143 public String apiProperty() { 144 return name; 145 } 146 147 /** 148 * Returns the name of the corresponding System Property. 149 * 150 * @return the name of the System Property 151 */ 152 String systemProperty() { 153 return nameSP; 154 } 155 156 /** 157 * Returns the name of the legacy System Property. 158 * 159 * @return the name of the legacy System Property 160 */ 161 String systemPropertyOld() { 162 return nameOldSP; 163 } 164 165 /** 166 * Returns the default value of the property. 167 * @return the default value of the property 168 */ 169 public boolean defaultValue() { 170 return valueDefault; 171 } 172 173 /** 174 * Returns the FSP-enforced value. 175 * @return the FSP-enforced value 176 */ 177 public boolean enforcedValue() { 178 return valueEnforced; 179 } 180 181 /** 182 * Checks whether System property is supported for the feature. 183 * @return true it is supported, false otherwise 184 */ 185 boolean hasSystemProperty() { 186 return hasSystem; 187 } 188 189 /** 190 * Checks whether the property is enforced by FSP 191 * @return true it is, false otherwise 192 */ 193 boolean enforced() { 194 return enforced; 195 } 196 197 } 198 199 /** 200 * States of the settings of a property, in the order: default value, value 201 * set by FEATURE_SECURE_PROCESSING, jaxp.properties file, jaxp system 202 * properties, and jaxp api properties 203 */ 204 public static enum State { 205 //this order reflects the overriding order 206 207 DEFAULT("default"), FSP("FEATURE_SECURE_PROCESSING"), 208 JAXPDOTPROPERTIES("jaxp.properties"), SYSTEMPROPERTY("system property"), 209 APIPROPERTY("property"); 210 211 final String literal; 212 State(String literal) { 213 this.literal = literal; 214 } 215 216 String literal() { 217 return literal; 218 } 219 } 220 221 /** 222 * Values of the features 223 */ 224 private final boolean[] featureValues; 225 226 /** 227 * States of the settings for each property 228 */ 229 private final State[] states; 230 231 /** 232 * Flag indicating if secure processing is set 233 */ 234 boolean secureProcessing; 235 236 /** 237 * Instantiate JdkXmlFeatures and initialize the fields 238 * @param secureProcessing 239 */ 240 public JdkXmlFeatures(boolean secureProcessing) { 241 featureValues = new boolean[XmlFeature.values().length]; 242 states = new State[XmlFeature.values().length]; 243 this.secureProcessing = secureProcessing; 244 for (XmlFeature f : XmlFeature.values()) { 245 if (secureProcessing && f.enforced()) { 246 featureValues[f.ordinal()] = f.enforcedValue(); 247 states[f.ordinal()] = State.FSP; 248 } else { 249 featureValues[f.ordinal()] = f.defaultValue(); 250 states[f.ordinal()] = State.DEFAULT; 251 } 252 } 253 //read system properties or jaxp.properties 254 readSystemProperties(); 255 } 256 257 /** 258 * Updates the JdkXmlFeatures instance by reading the system properties again. 259 * This will become necessary in case the system properties are set after 260 * the instance has been created. 261 */ 262 public void update() { 263 readSystemProperties(); 264 } 265 266 /** 267 * Set feature by property name and state 268 * @param propertyName property name 269 * @param state the state of the property 270 * @param value the value of the property 271 * @return true if the property is managed by the JdkXmlFeatures instance; 272 * false otherwise. 273 */ 274 public boolean setFeature(String propertyName, State state, Object value) { 275 int index = getIndex(propertyName); 276 if (index > -1) { 277 setFeature(index, state, value); 278 return true; 279 } 280 return false; 281 } 282 283 /** 284 * Set the value for a specific feature. 285 * 286 * @param feature the feature 287 * @param state the state of the property 288 * @param value the value of the property 289 */ 290 public void setFeature(XmlFeature feature, State state, boolean value) { 291 setFeature(feature.ordinal(), state, value); 292 } 293 294 /** 295 * Return the value of the specified property 296 * 297 * @param feature the property 298 * @return the value of the property 299 */ 300 public boolean getFeature(XmlFeature feature) { 301 return featureValues[feature.ordinal()]; 302 } 303 304 /** 305 * Return the value of a feature by its index (the Feature's ordinal) 306 * @param index the index of a feature 307 * @return value of a feature 308 */ 309 public boolean getFeature(int index) { 310 return featureValues[index]; 311 } 312 313 /** 314 * Set the value of a property by its index 315 * 316 * @param index the index of the property 317 * @param state the state of the property 318 * @param value the value of the property 319 */ 320 public void setFeature(int index, State state, Object value) { 321 boolean temp; 322 if (Boolean.class.isAssignableFrom(value.getClass())) { 323 temp = (Boolean)value; 324 } else { 325 temp = Boolean.parseBoolean((String) value); 326 } 327 setFeature(index, state, temp); 328 } 329 330 /** 331 * Set the value of a property by its index 332 * 333 * @param index the index of the property 334 * @param state the state of the property 335 * @param value the value of the property 336 */ 337 public void setFeature(int index, State state, boolean value) { 338 //only update if it shall override 339 if (state.compareTo(states[index]) >= 0) { 340 featureValues[index] = value; 341 states[index] = state; 342 } 343 } 344 345 /** 346 * Get the index by property name 347 * 348 * @param propertyName property name 349 * @return the index of the property if found; return -1 if not 350 */ 351 public int getIndex(String propertyName) { 352 for (XmlFeature feature : XmlFeature.values()) { 353 if (feature.equalsPropertyName(propertyName)) { 354 //internally, ordinal is used as index 355 return feature.ordinal(); 356 } 357 } 358 return -1; 359 } 360 361 /** 362 * Read from system properties, or those in jaxp.properties 363 */ 364 private void readSystemProperties() { 365 for (XmlFeature feature : XmlFeature.values()) { 366 if (!getSystemProperty(feature, feature.systemProperty())) { 367 //if system property is not found, try the older form if any 368 String oldName = feature.systemPropertyOld(); 369 if (oldName != null) { 370 getSystemProperty(feature, oldName); 371 } 372 } 373 } 374 } 375 376 /** 377 * Read from system properties, or those in jaxp.properties 378 * 379 * @param property the type of the property 380 * @param sysPropertyName the name of system property 381 * @return true if the system property is found, false otherwise 382 */ 383 private boolean getSystemProperty(XmlFeature feature, String sysPropertyName) { 384 try { 385 String value = SecuritySupport.getSystemProperty(sysPropertyName); 386 if (value != null && !value.equals("")) { 387 setFeature(feature, State.SYSTEMPROPERTY, Boolean.parseBoolean(value)); 388 return true; 389 } 390 391 value = SecuritySupport.readJAXPProperty(sysPropertyName); 392 if (value != null && !value.equals("")) { 393 setFeature(feature, State.JAXPDOTPROPERTIES, Boolean.parseBoolean(value)); 394 return true; 395 } 396 } catch (NumberFormatException e) { 397 //invalid setting 398 throw new NumberFormatException("Invalid setting for system property: " + feature.systemProperty()); 399 } 400 return false; 401 } 402 403 }