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

org.efaps.db.query.OneRoundQuery Maven / Gradle / Ivy

/*
 * Copyright 2003 - 2012 The eFaps Team
 *
 * 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.
 *
 * Revision:        $Rev: 7483 $
 * Last Changed:    $Date: 2012-05-11 11:57:38 -0500 (Fri, 11 May 2012) $
 * Last Changed By: $Author: [email protected] $
 */

package org.efaps.db.query;

import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.efaps.admin.datamodel.Attribute;
import org.efaps.admin.datamodel.AttributeSet;
import org.efaps.admin.datamodel.SQLTable;
import org.efaps.admin.datamodel.Type;
import org.efaps.db.Context;
import org.efaps.db.Instance;
import org.efaps.db.ListQuery;
import org.efaps.db.transaction.ConnectionResource;
import org.efaps.util.EFapsException;

/**
 * @author The eFaps Team
 * @version $Id: OneRoundQuery.java 7483 2012-05-11 16:57:38Z [email protected] $
 * TODO: description
 * @deprecated will be removed with version 2.0
 */
//CHECKSTYLE:OFF
@Deprecated
public class OneRoundQuery
{

    /**
     * Stores all instances for which this query is executed.
     */
    private final List instances;

    /**
     * The main sql table.
     */
    private final SQLTable mainSQLTable;

    /**
     * The type of this query.
     */
    private final Type type;

    /**
     * Stores all select statements for this query.
     */
    private final Set selects;

    /**
     * Mapping of type to typemapping.
     */
    private final Map typeMappings = new HashMap();

    /**
     * Mappeing of sql tables.
     */
    private final Map sqlTableMappings
                                                                  = new HashMap();

    /**
     * The result of this query will be cached.
     */
    private final CachedResult cachedResult = new CachedResult();

    /**
     * Number of the column containing the type id.
     */
    private int colTypeId = 0;

    /**
     * Listquery this query is based on.
     */
    private final ListQuery listquery;

    /**
     * @param _instances list of instances for which this query is executed
     * @param _selects aset of attributes to be selected
     * @param _listquery listquery
     * TODO:  check das alle instanzen von gleicher main table sind
     * TODO:  if no column for the type exists, all types must be the same!
     */
    public OneRoundQuery(final List _instances, final Set _selects, final ListQuery _listquery)
    {

        this.instances = _instances;
        this.selects = _selects;
        this.listquery = _listquery;
        if (this.listquery.getAttributeSet() != null) {
            this.mainSQLTable = this.listquery.getAttributeSet().getMainTable();
            this.type = this.listquery.getAttributeSet();
        } else {
            this.mainSQLTable = _instances.get(0).getType().getMainTable();

            // if no column for the type exists, the type must be defined
            // directly
            if (this.mainSQLTable.getSqlColType() == null) {
                this.type = _instances.get(0).getType();
            } else {
                this.type = null;
            }

            // das muss nur gemacht werden, wenn unterschiedliche typen
            // existieren!?
            final SQLTableMapping2Attributes tmp = new SQLTableMapping2Attributes(this.mainSQLTable);
            tmp.addInstances(this.instances);
            this.sqlTableMappings.put(this.mainSQLTable, tmp);
        }
    }

    /**
     * Method to execute the Query.
     *
     * @throws EFapsException on error during execution of statement
     */
    public void execute() throws EFapsException
    {

        if (this.listquery.getAttributeSet() == null) {
            // make type mapping to instances
            for (final Instance instance : this.instances) {
                TypeMapping2Instances typeMapping = this.typeMappings.get(instance.getType());
                if (typeMapping == null) {
                    typeMapping = new TypeMapping2Instances(instance.getType());
                    this.typeMappings.put(instance.getType(), typeMapping);
                }
                typeMapping.addInstance(instance);
            }

            for (final TypeMapping2Instances typeMapping : this.typeMappings.values()) {
                typeMapping.evaluateSelects();
            }

            // evalute sql statements
            int curIndex = 2;
            for (final SQLTableMapping2Attributes sqlTableMapping : this.sqlTableMappings.values()) {
                curIndex = sqlTableMapping.evaluateSQLStatement(curIndex - 1);
            }

        } else {
            // expand
            for (final Instance instance : this.instances) {
                TypeMapping2Instances typeMapping = this.typeMappings.get(this.type);
                if (typeMapping == null) {
                    typeMapping = new TypeMapping2Instances(this.type);
                    this.typeMappings.put(this.type, typeMapping);
                }
                typeMapping.addInstance(instance);
            }
            for (final TypeMapping2Instances typeMapping : this.typeMappings.values()) {
                typeMapping.evaluateSelects();
            }
            // evalute sql statements
            int curIndex = 2;
            for (final SQLTableMapping2Attributes sqlTableMapping : this.sqlTableMappings.values()) {
                sqlTableMapping.setExpand(true);
                sqlTableMapping.setAttributeSet((this.listquery.getAttributeSet()));
                curIndex = sqlTableMapping.evaluateSQLStatement(curIndex - 1);
            }
        }
        beforeFirst();

        // get index of type id
        if (this.mainSQLTable.getSqlColType() != null) {
            final SQLTableMapping2Attributes sqlTableMapping = this.sqlTableMappings.get(this.mainSQLTable);
            this.colTypeId = sqlTableMapping.col2index.get(this.mainSQLTable.getSqlColType());
        }
    }

    /**
     * Adds one select statement to this query.
     *
     * @param _select select statement to add
     * @see #selects
     */
    public void addSelect(final String _select)
    {
        this.selects.add(_select);
    }

    /**
     * @return true if a new row is selected and exists, otherwise
     *         false
     */
    public boolean next()
    {
        return this.cachedResult.next();
    }

    /**
     * Move the cached result before the first.
     */
    public void beforeFirst()
    {
        this.cachedResult.beforeFirst();
    }

    /**
     * Move the cached result to a defined position.
     *
     * @param _key Key to move to
     * @return true if cache result was moves sucessfully
     */
    public boolean gotoKey(final Object _key)
    {
        return this.cachedResult.gotoKey(_key);
    }

    /**
     * The instance method returns for the given key the attribute value.
     *
     * @param _expression expression for which the attribute value must returned
     * @return attribute value for given key
     * @throws EFapsException
     * @throws Exception on error
     */
    public Object getValue(final String _expression) throws EFapsException
    {
        Object ret = null;

        Type typeTmp = getType();
        TypeMapping2Instances typeMapping = this.typeMappings.get(typeTmp);
        while ((typeTmp != null) && (typeMapping == null)) {
            typeTmp = typeTmp.getParentType();
            typeMapping = this.typeMappings.get(typeTmp);
        }
        ret = typeMapping.getValue(_expression);
        return ret;
    }

    /**
     * Get the type of this query.
     *
     * @return Type of this query
     */
    public Type getType()
    {
        Type ret = this.type;
        if (this.colTypeId > 0) {
            ret = Type.get(this.cachedResult.getLong(this.colTypeId));
        }
        return ret;
    }

    /**
     * Method to get the first instance of the cached result.
     *
     * @return Instance
     *
     */
    public Instance getInstance()
    {
        return Instance.get(getType(), this.cachedResult.getLong(1));
    }

    /**
     * Method to get all instances.
     *
     * @return List of instances
     */
    public List getInstances()
    {
        if (this.listquery.getAttributeSet() != null) {
            this.instances.clear();
            final SQLTableMapping2Attributes sqlTableMapping = this.sqlTableMappings.get(this.mainSQLTable);
            final List ids = (List) this.cachedResult.getObject(sqlTableMapping.col2index.get(this.mainSQLTable
                            .getSqlColId()));
            for (final Object id : ids) {
                this.instances.add(Instance.get(getType(), (Long) id));
            }
        }
        return this.instances;
    }

    /**
     * The instance method returns for the given key the attribute.
     *
     * @param _expression expression for which the attribute value must returned
     * @return attribute for given expression
     *
     */
    public Attribute getAttribute(final String _expression)
    {
        Attribute ret = null;
        ret = getType().getAttribute(_expression);
        if (ret == null) {
            ret = getType().getLinks().get(_expression);
        }
        return ret;
    }

    /**
     * The instance method returns for the given key the attribute set.
     *
     * @param _expression expression for which the attribute value must returned
     * @return attribute for given expression
     */
    public AttributeSet getAttributeSet(final String _expression)
    {
        return (AttributeSet) Type.get(AttributeSet.evaluateName(getType().getName(), _expression));
    }

    /**
     * Method to get the values of a attribute set.
     *
     * @return Object
     * @throws Exception on error
     */
    public Object getMultiLineValue() throws Exception
    {

        final Map indexes = new HashMap();

        for (final SQLTableMapping2Attributes sql2attr : this.sqlTableMappings.values()) {
            for (final String select : this.selects) {
                final Attribute attr = this.type.getAttribute(select);
                if (attr != null) {
                    final List idx = sql2attr.attr2index.get(attr);
                    if (idx != null) {
                        indexes.put(idx.get(0), attr.getName());
                    }
                }
            }
        }

        return  this.listquery.getAttributeSet().readValues(OneRoundQuery.this.cachedResult, indexes);
    }

    /**
     * Class used to store all types related to instances.
     */
    private class TypeMapping2Instances
    {

        /**
         * Defines the instances for which this type mapping to instances is
         * defined.
         *
         * @see #addInstance
         */
        private final Set instances = new HashSet();

        /**
         * Stores the type for which this type mapping is defined.
         */
        private final Type type;

        /**
         * Mapping between the expression and the attribute.
         */
        private final Map expr2Attr = new HashMap();

        /**
         *
         */
        private final Set multiExpr = new HashSet();

        /**
         *
         */
        private final Map sqlTable2Attrs
            = new HashMap();

        /**
         * @param _type type for which this type mapping is defined
         * @see type
         */
        public TypeMapping2Instances(final Type _type)
        {
            this.type = _type;
        }

        /**
         * Adds an instance to the type mapping to instances.
         *
         * @param _instance instance to add @
         * @see #instances
         */
        public void addInstance(final Instance _instance)
        {
            this.instances.add(_instance);
        }

        /**
         * Method to evaluate the selects.
         */
        public void evaluateSelects()
        {
            for (final String select : OneRoundQuery.this.selects) {
                final Attribute attr = this.type.getAttribute(select);
                if (attr != null) {
                    this.expr2Attr.put(select, attr);
                } else {
                    final AttributeSet set = AttributeSet.find(this.type.getName(), select);
                    if (set != null) {
                        for (final String subSelect : set.getSetAttributes()) {
                            ListQuery subQuery = OneRoundQuery.this.listquery.getSubSelects().get(select);
                            if (subQuery == null) {
                                subQuery = new ListQuery();
                                OneRoundQuery.this.listquery.getSubSelects().put(select, subQuery);
                            }
                            subQuery.addSelect(subSelect);
                            subQuery.setExpand(set);
                        }
                        OneRoundQuery.this.listquery.getMultiSelects().add(select);
                        this.multiExpr.add(select);
                    }
                }
            }

            for (final Attribute attribute : this.expr2Attr.values()) {
                SQLTableMapping2Attributes sqlTable2Attr = this.sqlTable2Attrs.get(attribute.getTable());
                if (sqlTable2Attr == null) {
                    sqlTable2Attr = OneRoundQuery.this.sqlTableMappings.get(attribute.getTable());
                    if (sqlTable2Attr == null) {
                        sqlTable2Attr = new SQLTableMapping2Attributes(attribute.getTable());
                        OneRoundQuery.this.sqlTableMappings.put(attribute.getTable(), sqlTable2Attr);
                    }
                    this.sqlTable2Attrs.put(attribute.getTable(), sqlTable2Attr);
                }
                sqlTable2Attr.addAttribute(attribute);
            }
            // in case that only fieldsets are selected, it must be added at least one SQLTableMapping2Attributes
            // to the sqlTable2Atte mapping so that the table is stored for later access
            if (this.expr2Attr.values().isEmpty() && !this.multiExpr.isEmpty()) {
                final SQLTableMapping2Attributes sqlTable2Attr
                                                      = new SQLTableMapping2Attributes(OneRoundQuery.this.mainSQLTable);
                OneRoundQuery.this.sqlTableMappings.put(OneRoundQuery.this.mainSQLTable, sqlTable2Attr);
                this.sqlTable2Attrs.put(OneRoundQuery.this.mainSQLTable, sqlTable2Attr);
            }

            // add all instances to the sql table mapping
            for (final SQLTableMapping2Attributes sqlTableMapping : this.sqlTable2Attrs.values()) {
                sqlTableMapping.addInstances(this.instances);
            }
        }

        /**
         * Method to get the value for an expression.
         *
         * @param _expr expression the value will be returned for
         * @return Object
         * @throws EFapsException
         * @throws Exception on error
         */
        public Object getValue(final String _expr) throws EFapsException
        {
            // System.out.println("getValue.expression="+_expression);
            Object ret = null;
            final Attribute attr = this.expr2Attr.get(_expr);
            if (attr != null) {
                final SQLTableMapping2Attributes sqlTable2attr = this.sqlTable2Attrs.get(attr.getTable());
                if (sqlTable2attr != null) {
                    ret = sqlTable2attr.getValue(attr);
                } else {
                    System.out.println("!!! NULLLLLLLL " + _expr);
                }
            } else {
                // in case we have an expand we return the id of the object
                if (_expr.contains("\\") || this.multiExpr.contains(_expr)) {
                    final SQLTableMapping2Attributes sqlTable2attr = this.sqlTable2Attrs.get(getType().getMainTable());
                    if (sqlTable2attr != null) {
                        final Integer idx = sqlTable2attr.col2index.get(getType().getMainTable().getSqlColId());
                        ret = OneRoundQuery.this.cachedResult.getLong(idx);
                    }
                }
            }
            return ret;
        }

        /**
         * Returns a string representation of this type mapping to instances.
         *
         * @return string representation of this type mapping to instances
         */
        @Override
        public String toString()
        {
            return new ToStringBuilder(this).appendSuper(super.toString()).append("type", this.type.toString()).append(
                            "instances", this.instances.toString()).append("sqlTable2Attrs",
                            this.sqlTable2Attrs.toString()).toString();
        }
    }

    /**
     * Class used to store all sql tables related to attributes.
     */
    private class SQLTableMapping2Attributes
    {

        /**
         * Sql table.
         */
        private final SQLTable sqlTable;

        /**
         * @see #addAttribute
         */
        private final Set attributes = new HashSet();

        /**
         * List of all columns.
         */
        private final List cols = new ArrayList();

        /**
         * Mapping of name of the column to its index.
         */
        private final Map col2index = new HashMap();

        /**
         * Mapping of attribute to indexes.
         */
        private final Map> attr2index = new HashMap>();

        /**
         * Set of Instances.
         */
        private final Set instances = new HashSet();

        /**
         * Actual index.
         */
        private int index = 0;

        /**
         * Is this query an expand.
         */
        private boolean expand;

        /**
         * Has the expand a result.
         */
        private boolean expandHasResult = true;

        /**
         * Contains the active attributeset.
         */
        private AttributeSet attributeSet;

        /**
         * Constructor.
         *
         * @param _sqlTable SQL table
         */
        public SQLTableMapping2Attributes(final SQLTable _sqlTable)
        {
            this.sqlTable = _sqlTable;
            this.col2index.put(this.sqlTable.getSqlColId(), this.index++);
            this.cols.add(this.sqlTable.getSqlColId());

            if (this.sqlTable.getSqlColType() != null) {
                this.col2index.put(this.sqlTable.getSqlColType(), this.index++);
                this.cols.add(this.sqlTable.getSqlColType());
            }
        }

        /**
         * Set an attribute set.
         *
         * @param _attributeSet AttributeSet
         */
        public void setAttributeSet(final AttributeSet _attributeSet)
        {
            this.attributeSet = _attributeSet;
            final String column = this.attributeSet.getSqlColNames().get(0);
            if (!this.col2index.containsKey(column)) {
                this.col2index.put(column, this.index++);
                this.cols.add(column);
            }
        }

        /**
         * Method to add an attribute.
         *
         * @param _attribute Attribute to add
         */
        public void addAttribute(final Attribute _attribute)
        {
            if (!this.attr2index.containsKey(_attribute)) {
                final ArrayList idxs = new ArrayList();
                for (final String col : _attribute.getSqlColNames()) {
                    Integer idx = this.col2index.get(col);
                    if (idx == null) {
                        idx = this.index++;
                        this.col2index.put(col, idx);
                        this.cols.add(col);
                    }
                    idxs.add(idx);
                }
                this.attr2index.put(_attribute, idxs);
            }
            this.attributes.add(_attribute);
        }

        /**
         * Method to add a collection of Instances.
         *
         * @param _instances Instance to add
         */
        public void addInstances(final Collection _instances)
        {
            this.instances.addAll(_instances);
        }

        /**
         * Method to get the value for an attribute.
         *
         * @param _attribute Attribute the value is wanted for
         * @return value Object
         * @throws EFapsException
         * @throws Exception on error
         */
        public Object getValue(final Attribute _attribute) throws EFapsException
        {
            Object ret = null;
            if (this.expandHasResult) {
                try {
                    ret = _attribute.readDBValue(OneRoundQuery.this.cachedResult, this.attr2index.get(_attribute));
                } catch (final Exception e) {
                    // TODO correct errorhandling
                    throw new EFapsException(SQLTableMapping2Attributes.class, "TODO", e);
                }
            }
            return ret;
        }

        /**
         * Method to evaluate a sql statement.
         *
         * @param _startIndex index to start from
         * @return new index
         * @throws EFapsException on error during execution of statement
         */
        public int evaluateSQLStatement(final int _startIndex) throws EFapsException
        {

            final int maxExpression = Context.getDbType().getMaxExpressions();
            final List instSQLs = new ArrayList();
            StringBuilder instSQL = new StringBuilder();
            instSQLs.add(instSQL);
            int i = 0;
            for (final Instance instance : this.instances) {
                i++;
                if (i > maxExpression - 1 && maxExpression > 0) {
                    instSQL.deleteCharAt(instSQL.length() - 1);
                    instSQL = new StringBuilder();
                    instSQLs.add(instSQL);
                    i = 0;
                }
                instSQL.append(instance.getId()).append(",");
            }
            if (this.instances.size() > 0) {
                instSQL.deleteCharAt(instSQL.length() - 1);
            }

            // update mapping from attribute to indexes
            for (final Map.Entry> entry : this.attr2index.entrySet()) {
                final List newList = new ArrayList();
                for (int curIndex : entry.getValue()) {
                    if (curIndex > 0) {
                        curIndex += _startIndex;
                    } else {
                        curIndex = 1;
                    }
                    newList.add(curIndex);
                }
                this.attr2index.put(entry.getKey(), newList);
            }

            // update mapping from columns to index
            for (final Map.Entry entry : this.col2index.entrySet()) {
                int curIndex = entry.getValue();
                if (curIndex > 0) {
                    curIndex += _startIndex;
                } else {
                    curIndex = 1;
                }
                this.col2index.put(entry.getKey(), curIndex);
            }

            final boolean shiftIndex = executeSQLStatement(instSQLs);
            // if we don't want to shift we must return the startvalue again
            return shiftIndex ? (_startIndex + this.index) : _startIndex + 1;
        }

        /**
         * Method to execute an sql statement.
         *
         * @param _instSQLs builders
         * @return false if we had an expand that did not deliver any Data
         * @throws EFapsException on error during execution of statement
         */
        private boolean executeSQLStatement(final List _instSQLs) throws EFapsException
        {

            final StringBuilder sql = new StringBuilder();
            boolean ret = true;
            boolean first = true;

            for (final StringBuilder instSQL : _instSQLs) {
                if (first) {
                    sql.append("select distinct ");
                    first = false;
                } else {
                    sql.append("union select ");
                }

                // append columns including the id
                for (final String col : this.cols) {
                    sql.append(col).append(",");
                }

                sql.deleteCharAt(sql.length() - 1);

                sql.append(" from ").append(this.sqlTable.getSqlTable()).append(" where ");
                if (this.expand) {
                    sql.append(this.attributeSet.getSqlColNames().get(0));
                } else {
                    sql.append(" ID ");
                }
                sql.append(" in (").append(instSQL).append(")");
                // in case of a attributeset we must also give the type as a
                // additional
                // filter
                if (this.expand && this.sqlTable.getSqlColType() != null) {
                    sql.append(" and ").append(this.sqlTable.getSqlColType()).append(" = ").append(
                                    this.attributeSet.getId());
                }
            }
            ConnectionResource con = null;
            try {
                con = Context.getThreadContext().getConnectionResource();

                final Statement stmt = con.getConnection().createStatement();
                final ResultSet rs = stmt.executeQuery(sql.toString());
                int keyIndex = 1;
                int subKeyIndex = 0;
                if (this.expand) {
                    int idx = 1;
                    for (final String col : this.cols) {
                        if (col.equals(this.attributeSet.getSqlColNames().get(0))) {
                            keyIndex = idx;
                        }
                        idx++;
                    }
                    subKeyIndex = 1;
                }
                OneRoundQuery.this.cachedResult.populate(rs, keyIndex, subKeyIndex);
                // we had an expand that did not deliver any Data
                if (!rs.isAfterLast() && this.expand) {
                    ret = false;
                    this.expandHasResult = false;
                }
                rs.close();
                stmt.close();
                con.commit();
                con = null;
            } catch (final Throwable e) {
                throw new EFapsException(getClass(), "executeOneCompleteStmt.Throwable", e);
            } finally {
                if (con != null) {
                    try {
                        con.abort();
                    } catch (final Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return ret;
        }

        /**
         * Getter method for instance variable {@link #expand}.
         *
         * @return value of instance variable {@link #expand}
         */
        public boolean isExpand()
        {
            return this.expand;
        }

        /**
         * Setter method for instance variable {@link #expand}.
         *
         * @param _expand value for instance variable {@link #expand}
         */
        public void setExpand(final boolean _expand)
        {
            this.expand = _expand;
        }

        /**
         * Returns a string representation of this .
         *
         * @return string representation of this
         */
        @Override
        public String toString()
        {
            return new ToStringBuilder(this).appendSuper(super.toString()).append("sqlTable", this.sqlTable.toString())
                            .append("attributes", this.attributes.toString()).toString();
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy