view flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/meta/CompiledStatement.java @ 972:0c8aca463bd4

Added caching support for the static part of the datacage. flys-artifacts/trunk@2398 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Fri, 22 Jul 2011 16:55:36 +0000
parents 2c8fc60125b9
children c30ada285d45
line wrap: on
line source
package de.intevation.flys.artifacts.services.meta;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.ArrayList;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import de.intevation.flys.artifacts.cache.CacheFactory;

public class CompiledStatement
{
    public static final String DATACAGE_DB_CACHE =
        "datacage.db";

    public static final Pattern VAR =
        Pattern.compile("\\$\\{([a-zA-Z0-9_-]+)\\}");

    protected String original;
    protected String statement;

    protected Map<String, List<Integer>> positions;

    protected PreparedStatement preparedStatement;

    protected int numVars;

    public CompiledStatement() {
    }

    public CompiledStatement(String original) {
        this.original = original;
        // TreeMap to ensure order
        positions = new TreeMap<String, List<Integer>>();
        compile();
    }

    protected void compile() {

        StringBuffer sb = new StringBuffer();

        Matcher m = VAR.matcher(original);

        int index = 0;

        while (m.find()) {
            String key = m.group(1);
            List<Integer> indices = positions.get(key);
            if (indices == null) {
                indices = new ArrayList<Integer>();
                positions.put(key, indices);
            }
            indices.add(index);
            m.appendReplacement(sb, "?");
            ++index;
        }

        m.appendTail(sb);

        numVars = index;

        statement = sb.toString();
    }

    public String getStatement() {
        return statement;
    }

    protected ResultData executeCached(
        Cache       cache,
        Connection  connection,
        StackFrames frames
    )
    throws SQLException
    {
        Object [] values = new Object[numVars];

        StringBuilder sb = new StringBuilder(original);

        for (Map.Entry<String, List<Integer>> entry: positions.entrySet()) {
            String key   = entry.getKey();
            Object value = frames.get(key);
            sb.append(';').append(key).append(':').append(value);
            for (Integer index: entry.getValue()) {
                values[index] = value;
            }
        }

        // XXX: Maybe too many collisions?
        // String key = original + Arrays.hashCode(values);
        String key = sb.toString();

        Element element = cache.get(key);

        if (element != null) {
            return (ResultData)element.getValue();
        }

        if (preparedStatement == null) {
            preparedStatement = connection.prepareStatement(statement);
        }

        for (int i = 0; i < values.length; ++i) {
            preparedStatement.setObject(i+1, values[i]);
        }

        ResultData data;

        ResultSet result = preparedStatement.executeQuery();
        try {
            data = new ResultData(preparedStatement.getMetaData())
                .addAll(result);
        }
        finally {
            result.close();
        }

        element = new Element(key, data);
        cache.put(element);

        return data;
    }

    protected ResultData executeUncached(
        Connection  connection,
        StackFrames frames
    ) 
    throws SQLException
    {
        if (preparedStatement == null) {
            preparedStatement = connection.prepareStatement(statement);
        }

        for (Map.Entry<String, List<Integer>> entry: positions.entrySet()) {
            Object value = frames.get(entry.getKey());
            for (Integer index: entry.getValue()) {
                preparedStatement.setObject(index+1, value);
            }
        }

        ResultSet result = preparedStatement.executeQuery();
        try {
            return new ResultData(preparedStatement.getMetaData())
                .addAll(result);
        }
        finally {
            result.close();
        }
    }

    public ResultData execute(Connection connection, StackFrames frames)
    throws SQLException
    {
        Cache cache = CacheFactory.getCache(DATACAGE_DB_CACHE);

        return cache != null
            ? executeCached(cache, connection, frames)
            : executeUncached(connection, frames);
    }

    public void close() {
        if (preparedStatement != null) {
            try {
                preparedStatement.close();
            }
            catch (SQLException sqle) {
            }
            preparedStatement = null;
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org