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

io.devbench.uibuilder.spring.data.jpa.SpringJpaDataSourceProvider Maven / Gradle / Ivy

The newest version!
/*
 *
 * Copyright © 2018 Webvalto Ltd.
 *
 * 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 io.devbench.uibuilder.spring.data.jpa;

import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import io.devbench.uibuilder.components.util.datasource.DataSourceBindingContext;
import io.devbench.uibuilder.data.api.annotations.TargetDataSource;
import io.devbench.uibuilder.data.api.exceptions.DataSourceNotFoundException;
import io.devbench.uibuilder.spring.data.IdHandler;
import io.devbench.uibuilder.spring.data.SpringCommonDataSourceProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.repository.JpaContext;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;

import javax.persistence.EntityManager;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Slf4j
@Component
public class SpringJpaDataSourceProvider extends SpringCommonDataSourceProvider, JpaRepository> implements IdHandler {

    private final JpaContext jpaContext;

    public Set> getInterestedAnnotationTypes() {
        return Collections.singleton(TargetDataSource.class);
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void lateInit() {
        dataSourceRepositories = Collections.unmodifiableMap(
            getAnnotatedClasses().getOrDefault(TargetDataSource.class, Collections.emptySet()).stream()
                .filter(JpaRepository.class::isAssignableFrom)
                .>>>map(repoClass ->
                    Pair.of(repoClass.getAnnotation(TargetDataSource.class), (Class>) repoClass))
                .collect(Collectors.toMap(pair -> pair.getKey().name(), Function.identity()))
        );
    }

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    public SpringJpaDataSourceProvider(ApplicationContext applicationContext, JpaContext jpaContext) {
        super(applicationContext);
        this.jpaContext = jpaContext;
    }

    private Optional> tryToFindQueryByMethodNameInRepository(JpaRepository repository, String methodName) {
        //TODO add an abstraction to the default query by using an annotation to name the method, to hide method names from frontend
        try {
            Object methodResult = repository.getClass().getDeclaredMethod(methodName).invoke(repository);
            if (methodResult instanceof JPAQuery) {
                JPAQuery query = (JPAQuery) methodResult;
                return Optional.of(query);
            } else {
                log.error("Query type not supported:" + methodResult.getClass());
            }
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error(e.getMessage(), e); //TODO implement better error handling
        }
        return Optional.empty();
    }

    @Override
    @SuppressWarnings("unchecked")
    public SpringJpaDataSource createNewDataSource(@NotNull String dataSourceId, @Nullable String optionalDefaultQueryName) {
        return findDataSourceNameById(dataSourceId).map(repo -> {
            final DataSourceBindingContext bindings = (DataSourceBindingContext)
                registeredBindingContexts.get(createBindingsKey(dataSourceId, optionalDefaultQueryName));
            final Class entityType = (Class) tryToFindEntityClassByRepositoryClass(repo.getValue())
                .orElseThrow(IllegalStateException::new);
            final PathBuilder queryPath = new PathBuilder<>(entityType, entityType.getSimpleName());
            final EntityManager entityManager = jpaContext.getEntityManagerByManagedType(entityType);
            final Supplier> query = buildJpaQuerySupplier(optionalDefaultQueryName, repo, entityManager, queryPath);
            final Supplier> base = buildJpaQuerySupplier(null, repo, entityManager, queryPath);
            final List keyPaths = getKeyPaths(repo.getKey(), entityType);
            return new SpringJpaDataSource<>(bindings, queryPath, keyPaths, entityType, query, base);
        }).orElseThrow(() -> new DataSourceNotFoundException("Couldn't find data source with  id:" + dataSourceId
            + " name: " + idToDataSourceName.get(dataSourceId)));

    }

    private Supplier> buildJpaQuerySupplier(@Nullable String optionalDefaultQueryName,
                                                        Pair>> targetDSRepo,
                                                        EntityManager entityManager, PathBuilder queryPath) {
        final JpaRepository repository = applicationContext.getBean(targetDSRepo.getValue());
        return () -> Optional
            .ofNullable(optionalDefaultQueryName)
            .flatMap(defaultQuery -> this.tryToFindQueryByMethodNameInRepository(repository, defaultQuery)
                .>map(query -> query.clone(entityManager)))
            .orElse(new JPAQuery<>(entityManager).from(queryPath));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy