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