HHH-6092 : Domain and relational state for SimpleAttributeBinding

This commit is contained in:
Gail Badner 2011-04-06 11:00:07 -07:00 committed by Gail Badner
parent 014702fa23
commit 412fa9406f
15 changed files with 543 additions and 256 deletions

View File

@ -102,8 +102,7 @@ public abstract class AbstractAttributeBinding implements AttributeBinding {
return attribute; return attribute;
} }
@Override protected void setAttribute(Attribute attribute) {
public void setAttribute(Attribute attribute) {
this.attribute = attribute; this.attribute = attribute;
} }
@ -112,8 +111,7 @@ public abstract class AbstractAttributeBinding implements AttributeBinding {
return value; return value;
} }
@Override protected void setValue(Value value) {
public void setValue(Value value) {
this.value = value; this.value = value;
} }
@ -215,8 +213,6 @@ public abstract class AbstractAttributeBinding implements AttributeBinding {
return isLazy; return isLazy;
} }
protected abstract boolean isLazyDefault(MappingDefaults defaults);
protected void setLazy(boolean isLazy) { protected void setLazy(boolean isLazy) {
this.isLazy = isLazy; this.isLazy = isLazy;
} }

View File

@ -52,13 +52,6 @@ public interface AttributeBinding {
*/ */
public Attribute getAttribute(); public Attribute getAttribute();
/**
* Set the attribute being bound.
*
* @param attribute The attribute
*/
public void setAttribute(Attribute attribute);
/** /**
* Obtain the value bound * Obtain the value bound
* *
@ -66,13 +59,6 @@ public interface AttributeBinding {
*/ */
public Value getValue(); public Value getValue();
/**
* Set the value being bound.
*
* @param value The value
*/
public void setValue(Value value);
/** /**
* Obtain the descriptor for the Hibernate Type for this binding. * Obtain the descriptor for the Hibernate Type for this binding.
* *

View File

@ -37,6 +37,7 @@ import org.hibernate.engine.Versioning;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.MetaAttribute; import org.hibernate.mapping.MetaAttribute;
import org.hibernate.metamodel.domain.Entity; import org.hibernate.metamodel.domain.Entity;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.source.hbm.HbmHelper; import org.hibernate.metamodel.source.hbm.HbmHelper;
import org.hibernate.metamodel.source.util.DomHelper; import org.hibernate.metamodel.source.util.DomHelper;
@ -84,7 +85,7 @@ public class EntityBinding {
private List<String> synchronizedTableNames; private List<String> synchronizedTableNames;
// TODO: change to initialize from DomainState // TODO: change to intialize from Doimain
public void fromHbmXml(MappingDefaults defaults, Element node, Entity entity) { public void fromHbmXml(MappingDefaults defaults, Element node, Entity entity) {
this.entity = entity; this.entity = entity;
metaAttributes = HbmHelper.extractMetas( node, true, defaults.getMappingMetas() ); metaAttributes = HbmHelper.extractMetas( node, true, defaults.getMappingMetas() );
@ -161,21 +162,33 @@ public class EntityBinding {
return entityIdentifier; return entityIdentifier;
} }
public EntityDiscriminator makeEntityDiscriminator() { public void bindEntityIdentifier(SimpleAttributeBinding attributeBinding) {
entityDiscriminator = new EntityDiscriminator( this ); if ( ! Column.class.isInstance( attributeBinding.getValue() ) ) {
return entityDiscriminator; throw new MappingException(
"Identifier value must be a Column; instead it is: " + attributeBinding.getValue().getClass()
);
}
entityIdentifier.setValueBinding( attributeBinding );
baseTable.getPrimaryKey().addColumn( Column.class.cast( attributeBinding.getValue() ) );
} }
public EntityDiscriminator getEntityDiscriminator() { public EntityDiscriminator getEntityDiscriminator() {
return entityDiscriminator; return entityDiscriminator;
} }
public SimpleAttributeBinding getVersioningValueBinding() { public void bindEntityDiscriminator(SimpleAttributeBinding attributeBinding) {
return versionBinding; if ( ! Column.class.isInstance( attributeBinding.getValue() ) ) {
throw new MappingException(
"Identifier value must be a Column; instead it is: " + attributeBinding.getValue().getClass()
);
}
entityDiscriminator.setValueBinding( attributeBinding );
baseTable.getPrimaryKey().addColumn( Column.class.cast( attributeBinding.getValue() ) );
} }
public void setVersioningValueBinding(SimpleAttributeBinding versionBinding) {
this.versionBinding = versionBinding; public SimpleAttributeBinding getVersioningValueBinding() {
return versionBinding;
} }
public Iterable<AttributeBinding> getAttributeBindings() { public Iterable<AttributeBinding> getAttributeBindings() {
@ -186,8 +199,34 @@ public class EntityBinding {
return attributeBindingMap.get( name ); return attributeBindingMap.get( name );
} }
public SimpleAttributeBinding makeSimplePrimaryKeyAttributeBinding(String name) {
final SimpleAttributeBinding binding = makeSimpleAttributeBinding( name, true, true );
getEntityIdentifier().setValueBinding( binding );
return binding;
}
public SimpleAttributeBinding makeEntityDiscriminatorBinding(String name) {
if ( entityDiscriminator != null ) {
// TODO: LOG this!!!
}
entityDiscriminator = new EntityDiscriminator( this );
entityDiscriminator.setValueBinding( makeSimpleAttributeBinding( name, true, false ) );
return entityDiscriminator.getValueBinding();
}
public SimpleAttributeBinding makeVersionBinding(String name) {
versionBinding = makeSimpleAttributeBinding( name, true, false );
return versionBinding;
}
public SimpleAttributeBinding makeSimpleAttributeBinding(String name) { public SimpleAttributeBinding makeSimpleAttributeBinding(String name) {
final SimpleAttributeBinding binding = new SimpleAttributeBinding( this ); return makeSimpleAttributeBinding( name, false, false );
}
private SimpleAttributeBinding makeSimpleAttributeBinding(String name, boolean forceNonNullable, boolean forceUnique) {
final SimpleAttributeBinding binding = new SimpleAttributeBinding( this, forceNonNullable, forceUnique );
attributeBindingMap.put( name, binding ); attributeBindingMap.put( name, binding );
binding.setAttribute( entity.getAttribute( name ) ); binding.setAttribute( entity.getAttribute( name ) );
return binding; return binding;

View File

@ -25,6 +25,7 @@ package org.hibernate.metamodel.binding;
import java.util.Map; import java.util.Map;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.mapping.MetaAttribute; import org.hibernate.mapping.MetaAttribute;
/** /**
@ -37,4 +38,5 @@ public interface MappingDefaults {
String getDefaultCascade(); String getDefaultCascade();
String getDefaultAccess(); String getDefaultAccess();
boolean isDefaultLazy(); boolean isDefaultLazy();
NamingStrategy getNamingStrategy();
} }

View File

@ -23,12 +23,19 @@
*/ */
package org.hibernate.metamodel.binding; package org.hibernate.metamodel.binding;
import org.dom4j.Attribute; import java.util.LinkedHashSet;
import org.dom4j.Element; import java.util.Set;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.mapping.PropertyGeneration; import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.source.util.DomHelper; import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.DerivedValue;
import org.hibernate.metamodel.relational.SimpleValue;
import org.hibernate.metamodel.relational.Size;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.relational.Tuple;
import org.hibernate.metamodel.relational.Value;
/** /**
* TODO : javadoc * TODO : javadoc
@ -37,12 +44,38 @@ import org.hibernate.metamodel.source.util.DomHelper;
*/ */
public class SimpleAttributeBinding extends SingularAttributeBinding { public class SimpleAttributeBinding extends SingularAttributeBinding {
public static interface DomainState extends SingularAttributeBinding.DomainState { public static interface DomainState extends SingularAttributeBinding.DomainState {
public abstract PropertyGeneration getPropertyGeneration(); public PropertyGeneration getPropertyGeneration();
} }
public static interface SingleValueRelationalState {}
public static interface ColumnRelationalState extends SingleValueRelationalState {
NamingStrategy getNamingStrategy();
String getExplicitColumnName();
boolean isUnique();
Size getSize();
boolean isNullable();
String getCheckCondition();
String getDefault();
String getSqlType();
String getCustomWriteFragment();
String getCustomReadFragment();
String getComment();
Set<String> getUniqueKeys();
Set<String> getIndexes();
}
public static interface DerivedRelationalState extends SingleValueRelationalState {
String getFormula();
}
public static interface TupleRelationalState {
LinkedHashSet<SingleValueRelationalState> getSingleValueRelationalStates();
}
private PropertyGeneration generation; private PropertyGeneration generation;
SimpleAttributeBinding(EntityBinding entityBinding) { SimpleAttributeBinding(EntityBinding entityBinding, boolean forceNonNullable, boolean forceUnique) {
super( entityBinding ); super( entityBinding, forceNonNullable, forceUnique );
} }
public final void initialize(DomainState state) { public final void initialize(DomainState state) {
@ -50,8 +83,79 @@ public class SimpleAttributeBinding extends SingularAttributeBinding {
generation = state.getPropertyGeneration(); generation = state.getPropertyGeneration();
} }
protected boolean isLazyDefault(MappingDefaults defaults) { public final void initializeColumnValue(ColumnRelationalState state) {
return false; Column columnValue = createColumn( state );
setValue( columnValue );
}
private Column createColumn(ColumnRelationalState state) {
final String explicitName = state.getExplicitColumnName();
final String logicalColumnName = state.getNamingStrategy().logicalColumnName( explicitName, getAttribute().getName() );
final TableSpecification table = getEntityBinding().getBaseTable();
final String columnName =
explicitName == null ?
state.getNamingStrategy().propertyToColumnName( getAttribute().getName() ) :
state.getNamingStrategy().columnName( explicitName );
// todo : find out the purpose of these logical bindings
// mappings.addColumnBinding( logicalColumnName, column, table );
Column columnValue = table.createColumn( columnName );
columnValue.getSize().initialize( state.getSize() );
columnValue.setNullable( ! forceNonNullable() && state.isNullable() );
columnValue.setUnique( ! forceUnique() && state.isUnique() );
columnValue.setCheckCondition( state.getCheckCondition() );
columnValue.setDefaultValue( state.getDefault() );
columnValue.setSqlType( state.getSqlType() );
columnValue.setWriteFragment( state.getCustomWriteFragment() );
columnValue.setReadFragment( state.getCustomReadFragment() );
columnValue.setComment( state.getComment() );
for ( String uniqueKey : state.getUniqueKeys() ) {
table.getOrCreateUniqueKey( uniqueKey ).addColumn( columnValue );
}
for ( String index : state.getIndexes() ) {
table.getOrCreateIndex( index ).addColumn( columnValue );
}
return columnValue;
}
private boolean isUnique(ColumnRelationalState state) {
return isPrimaryKey() || state.isUnique();
}
public final <T extends DerivedRelationalState> void initializeDerivedValue(T state) {
setValue( createDerivedValue( state ) );
}
private DerivedValue createDerivedValue(DerivedRelationalState state) {
return getEntityBinding().getBaseTable().createDerivedValue( state.getFormula() );
}
public final void initializeTupleValue(TupleRelationalState state) {
if ( state.getSingleValueRelationalStates().size() == 0 ) {
throw new MappingException( "Tuple state does not contain any values." );
}
if ( state.getSingleValueRelationalStates().size() == 1 ) {
setValue( createSingleValue( state.getSingleValueRelationalStates().iterator().next() ) );
}
else {
Tuple tuple = getEntityBinding().getBaseTable().createTuple( "[" + getAttribute().getName() + "]" );
for ( SingleValueRelationalState singleValueState : state.getSingleValueRelationalStates() ) {
tuple.addValue( createSingleValue( singleValueState ) );
}
setValue( tuple );
}
}
private SimpleValue createSingleValue(SingleValueRelationalState state) {
if ( state instanceof ColumnRelationalState ) {
return createColumn( ColumnRelationalState.class.cast( state ) );
}
else if ( state instanceof DerivedRelationalState ) {
return createDerivedValue( DerivedRelationalState.class.cast( state ) );
}
else {
throw new MappingException( "unknown relational state:" + state.getClass().getName() );
}
} }
@Override @Override
@ -59,6 +163,10 @@ public class SimpleAttributeBinding extends SingularAttributeBinding {
return true; return true;
} }
private boolean isPrimaryKey() {
return this == getEntityBinding().getEntityIdentifier().getValueBinding();
}
public PropertyGeneration getGeneration() { public PropertyGeneration getGeneration() {
return generation; return generation;
} }

View File

@ -41,13 +41,17 @@ public abstract class SingularAttributeBinding extends AbstractAttributeBinding
String getUnsavedValue(); String getUnsavedValue();
} }
private final boolean forceNonNullable;
private final boolean forceUnique;
private boolean insertable; private boolean insertable;
private boolean updateable; private boolean updateable;
private boolean keyCasadeDeleteEnabled; private boolean keyCasadeDeleteEnabled;
private String unsavedValue; private String unsavedValue;
SingularAttributeBinding(EntityBinding entityBinding) { SingularAttributeBinding(EntityBinding entityBinding, boolean forceNonNullable, boolean forceUnique) {
super( entityBinding ); super( entityBinding );
this.forceNonNullable = forceNonNullable;
this.forceUnique = forceUnique;
} }
public final void initialize(DomainState state) { public final void initialize(DomainState state) {
@ -91,4 +95,12 @@ public abstract class SingularAttributeBinding extends AbstractAttributeBinding
public void setUnsavedValue(String unsaveValue) { public void setUnsavedValue(String unsaveValue) {
this.unsavedValue = unsaveValue; this.unsavedValue = unsaveValue;
} }
public boolean forceNonNullable() {
return forceNonNullable;
}
public boolean forceUnique() {
return forceUnique;
}
} }

View File

@ -107,6 +107,12 @@ public class Size implements Serializable {
return lobMultiplier; return lobMultiplier;
} }
public void initialize(Size size) {
this.precision = size.precision;
this.scale = size.scale;
this.length = size.length;
}
public void setPrecision(int precision) { public void setPrecision(int precision) {
this.precision = precision; this.precision = precision;
} }

View File

@ -23,11 +23,7 @@
*/ */
package org.hibernate.metamodel.source.hbm; package org.hibernate.metamodel.source.hbm;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.dom4j.Attribute; import org.dom4j.Attribute;
import org.dom4j.Element; import org.dom4j.Element;
@ -46,18 +42,14 @@ import org.hibernate.metamodel.binding.SimpleAttributeBinding;
import org.hibernate.metamodel.domain.Entity; import org.hibernate.metamodel.domain.Entity;
import org.hibernate.metamodel.domain.Hierarchical; import org.hibernate.metamodel.domain.Hierarchical;
import org.hibernate.metamodel.domain.PluralAttributeNature; import org.hibernate.metamodel.domain.PluralAttributeNature;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.Index;
import org.hibernate.metamodel.relational.Schema; import org.hibernate.metamodel.relational.Schema;
import org.hibernate.metamodel.relational.SimpleValue;
import org.hibernate.metamodel.relational.Table; import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.relational.Tuple;
import org.hibernate.metamodel.relational.UniqueKey; import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.relational.Value;
import org.hibernate.metamodel.source.Metadata; import org.hibernate.metamodel.source.Metadata;
import org.hibernate.metamodel.source.hbm.state.domain.HbmPluralAttributeDomainState; import org.hibernate.metamodel.source.hbm.state.domain.HbmPluralAttributeDomainState;
import org.hibernate.metamodel.source.hbm.state.domain.HbmSimpleAttributeDomainState; import org.hibernate.metamodel.source.hbm.state.domain.HbmSimpleAttributeDomainState;
import org.hibernate.metamodel.source.hbm.state.relational.HbmSimpleValueRelationalStateContainer;
/** /**
* TODO : javadoc * TODO : javadoc
@ -416,7 +408,10 @@ abstract class AbstractEntityBinder {
} }
} }
protected void bindSimpleAttribute(Element propertyElement, SimpleAttributeBinding attributeBinding, EntityBinding entityBinding, String attributeName) { protected void bindSimpleAttribute(Element propertyElement,
SimpleAttributeBinding attributeBinding,
EntityBinding entityBinding,
String attributeName) {
if ( attributeBinding.getAttribute() == null ) { if ( attributeBinding.getAttribute() == null ) {
attributeBinding.initialize( attributeBinding.initialize(
new HbmSimpleAttributeDomainState( new HbmSimpleAttributeDomainState(
@ -429,8 +424,14 @@ abstract class AbstractEntityBinder {
if ( attributeBinding.getValue() == null ) { if ( attributeBinding.getValue() == null ) {
// relational model has not been bound yet // relational model has not been bound yet
Value idValue = processValues( propertyElement, entityBinding.getBaseTable(), attributeName ); // boolean (true here) indicates that by default column names should be guessed
attributeBinding.setValue( idValue ); attributeBinding.initializeTupleValue(
new HbmSimpleValueRelationalStateContainer(
getHibernateMappingBinder(),
propertyElement,
true
)
);
} }
} }
@ -495,57 +496,10 @@ abstract class AbstractEntityBinder {
// return prop; // return prop;
// } // }
protected Value processValues(Element identifierElement, TableSpecification baseTable, String propertyPath) {
// protected HbmRelationalState processValues(Element identifierElement, TableSpecification baseTable, String propertyPath, boolean isSimplePrimaryKey) {
// first boolean (false here) indicates that by default columns are nullable // first boolean (false here) indicates that by default columns are nullable
// second boolean (true here) indicates that by default column names should be guessed // second boolean (true here) indicates that by default column names should be guessed
return processValues( identifierElement, baseTable, false, true, propertyPath );
}
protected Value processValues(
Element propertyElement,
TableSpecification table,
boolean isNullableByDefault,
boolean autoColumnCreation,
String propertyPath) {
final UniqueKeyBinder propertyUniqueKeyBinder = new UniqueKeyBinder( propertyElement.attribute( "unique-key" ), table );
final IndexBinder propertyIndexBinder = new IndexBinder( propertyElement.attribute( "index" ), table );
final Attribute columnAttribute = propertyElement.attribute( "column" );
if ( columnAttribute == null ) {
SimpleValue value = null;
Tuple tuple = null;
final Iterator valueElements = propertyElement.elementIterator();
while ( valueElements.hasNext() ) {
if ( value != null ) {
if ( tuple == null ) {
tuple = table.createTuple( "[" + propertyPath + "]" );
}
tuple.addValue( value );
}
final Element valueElement = (Element) valueElements.next();
if ( "column".equals( valueElement.getName() ) ) {
final Element columnElement = valueElement;
final String explicitName = columnElement.attributeValue( "name" );
final String logicalColumnName = getNamingStrategy().logicalColumnName( explicitName, propertyPath );
final String columnName = getNamingStrategy().columnName( explicitName );
// todo : find out the purpose of these logical bindings
// mappings.addColumnBinding( logicalColumnName, column, table );
Column column = table.createColumn( columnName );
value = column;
basicColumnBinding( columnElement, column, isNullableByDefault );
propertyUniqueKeyBinder.bindColumn( column );
propertyIndexBinder.bindColumn( column );
new UniqueKeyBinder( columnElement.attribute( "unique-key" ), table ).bindColumn( column );
new IndexBinder( columnElement.attribute( "index" ), table ).bindColumn( column );
}
else if ( "formula".equals( valueElement.getName() ) ) {
value = table.createDerivedValue( valueElement.getTextTrim() );
}
}
// todo : logical 1-1 handling // todo : logical 1-1 handling
// final Attribute uniqueAttribute = node.attribute( "unique" ); // final Attribute uniqueAttribute = node.attribute( "unique" );
// if ( uniqueAttribute != null // if ( uniqueAttribute != null
@ -553,130 +507,8 @@ abstract class AbstractEntityBinder {
// && ManyToOne.class.isInstance( simpleValue ) ) { // && ManyToOne.class.isInstance( simpleValue ) ) {
// ( (ManyToOne) simpleValue ).markAsLogicalOneToOne(); // ( (ManyToOne) simpleValue ).markAsLogicalOneToOne();
// } // }
//return processValues( identifierElement, baseTable, false, true, propertyPath, isSimplePrimaryKey );
if ( tuple != null ) {
return tuple;
}
else if ( value != null ) {
return value;
}
else if ( autoColumnCreation ) {
final String columnName = getNamingStrategy().propertyToColumnName( propertyPath );
final String logicalColumnName = getNamingStrategy().logicalColumnName( null, propertyPath );
// todo : find out the purpose of these logical bindings
// mappings.addColumnBinding( logicalColumnName, column, table );
Column column = table.createColumn( columnName );
basicColumnBinding( propertyElement, column, isNullableByDefault );
propertyUniqueKeyBinder.bindColumn( column );
propertyIndexBinder.bindColumn( column );
return column;
}
}
if ( propertyElement.elementIterator( "column" ).hasNext() ) {
throw new MappingException( "column attribute may not be used together with <column> subelement" );
}
if ( propertyElement.elementIterator( "formula" ).hasNext() ) { }
throw new MappingException( "column attribute may not be used together with <formula> subelement" );
}
final String explicitName = columnAttribute.getValue();
final String logicalColumnName = getNamingStrategy().logicalColumnName( explicitName, propertyPath );
final String columnName = getNamingStrategy().columnName( explicitName );
// todo : find out the purpose of these logical bindings
// mappings.addColumnBinding( logicalColumnName, column, table );
Column column = table.createColumn( columnName );
basicColumnBinding( propertyElement, column, isNullableByDefault );
propertyUniqueKeyBinder.bindColumn( column );
propertyIndexBinder.bindColumn( column );
return column;
}
protected static class UniqueKeyBinder {
private final List<UniqueKey> uniqueKeys;
UniqueKeyBinder(Attribute uniqueKeyAttribute, TableSpecification table) {
if ( uniqueKeyAttribute == null ) {
uniqueKeys = Collections.emptyList();
}
else {
uniqueKeys = new ArrayList<UniqueKey>();
StringTokenizer uniqueKeyNames = new StringTokenizer( uniqueKeyAttribute.getValue(), ", " );
while ( uniqueKeyNames.hasMoreTokens() ) {
uniqueKeys.add( table.getOrCreateUniqueKey( uniqueKeyNames.nextToken() ) );
}
}
}
void bindColumn(Column column) {
for ( UniqueKey uniqueKey : uniqueKeys ) {
uniqueKey.addColumn( column );
}
}
}
protected static class IndexBinder {
private final List<Index> indexes;
IndexBinder(Attribute indexAttribute, TableSpecification table) {
if ( indexAttribute == null ) {
indexes = Collections.emptyList();
}
else {
indexes = new ArrayList<Index>();
StringTokenizer indexNames = new StringTokenizer( indexAttribute.getValue(), ", " );
while ( indexNames.hasMoreTokens() ) {
indexes.add( table.getOrCreateIndex( indexNames.nextToken() ) );
}
}
}
void bindColumn(Column column) {
for ( Index index : indexes ) {
index.addColumn( column );
}
}
}
public static void basicColumnBinding(Element node, Column column, boolean isNullable) throws MappingException {
Attribute lengthNode = node.attribute( "length" );
if ( lengthNode != null ) {
column.getSize().setLength( Integer.parseInt( lengthNode.getValue() ) );
}
Attribute scalNode = node.attribute( "scale" );
if ( scalNode != null ) {
column.getSize().setScale( Integer.parseInt( scalNode.getValue() ) );
}
Attribute precNode = node.attribute( "precision" );
if ( precNode != null ) {
column.getSize().setPrecision( Integer.parseInt( precNode.getValue() ) );
}
Attribute nullNode = node.attribute( "not-null" );
column.setNullable( nullNode == null ? isNullable : nullNode.getValue().equals( "false" ) );
Attribute unqNode = node.attribute( "unique" );
if ( unqNode != null ) {
column.setUnique( unqNode.getValue().equals( "true" ) );
}
column.setCheckCondition( node.attributeValue( "check" ) );
column.setDefaultValue( node.attributeValue( "default" ) );
Attribute typeNode = node.attribute( "sql-type" );
if ( typeNode != null ) column.setSqlType( typeNode.getValue() );
String customWrite = node.attributeValue( "write" );
if(customWrite != null && !customWrite.matches("[^?]*\\?[^?]*")) {
throw new MappingException("write expression must contain exactly one value placeholder ('?') character");
}
column.setWriteFragment( customWrite );
column.setReadFragment( node.attributeValue( "read" ) );
Element comment = node.element("comment");
if ( comment != null ) {
column.setComment( comment.getTextTrim() );
}
}
}

View File

@ -30,6 +30,7 @@ import org.dom4j.Attribute;
import org.dom4j.Element; import org.dom4j.Element;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.xml.XmlDocument; import org.hibernate.internal.util.xml.XmlDocument;
import org.hibernate.mapping.FetchProfile; import org.hibernate.mapping.FetchProfile;
@ -100,6 +101,10 @@ class HibernateMappingBinder implements MappingDefaults {
return defaultLazy; return defaultLazy;
} }
public NamingStrategy getNamingStrategy() {
return hibernateXmlBinder.getMetadata().getNamingStrategy();
}
String getPackageName() { String getPackageName() {
return packageName; return packageName;
} }

View File

@ -33,12 +33,10 @@ import org.hibernate.mapping.RootClass;
import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.SimpleAttributeBinding; import org.hibernate.metamodel.binding.SimpleAttributeBinding;
import org.hibernate.metamodel.domain.Entity;
import org.hibernate.metamodel.relational.Column; import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.Identifier; import org.hibernate.metamodel.relational.Identifier;
import org.hibernate.metamodel.relational.InLineView; import org.hibernate.metamodel.relational.InLineView;
import org.hibernate.metamodel.relational.Schema; import org.hibernate.metamodel.relational.Schema;
import org.hibernate.metamodel.relational.Tuple;
import org.hibernate.metamodel.relational.Value; import org.hibernate.metamodel.relational.Value;
/** /**
@ -147,27 +145,16 @@ class RootEntityBinder extends AbstractEntityBinder {
final String attributeName = explicitName == null ? RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME : explicitName; final String attributeName = explicitName == null ? RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME : explicitName;
entityBinding.getEntity().getOrCreateSingularAttribute( attributeName ); entityBinding.getEntity().getOrCreateSingularAttribute( attributeName );
SimpleAttributeBinding idBinding = entityBinding.makeSimpleAttributeBinding( attributeName ); SimpleAttributeBinding idBinding = entityBinding.makeSimplePrimaryKeyAttributeBinding( attributeName );
bindSimpleAttribute( identifierElement, idBinding, entityBinding, attributeName ); bindSimpleAttribute( identifierElement, idBinding, entityBinding, attributeName );
// Handle the relational portion of the binding... if ( ! Column.class.isInstance( idBinding.getValue() ) ) {
Value idValue = processValues( identifierElement, entityBinding.getBaseTable(), attributeName );
idBinding.setValue( idValue );
// ear-mark this value binding as the identifier...
entityBinding.getEntityIdentifier().setValueBinding( idBinding );
if ( idValue instanceof Tuple ) {
// this should never ever happen.. // this should never ever happen..
throw new MappingException( "Unanticipated situation" ); throw new MappingException( "Unanticipated situation" );
} }
entityBinding.getBaseTable().getPrimaryKey().addColumn( (Column) idValue ); entityBinding.getBaseTable().getPrimaryKey().addColumn( Column.class.cast( idBinding.getValue() ) );
// SimpleValue id = new SimpleValue( mappings, entity.getTable() );
// entity.setIdentifier( id );
// if ( propertyName == null || entity.getPojoRepresentation() == null ) { // if ( propertyName == null || entity.getPojoRepresentation() == null ) {
// bindSimpleValue( idNode, id, false, RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME, mappings ); // bindSimpleValue( idNode, id, false, RootClass.DEFAULT_IDENTIFIER_COLUMN_NAME, mappings );
// if ( !id.isTypeSpecified() ) { // if ( !id.isTypeSpecified() ) {
@ -258,21 +245,14 @@ class RootEntityBinder extends AbstractEntityBinder {
final String attributeName = explicitName == null ? RootClass.DEFAULT_DISCRIMINATOR_COLUMN_NAME : explicitName; final String attributeName = explicitName == null ? RootClass.DEFAULT_DISCRIMINATOR_COLUMN_NAME : explicitName;
entityBinding.getEntity().getOrCreateSingularAttribute( attributeName ); entityBinding.getEntity().getOrCreateSingularAttribute( attributeName );
SimpleAttributeBinding discriminatorBinding = entityBinding.makeSimpleAttributeBinding( attributeName ); SimpleAttributeBinding discriminatorBinding = entityBinding.makeEntityDiscriminatorBinding( attributeName );
// Handle the relational portion of the binding...
bindSimpleAttribute( discriminatorElement, discriminatorBinding, entityBinding, attributeName ); bindSimpleAttribute( discriminatorElement, discriminatorBinding, entityBinding, attributeName );
if ( discriminatorBinding.getHibernateTypeDescriptor().getTypeName() == null ) { if ( discriminatorBinding.getHibernateTypeDescriptor().getTypeName() == null ) {
discriminatorBinding.getHibernateTypeDescriptor().setTypeName( "string" ); discriminatorBinding.getHibernateTypeDescriptor().setTypeName( "string" );
} }
// Handle the relational portion of the binding...
Value discriminatorValue = processValues( discriminatorElement, entityBinding.getBaseTable(), attributeName );
discriminatorBinding.setValue( discriminatorValue );
// ear-mark this value binding as the discriminator...
entityBinding.makeEntityDiscriminator();
entityBinding.getEntityDiscriminator().setValueBinding( discriminatorBinding );
if ( "true".equals( discriminatorElement.attributeValue( "force" ) ) ) { if ( "true".equals( discriminatorElement.attributeValue( "force" ) ) ) {
entityBinding.getEntityDiscriminator().setForced( true ); entityBinding.getEntityDiscriminator().setForced( true );
} }
@ -297,7 +277,7 @@ class RootEntityBinder extends AbstractEntityBinder {
throw new MappingException( "Mising property name for version/timestamp mapping [" + entityBinding.getEntity().getName() + "]" ); throw new MappingException( "Mising property name for version/timestamp mapping [" + entityBinding.getEntity().getName() + "]" );
} }
entityBinding.getEntity().getOrCreateSingularAttribute( explicitName ); entityBinding.getEntity().getOrCreateSingularAttribute( explicitName );
SimpleAttributeBinding versionBinding = entityBinding.makeSimpleAttributeBinding( explicitName ); SimpleAttributeBinding versionBinding = entityBinding.makeVersionBinding( explicitName );
bindSimpleAttribute( versioningElement, versionBinding, entityBinding, explicitName ); bindSimpleAttribute( versioningElement, versionBinding, entityBinding, explicitName );
if ( versionBinding.getHibernateTypeDescriptor().getTypeName() == null ) { if ( versionBinding.getHibernateTypeDescriptor().getTypeName() == null ) {
@ -315,18 +295,12 @@ class RootEntityBinder extends AbstractEntityBinder {
} }
} }
// Handle the relational portion of the binding...
Value discriminatorValue = processValues( versioningElement, entityBinding.getBaseTable(), explicitName );
versionBinding.setValue( discriminatorValue );
// for version properties marked as being generated, make sure they are "always" // for version properties marked as being generated, make sure they are "always"
// generated; aka, "insert" is invalid; this is dis-allowed by the DTD, // generated; aka, "insert" is invalid; this is dis-allowed by the DTD,
// but just to make sure... // but just to make sure...
if ( versionBinding.getGeneration() == PropertyGeneration.INSERT ) { if ( versionBinding.getGeneration() == PropertyGeneration.INSERT ) {
throw new MappingException( "'generated' attribute cannot be 'insert' for versioning property" ); throw new MappingException( "'generated' attribute cannot be 'insert' for versioning property" );
} }
entityBinding.setVersioningValueBinding( versionBinding );
} }
private void bindCaching(Element entityElement, EntityBinding entityBinding) { private void bindCaching(Element entityElement, EntityBinding entityBinding) {

View File

@ -0,0 +1,116 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.hbm.state.relational;
import java.util.Set;
import org.dom4j.Element;
import org.hibernate.MappingException;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.metamodel.binding.SimpleAttributeBinding;
import org.hibernate.metamodel.relational.Size;
import org.hibernate.metamodel.source.util.DomHelper;
/**
* @author Gail Badner
*/
public class HbmColumnRelationalState extends HbmRelationalState implements SimpleAttributeBinding.ColumnRelationalState {
private final HbmSimpleValueRelationalStateContainer container;
/* package-protected */
HbmColumnRelationalState(Element columnElement,
HbmSimpleValueRelationalStateContainer container) {
super( columnElement );
this.container = container;
}
public NamingStrategy getNamingStrategy() {
return container.getNamingStrategy();
}
public String getExplicitColumnName() {
return getElement().attributeValue( "name" );
}
public Size getSize() {
// TODO: should this set defaults if length, scale, precision is not specified?
Size size = new Size();
org.dom4j.Attribute lengthNode = getElement().attribute( "length" );
if ( lengthNode != null ) {
size.setLength( Integer.parseInt( lengthNode.getValue() ) );
}
org.dom4j.Attribute scaleNode = getElement().attribute( "scale" );
if ( scaleNode != null ) {
size.setScale( Integer.parseInt( scaleNode.getValue() ) );
}
org.dom4j.Attribute precisionNode = getElement().attribute( "precision" );
if ( precisionNode != null ) {
size.setPrecision( Integer.parseInt( precisionNode.getValue() ) );
}
// TODO: is there an attribute for lobMultiplier?
return size;
}
public boolean isNullable() {
return ! DomHelper.extractBooleanAttributeValue( getElement(), "not-null", false );
}
public boolean isUnique() {
return ! DomHelper.extractBooleanAttributeValue( getElement(), "unique", false );
}
public String getCheckCondition() {
return getElement().attributeValue( "check" );
}
public String getDefault() {
return getElement().attributeValue( "default" );
}
public String getSqlType() {
return getElement().attributeValue( "sql-type" );
}
public String getCustomWriteFragment() {
String customWrite = getElement().attributeValue( "write" );
if ( customWrite != null && ! customWrite.matches("[^?]*\\?[^?]*") ) {
throw new MappingException("write expression must contain exactly one value placeholder ('?') character");
}
return customWrite;
}
public String getCustomReadFragment() {
return getElement().attributeValue( "read" );
}
public String getComment() {
Element comment = getElement().element( "comment" );
return comment == null ?
null :
comment.getTextTrim();
}
public Set<String> getUniqueKeys() {
Set<String> uniqueKeys = DomHelper.extractUniqueAttributeValueTokens( getElement(), "unique-key", ", " );
uniqueKeys.addAll( container.getPropertyUniqueKeys() );
return uniqueKeys;
}
public Set<String> getIndexes() {
Set<String> indexes = DomHelper.extractUniqueAttributeValueTokens( getElement(), "index", ", " );
indexes.addAll( container.getPropertyIndexes() );
return indexes;
}
}

View File

@ -0,0 +1,42 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.hbm.state.relational;
import org.dom4j.Element;
import org.hibernate.metamodel.binding.SimpleAttributeBinding;
/**
* @author Gail Badner
*/
public class HbmDerivedValueRelationalState extends HbmRelationalState implements SimpleAttributeBinding.DerivedRelationalState {
public HbmDerivedValueRelationalState(Element element, HbmSimpleValueRelationalStateContainer container) {
super( element );
}
public String getFormula() {
return getElement().getTextTrim();
}
}

View File

@ -0,0 +1,51 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.hbm.state.relational;
import java.util.Set;
import org.dom4j.Element;
import org.hibernate.MappingException;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.metamodel.binding.MappingDefaults;
import org.hibernate.metamodel.binding.SimpleAttributeBinding;
import org.hibernate.metamodel.relational.Size;
import org.hibernate.metamodel.relational.TableSpecification;
import org.hibernate.metamodel.source.util.DomHelper;
/**
* @author Gail Badner
*/
public class HbmRelationalState {
private final Element element;
public HbmRelationalState(Element element) {
this.element = element;
}
protected Element getElement() {
return element;
}
}

View File

@ -0,0 +1,99 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.hbm.state.relational;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.hibernate.MappingException;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.metamodel.binding.MappingDefaults;
import org.hibernate.metamodel.binding.SimpleAttributeBinding;
import org.hibernate.metamodel.source.util.DomHelper;
/**
* @author Gail Badner
*/
public class HbmSimpleValueRelationalStateContainer extends HbmRelationalState implements SimpleAttributeBinding.TupleRelationalState {
private final MappingDefaults defaults;
private final Set<String> propertyUniqueKeys;
private final Set<String> propertyIndexes;
private final LinkedHashSet<SimpleAttributeBinding.SingleValueRelationalState> singleValueStates =
new LinkedHashSet<SimpleAttributeBinding.SingleValueRelationalState>();
public NamingStrategy getNamingStrategy() {
return defaults.getNamingStrategy();
}
public HbmSimpleValueRelationalStateContainer(MappingDefaults defaults,
Element propertyElement,
boolean autoColumnCreation) {
super( propertyElement );
this.defaults = defaults;
this.propertyUniqueKeys = DomHelper.extractUniqueAttributeValueTokens( propertyElement, "unique-key", ", " );
this.propertyIndexes = DomHelper.extractUniqueAttributeValueTokens( propertyElement, "index", ", " );
final Attribute columnAttribute = getElement().attribute( "column" );
if ( columnAttribute == null ) {
final Iterator valueElements = getElement().elementIterator();
while ( valueElements.hasNext() ) {
final Element valueElement = (Element) valueElements.next();
if ( "column".equals( valueElement.getName() ) ) {
singleValueStates.add( new HbmColumnRelationalState( valueElement, this ) );
}
else if ( "formula".equals( valueElement.getName() ) ) {
singleValueStates.add( new HbmDerivedValueRelationalState( valueElement, this ) );
}
}
}
else {
if ( propertyElement.elementIterator( "column" ).hasNext() ) {
throw new MappingException( "column attribute may not be used together with <column> subelement" );
}
if ( propertyElement.elementIterator( "formula" ).hasNext() ) {
throw new MappingException( "column attribute may not be used together with <formula> subelement" );
}
singleValueStates.add( new HbmColumnRelationalState( propertyElement, this ) );
}
// TODO: should it actually check for 0 columns???
if ( singleValueStates.isEmpty() && autoColumnCreation ) {
singleValueStates.add( new HbmColumnRelationalState( propertyElement, this ) );
}
}
public LinkedHashSet<SimpleAttributeBinding.SingleValueRelationalState> getSingleValueRelationalStates() {
return singleValueStates;
}
Set<String> getPropertyUniqueKeys() {
return propertyUniqueKeys;
}
Set<String> getPropertyIndexes() {
return propertyIndexes;
}
}

View File

@ -23,6 +23,12 @@
*/ */
package org.hibernate.metamodel.source.util; package org.hibernate.metamodel.source.util;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import org.dom4j.Attribute; import org.dom4j.Attribute;
import org.dom4j.Element; import org.dom4j.Element;
@ -74,5 +80,18 @@ public class DomHelper {
); );
} }
public static Set<String> extractUniqueAttributeValueTokens(Element element, String attributeName, String delimiters) {
String attributeValue = element.attributeValue( attributeName );
if ( attributeValue == null ) {
return Collections.emptySet();
}
else {
StringTokenizer tokenizer = new StringTokenizer( attributeValue, delimiters );
Set<String> tokens = new HashSet<String>();
while ( tokenizer.hasMoreTokens() ) {
tokens.add( tokenizer.nextToken() );
}
return tokens;
}
}
} }