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 core library for Active Objects. It is generic and can be embedded in any environment. As such it is generic and won't contain all connection pooling, etc.

There is a newer version: 6.1.1
Show 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()));
    }

    private DDLIndex createIndex(Stream indexFields, String tableName, String indexName) {
        return DDLIndex.builder()
                .indexName(indexName)
                .table(tableName)
                .fields(indexFields.toArray(DDLIndexField[]::new))
                .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);
    }

    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