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

net.n2oapp.framework.engine.sql.SqlDataProviderEngine Maven / Gradle / Ivy

There is a newer version: 7.4.18
Show newest version
package net.n2oapp.framework.engine.sql;

import net.n2oapp.engine.factory.EngineFactory;
import net.n2oapp.engine.factory.TypicalEngine;
import net.n2oapp.engine.factory.integration.spring.SpringEngineFactory;
import net.n2oapp.framework.api.data.MapInvocationEngine;
import net.n2oapp.framework.api.exception.N2oException;
import net.n2oapp.framework.api.metadata.dataprovider.N2oSqlDataProvider;
import net.n2oapp.framework.engine.data.QueryUtil;
import net.n2oapp.framework.engine.util.NamedParameterUtils;
import net.n2oapp.framework.engine.util.QueryBlank;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

import static net.n2oapp.framework.api.metadata.local.util.CompileUtil.castDefault;
import static net.n2oapp.framework.engine.data.QueryUtil.*;

/**
 * Выполнение sql действия. На вход приходит map аргументов, на выход отправляется
 * List если mapByIndex = true, иначе List>.
 */
public class SqlDataProviderEngine implements MapInvocationEngine,
        ApplicationContextAware, ResourceLoaderAware {
    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    private EngineFactory rowMapperFactory;
    private ResourceLoader resourceLoader;

    @Override
    public Object invoke(N2oSqlDataProvider invocation, Map data) {
        Map args = new HashMap<>(data);
        String query = loadQuery(invocation);
        query = replaceListPlaceholder(query, ":select", args.remove("select"), "*", QueryUtil::reduceComma);
        query = replaceListPlaceholder(query, ":join", args.remove("join"), "", QueryUtil::reduceSpace);
        query = replaceListPlaceholder(query, ":filters", args.remove("filters"), "1=1", QueryUtil::reduceAnd);
        query = replaceListPlaceholder(query, ":sorting", args.remove("sorting"), "1",
                s -> replaceSortDirection(s, data), QueryUtil::reduceComma);
        query = replacePlaceholder(query, ":limit", args.remove("limit"), "10");
        query = replacePlaceholder(query, ":offset", args.remove("offset"), "0");
        query = replacePlaceholder(query, ":count", args.remove("count"), "-1");
        return executeQuery(args, query, rowMapperFactory.produce(castDefault(invocation.getRowMapper(), "map")));
    }

    private String replaceSortDirection(String sortCause, Map data) {
        return replacePlaceholders(sortCause, t -> t.startsWith(":"), p -> data.get(p.substring(1)));
    }

    private String loadQuery(N2oSqlDataProvider invocation) {
        if (invocation.getFilePath() != null) {
            if (resourceLoader == null)
                throw new IllegalStateException("Resource Loader should not be null");
            try (InputStream is = resourceLoader.getResource(invocation.getFilePath()).getInputStream()) {
                return IOUtils.toString(is, "UTF-8");
            } catch (IOException e) {
                throw new N2oException(e);
            }
        }
        return invocation.getQuery();
    }

    @Override
    public Class getType() {
        return N2oSqlDataProvider.class;
    }

    private Object executeQuery(Map args, String query, RowMapper mapper) {
        QueryBlank queryBlank = NamedParameterUtils.prepareQuery(query, args);
        query = queryBlank.getQuery();
        args = queryBlank.getArgs();
        if (isSelect(query)) {
            return namedParameterJdbcTemplate.query(query, args, mapper);
        } else {
            MapSqlParameterSource paramSource = new MapSqlParameterSource(args);
            GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
            namedParameterJdbcTemplate.update(query, paramSource, generatedKeyHolder);
            return getResult(generatedKeyHolder);
        }
    }

    private Object getResult(GeneratedKeyHolder generatedKeyHolder) {
        List> keyList = generatedKeyHolder.getKeyList();
        if (keyList != null) {
            if (keyList.size() > 1)  {
                List rows = new ArrayList<>(keyList.size());
                for (Map row : keyList) {
                    rows.add(row.values().toArray());
                }
                return rows.toArray();
            } else if (keyList.size() == 1) {
                return keyList.get(0).values().toArray();
            }
        }
        return null;
    }

    private boolean isSelect(String query) {
        return query.trim().toLowerCase().startsWith("select");
    }

    public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
        this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.rowMapperFactory = new SpringEngineFactory(applicationContext) {
            @Override
            public Class getEngineClass() {
                return RowMapper.class;
            }

            @Override
            public String getType(RowMapper engine) {
                if (engine instanceof TypicalEngine)
                    return ((TypicalEngine)engine).getType();
                else
                    return engine.getClass().getSimpleName();
            }
        };
    }

    public void setRowMapperFactory(EngineFactory rowMapperFactory) {
        this.rowMapperFactory = rowMapperFactory;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}