All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.java.ao.schema.index.IndexParser Maven / Gradle / Ivy

Go to download

This is the full Active Objects library, if you don't know which one to use, you probably want this one.

The newest version!
package net.java.ao.schema.index;

import net.java.ao.AnnotationDelegate;
import net.java.ao.Common;
import net.java.ao.DatabaseProvider;
import net.java.ao.Polymorphic;
import net.java.ao.RawEntity;
import net.java.ao.schema.FieldNameConverter;
import net.java.ao.schema.Index;
import net.java.ao.schema.IndexNameConverter;
import net.java.ao.schema.Indexed;
import net.java.ao.schema.Indexes;
import net.java.ao.schema.NameConverters;
import net.java.ao.schema.SchemaGenerator;
import net.java.ao.schema.TableNameConverter;
import net.java.ao.schema.ddl.DDLIndex;
import net.java.ao.schema.ddl.DDLIndexField;
import net.java.ao.types.TypeManager;
import net.java.ao.util.StreamUtils;

import javax.annotation.Nullable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * A component responsible for parsing given ORM entity class to extract index declarations from it.
 */
public class IndexParser {

    private final DatabaseProvider databaseProvider;
    private final TableNameConverter tableNameConverter;
    private final FieldNameConverter fieldNameConverter;
    private final IndexNameConverter indexNameConverter;
    private final TypeManager typeManager;

    private Predicate> extendsRawEntity = RawEntity.class::isAssignableFrom;
    private Predicate> isPolymorphic = clazz -> clazz.isAnnotationPresent(Polymorphic.class);
    private Predicate> isRawEntity = RawEntity.class::equals;

    public IndexParser(
            final DatabaseProvider databaseProvider,
            final NameConverters nameConverters,
            final TypeManager typeManager
    ) {
        this.databaseProvider = databaseProvider;
        this.tableNameConverter = nameConverters.getTableNameConverter();
        this.fieldNameConverter = nameConverters.getFieldNameConverter();
        this.indexNameConverter = nameConverters.getIndexNameConverter();
        this.typeManager = typeManager;
    }

    public Set parseIndexes(Class> clazz) {
        final String tableName = tableNameConverter.getName(clazz);

        final Stream methodIndexes = Arrays.stream(clazz.getMethods())
                .filter(Common::isMutatorOrAccessor)
                .filter(method -> isIndexed(method) || attributeExtendsRawEntity(method))
                .map(this::parseIndexField)
                .map(indexField -> createIndex(indexField, tableName));

        final Stream classIndexes = StreamUtils.ofNullable(clazz.getAnnotation(Indexes.class))
                .map(Indexes::value)
                .flatMap(Stream::of)
                .map(index -> parseCompositeIndex(index, tableName, clazz));

        final Stream superInterfaceIndexes = Arrays.stream(clazz.getInterfaces())
                .filter(extendsRawEntity)
                .filter(isRawEntity.negate())
                .filter(isPolymorphic.negate())
                .map(superInterface -> parseIndexes((Class>) superInterface))
                .flatMap(Set::stream);

        return Stream.of(methodIndexes, classIndexes, superInterfaceIndexes)
                .flatMap(Function.identity())
                .filter(this::hasFields)
                .filter(this::hasOnlyValidFields)
                .collect(Collectors.toSet());
    }

    private boolean isIndexed(Method method) {
        final AnnotationDelegate annotations = Common.getAnnotationDelegate(fieldNameConverter, method);
        final Indexed indexed = annotations.getAnnotation(Indexed.class);

        return indexed != null;
    }

    private boolean attributeExtendsRawEntity(Method method) {
        Class type = Common.getAttributeTypeFromMethod(method);

        return type != null && extendsRawEntity.test(type);
    }

    @Nullable
    private DDLIndexField parseIndexField(@Nullable Method method) {
        if (method == null) {
            return null;
        }

        Class type = Common.getAttributeTypeFromMethod(method);

        String attributeName = fieldNameConverter.getName(method);
        AnnotationDelegate annotations = Common.getAnnotationDelegate(fieldNameConverter, method);

        return DDLIndexField.builder()
                .fieldName(attributeName)
                .type(SchemaGenerator.getSQLTypeFromMethod(typeManager, type, method, annotations))
                .build();
    }

    private DDLIndex createIndex(DDLIndexField indexField, String tableName) {
        return createIndex(Stream.of(indexField), tableName, computeIndexName(tableName, indexField.getFieldName()), false);
    }

    private DDLIndex createIndex(Stream indexFields, String tableName, String indexName, boolean unique) {
        final DDLIndex.DDLIndexBuilder builder = DDLIndex.builder()
                .indexName(indexName)
                .table(tableName)
                .fields(indexFields.toArray(DDLIndexField[]::new));

        return unique ? builder.unique().build() : builder.build();
    }

    private DDLIndex parseCompositeIndex(Index index, String tableName, Class> clazz) {

        final Map methodsApplicableForIndexing = Stream.of(clazz.getMethods())
                .filter(Common::isMutatorOrAccessor)
                .collect(Collectors.toMap(Method::getName, Function.identity()));

        final Stream indexFields = Stream.of(index.methodNames())
                .map(methodsApplicableForIndexing::get)
                .map(this::parseIndexField);

        final String indexName = computeIndexName(tableName, index.name());

        return createIndex(indexFields, tableName, indexName, index.unique());
    }

    private String computeIndexName(String tableName, String indexName) {
        return indexNameConverter.getName(databaseProvider.shorten(tableName), databaseProvider.shorten(indexName));
    }

    private boolean hasFields(DDLIndex index) {
        return index.getFields().length > 0;
    }

    private boolean hasOnlyValidFields(DDLIndex index) {
        return Stream.of(index.getFields())
                .allMatch(Objects::nonNull);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy