| /* |
| * 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); |
| } |
| |
| } |