/* * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * @LastModified: Nov 2017 */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sun.org.apache.xerces.internal.impl; import com.sun.org.apache.xerces.internal.util.DefaultErrorHandler; import com.sun.org.apache.xerces.internal.util.ErrorHandlerProxy; import com.sun.org.apache.xerces.internal.util.MessageFormatter; import com.sun.org.apache.xerces.internal.xni.XMLLocator; import com.sun.org.apache.xerces.internal.xni.XNIException; import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler; import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.xml.sax.ErrorHandler; /** * This class is a common element of all parser configurations and is * used to report errors that occur. This component can be queried by * parser components from the component manager using the following * property ID: *
* http://apache.org/xml/properties/internal/error-reporter **
* Errors are separated into domains that categorize a class of errors.
* In a parser configuration, the parser would register a
* MessageFormatter
for each domain that is capable of
* localizing error messages and formatting them based on information
* about the error. Any parser component can invent new error domains
* and register additional message formatters to localize messages in
* those domains.
*
* This component requires the following features and properties from the * component manager that uses it: *
* This component can use the following features and properties but they * are not required: *
* Note: The parser does have a "continue after fatal
* error" feature but it should be used with extreme caution and care.
*/
public static final short SEVERITY_FATAL_ERROR = 2;
// feature identifiers
/** Feature identifier: continue after fatal error. */
protected static final String CONTINUE_AFTER_FATAL_ERROR =
Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
// property identifiers
/** Property identifier: error handler. */
protected static final String ERROR_HANDLER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
// recognized features and properties
/** Recognized features. */
private static final String[] RECOGNIZED_FEATURES = {
CONTINUE_AFTER_FATAL_ERROR,
};
/** Feature defaults. */
private static final Boolean[] FEATURE_DEFAULTS = {
null,
};
/** Recognized properties. */
private static final String[] RECOGNIZED_PROPERTIES = {
ERROR_HANDLER,
};
/** Property defaults. */
private static final Object[] PROPERTY_DEFAULTS = {
null,
};
//
// Data
//
/** The locale to be used to format error messages. */
protected Locale fLocale;
/** Mapping of Message formatters for domains. */
protected Map
* Note: Registering a message formatter for a domain
* when there is already a formatter registered will cause the previous
* formatter to be lost. This method replaces any previously registered
* message formatter for the specified domain.
*
* @param domain
* @param messageFormatter
*/
public void putMessageFormatter(String domain,
MessageFormatter messageFormatter) {
fMessageFormatters.put(domain, messageFormatter);
} // putMessageFormatter(String,MessageFormatter)
/**
* Returns the message formatter associated with the specified domain,
* or null if no message formatter is registered for that domain.
*
* @param domain The domain of the message formatter.
*/
public MessageFormatter getMessageFormatter(String domain) {
return fMessageFormatters.get(domain);
} // getMessageFormatter(String):MessageFormatter
/**
* Removes the message formatter for the specified domain and
* returns the removed message formatter.
*
* @param domain The domain of the message formatter.
*/
public MessageFormatter removeMessageFormatter(String domain) {
return fMessageFormatters.remove(domain);
} // removeMessageFormatter(String):MessageFormatter
/**
* Reports an error. The error message passed to the error handler
* is formatted for the locale by the message formatter installed
* for the specified error domain.
*
* @param domain The error domain.
* @param key The key of the error message.
* @param arguments The replacement arguments for the error message,
* if needed.
* @param severity The severity of the error.
* @return The formatted error message.
*
* @see #SEVERITY_WARNING
* @see #SEVERITY_ERROR
* @see #SEVERITY_FATAL_ERROR
*/
public String reportError(String domain, String key, Object[] arguments,
short severity) throws XNIException {
return reportError(fLocator, domain, key, arguments, severity);
} // reportError(String,String,Object[],short):String
/**
* Reports an error. The error message passed to the error handler
* is formatted for the locale by the message formatter installed
* for the specified error domain.
*
* @param domain The error domain.
* @param key The key of the error message.
* @param arguments The replacement arguments for the error message,
* if needed.
* @param severity The severity of the error.
* @param exception The exception to wrap.
* @return The formatted error message.
*
* @see #SEVERITY_WARNING
* @see #SEVERITY_ERROR
* @see #SEVERITY_FATAL_ERROR
*/
public String reportError(String domain, String key, Object[] arguments,
short severity, Exception exception) throws XNIException {
return reportError(fLocator, domain, key, arguments, severity, exception);
} // reportError(String,String,Object[],short,Exception):String
/**
* Reports an error at a specific location.
*
* @param location The error location.
* @param domain The error domain.
* @param key The key of the error message.
* @param arguments The replacement arguments for the error message,
* if needed.
* @param severity The severity of the error.
* @return The formatted error message.
*
* @see #SEVERITY_WARNING
* @see #SEVERITY_ERROR
* @see #SEVERITY_FATAL_ERROR
*/
public String reportError(XMLLocator location,
String domain, String key, Object[] arguments,
short severity) throws XNIException {
return reportError(location, domain, key, arguments, severity, null);
} // reportError(XMLLocator,String,String,Object[],short):String
/**
* Reports an error at a specific location.
*
* @param location The error location.
* @param domain The error domain.
* @param key The key of the error message.
* @param arguments The replacement arguments for the error message,
* if needed.
* @param severity The severity of the error.
* @param exception The exception to wrap.
* @return The formatted error message.
*
* @see #SEVERITY_WARNING
* @see #SEVERITY_ERROR
* @see #SEVERITY_FATAL_ERROR
*/
public String reportError(XMLLocator location,
String domain, String key, Object[] arguments,
short severity, Exception exception) throws XNIException {
// REVISIT: [Q] Should we do anything about invalid severity
// parameter? -Ac
// format error message and create parse exception
MessageFormatter messageFormatter = getMessageFormatter(domain);
String message;
if (messageFormatter != null) {
message = messageFormatter.formatMessage(fLocale, key, arguments);
}
else {
StringBuffer str = new StringBuffer();
str.append(domain);
str.append('#');
str.append(key);
int argCount = arguments != null ? arguments.length : 0;
if (argCount > 0) {
str.append('?');
for (int i = 0; i < argCount; i++) {
str.append(arguments[i]);
if (i < argCount -1) {
str.append('&');
}
}
}
message = str.toString();
}
XMLParseException parseException = (exception != null) ?
new XMLParseException(location, message, exception) :
new XMLParseException(location, message);
// get error handler
XMLErrorHandler errorHandler = fErrorHandler;
if (errorHandler == null) {
if (fDefaultErrorHandler == null) {
fDefaultErrorHandler = new DefaultErrorHandler();
}
errorHandler = fDefaultErrorHandler;
}
// call error handler
switch (severity) {
case SEVERITY_WARNING: {
errorHandler.warning(domain, key, parseException);
break;
}
case SEVERITY_ERROR: {
errorHandler.error(domain, key, parseException);
break;
}
case SEVERITY_FATAL_ERROR: {
errorHandler.fatalError(domain, key, parseException);
if (!fContinueAfterFatalError) {
throw parseException;
}
break;
}
}
return message;
} // reportError(XMLLocator,String,String,Object[],short,Exception):String
//
// XMLComponent methods
//
/**
* Resets the component. The component can query the component manager
* about any features and properties that affect the operation of the
* component.
*
* @param componentManager The component manager.
*
* @throws SAXException Thrown by component on initialization error.
* For example, if a feature or property is
* required for the operation of the component, the
* component manager may throw a
* SAXNotRecognizedException or a
* SAXNotSupportedException.
*/
public void reset(XMLComponentManager componentManager)
throws XNIException {
// features
fContinueAfterFatalError = componentManager.getFeature(CONTINUE_AFTER_FATAL_ERROR, false);
// properties
fErrorHandler = (XMLErrorHandler)componentManager.getProperty(ERROR_HANDLER);
} // reset(XMLComponentManager)
/**
* Returns a list of feature identifiers that are recognized by
* this component. This method may return null if no features
* are recognized by this component.
*/
public String[] getRecognizedFeatures() {
return RECOGNIZED_FEATURES.clone();
} // getRecognizedFeatures():String[]
/**
* Sets the state of a feature. This method is called by the component
* manager any time after reset when a feature changes state.
*
* Note: Components should silently ignore features
* that do not affect the operation of the component.
*
* @param featureId The feature identifier.
* @param state The state of the feature.
*
* @throws SAXNotRecognizedException The component should not throw
* this exception.
* @throws SAXNotSupportedException The component should not throw
* this exception.
*/
public void setFeature(String featureId, boolean state)
throws XMLConfigurationException {
//
// Xerces features
//
if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length();
//
// http://apache.org/xml/features/continue-after-fatal-error
// Allows the parser to continue after a fatal error.
// Normally, a fatal error would stop the parse.
//
if (suffixLength == Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE.length() &&
featureId.endsWith(Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE)) {
fContinueAfterFatalError = state;
}
}
} // setFeature(String,boolean)
// return state of given feature or false if unsupported.
public boolean getFeature(String featureId)
throws XMLConfigurationException {
//
// Xerces features
//
if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length();
//
// http://apache.org/xml/features/continue-after-fatal-error
// Allows the parser to continue after a fatal error.
// Normally, a fatal error would stop the parse.
//
if (suffixLength == Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE.length() &&
featureId.endsWith(Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE)) {
return fContinueAfterFatalError ;
}
}
return false;
} // setFeature(String,boolean)
/**
* Returns a list of property identifiers that are recognized by
* this component. This method may return null if no properties
* are recognized by this component.
*/
public String[] getRecognizedProperties() {
return RECOGNIZED_PROPERTIES.clone();
} // getRecognizedProperties():String[]
/**
* Sets the value of a property. This method is called by the component
* manager any time after reset when a property changes value.
*
* Note: Components should silently ignore properties
* that do not affect the operation of the component.
*
* @param propertyId The property identifier.
* @param value The value of the property.
*
* @throws SAXNotRecognizedException The component should not throw
* this exception.
* @throws SAXNotSupportedException The component should not throw
* this exception.
*/
public void setProperty(String propertyId, Object value)
throws XMLConfigurationException {
//
// Xerces properties
//
if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
if (suffixLength == Constants.ERROR_HANDLER_PROPERTY.length() &&
propertyId.endsWith(Constants.ERROR_HANDLER_PROPERTY)) {
fErrorHandler = (XMLErrorHandler)value;
}
}
} // setProperty(String,Object)
/**
* Returns the default state for a feature, or null if this
* component does not want to report a default value for this
* feature.
*
* @param featureId The feature identifier.
*
* @since Xerces 2.2.0
*/
public Boolean getFeatureDefault(String featureId) {
for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
if (RECOGNIZED_FEATURES[i].equals(featureId)) {
return FEATURE_DEFAULTS[i];
}
}
return null;
} // getFeatureDefault(String):Boolean
/**
* Returns the default state for a property, or null if this
* component does not want to report a default value for this
* property.
*
* @param propertyId The property identifier.
*
* @since Xerces 2.2.0
*/
public Object getPropertyDefault(String propertyId) {
for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
return PROPERTY_DEFAULTS[i];
}
}
return null;
} // getPropertyDefault(String):Object
/**
* Get the internal XMLErrrorHandler.
*/
public XMLErrorHandler getErrorHandler() {
return fErrorHandler;
}
/**
* Gets the internal XMLErrorHandler
* as SAX ErrorHandler.
*/
public ErrorHandler getSAXErrorHandler() {
if (fSaxProxy == null) {
fSaxProxy = new ErrorHandlerProxy() {
protected XMLErrorHandler getErrorHandler() {
return fErrorHandler;
}
};
}
return fSaxProxy;
}
} // class XMLErrorReporter