/*
* 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.datastore.infinispanremote.impl.protobuf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.hibernate.AssertionFailure;
import org.hibernate.ogm.datastore.infinispanremote.impl.protostream.ProtostreamMappedField;
import org.hibernate.ogm.datastore.infinispanremote.impl.schema.ProtobufFieldConsumer;
import org.hibernate.ogm.datastore.infinispanremote.impl.schema.ProtobufTypeConsumer;
import org.hibernate.ogm.datastore.infinispanremote.impl.schema.SanitationUtils;
import org.hibernate.ogm.type.descriptor.impl.AttributeConverterGridTypeDescriptorAdaptor;
import org.hibernate.ogm.type.descriptor.impl.GridTypeDescriptor;
import org.hibernate.ogm.type.impl.AttributeConverterGridTypeAdaptor;
import org.hibernate.ogm.type.impl.BigDecimalType;
import org.hibernate.ogm.type.impl.BigIntegerType;
import org.hibernate.ogm.type.impl.BooleanType;
import org.hibernate.ogm.type.impl.ByteType;
import org.hibernate.ogm.type.impl.CalendarDateType;
import org.hibernate.ogm.type.impl.CalendarType;
import org.hibernate.ogm.type.impl.CharacterType;
import org.hibernate.ogm.type.impl.DateType;
import org.hibernate.ogm.type.impl.DoubleType;
import org.hibernate.ogm.type.impl.EntityType;
import org.hibernate.ogm.type.impl.EnumType;
import org.hibernate.ogm.type.impl.FloatType;
import org.hibernate.ogm.type.impl.IntegerType;
import org.hibernate.ogm.type.impl.LongType;
import org.hibernate.ogm.type.impl.NumericBooleanType;
import org.hibernate.ogm.type.impl.PrimitiveByteArrayType;
import org.hibernate.ogm.type.impl.SerializableAsByteArrayType;
import org.hibernate.ogm.type.impl.ShortType;
import org.hibernate.ogm.type.impl.StringType;
import org.hibernate.ogm.type.impl.TimeType;
import org.hibernate.ogm.type.impl.TimestampType;
import org.hibernate.ogm.type.impl.TrueFalseType;
import org.hibernate.ogm.type.impl.UUIDType;
import org.hibernate.ogm.type.impl.UrlType;
import org.hibernate.ogm.type.impl.YesNoType;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.type.Type;
public class ProtofieldAccessorSet {
//Counter to assign unique Tag ids in protobuf. First to be assigned is '1'.
private int uniqueTagAssigningCounter = 0;
private List<UnsafeProtofield> orderedFields = new ArrayList<>();
private Map<String,UnsafeProtofield> fieldsPerORMName = new HashMap<>();
private Map<String,UnsafeProtofield> fieldsPerProtobufName = new HashMap<>();
public void addMapping(String ormMappedName, GridType gridType, Type ormType, boolean nullable) {
final String name = SanitationUtils.convertNameSafely( ormMappedName );
uniqueTagAssigningCounter++;
gridType = extractGridTypeOnRecursiveTypes( gridType, ormType );
if ( gridType instanceof StringType ) {
add( new StringProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof IntegerType ) {
add( new IntegerProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof LongType ) {
add( new LongProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof DoubleType ) {
add( new DoubleProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof UUIDType ) {
add( new StringProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof CalendarDateType ) {
add( new CalendarDateProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof CalendarType ) {
//TODO same as CalendarDateType ?
add( new CalendarDateProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof DateType ) {
add( new DateProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof TimestampType ) {
//TODO same as DateType?
add( new DateProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof TimeType ) {
//TODO same as DateType?
add( new DateProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof PrimitiveByteArrayType ) {
add( new PrimitiveBytearrayProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof SerializableAsByteArrayType ) {
//TODO same as PrimitiveByteArrayType?
add( new PrimitiveBytearrayProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof CharacterType ) {
add( new CharacterProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof ByteType ) {
add( new ByteProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof BooleanType ) {
add( new BooleanProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof TrueFalseType ) {
add( new CharacterProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof YesNoType ) {
add( new CharacterProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof NumericBooleanType ) {
add( new IntegerProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof BigDecimalType ) {
add( new StringProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof UrlType ) {
add( new StringProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof ShortType ) {
add( new ShortProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof BigIntegerType ) {
add( new StringProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof FloatType ) {
add( new FloatProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else if ( gridType instanceof EnumType ) {
EnumType etype = (EnumType) gridType;
if ( etype.isOrdinal() ) {
add( new IntegerProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
}
else {
add( new StringProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, ormMappedName ) );
/* FIXME Alternative: Support of native Enum mapping in protobuf:
if ( ormType instanceof CustomType ) {
CustomType customOrmType = (CustomType) ormType;
UserType userType = customOrmType.getUserType();
org.hibernate.type.EnumType enumtype = (org.hibernate.type.EnumType) userType;
Class returnedClass = enumtype.returnedClass();
add( new EnumProtofieldAccessor( uniqueTagAssigningCounter, name, nullable, returnedClass, ormMappedName ) );
}
else {
throw new AssertionFailure( "Type not implemented yet! " );
} */
}
}
else if ( gridType instanceof EntityType ) {
throw new AssertionFailure( "EntityType not implemented yet! " + gridType.getName() );
}
else {
throw new AssertionFailure( "Type not implemented yet! " + gridType.getName() );
}
}
private GridType extractGridTypeOnRecursiveTypes(GridType gridType, Type ormType) {
if ( gridType instanceof AttributeConverterGridTypeAdaptor ) {
AttributeConverterGridTypeAdaptor acgta = (AttributeConverterGridTypeAdaptor) gridType;
GridTypeDescriptor descriptor = acgta.getGridTypeDescriptor();
if ( descriptor instanceof AttributeConverterGridTypeDescriptorAdaptor ) {
AttributeConverterGridTypeDescriptorAdaptor internalType = (AttributeConverterGridTypeDescriptorAdaptor) descriptor;
return internalType.unwrapTargetGridType();
}
}
return gridType;
}
public void forEachProtobufFieldExporter(ProtobufFieldConsumer action) {
orderedFields.forEach( action );
}
public void forEach(ProtobufTypeConsumer action) {
orderedFields.forEach( action );
}
public void forEachProtostreamMappedField(Consumer<ProtostreamMappedField> action) {
orderedFields.forEach( action );
}
private void add(ProtofieldAccessor unsafeWriter) {
UnsafeProtofield wrapped = new UnsafeProtofield( unsafeWriter );
UnsafeProtofield previous = fieldsPerORMName.put( unsafeWriter.getColumnName(), wrapped );
if ( previous != null ) {
throw new AssertionFailure( "Duplicate or ambiguous property: '" + unsafeWriter.getColumnName() );
}
previous = fieldsPerProtobufName.put( wrapped.getProtobufName(), wrapped );
if ( previous != null ) {
throw new AssertionFailure( "Duplicate or ambiguous property after convertion to Protobuf requirements: '"
+ wrapped.getProtobufName() + "'" );
}
orderedFields.add( wrapped );
}
public int size() {
return orderedFields.size();
}
public UnsafeProtofield getDecoderByListOrder(int i) {
return orderedFields.get( i );
}
public UnsafeProtofield getDecoderByColumnName(String columnName) {
return fieldsPerORMName.get( columnName );
}
public boolean columnNameExists(String columnName) {
return fieldsPerORMName.containsKey( columnName );
}
public String[] getColumnNames() {
return fieldsPerORMName.keySet().toArray( new String[0] );
}
}