/* * JBoss, Home of Professional Open Source * Copyright 2013, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed 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 org.hibernate.jpamodelgen.util.xml; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.Attribute; import javax.xml.stream.events.Namespace; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import javax.xml.stream.util.EventReaderDelegate; /** * Transforms the version attribute and namespace of the JPA configuration files (persistence.xml and orm.xml) to * the default. For the purpose of the metamodel it is enough to parse the xml against the latest specification version * and schema. * * @author Hardy Ferentschik */ public class JpaNamespaceTransformingEventReader extends EventReaderDelegate { private static final String VERSION_ATTRIBUTE_NAME = "version"; private static final String DEFAULT_VERSION = "2.1"; private static final String DEFAULT_PERSISTENCE_NAMESPACE = "http://xmlns.jcp.org/xml/ns/persistence"; private static final String DEFAULT_ORM_NAMESPACE = "http://xmlns.jcp.org/xml/ns/persistence/orm"; private static final Map<String, String> NAMESPACE_MAPPING = new HashMap<String, String>( 2 ); static { NAMESPACE_MAPPING.put( "http://java.sun.com/xml/ns/persistence", DEFAULT_PERSISTENCE_NAMESPACE ); NAMESPACE_MAPPING.put( "http://java.sun.com/xml/ns/persistence/orm", DEFAULT_ORM_NAMESPACE ); } private static final Map<String, String> START_ELEMENT_TO_NAMESPACE_URI = new HashMap<String, String>( 2 ); static { START_ELEMENT_TO_NAMESPACE_URI.put( "persistence", DEFAULT_PERSISTENCE_NAMESPACE ); START_ELEMENT_TO_NAMESPACE_URI.put( "entity-mappings", DEFAULT_ORM_NAMESPACE ); } private static final String EMPTY_PREFIX = ""; private final XMLEventFactory xmlEventFactory; private String currentDocumentNamespaceUri; public JpaNamespaceTransformingEventReader(XMLEventReader reader) { super( reader ); this.xmlEventFactory = XMLEventFactory.newInstance(); } @Override public XMLEvent peek() throws XMLStreamException { return wrap( super.peek() ); } @Override public XMLEvent nextEvent() throws XMLStreamException { return wrap( super.nextEvent() ); } private XMLEvent wrap(XMLEvent event) { if ( event != null && event.isStartElement() ) { return transform( event.asStartElement() ); } return event; } private StartElement transform(StartElement startElement) { String elementName = startElement.getName().getLocalPart(); // use the start element to determine whether we have a persistence.xml or orm.xml if ( START_ELEMENT_TO_NAMESPACE_URI.containsKey( elementName ) ) { currentDocumentNamespaceUri = START_ELEMENT_TO_NAMESPACE_URI.get( elementName ); } List<Attribute> newElementAttributeList = updateElementAttributes( startElement ); List<Namespace> newNamespaceList = updateElementNamespaces( startElement ); // create the new element return xmlEventFactory.createStartElement( new QName( currentDocumentNamespaceUri, startElement.getName().getLocalPart() ), newElementAttributeList.iterator(), newNamespaceList.iterator() ); } private List<Namespace> updateElementNamespaces(StartElement startElement) { List<Namespace> newNamespaceList = new ArrayList<Namespace>(); Iterator<?> existingNamespaceIterator = startElement.getNamespaces(); while ( existingNamespaceIterator.hasNext() ) { Namespace namespace = (Namespace) existingNamespaceIterator.next(); if ( NAMESPACE_MAPPING.containsKey( namespace.getNamespaceURI() ) ) { newNamespaceList.add( xmlEventFactory.createNamespace( EMPTY_PREFIX, currentDocumentNamespaceUri ) ); } else { newNamespaceList.add( namespace ); } } // if there is no namespace at all we add the main one. All elements need the namespace if ( newNamespaceList.isEmpty() ) { newNamespaceList.add( xmlEventFactory.createNamespace( EMPTY_PREFIX, currentDocumentNamespaceUri ) ); } return newNamespaceList; } private List<Attribute> updateElementAttributes(StartElement startElement) { // adjust the version attribute List<Attribute> newElementAttributeList = new ArrayList<Attribute>(); Iterator<?> existingAttributesIterator = startElement.getAttributes(); while ( existingAttributesIterator.hasNext() ) { Attribute attribute = (Attribute) existingAttributesIterator.next(); if ( VERSION_ATTRIBUTE_NAME.equals( attribute.getName().getLocalPart() ) ) { if ( !DEFAULT_VERSION.equals( attribute.getName().getPrefix() ) ) { newElementAttributeList.add( xmlEventFactory.createAttribute( attribute.getName(), DEFAULT_VERSION ) ); } } else { newElementAttributeList.add( attribute ); } } return newElementAttributeList; } }