/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.type.impl;
import java.util.Arrays;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.ogm.model.spi.Tuple;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.ogm.type.spi.TypeTranslator;
import org.hibernate.ogm.util.impl.ArrayHelper;
import org.hibernate.type.Type;
/**
* @author Emmanuel Bernard
*/
public class ComponentType extends GridTypeDelegatingToCoreType implements GridType {
private final org.hibernate.type.ComponentType componentType;
private final int propertySpan;
private final GridType[] propertyTypes;
public ComponentType(org.hibernate.type.ComponentType componentType, TypeTranslator typeTranslator) {
super( componentType );
this.componentType = componentType;
this.propertySpan = componentType.getPropertyNames().length;
final Type[] coreSubtypes = componentType.getSubtypes();
this.propertyTypes = new GridType[propertySpan];
for ( int i = 0 ; i < propertySpan ; i++ ) {
this.propertyTypes[i] = typeTranslator.getType( coreSubtypes[i] );
}
}
@Override
public Object nullSafeGet(Tuple rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException {
return resolve( hydrate( rs, names, session, owner ), session, owner ) ;
}
@Override
public Object nullSafeGet(Tuple rs, String name, SessionImplementor session, Object owner)
throws HibernateException {
return nullSafeGet( rs, new String[] {name}, session, owner );
}
@Override
public void nullSafeSet(Tuple resultset, Object value, String[] names, boolean[] settable, SessionImplementor session)
throws HibernateException {
Object[] subvalues = nullSafeGetValues( value, componentType.getEntityMode() );
//TODO in the original componentType begin and loc are different (namely begin only counts settable slots
//I don't think that's relevant for us
int columnCurrentIndex = 0;
for ( int i = 0; i < propertySpan; i++ ) {
int columnSpanOnProperty = propertyTypes[i].getColumnSpan( session.getFactory() );
if ( columnSpanOnProperty == 0 ) {
//no-op
}
else if ( columnSpanOnProperty == 1 ) {
if ( settable[columnCurrentIndex] ) {
propertyTypes[i].nullSafeSet( resultset, subvalues[i], new String[] { names[columnCurrentIndex] }, session );
}
}
else {
final boolean[] subsettable = new boolean[columnSpanOnProperty];
System.arraycopy( settable, columnCurrentIndex, subsettable, 0, columnSpanOnProperty );
final String[] subnames = new String[columnSpanOnProperty];
System.arraycopy( names, columnCurrentIndex, subnames, 0, columnSpanOnProperty );
propertyTypes[i].nullSafeSet( resultset, subvalues[i], subnames, subsettable, session );
}
columnCurrentIndex += columnSpanOnProperty;
}
}
@Override
public void nullSafeSet(Tuple resultset, Object value, String[] names, SessionImplementor session)
throws HibernateException {
final boolean[] trueSettable = new boolean[names.length];
Arrays.fill( trueSettable, true );
nullSafeSet( resultset, value, names, trueSettable, session );
}
@Override
public Object hydrate(Tuple rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException {
int begin = 0;
boolean notNull = false;
Object[] values = new Object[propertySpan];
for ( int i = 0; i < propertySpan; i++ ) {
int length = propertyTypes[i].getColumnSpan( session.getFactory() );
String[] range = ArrayHelper.slice( names, begin, length ); //cache this
Object val = propertyTypes[i].hydrate( rs, range, session, owner );
if ( val == null ) {
if ( componentType.isKey() ) {
return null; //different nullability rules for pk/fk
}
}
else {
notNull = true;
}
values[i] = val;
begin += length;
}
return notNull ? values : null;
}
@Override
public Object convertToBackendType(Object value, SessionFactoryImplementor sessionFactory) {
Tuple tuple = new Tuple();
nullSafeSet( tuple, value, new String[] { "dummy" }, (SessionImplementor) null );
return tuple.get( "dummy" );
}
//utility methods
private Object[] nullSafeGetValues(Object value, EntityMode entityMode) throws HibernateException {
if ( value == null ) {
return new Object[propertySpan];
}
else {
return componentType.getPropertyValues( value, entityMode );
}
}
}