org.hibernate.cfg.annotations.reflection.XMLContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-annotations
Show all versions of hibernate-annotations
Annotations metadata for Hibernate
// $Id: XMLContext.java 19255 2010-04-21 01:57:44Z [email protected] $
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg.annotations.reflection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.AccessType;
import org.dom4j.Document;
import org.dom4j.Element;
import org.hibernate.AnnotationException;
import org.hibernate.util.StringHelper;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
/**
* @author Emmanuel Bernard
*/
public class XMLContext {
private Logger log = LoggerFactory.getLogger( XMLContext.class );
private Default globalDefaults;
private Map classOverriding = new HashMap();
private Map defaultsOverriding = new HashMap();
private List defaultElements = new ArrayList();
private List defaultEntityListeners = new ArrayList();
private boolean hasContext = false;
/**
* @param doc The xml document to add
* @return Add a xml document to this context and return the list of added class names.
*/
@SuppressWarnings( "unchecked" )
public List addDocument(Document doc) {
hasContext = true;
List addedClasses = new ArrayList();
Element root = doc.getRootElement();
//global defaults
Element metadata = root.element( "persistence-unit-metadata" );
if ( metadata != null ) {
if ( globalDefaults == null ) {
globalDefaults = new Default();
globalDefaults.setMetadataComplete(
metadata.element( "xml-mapping-metadata-complete" ) != null ?
Boolean.TRUE :
null
);
Element defaultElement = metadata.element( "persistence-unit-defaults" );
if ( defaultElement != null ) {
Element unitElement = defaultElement.element( "schema" );
globalDefaults.setSchema( unitElement != null ? unitElement.getTextTrim() : null );
unitElement = defaultElement.element( "catalog" );
globalDefaults.setCatalog( unitElement != null ? unitElement.getTextTrim() : null );
unitElement = defaultElement.element( "access" );
setAccess( unitElement, globalDefaults );
unitElement = defaultElement.element( "cascade-persist" );
globalDefaults.setCascadePersist( unitElement != null ? Boolean.TRUE : null );
unitElement = defaultElement.element( "delimited-identifiers" );
globalDefaults.setDelimitedIdentifiers( unitElement != null ? Boolean.TRUE : null );
defaultEntityListeners.addAll( addEntityListenerClasses( defaultElement, null, addedClasses ) );
}
}
else {
log.warn( "Found more than one , subsequent ignored" );
}
}
//entity mapping default
Default entityMappingDefault = new Default();
Element unitElement = root.element( "package" );
String packageName = unitElement != null ? unitElement.getTextTrim() : null;
entityMappingDefault.setPackageName( packageName );
unitElement = root.element( "schema" );
entityMappingDefault.setSchema( unitElement != null ? unitElement.getTextTrim() : null );
unitElement = root.element( "catalog" );
entityMappingDefault.setCatalog( unitElement != null ? unitElement.getTextTrim() : null );
unitElement = root.element( "access" );
setAccess( unitElement, entityMappingDefault );
defaultElements.add( root );
List entities = (List) root.elements( "entity" );
addClass( entities, packageName, entityMappingDefault, addedClasses );
entities = (List) root.elements( "mapped-superclass" );
addClass( entities, packageName, entityMappingDefault, addedClasses );
entities = (List) root.elements( "embeddable" );
addClass( entities, packageName, entityMappingDefault, addedClasses );
return addedClasses;
}
private void setAccess(Element unitElement, Default defaultType) {
if ( unitElement != null ) {
String access = unitElement.getTextTrim();
setAccess( access, defaultType );
}
}
private void setAccess( String access, Default defaultType) {
AccessType type;
if ( access != null ) {
try {
type = AccessType.valueOf( access );
}
catch ( IllegalArgumentException e ) {
throw new AnnotationException( "Invalid access type " + access + " (check your xml configuration)" );
}
defaultType.setAccess( type );
}
}
private void addClass(List entities, String packageName, Default defaults, List addedClasses) {
for (Element element : entities) {
String className = buildSafeClassName( element.attributeValue( "class" ), packageName );
if ( classOverriding.containsKey( className ) ) {
//maybe switch it to warn?
throw new IllegalStateException( "Duplicate XML entry for " + className );
}
addedClasses.add( className );
classOverriding.put( className, element );
Default localDefault = new Default();
localDefault.override( defaults );
String metadataCompleteString = element.attributeValue( "metadata-complete" );
if ( metadataCompleteString != null ) {
localDefault.setMetadataComplete( Boolean.parseBoolean( metadataCompleteString ) );
}
String access = element.attributeValue( "access" );
setAccess( access, localDefault );
defaultsOverriding.put( className, localDefault );
log.debug( "Adding XML overriding information for {}", className );
addEntityListenerClasses( element, packageName, addedClasses );
}
}
private List addEntityListenerClasses(Element element, String packageName, List addedClasses) {
List localAddedClasses = new ArrayList();
Element listeners = element.element( "entity-listeners" );
if ( listeners != null ) {
@SuppressWarnings( "unchecked" )
List elements = (List) listeners.elements( "entity-listener" );
for (Element listener : elements) {
String listenerClassName = buildSafeClassName( listener.attributeValue( "class" ), packageName );
if ( classOverriding.containsKey( listenerClassName ) ) {
//maybe switch it to warn?
if ( "entity-listener".equals( classOverriding.get( listenerClassName ).getName() ) ) {
log.info(
"entity-listener duplication, first event definition will be used: {}",
listenerClassName
);
continue;
}
else {
throw new IllegalStateException( "Duplicate XML entry for " + listenerClassName );
}
}
localAddedClasses.add( listenerClassName );
classOverriding.put( listenerClassName, listener );
}
}
log.debug( "Adding XML overriding information for listener: {}", localAddedClasses );
addedClasses.addAll( localAddedClasses );
return localAddedClasses;
}
public static String buildSafeClassName(String className, String defaultPackageName) {
if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty( defaultPackageName ) ) {
className = StringHelper.qualify( defaultPackageName, className );
}
return className;
}
public static String buildSafeClassName(String className, XMLContext.Default defaults) {
return buildSafeClassName( className, defaults.getPackageName() );
}
public Default getDefault(String className) {
Default xmlDefault = new Default();
xmlDefault.override( globalDefaults );
if ( className != null ) {
Default entityMappingOverriding = defaultsOverriding.get( className );
xmlDefault.override( entityMappingOverriding );
}
return xmlDefault;
}
public Element getXMLTree(String className ) {
return classOverriding.get( className );
}
public List getAllDocuments() {
return defaultElements;
}
public boolean hasContext() {
return hasContext;
}
public static class Default {
private AccessType access;
private String packageName;
private String schema;
private String catalog;
private Boolean metadataComplete;
private Boolean cascadePersist;
private Boolean delimitedIdentifier;
public AccessType getAccess() {
return access;
}
protected void setAccess(AccessType access) {
this.access = access;
}
public String getCatalog() {
return catalog;
}
protected void setCatalog(String catalog) {
this.catalog = catalog;
}
public String getPackageName() {
return packageName;
}
protected void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getSchema() {
return schema;
}
protected void setSchema(String schema) {
this.schema = schema;
}
public Boolean getMetadataComplete() {
return metadataComplete;
}
public boolean canUseJavaAnnotations() {
return metadataComplete == null || !metadataComplete;
}
protected void setMetadataComplete(Boolean metadataComplete) {
this.metadataComplete = metadataComplete;
}
public Boolean getCascadePersist() {
return cascadePersist;
}
void setCascadePersist(Boolean cascadePersist) {
this.cascadePersist = cascadePersist;
}
public void override(Default globalDefault) {
if ( globalDefault != null ) {
if ( globalDefault.getAccess() != null ) access = globalDefault.getAccess();
if ( globalDefault.getPackageName() != null ) packageName = globalDefault.getPackageName();
if ( globalDefault.getSchema() != null ) schema = globalDefault.getSchema();
if ( globalDefault.getCatalog() != null ) catalog = globalDefault.getCatalog();
if ( globalDefault.getDelimitedIdentifier() != null ) delimitedIdentifier = globalDefault.getDelimitedIdentifier();
if ( globalDefault.getMetadataComplete() != null ) {
metadataComplete = globalDefault.getMetadataComplete();
}
//TODO fix that in stone if cascade-persist is set already?
if ( globalDefault.getCascadePersist() != null ) cascadePersist = globalDefault.getCascadePersist();
}
}
public void setDelimitedIdentifiers(Boolean delimitedIdentifier) {
this.delimitedIdentifier = delimitedIdentifier;
}
public Boolean getDelimitedIdentifier() {
return delimitedIdentifier;
}
}
public List getDefaultEntityListeners() {
return defaultEntityListeners;
}
}