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