package org.hibernate.cfg;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue;
import org.jboss.logging.Logger;
public class CopyIdentifierComponentSecondPass implements SecondPass {
private static final Logger log = Logger.getLogger( CopyIdentifierComponentSecondPass.class );
private final String referencedEntityName;
private final Component component;
private final MetadataBuildingContext buildingContext;
private final Ejb3JoinColumn[] joinColumns;
public CopyIdentifierComponentSecondPass(
Component comp,
String referencedEntityName,
Ejb3JoinColumn[] joinColumns,
MetadataBuildingContext buildingContext) {
this.component = comp;
this.referencedEntityName = referencedEntityName;
this.buildingContext = buildingContext;
this.joinColumns = joinColumns;
}
@SuppressWarnings({ "unchecked" })
public void doSecondPass(Map persistentClasses) throws MappingException {
PersistentClass referencedPersistentClass = (PersistentClass) persistentClasses.get( referencedEntityName );
if ( referencedPersistentClass == null ) {
throw new AnnotationException( "Unknown entity name: " + referencedEntityName );
}
if ( ! ( referencedPersistentClass.getIdentifier() instanceof Component ) ) {
throw new AssertionFailure(
"Unexpected identifier type on the referenced entity when mapping a @MapsId: "
+ referencedEntityName
);
}
Component referencedComponent = (Component) referencedPersistentClass.getIdentifier();
Iterator<Property> properties = referencedComponent.getPropertyIterator();
boolean isExplicitReference = true;
Map<String, Ejb3JoinColumn> columnByReferencedName = new HashMap<>(joinColumns.length);
for (Ejb3JoinColumn joinColumn : joinColumns) {
final String referencedColumnName = joinColumn.getReferencedColumn();
if ( referencedColumnName == null || BinderHelper.isEmptyAnnotationValue( referencedColumnName ) ) {
break;
}
columnByReferencedName.put( referencedColumnName.toLowerCase(Locale.ROOT), joinColumn );
}
AtomicInteger index = new AtomicInteger( 0 );
if ( columnByReferencedName.isEmpty() ) {
isExplicitReference = false;
for (Ejb3JoinColumn joinColumn : joinColumns) {
columnByReferencedName.put( "" + index.get(), joinColumn );
index.getAndIncrement();
}
index.set( 0 );
}
while ( properties.hasNext() ) {
Property referencedProperty = properties.next();
if ( referencedProperty.isComposite() ) {
Property property = createComponentProperty( referencedPersistentClass, isExplicitReference, columnByReferencedName, index, referencedProperty );
component.addProperty( property );
}
else {
Property property = createSimpleProperty( referencedPersistentClass, isExplicitReference, columnByReferencedName, index, referencedProperty );
component.addProperty( property );
}
}
}
private Property createComponentProperty(
PersistentClass referencedPersistentClass,
boolean isExplicitReference,
Map<String, Ejb3JoinColumn> columnByReferencedName,
AtomicInteger index,
Property referencedProperty ) {
Property property = new Property();
property.setName( referencedProperty.getName() );
property.setPersistentClass( component.getOwner() );
property.setPropertyAccessorName( referencedProperty.getPropertyAccessorName() );
Component value = new Component( buildingContext, component.getOwner() );
property.setValue( value );
final Component referencedValue = (Component) referencedProperty.getValue();
value.setTypeName( referencedValue.getTypeName() );
value.setTypeParameters( referencedValue.getTypeParameters() );
value.setComponentClassName( referencedValue.getComponentClassName() );
Iterator<Property> propertyIterator = referencedValue.getPropertyIterator();
while(propertyIterator.hasNext()) {
Property referencedComponentProperty = propertyIterator.next();
if ( referencedComponentProperty.isComposite() ) {
Property componentProperty = createComponentProperty( referencedValue.getOwner(), isExplicitReference, columnByReferencedName, index, referencedComponentProperty );
value.addProperty( componentProperty );
}
else {
Property componentProperty = createSimpleProperty( referencedValue.getOwner(), isExplicitReference, columnByReferencedName, index, referencedComponentProperty );
value.addProperty( componentProperty );
}
}
return property;
}
private Property createSimpleProperty(
PersistentClass referencedPersistentClass,
boolean isExplicitReference,
Map<String, Ejb3JoinColumn> columnByReferencedName,
AtomicInteger index,
Property referencedProperty ) {
Property property = new Property();
property.setName( referencedProperty.getName() );
property.setPersistentClass( component.getOwner() );
property.setPropertyAccessorName( referencedProperty.getPropertyAccessorName() );
SimpleValue value = new SimpleValue( buildingContext, component.getTable() );
property.setValue( value );
final SimpleValue referencedValue = (SimpleValue) referencedProperty.getValue();
value.setTypeName( referencedValue.getTypeName() );
value.setTypeParameters( referencedValue.getTypeParameters() );
final Iterator<Selectable> columns = referencedValue.getColumnIterator();
if ( joinColumns[0].isNameDeferred() ) {
joinColumns[0].copyReferencedStructureAndCreateDefaultJoinColumns(
referencedPersistentClass,
columns,
value);
}
else {
while ( columns.hasNext() ) {
final Selectable selectable = columns.next();
if ( ! Column.class.isInstance( selectable ) ) {
log.debug( "Encountered formula definition; skipping" );
continue;
}
final Column column = (Column) selectable;
final Ejb3JoinColumn joinColumn;
String logicalColumnName = null;
if ( isExplicitReference ) {
final String columnName = column.getName();
logicalColumnName = buildingContext.getMetadataCollector().getLogicalColumnName(
referencedPersistentClass.getTable(),
columnName
);
joinColumn = columnByReferencedName.get( logicalColumnName.toLowerCase(Locale.ROOT ) );
}
else {
joinColumn = columnByReferencedName.get( "" + index.get() );
index.getAndIncrement();
}
if ( joinColumn == null && ! joinColumns[0].isNameDeferred() ) {
throw new AnnotationException(
isExplicitReference ?
"Unable to find column reference in the @MapsId mapping: " + logicalColumnName :
"Implicit column reference in the @MapsId mapping fails, try to use explicit referenceColumnNames: " + referencedEntityName
);
}
final String columnName = joinColumn == null || joinColumn.isNameDeferred() ? "tata_" + column.getName() : joinColumn
.getName();
value.addColumn( new Column( columnName ) );
if ( joinColumn != null ) {
applyComponentColumnSizeValueToJoinColumn( column, joinColumn );
joinColumn.linkWithValue( value );
}
column.setValue( value );
}
}
return property;
}
private void applyComponentColumnSizeValueToJoinColumn(Column column, Ejb3JoinColumn joinColumn) {
Column mappingColumn = joinColumn.getMappingColumn();
mappingColumn.setLength( column.getLength() );
mappingColumn.setPrecision( column.getPrecision() );
mappingColumn.setScale( column.getScale() );
}
public boolean dependentUpon( CopyIdentifierComponentSecondPass other ) {
return this.referencedEntityName.equals( other.component.getOwner().getEntityName() );
}
}