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

org.specrunner.sql.database.impl.IdManagerDefault Maven / Gradle / Ivy

There is a newer version: 1.5.17
Show newest version
/*
    SpecRunner - Acceptance Test Driven Development Tool
    Copyright (C) 2011-2016  Thiago Santos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see 
 */
package org.specrunner.sql.database.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.specrunner.comparators.IComparator;
import org.specrunner.comparators.core.ComparatorDate;
import org.specrunner.converters.ConverterException;
import org.specrunner.sql.database.DatabaseException;
import org.specrunner.sql.database.IIdManager;
import org.specrunner.sql.database.IStatementFactory;
import org.specrunner.sql.database.SqlWrapper;
import org.specrunner.sql.meta.Column;
import org.specrunner.sql.meta.IRegister;
import org.specrunner.sql.meta.Schema;
import org.specrunner.sql.meta.Table;
import org.specrunner.sql.meta.Value;
import org.specrunner.util.UtilLog;

/**
 * Manage tables and columns key fields.
 * 
 * @author Thiago Santos.
 * 
 */
public class IdManagerDefault implements IIdManager {

    /**
     * Mapping from values to IDs.
     */
    protected Map valuesToIds = new HashMap();
    /**
     * Local table name.
     */
    protected String table;
    /**
     * Local value.
     */
    protected String value;

    @Override
    public void reset() {
        valuesToIds.clear();
    }

    @Override
    public void clear() {
        table = null;
        value = null;
    }

    @Override
    public void append(String table, String value) {
        if (this.table == null) {
            this.table = table;
            this.value = value;
        } else {
            this.value += SEPARATOR + value;
        }
    }

    @Override
    public boolean hasKeys() {
        return table != null;
    }

    @Override
    public void readKeys(SqlWrapper wrapper, Table table, IRegister register, PreparedStatement pstmt) throws SQLException {
        switch (wrapper.getType()) {
        case INSERT:
            ResultSet rs = null;
            try {
                rs = pstmt.getGeneratedKeys();
                ResultSetMetaData metaData = rs.getMetaData();
                while (rs.next()) {
                    for (int j = 1; j < metaData.getColumnCount() + 1; j++) {
                        bind(rs.getObject(j));
                    }
                }
            } finally {
                if (rs != null) {
                    rs.close();
                }
            }
            break;
        case UPDATE:
            for (Value value : register) {
                if (value.getColumn().isKey()) {
                    bind(value.getValue());
                }
            }
            break;
        case DELETE:
            break;
        }
    }

    /**
     * Bind value to current context information.
     * 
     * @param obj
     *            An object.
     */
    protected void bind(Object obj) {
        bind(makeKey(table, value), obj);
    }

    /**
     * Bind data to specific mappings.
     * 
     * @param value
     *            Value.
     * @param id
     *            Id value.
     */
    protected void bind(String value, Object id) {
        valuesToIds.put(value, id);
        if (UtilLog.LOG.isDebugEnabled()) {
            UtilLog.LOG.debug("Added value -> id: " + value + " -> " + id);
        }
    }

    @Override
    public Object lookup(String table, String value) {
        String key = makeKey(table, value);
        Object obj = valuesToIds.get(key);
        if (UtilLog.LOG.isDebugEnabled()) {
            UtilLog.LOG.debug("'" + key + "' recovered as " + obj);
        }
        return obj;
    }

    /**
     * Create data key.
     * 
     * @param table
     *            Table name.
     * @param value
     *            Value.
     * @return A key.
     */
    protected String makeKey(String table, Object value) {
        return table + "." + value;
    }

    @Override
    public Object find(String tableOrAlias, String value, Column column, Connection connection, IStatementFactory statementFactory) throws DatabaseException, SQLException {
        String key = makeKey(tableOrAlias, value);
        Object result = lookup(tableOrAlias, value);
        if (result == null) {
            Schema schema = column.getParent().getParent();
            Table table = schema.getAlias(tableOrAlias);
            if (table == null) {
                throw new DatabaseException("Virtual column '" + tableOrAlias + "' not found in schema " + schema.getName() + ". It must be a name in domain set of: " + schema.getAliasToTables());
            }
            if (UtilLog.LOG.isDebugEnabled()) {
                UtilLog.LOG.debug("Recover virtual key for (" + key + ") at " + schema.getName() + "." + table.getName());
            }
            StringTokenizer st = new StringTokenizer(String.valueOf(value), SEPARATOR);
            List references = table.getReferences();
            if (st.countTokens() != references.size()) {
                throw new DatabaseException("Number of reference columns (" + references.size() + ") is different from value tokens (" + st.countTokens() + ").");
            }
            PreparedStatement pstmt = statementFactory.getOutput(connection, createSelect(table), table);
            int i = 1;
            while (st.hasMoreTokens()) {
                Column reference = references.get(i - 1);
                String token = st.nextToken();
                if (UtilLog.LOG.isDebugEnabled()) {
                    UtilLog.LOG.debug("Convert(" + reference.getTableOrAlias() + "." + token + ")");
                }
                Object tmp = null;
                if (reference.isVirtual()) {
                    tmp = find(reference.getTableOrAlias(), token, reference, connection, statementFactory);
                    if (UtilLog.LOG.isDebugEnabled()) {
                        UtilLog.LOG.debug("Virtual part(" + token + ") found:" + tmp + " ." + (tmp != null ? tmp.getClass() : "null"));
                    }
                } else {
                    try {
                        tmp = reference.getConverter().convert(token, reference.getArguments().toArray());
                        if (UtilLog.LOG.isDebugEnabled()) {
                            UtilLog.LOG.debug("Converted to:" + tmp + " ." + (tmp != null ? tmp.getClass() : "null"));
                        }
                    } catch (ConverterException e) {
                        throw new DatabaseException(e);
                    }
                }
                if (reference.isDate()) {
                    IComparator comp = reference.getComparator();
                    if (!(comp instanceof ComparatorDate)) {
                        throw new DatabaseException("Date columns must have comparators of type 'date'. Current type:" + comp.getClass());
                    }
                    ComparatorDate comparator = (ComparatorDate) comp;
                    comparator.initialize();
                    Date dateBefore = new Date(((Date) tmp).getTime() - comparator.getTolerance());
                    Date dateAfter = new Date(((Date) tmp).getTime() + comparator.getTolerance());
                    if (UtilLog.LOG.isDebugEnabled()) {
                        UtilLog.LOG.debug("Date range in virtual lookup [" + dateBefore + " to " + dateAfter + "]");
                    }
                    pstmt.setObject(i++, dateBefore);
                    pstmt.setObject(i++, dateAfter);
                } else {
                    if (UtilLog.LOG.isDebugEnabled()) {
                        UtilLog.LOG.debug("findValue.SET(" + i + "," + reference.getTableOrAlias() + "," + reference.getName() + ") = " + tmp);
                    }
                    pstmt.setObject(i++, tmp);
                }
            }
            ResultSet rs = null;
            try {
                if (UtilLog.LOG.isDebugEnabled()) {
                    UtilLog.LOG.debug("Query(" + key + "): " + pstmt);
                }
                rs = pstmt.executeQuery();
                while (rs.next()) {
                    for (Column c : table.getKeys()) {
                        result = rs.getObject(c.getName());
                        bind(key, result);
                    }
                    if (UtilLog.LOG.isDebugEnabled()) {
                        for (Column c : references) {
                            UtilLog.LOG.debug("Value for " + c.getName() + ": " + rs.getObject(c.getName()));
                        }
                    }
                }
            } finally {
                if (rs != null) {
                    rs.close();
                }
            }
        }
        if (UtilLog.LOG.isDebugEnabled()) {
            UtilLog.LOG.debug("Virtual key (" + key + ") replaced by '" + result + "'");
        }
        return result;
    }

    /**
     * Create select SQL.
     * 
     * @param table
     *            A table.
     * @return A select SQL.
     */
    protected String createSelect(Table table) {
        StringBuilder sb = new StringBuilder();
        sb.append("select ");
        List keys = table.getKeys();
        int i = 0;
        for (Column c : keys) {
            sb.append((i++ == 0 ? "" : ",") + c.getName());
        }
        List references = table.getReferences();
        if (UtilLog.LOG.isDebugEnabled()) {
            for (Column c : references) {
                sb.append((i++ == 0 ? "" : ",") + c.getName());
            }
        }
        sb.append(" from ");
        sb.append(table.getParent().getName() + "." + table.getName());
        sb.append(" where ");
        i = 0;
        for (Column c : references) {
            sb.append((i++ == 0 ? "" : " AND ") + c.getName() + (c.isDate() ? " between ? and ?" : " = ?"));
        }
        return sb.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy