/** * * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); You may not * use this file except in compliance with the License. You may obtain a copy of * the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.speedment.generator.standard.internal.util; import com.speedment.common.codegen.constant.SimpleParameterizedType; import com.speedment.common.codegen.constant.SimpleType; import com.speedment.common.codegen.model.File; import com.speedment.common.codegen.model.Import; import com.speedment.common.codegen.model.Method; import com.speedment.common.injector.Injector; import com.speedment.generator.translator.TranslatorSupport; import com.speedment.generator.translator.component.TypeMapperComponent; import com.speedment.generator.translator.namer.JavaLanguageNamer; import com.speedment.generator.translator.util.Pluralis; import com.speedment.runtime.config.Column; import com.speedment.runtime.config.ForeignKey; import com.speedment.runtime.config.ForeignKeyColumn; import com.speedment.runtime.config.Table; import com.speedment.runtime.config.trait.HasEnabled; import com.speedment.runtime.config.util.DocumentDbUtil; import com.speedment.runtime.core.exception.SpeedmentException; import com.speedment.runtime.field.*; import com.speedment.runtime.field.internal.*; import java.lang.reflect.Type; import java.util.Optional; import static com.speedment.common.codegen.internal.util.StaticClassUtil.instanceNotAllowed; import static com.speedment.common.invariant.NullUtil.requireNonNulls; import static java.util.Objects.requireNonNull; /** * * @author Per Minborg */ public final class EntityTranslatorSupport { public static final String CONSUMER_NAME = "consumer"; public static final String FIND = "find"; private enum FieldType { STRING, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, CHAR, BOOLEAN, COMPARABLE, REFERENCE } public static class ReferenceFieldType { public final Type type, implType; public ReferenceFieldType(Type type, Type implType) { this.type = requireNonNull(type); this.implType = requireNonNull(implType); } } public static ReferenceFieldType getReferenceFieldType( File file, Table table, Column column, Type entityType, Injector injector) { requireNonNulls(file, table, column, entityType, injector); final Type mapping = injector.getOrThrow(TypeMapperComponent.class).get(column).getJavaType(column); final Type databaseType = SimpleType.create(column.getDatabaseType()); final FieldType fieldType; if (mapping.equals(String.class)) { fieldType = FieldType.STRING; } else if (mapping.equals(byte.class)) { fieldType = FieldType.BYTE; } else if (mapping.equals(short.class)) { fieldType = FieldType.SHORT; } else if (mapping.equals(int.class)) { fieldType = FieldType.INT; } else if (mapping.equals(long.class)) { fieldType = FieldType.LONG; } else if (mapping.equals(float.class)) { fieldType = FieldType.FLOAT; } else if (mapping.equals(double.class)) { fieldType = FieldType.DOUBLE; } else if (mapping.equals(char.class)) { fieldType = FieldType.CHAR; } else if (mapping.equals(boolean.class)) { fieldType = FieldType.BOOLEAN; } else { if (mapping instanceof Class<?>) { final Class<?> casted = (Class<?>) mapping; if (Comparable.class.isAssignableFrom(casted)) { fieldType = FieldType.COMPARABLE; } else { fieldType = FieldType.REFERENCE; } } else { fieldType = FieldType.REFERENCE; } } return EntityTranslatorSupport.getForeignKey(table, column) // If this is a foreign key. .map(fkc -> { final Type type, implType; final Type fkType = new TranslatorSupport<>(injector, fkc.findForeignTable().orElseThrow( () -> new SpeedmentException( "Could not find referenced foreign table '" + fkc.getForeignTableName() + "'." ))).entityType(); file.add(Import.of(fkType)); switch (fieldType) { case STRING : type = SimpleParameterizedType.create( StringForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( StringForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case BYTE : type = SimpleParameterizedType.create( ByteForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( ByteForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case SHORT : type = SimpleParameterizedType.create( ShortForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( ShortForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case INT : type = SimpleParameterizedType.create( IntForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( IntForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case LONG : type = SimpleParameterizedType.create( LongForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( LongForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case FLOAT : type = SimpleParameterizedType.create( FloatForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( FloatForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case DOUBLE : type = SimpleParameterizedType.create( DoubleForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( DoubleForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case CHAR : type = SimpleParameterizedType.create( CharForeignKeyField.class, entityType, databaseType, fkType ); implType = SimpleParameterizedType.create( CharForeignKeyFieldImpl.class, entityType, databaseType, fkType ); break; case BOOLEAN : throw new UnsupportedOperationException( "Boolean foreign key fields are not supported." ); case COMPARABLE : type = SimpleParameterizedType.create( ComparableForeignKeyField.class, entityType, databaseType, mapping, fkType ); implType = SimpleParameterizedType.create( ComparableForeignKeyFieldImpl.class, entityType, databaseType, mapping, fkType ); break; case REFERENCE : throw new UnsupportedOperationException( "Foreign key types that are not either primitive " + "or comparable are not supported." ); default : throw new UnsupportedOperationException( "Unknown enum constant '" + fieldType + "'." ); } return new ReferenceFieldType(type, implType); // If it is not a foreign key }).orElseGet(() -> { final Type type, implType; switch (fieldType) { case STRING : type = SimpleParameterizedType.create( StringField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( StringFieldImpl.class, entityType, databaseType ); break; case BYTE : type = SimpleParameterizedType.create( ByteField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( ByteFieldImpl.class, entityType, databaseType ); break; case SHORT : type = SimpleParameterizedType.create( ShortField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( ShortFieldImpl.class, entityType, databaseType ); break; case INT : type = SimpleParameterizedType.create( IntField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( IntFieldImpl.class, entityType, databaseType ); break; case LONG : type = SimpleParameterizedType.create( LongField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( LongFieldImpl.class, entityType, databaseType ); break; case FLOAT : type = SimpleParameterizedType.create( FloatField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( FloatFieldImpl.class, entityType, databaseType ); break; case DOUBLE : type = SimpleParameterizedType.create( DoubleField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( DoubleFieldImpl.class, entityType, databaseType ); break; case CHAR : type = SimpleParameterizedType.create( CharField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( CharFieldImpl.class, entityType, databaseType ); break; case BOOLEAN : type = SimpleParameterizedType.create( BooleanField.class, entityType, databaseType ); implType = SimpleParameterizedType.create( BooleanFieldImpl.class, entityType, databaseType ); break; case COMPARABLE : type = SimpleParameterizedType.create( ComparableField.class, entityType, databaseType, mapping ); implType = SimpleParameterizedType.create( ComparableFieldImpl.class, entityType, databaseType, mapping ); break; case REFERENCE : type = SimpleParameterizedType.create( ReferenceField.class, entityType, databaseType, mapping ); implType = SimpleParameterizedType.create( ReferenceFieldImpl.class, entityType, databaseType, mapping ); break; default : throw new UnsupportedOperationException( "Unknown enum constant '" + fieldType + "'." ); } return new ReferenceFieldType(type, implType); }); } public static String pluralis(Table table, JavaLanguageNamer javaLanguageNamer) { requireNonNull(table); return Pluralis.INSTANCE.pluralizeJavaIdentifier(javaLanguageNamer.javaTypeName(table.getJavaName()), javaLanguageNamer); } public static Optional<? extends ForeignKeyColumn> getForeignKey(Table table, Column column) { requireNonNulls(table, column); return table.foreignKeys() .filter(HasEnabled::test) .flatMap(ForeignKey::foreignKeyColumns) .filter(fkc -> DocumentDbUtil.isSame(column, fkc.findColumn().orElse(null))) .findFirst(); } public static Method dbMethod(String name, Type entityType) { requireNonNulls(name, entityType); return Method.of(name, entityType).add(SpeedmentException.class); } // public static Method dbMethodWithListener(String name, Type entityType) { // requireNonNulls(name, entityType); // return Method.of(name, entityType).add(SpeedmentException.class) // .add(Field.of( // CONSUMER_NAME, // SimpleParameterizedType.create(Consumer.class, // SimpleParameterizedType.create(MetaResult.class, entityType) // ) // )); // } public static Method persist(Type entityType) { return EntityTranslatorSupport.dbMethod("persist", requireNonNull(entityType)); } public static Method update(Type entityType) { return EntityTranslatorSupport.dbMethod("update", requireNonNull(entityType)); } public static Method remove(Type entityType) { return EntityTranslatorSupport.dbMethod("remove", requireNonNull(entityType)); } // public static Method persistWithListener(Type entityType) { // return EntityTranslatorSupport.dbMethodWithListener("persist", requireNonNull(entityType)); // } // // public static Method updateWithListener(Type entityType) { // return EntityTranslatorSupport.dbMethodWithListener("update", requireNonNull(entityType)); // } // // public static Method removeWithListener(Type entityType) { // return EntityTranslatorSupport.dbMethodWithListener("remove", requireNonNull(entityType)); // } private EntityTranslatorSupport() { instanceNotAllowed(getClass()); } }