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

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

Go to download

eFaps is a framework used to map objects with or without attached files to a relational database and optional file systems (only for attaches files). Configurable access control can be provided down to object and attribute level depending on implementation and use case. Depending on requirements, events (like triggers) allow to implement business logic and to separate business logic from user interface. The framework includes integrations (e.g. webdav, full text search) and a web application as 'simple' configurable user interface. Some best practises, example web application modules (e.g. team work module) support administrators and implementers using this framework.

There is a newer version: 3.2.0
Show newest version
/*
 * 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 - 2024 Weber Informatics LLC | Privacy Policy