blob: 5b73fc8b886e31e0b2f17c4187b7676bb089e011 [file] [log] [blame]
/*
* Copyright (c) 2011, 2020 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:
// Blaise Doughan - 2.2 - initial implementation
package org.eclipse.persistence.oxm.record;
import java.util.HashMap;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.validation.Schema;
import javax.xml.validation.ValidatorHandler;
import org.eclipse.persistence.internal.core.helper.CoreField;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.Marshaller;
import org.eclipse.persistence.internal.oxm.Namespace;
import org.eclipse.persistence.internal.oxm.NamespaceResolver;
import org.eclipse.persistence.internal.oxm.XMLMarshaller;
import org.eclipse.persistence.internal.oxm.XPathFragment;
import org.eclipse.persistence.internal.oxm.XPathNode;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.oxm.schema.XMLSchemaReference;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
public class ValidatingMarshalRecord extends MarshalRecord<Marshaller> {
private MarshalRecord marshalRecord;
private ContentHandlerRecord validatingRecord;
public ValidatingMarshalRecord(MarshalRecord marshalRecord, XMLMarshaller xmlMarshaller) {
this.marshalRecord = marshalRecord;
Schema schema = xmlMarshaller.getSchema();
ValidatorHandler validatorHandler = schema.newValidatorHandler();
validatorHandler.setErrorHandler(new ValidatingMarshalRecordErrorHandler(marshalRecord, xmlMarshaller.getErrorHandler()));
if(xmlMarshaller.isFragment()) {
try {
validatorHandler.startDocument();
} catch (SAXException e) {
}
}
validatingRecord = new ContentHandlerRecord();
validatingRecord.setMarshaller(xmlMarshaller);
validatingRecord.setContentHandler(validatorHandler);
validatingRecord.setEqualNamespaceResolvers(marshalRecord.hasEqualNamespaceResolvers());
}
@Override
public void startDocument(String encoding, String version) {
validatingRecord.startDocument(encoding, version);
marshalRecord.startDocument(encoding, version);
}
@Override
public void endDocument() {
validatingRecord.endDocument();
marshalRecord.endDocument();
}
@Override
public void element(XPathFragment frag) {
validatingRecord.element(frag);
marshalRecord.element(frag);
}
@Override
public void attribute(XPathFragment xPathFragment, NamespaceResolver namespaceResolver, String value) {
validatingRecord.attribute(xPathFragment, namespaceResolver, value);
marshalRecord.attribute(xPathFragment, namespaceResolver, value);
}
@Override
public void attribute(String namespaceURI, String localName, String qName, String value) {
validatingRecord.attribute(namespaceURI, localName, qName, value);
marshalRecord.attribute(namespaceURI, localName, qName, value);
}
@Override
public void closeStartElement() {
validatingRecord.closeStartElement();
marshalRecord.closeStartElement();
}
@Override
public void endElement(XPathFragment xPathFragment, NamespaceResolver namespaceResolver) {
validatingRecord.endElement(xPathFragment, namespaceResolver);
marshalRecord.endElement(xPathFragment, namespaceResolver);
}
@Override
public HashMap getPositionalNodes() {
return marshalRecord.getPositionalNodes();
}
@Override
public void addGroupingElement(XPathNode xPathNode) {
validatingRecord.addGroupingElement(xPathNode);
marshalRecord.addGroupingElement(xPathNode);
}
@Override
public void removeGroupingElement(XPathNode xPathNode) {
validatingRecord.removeGroupingElement(xPathNode);
marshalRecord.removeGroupingElement(xPathNode);
}
@Override
public void add(CoreField key, Object value) {
validatingRecord.add(key, value);
marshalRecord.add(key, value);
}
@Override
public Object put(CoreField key, Object value) {
validatingRecord.put(key, value);
return marshalRecord.put(key, value);
}
@Override
public void namespaceDeclarations(NamespaceResolver namespaceResolver) {
validatingRecord.namespaceDeclarations(namespaceResolver);
marshalRecord.namespaceDeclarations(namespaceResolver);
}
@Override
public void startPrefixMapping(String prefix, String namespaceURI) {
validatingRecord.startPrefixMapping(prefix, namespaceURI);
marshalRecord.startPrefixMapping(prefix, namespaceURI);
}
@Override
public void startPrefixMappings(NamespaceResolver namespaceResolver) {
validatingRecord.startPrefixMappings(namespaceResolver);
marshalRecord.startPrefixMappings(namespaceResolver);
}
@Override
public void endPrefixMapping(String prefix) {
validatingRecord.endPrefixMapping(prefix);
marshalRecord.endPrefixMapping(prefix);
}
@Override
public void endPrefixMappings(NamespaceResolver namespaceResolver) {
validatingRecord.endPrefixMappings(namespaceResolver);
marshalRecord.endPrefixMappings(namespaceResolver);
}
@Override
public void openStartElement(XPathFragment xPathFragment, NamespaceResolver namespaceResolver) {
validatingRecord.openStartElement(xPathFragment, namespaceResolver);
marshalRecord.openStartElement(xPathFragment, namespaceResolver);
}
@Override
public XPathFragment openStartGroupingElements(NamespaceResolver namespaceResolver) {
validatingRecord.openStartGroupingElements(namespaceResolver);
return marshalRecord.openStartGroupingElements(namespaceResolver);
}
@Override
public void closeStartGroupingElements(XPathFragment groupingFragment) {
validatingRecord.closeStartGroupingElements(groupingFragment);
marshalRecord.closeStartGroupingElements(groupingFragment);
}
@Override
protected void addPositionalNodes(XPathFragment xPathFragment, NamespaceResolver namespaceResolver) {
validatingRecord.addPositionalNodes(xPathFragment, namespaceResolver);
marshalRecord.addPositionalNodes(xPathFragment, namespaceResolver);
}
@Override
public void characters(String value) {
validatingRecord.characters(value);
marshalRecord.characters(value);
}
@Override
public void cdata(String value) {
validatingRecord.cdata(value);
marshalRecord.cdata(value);
}
@Override
public void node(Node node, NamespaceResolver resolver, String uri, String name) {
validatingRecord.node(node, resolver, uri, name);
marshalRecord.node(node, resolver, uri, name);
}
@Override
public String getLocalName() {
return marshalRecord.getLocalName();
}
@Override
public String getNamespaceURI() {
return marshalRecord.getNamespaceURI();
}
@Override
public void clear() {
validatingRecord.clear();
marshalRecord.clear();
}
@Override
public Document getDocument() {
return marshalRecord.getDocument();
}
@Override
public Node getDOM() {
return marshalRecord.getDOM();
}
@Override
public String transformToXML() {
return marshalRecord.transformToXML();
}
@Override
public String resolveNamespacePrefix(String prefix) {
return marshalRecord.resolveNamespacePrefix(prefix);
}
@Override
public Marshaller getMarshaller() {
return marshalRecord.getMarshaller();
}
@Override
public void setMarshaller(Marshaller marshaller) {
super.setMarshaller(marshaller);
validatingRecord.setMarshaller(marshaller);
marshalRecord.setMarshaller(marshaller);
}
@Override
public Object getOwningObject() {
return marshalRecord.getOwningObject();
}
@Override
public void setOwningObject(Object obj) {
validatingRecord.setOwningObject(obj);
marshalRecord.setOwningObject(obj);
}
@Override
public void setLeafElementType(QName type) {
validatingRecord.setLeafElementType(type);
marshalRecord.setLeafElementType(type);
}
@Override
public void setNamespaceResolver(NamespaceResolver nr) {
validatingRecord.setNamespaceResolver(nr);
marshalRecord.setNamespaceResolver(nr);
}
@Override
public NamespaceResolver getNamespaceResolver() {
return marshalRecord.getNamespaceResolver();
}
@Override
public CoreAbstractSession getSession() {
return marshalRecord.getSession();
}
@Override
public void setSession(CoreAbstractSession session) {
super.setSession(session);
validatingRecord.setSession(session);
marshalRecord.setSession(session);
}
@Override
public boolean isXOPPackage() {
return marshalRecord.isXOPPackage();
}
@Override
public void beforeContainmentMarshal(Object child) {
marshalRecord.beforeContainmentMarshal(child);
}
@Override
public void afterContainmentMarshal(Object parent, Object child) {
marshalRecord.afterContainmentMarshal(parent, child);
}
private static class ValidatingMarshalRecordErrorHandler implements ErrorHandler {
private MarshalRecord marshalRecord;
private ErrorHandler errorHandler;
public ValidatingMarshalRecordErrorHandler(MarshalRecord marshalRecord, ErrorHandler errorHandler) {
this.marshalRecord = marshalRecord;
this.errorHandler = errorHandler;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
if(null == errorHandler) {
throw exception;
}
errorHandler.warning(marshalSAXParseException(exception));
}
@Override
public void error(SAXParseException exception) throws SAXException {
if(null == errorHandler) {
throw exception;
}
errorHandler.error(marshalSAXParseException(exception));
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
if(null == errorHandler) {
throw exception;
}
errorHandler.fatalError(marshalSAXParseException(exception));
}
private MarshalSAXParseException marshalSAXParseException(SAXParseException exception) {
return new MarshalSAXParseException(exception.getLocalizedMessage(), exception.getPublicId(), exception.getSystemId(), exception.getLineNumber(), exception.getColumnNumber(), exception.getException(), marshalRecord.getOwningObject());
}
}
public static class MarshalSAXParseException extends SAXParseException {
private Object object;
public MarshalSAXParseException(String message, String publicId,
String systemId, int lineNumber, int columnNumber, Exception e, Object object) {
super(message, publicId, systemId, lineNumber, columnNumber, e);
this.object = object;
}
public Object getObject() {
return object;
}
}
@Override
public void writeHeader() {
marshalRecord.writeHeader();
}
/**
* @since EclipseLink 2.5.0
*/
@Override
public List<Namespace> addExtraNamespacesToNamespaceResolver(
Descriptor descriptor, CoreAbstractSession session,
boolean allowOverride, boolean ignoreEqualResolvers) {
validatingRecord.addExtraNamespacesToNamespaceResolver(descriptor, session, allowOverride, ignoreEqualResolvers);
return marshalRecord.addExtraNamespacesToNamespaceResolver(descriptor, session, allowOverride, ignoreEqualResolvers);
}
/**
* @since EclipseLink 2.5.0
*/
@Override
public void removeExtraNamespacesFromNamespaceResolver(
List<Namespace> extraNamespaces, CoreAbstractSession session) {
validatingRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session);
marshalRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session);
}
/**
* @since EclipseLink 2.5.0
*/
@Override
public void attributeWithoutQName(String namespaceURI, String localName,
String prefix, String value) {
validatingRecord.attributeWithoutQName(namespaceURI, localName, prefix, value);
marshalRecord.attributeWithoutQName(namespaceURI, localName, prefix, value);
}
/**
* @since EclipseLink 2.5.0
*/
@Override
public boolean addXsiTypeAndClassIndicatorIfRequired(
Descriptor xmlDescriptor, Descriptor referenceDescriptor,
Field xmlField, boolean isRootElement) {
validatingRecord.addXsiTypeAndClassIndicatorIfRequired(xmlDescriptor, referenceDescriptor, xmlField, isRootElement);
return marshalRecord.addXsiTypeAndClassIndicatorIfRequired(xmlDescriptor, referenceDescriptor, xmlField, isRootElement);
}
/**
* @since EclipseLink 2.5.0
*/
@Override
public boolean addXsiTypeAndClassIndicatorIfRequired(
Descriptor xmlDescriptor, Descriptor referenceDescriptor,
Field xmlField, Object originalObject, Object obj,
boolean wasXMLRoot, boolean isRootElement) {
validatingRecord.setNamespaceResolver(new NamespaceResolver(marshalRecord.getNamespaceResolver()));
validatingRecord.addXsiTypeAndClassIndicatorIfRequired(xmlDescriptor, referenceDescriptor, xmlField, originalObject, obj, wasXMLRoot, isRootElement);
return marshalRecord.addXsiTypeAndClassIndicatorIfRequired(xmlDescriptor, referenceDescriptor, xmlField, originalObject, obj, wasXMLRoot, isRootElement);
}
/**
* @since EclipseLink 2.5.0
*/
@Override
public void writeXsiTypeAttribute(Descriptor descriptor, String typeUri,
String typeLocal, String typePrefix, boolean addToNamespaceResolver) {
validatingRecord.writeXsiTypeAttribute(descriptor, typeUri, typeLocal, typePrefix, addToNamespaceResolver);
marshalRecord.writeXsiTypeAttribute(descriptor, typeUri, typeLocal, typePrefix, addToNamespaceResolver);
}
/**
* @since EclipseLink 2.5.0
*/
@Override
public void writeXsiTypeAttribute(Descriptor xmlDescriptor,
XMLSchemaReference xmlRef, boolean addToNamespaceResolver) {
validatingRecord.writeXsiTypeAttribute(xmlDescriptor, xmlRef, addToNamespaceResolver);
marshalRecord.writeXsiTypeAttribute(xmlDescriptor, xmlRef, addToNamespaceResolver);
}
@Override
public void setXOPPackage(boolean isXOPPackage) {
validatingRecord.setXOPPackage(isXOPPackage);
marshalRecord.setXOPPackage(isXOPPackage);
}
}