org.eclipse.persistence.internal.oxm.record.XMLReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.persistence.core Show documentation
Show all versions of org.eclipse.persistence.core Show documentation
EclipseLink build based upon Git transaction ecdf3c32c4
/*
* Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.oxm.record;
import java.io.IOException;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.ext.LexicalHandler;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.validation.ValidatorHandler;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.ConversionManager;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.MediaType;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy;
/**
* INTERNAL:
* Purpose:Provide a wrapper for an org.xml.sax.XMLReader instance and define some extra
* event methods that can be used by TopLink during the unmarshal process. These events are no ops
* in this class, but may be overridden in subclasses.
*
Responsibilities
* - Wrap an instance of org.xml.sax.XMLReader and provide all the required API
* - Provide empty implementations of some callback methods that can be overridden in subclasses
*
* @see org.eclipse.persistence.internal.oxm.record.DOMReader
* @author mmacivor
* @since release specific (what release of product did this appear in)
*/
public class XMLReader implements org.xml.sax.XMLReader {
public static final String NAMESPACE_PREFIXES_FEATURE = "http://xml.org/sax/features/namespace-prefixes";
public static final String REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE_FEATURE = "http://java.sun.com/xml/schema/features/report-ignored-element-content-whitespace";
private org.xml.sax.XMLReader reader;
private boolean supportsLexicalHandler;
private LexicalHandlerWrapper lexicalHandlerWrapper;
protected ValidatingContentHandler validatingContentHandler;
private boolean namespaceAware;
private char namespaceSeparator;
protected Locator locator;
public XMLReader(org.xml.sax.XMLReader internalReader) {
this();
this.reader = internalReader;
}
public XMLReader() {
this.supportsLexicalHandler = true;
namespaceAware = true;
namespaceSeparator = Constants.COLON;
}
/**
* INTERNAL:
* return the Locator object associated with this reader
* @since 2.4
*/
public Locator getLocator(){
return locator;
}
/**
* INTERNAL:
* set the Locator object to associate with this reader
* @since 2.4
*/
public void setLocator(Locator newLocator){
locator = newLocator;
}
public ContentHandler getContentHandler () {
return reader.getContentHandler();
}
public void setContentHandler (ContentHandler handler) {
if(validatingContentHandler != null) {
validatingContentHandler.setContentHandler(handler);
} else {
reader.setContentHandler(handler);
}
}
/**
* INTERNAL:
* Determine if namespaces will be considered during marshal/unmarshal operations.
* @since 2.4
*/
public boolean isNamespaceAware() {
return namespaceAware;
}
/**
* If set to true, the reader will be aware of namespaces during marshal/unmarsal operations.
*
* @param namespaceAware if reader should be namespace aware
* @since 2.6.0
*/
public void setNamespaceAware(boolean namespaceAware) {
this.namespaceAware = namespaceAware;
}
/**
* INTERNAL:
* The character used to separate the prefix and uri portions when namespaces are present
* @since 2.4
*/
public char getNamespaceSeparator(){
return namespaceSeparator;
}
/**
* Sets namespace separator.
*
* @param namespaceSeparator namespace separator
* @since 2.6.0
*/
public void setNamespaceSeparator(char namespaceSeparator) {
this.namespaceSeparator = namespaceSeparator;
}
/**
* INTERNAL:
* @return The MediaType associated with this reader
*/
public MediaType getMediaType(){
return Constants.APPLICATION_XML;
}
/**
* INTERNAL:
* @since 2.4
*/
public Object convertValueBasedOnSchemaType(Field xmlField, Object value, ConversionManager conversionManager, AbstractUnmarshalRecord record) {
return xmlField.convertValueBasedOnSchemaType(value, conversionManager, record);
}
public DTDHandler getDTDHandler () {
return reader.getDTDHandler();
}
public void setDTDHandler (DTDHandler handler) {
reader.setDTDHandler(handler);
}
public void setEntityResolver (EntityResolver resolver) {
reader.setEntityResolver(resolver);
}
public EntityResolver getEntityResolver () {
return reader.getEntityResolver();
}
public ErrorHandler getErrorHandler () {
return reader.getErrorHandler();
}
public void setErrorHandler (ErrorHandler handler) {
if(validatingContentHandler != null) {
validatingContentHandler.setErrorHandler(handler);
} else {
reader.setErrorHandler(handler);
}
}
public LexicalHandler getLexicalHandler() {
if(supportsLexicalHandler) {
try {
return (LexicalHandler) reader.getProperty(Constants.LEXICAL_HANDLER_PROPERTY);
} catch (SAXException e) {
supportsLexicalHandler = false;
}
}
return null;
}
public void setLexicalHandler(LexicalHandler lexicalHandler) {
if(supportsLexicalHandler) {
if(null == lexicalHandlerWrapper) {
try {
lexicalHandlerWrapper = new LexicalHandlerWrapper(lexicalHandler);
reader.setProperty(Constants.LEXICAL_HANDLER_PROPERTY, lexicalHandlerWrapper);
} catch (SAXException e) {
supportsLexicalHandler = false;
}
} else {
lexicalHandlerWrapper.setLexicalHandler(lexicalHandler);
}
}
}
public boolean getFeature (String name) throws SAXNotRecognizedException, SAXNotSupportedException {
return reader.getFeature(name);
}
public void setFeature (String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
reader.setFeature(name, value);
}
public Object getProperty (String name) throws SAXNotRecognizedException, SAXNotSupportedException {
if(Constants.LEXICAL_HANDLER_PROPERTY.equals(name)) {
return getLexicalHandler();
} else {
return reader.getProperty(name);
}
}
public void setProperty (String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
if(Constants.LEXICAL_HANDLER_PROPERTY.equals(name)) {
setLexicalHandler((LexicalHandler) value);
} else {
reader.setProperty(name, value);
}
}
public void parse(InputSource input) throws IOException, SAXException {
try {
reader.parse(input);
} catch(SAXNotSupportedException e) {
String message = e.getMessage();
if(message != null && message.contains("namespace-prefix")) {
reader.setFeature(NAMESPACE_PREFIXES_FEATURE, false);
reader.parse(input);
} else {
throw e;
}
}
}
public void parse (String systemId) throws IOException, SAXException {
try {
reader.parse(systemId);
} catch(SAXNotSupportedException e) {
String message = e.getMessage();
if(message != null && message.contains("namespace-prefix")) {
reader.setFeature(NAMESPACE_PREFIXES_FEATURE, false);
reader.parse(systemId);
} else {
throw e;
}
}
}
public void setValidatorHandler(ValidatorHandler validatorHandler) {
ErrorHandler errorHandler = getErrorHandler();
ContentHandler contentHandler;
if(null == this.validatingContentHandler) {
contentHandler = getContentHandler();
} else {
contentHandler = validatorHandler.getContentHandler();
this.validatingContentHandler = null;
}
ValidatingContentHandler validatingContentHandler = null;
if(null != validatorHandler) {
validatingContentHandler = new ValidatingContentHandler(validatorHandler);
validatingContentHandler.setContentHandler(contentHandler);
contentHandler = validatingContentHandler;
}
if(null != reader) {
reader.setContentHandler(contentHandler);
}
setContentHandler(contentHandler);
this.validatingContentHandler = validatingContentHandler;
setErrorHandler(errorHandler);
}
public ValidatorHandler getValidatorHandler() {
if(null == validatingContentHandler) {
return null;
}
return this.validatingContentHandler.getValidatorHandler();
}
public void newObjectEvent(Object object, Object parent, Mapping selfRecordMapping) {
//no op in this class.
}
public Object getCurrentObject(CoreAbstractSession session, Mapping selfRecordMapping) {
return null;
}
/**
* This call back mechanism provides an opportunity for the XMLReader to
* provide an alternate conversion. This optimization is currently only
* leveraged for properties annotated with @XmlInlineBinaryData.
* @param characters The characters to be converted.
* @param dataType The type to be converted to.
* @return The converted value
*/
public Object getValue(CharSequence characters, Class dataType) {
return null;
}
public boolean isNullRepresentedByXsiNil(AbstractNullPolicy nullPolicy){
return nullPolicy.isNullRepresentedByXsiNil();
}
public boolean isNullRecord(AbstractNullPolicy nullPolicy, Attributes atts, UnmarshalRecord record) {
boolean isNil = isNullRepresentedByXsiNil(nullPolicy) && record.isNil();
if (!nullPolicy.ignoreAttributesForNil()) {
return isNil && !hasAttributes(atts);
}
return isNil;
}
private boolean hasAttributes(Attributes attributes) {
QName nilAttrName = new QName(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_NIL_ATTRIBUTE);
for (int i = 0; i < attributes.getLength(); i++) {
if (!(nilAttrName.getNamespaceURI().equals(attributes.getURI(i)) &&
nilAttrName.getLocalPart().equals(attributes.getLocalName(i))) &&
!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attributes.getURI(i))) {
return true;
}
}
return false;
}
public boolean isInCollection(){
return true;
}
/**
* Performance Optimization:
* It is expensive to change the LexicalHandler on the underlying XMLReader
* constantly through the setProperty(String, Object) mechanism. So instead
* the LexicalHandlerWrapper is set once this way, and the "real"
* LexicalHandler is changed on the LexicalHandlerWrapper.
*/
private static class LexicalHandlerWrapper implements LexicalHandler {
private LexicalHandler lexicalHandler;
public LexicalHandlerWrapper(LexicalHandler lexicalHandler) {
this.lexicalHandler = lexicalHandler;
}
public void setLexicalHandler(LexicalHandler lexicalHandler) {
this.lexicalHandler = lexicalHandler;
}
public void comment(char[] ch, int start, int length) throws SAXException {
if(null != lexicalHandler) {
lexicalHandler.comment(ch, start, length);
}
}
public void endCDATA() throws SAXException {
if(null != lexicalHandler) {
lexicalHandler.endCDATA();
}
}
public void endDTD() throws SAXException {
if(null != lexicalHandler) {
lexicalHandler.endDTD();
}
}
public void endEntity(String name) throws SAXException {
if(null != lexicalHandler) {
lexicalHandler.endEntity(name);
}
}
public void startCDATA() throws SAXException {
if(null != lexicalHandler) {
lexicalHandler.startCDATA();
}
}
public void startDTD(String name, String publicId, String systemId) throws SAXException {
if(null != lexicalHandler) {
lexicalHandler.startCDATA();
}
}
public void startEntity(String name) throws SAXException {
if(null != lexicalHandler) {
lexicalHandler.startEntity(name);
}
}
}
/**
* Validate the SAX events reported to the ContentHandler. This class is
* being used rather than a ValidatorHandler in order to prevent default
* values from being populated.
*/
protected static class ValidatingContentHandler implements ContentHandler {
private ValidatorHandler validatorHandler;
private ContentHandler contentHandler;
public ValidatingContentHandler(ValidatorHandler validatorHandler) {
this.validatorHandler = validatorHandler;
}
public ContentHandler getContentHandler() {
return contentHandler;
}
public void setContentHandler(ContentHandler contentHandler) {
this.contentHandler = contentHandler;
}
public void setErrorHandler(ErrorHandler errorHandler) {
validatorHandler.setErrorHandler(errorHandler);
}
public ValidatorHandler getValidatorHandler() {
return validatorHandler;
}
public void setValidatorHandler(ValidatorHandler validatorHandler) {
this.validatorHandler = validatorHandler;
}
public void setDocumentLocator(Locator locator) {
validatorHandler.setDocumentLocator(locator);
contentHandler.setDocumentLocator(locator);
}
public void startDocument() throws SAXException {
validatorHandler.startDocument();
contentHandler.startDocument();
}
public void endDocument() throws SAXException {
validatorHandler.endDocument();
contentHandler.endDocument();
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
validatorHandler.startPrefixMapping(prefix, uri);
contentHandler.startPrefixMapping(prefix, uri);
}
public void endPrefixMapping(String prefix) throws SAXException {
validatorHandler.endPrefixMapping(prefix);
contentHandler.endPrefixMapping(prefix);
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
validatorHandler.startElement(uri, localName, qName, atts);
contentHandler.startElement(uri, localName, qName, atts);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
validatorHandler.endElement(uri, localName, qName);
contentHandler.endElement(uri, localName, qName);
}
public void characters(char[] ch, int start, int length) throws SAXException {
validatorHandler.characters(ch, start, length);
contentHandler.characters(ch, start, length);
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
validatorHandler.ignorableWhitespace(ch, start, length);
contentHandler.characters(ch, start, length);
}
public void processingInstruction(String target, String data) throws SAXException {
validatorHandler.processingInstruction(target, data);
contentHandler.processingInstruction(target, data);
}
public void skippedEntity(String name) throws SAXException {
validatorHandler.skippedEntity(name);
contentHandler.skippedEntity(name);
}
}
}