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

org.efaps.db.AbstractQuery 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;

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

import org.efaps.admin.access.AccessTypeEnums;
import org.efaps.admin.datamodel.Attribute;
import org.efaps.admin.datamodel.SQLTable;
import org.efaps.admin.datamodel.Type;
import org.efaps.db.query.CachedResult;
import org.efaps.db.query.CompleteStatement;
import org.efaps.db.query.WhereClause;
import org.efaps.db.query.WhereClauseAttrEqAttr;
import org.efaps.db.transaction.ConnectionResource;
import org.efaps.util.EFapsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author The eFaps Team
 * @version $Id: AbstractQuery.java 7483 2012-05-11 16:57:38Z [email protected] $
 * TODO:  description
 */
//CHECKSTYLE:OFF
@Deprecated
public abstract class AbstractQuery
{

    /**
     * Logging instance used in this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(AbstractQuery.class);


    private boolean checkAccess = false;

    private CachedResult cachedResult = null;

    protected Type type = null;

    ArrayList types = new ArrayList();

    /**
     * The instance variable stores the order of the select types.
     *
     * @see #getSelectTypesOrder
     */
    private final List selectTypesOrder = new ArrayList();

    /**
     * The instance variable stores all single join elements.
     *
     * @see #getJoinElements
     */
    private final List joinElements = new ArrayList();

    /**
     * The instance variable maps expressions to join elements.
     */
    private final Map mapJoinElements = new HashMap();

    /**
     * The instance variable stores the main instance of the join element. The
     * main join element is that join elment which stores the direct selectable
     * attribute values.
     *
     * @see #getMainJoinElement
     */
    private final JoinElement mainJoinElement = new JoinElement();

    /**
     * The instance variable stores all main selected types. The key in this map
     * is the main table.
     *
     * @see #getSelectTypes
     */
    private final Map mainSelectTypes = new HashMap();

    /**
     * The instance variable stores all main where clauses. This where clauses
     * must be used by all join elements! This is a different behaviour than the
     * where clauses for a join element.
     *
     * @see #getMainWhereClauses
     */
    private final List mainWhereClauses = new ArrayList();

    /**
     * WHereClause for the company form the context. (if given)
     */
    private WhereClause companyClause;


    /**
     * Should the child types als be expanded?
     *
     * @see #isExpandChildTypes
     * @see #setExpandChildTypes
     */
    private boolean expandChildTypes = true;

    /**
     * The instance variable stores all select expressions and their relations
     * to attributes for this query.
     *
     * @see #getAllSelExprMap
     */
    private final Map allSelExprMap = new HashMap();

    /**
     * The instance variable stores all OID select expressions and their
     * relations to attributes for this query.
     *
     * @see #getAllOIDSelExprMap
     */
    private final Map allOIDSelExprMap = new HashMap();

    private final Map oid2access = new HashMap();

    // ///////////////////////////////////////////////////////////////////////////

    /**
     * The instance destructor calls the instance method {@link #close} to close
     * the SQL statement if not happend till now. The exception thrown from
     * method {@link #close} is catched and no error is thrown from this
     * destructor.
     *
     * @see #close
     */
    @Override
    public void finalize()
    {
        try {
            close();
        } catch (final Exception e) {
        }
    }

    /**
     * The method closes the SQL statement. The method must be always called to
     * close the query!
     *
     * @see #statement
     */
    public void close() throws EFapsException
    {
        /*
         * if (getStatement()!=null) { try { getStatement().close(); } catch
         * (Exception e) { throw e; } finally { setStatement(null); } }
         */
    }

    /**
     * The method adds an expression to the selectstatement.
     *
     * @param _expression expression to add
     */
    public void addSelect(final String _expression) throws EFapsException
    {
        addSelect(false, _expression, this.type, _expression);
    }

    /**
     * @param _isOID must be set to true is select expression selects the
     *            OID of the business object.
     * @param _key key to store the select expression in the select map
     *            expression
     * @param _attr attribute itself which must be selected
     */
    protected void addSelect(final boolean _isOID, final Object _key, final Attribute _attr) throws EFapsException
    {
        getSelectType(_attr.getParent()).addSelect(_isOID, _key, _attr);
    }

    /**
     * @param _isOID must be set to true is select expression selects the
     *            OID of the business object.
     * @param _key key to store the select expression in the select map
     *            expression
     * @param _expression
     */
    protected void addSelect(final boolean _isOID, final Object _key, final Type _type, final String _expression)
                    throws EFapsException
    {
        getSelectType(_type).addSelect(_isOID, _key, _expression);
    }

    /**
     * The instance method adds types in the order of the expand.
     *
     * @param _type type to add in the correct order
     * @see #addTypes4Order(Type,boolean)
     */
    protected void addTypes4Order(final Type _type)
    {
        addTypes4Order(_type, false);
    }

    /**
     * The instance method adds types in the order of the expand.
     *
     * @param _type type to add in the correct order
     * @param _nullAllowed type can be null
     * @see #selectTypesOrder
     * @see #getSelectType
     */
    protected void addTypes4Order(final Type _type, final boolean _nullAllowed)
    {
        final SelectType selectType = getSelectType(_type);
        selectType.setOrderIndex(getSelectTypesOrder().size());
        selectType.setNullAllowed(_nullAllowed);
        getSelectTypesOrder().add(selectType);
    }

    /**
     * Setter method for instance variable {@link #companyClause}.
     *
     * @param _companyClause value for instance variable {@link #companyClause}
     */

    protected void setCompanyClause(final WhereClause _companyClause)
    {
        this.companyClause = _companyClause;
    }

    // ///////////////////////////////////////////////////////////////////////////

    /**
     * The instance method returns for the given type the select type class
     * instance of {@link #SelectType}.
     *
     * @param _type type for which the instance of {@link #SelectType} is
     *            searched
     * @see #addTypes4Order
     * @see #selectTypesOrder
     */
    public SelectType getSelectType(final Type _type)
    {
        SelectType selectType = getMainSelectTypes().get(_type);
        if (selectType == null) {
            selectType = new SelectType(getMainJoinElement(), _type, getSelectTypesOrder().size());
            getMainSelectTypes().put(_type, selectType);
            for (final JoinElement elm : getJoinElements()) {
                elm.addSelectType(selectType);
            }
        }
        return selectType;
    }

    /**
     * The method returns the size of the select expressions.
     *
     * @return size of the select expressions
     * @see #getExpressions
     */
    public int selectSize()
    {
        int ret = 0;
        for (final JoinElement elm : getJoinElements()) {
            ret += elm.selectSize();
        }
        return ret;
    }

    // ///////////////////////////////////////////////////////////////////////////

    /**
     * The instance method returns for the given key the attribute value.
     *
     * @param _key key for which the attribute value must returned
     * @return atribute value for given key
     */
    public Object get(final String _key) throws EFapsException
    {
        Object ret = null;

        if (hasAccess(_key)) {
            final SelExpr2Attr selExpr = getAllSelExprMap().get(_key);
            if (selExpr != null) {
                ret = selExpr.getAttrValue();
            }
        }
        return ret;
    }

    private boolean hasAccess(final String _key) throws EFapsException
    {
        boolean hasAccess = true;
        if (this.checkAccess) {

            Instance instance = null;
            String oid = null;
            final SelExpr2Attr selExpr = getAllOIDSelExprMap().get(_key);
            if (selExpr != null) {
                oid = (String) selExpr.getAttrValue();
            }
            if ((oid != null) && !oid.equals("0.0")) {
                instance = Instance.get(oid);
            } else {
                instance = getInstance(this.type);
            }
            if (instance != null) {
                if (this.oid2access.containsKey(instance.getOid())) {
                    hasAccess = this.oid2access.get(instance.getOid());
                } else {
                    hasAccess = instance.getType().hasAccess(instance, AccessTypeEnums.SHOW.getAccessType());
                    this.oid2access.put(instance.getOid(), hasAccess);
                }
            }
        }
        return hasAccess;
    }

    /**
     * The instance method returns for the given key the atribute.
     *
     * @param _key key for which the attribute value must returned
     * @return attribute for given key
     */
    public Attribute getAttribute(final String _key) throws Exception
    {
        Attribute ret = null;
        final SelExpr2Attr selExpr = getAllSelExprMap().get(_key);
        if (selExpr != null) {
            ret = selExpr.getAttribute();
        }
        return ret;
    }

    /**
     * All object ids for one row are returned. The objects id defined in the
     * expand are returned in the same order.
     *
     * @return list of instances from the expand
     */
    public List getExpandInstances() throws EFapsException
    {
        final List ret = new ArrayList();
        for (final Type type : this.types) {
            ret.add(Instance.get(getOID(type)));
        }
        return ret;
    }

    /**
     * @param _key key for which the object id value must returned
     * @return object id for given key
     */
    protected String getOID(final Object _key) throws EFapsException
    {
        String ret = null;
        final SelExpr2Attr selExpr = getAllOIDSelExprMap().get(_key);
        if (selExpr != null) {
            ret = (String) selExpr.getAttrValue();
        }
        return ret;
    }

    /**
     * The instance method returns the instance for the current selected row.
     *
     * @param _type
     * TODO:  why is in this way implemented (other way than method getOID above)
     */
    protected Instance getInstance(final Type _type) throws EFapsException
    {
        final SelectType selectType = getMainSelectTypes().get(_type);
        if (selectType == null) {
            AbstractQuery.LOG.error("Type '" + _type.getName() + "' is not selected! New Instance can not created!");
            throw new EFapsException(getClass(), "getInstance.TypeNotSelected", _type.getName());
        }
        // String id =
        // getResultSet().getString(selectType.getIndexId().intValue());
        final String id = this.cachedResult.getString(selectType.getIndexId().intValue());

        Type type = _type;

        if (selectType.getIndexType() != null) {
            // long typeId =
            // getResultSet().getLong(selectType.getIndexType().intValue());
            final long typeId = this.cachedResult.getLong(selectType.getIndexType().intValue());
            type = Type.get(typeId);
        }

        return Instance.get(type, id);
    }

    // ///////////////////////////////////////////////////////////////////////////

    /**
     * The instance method executes the query.
     */
    public void execute() throws EFapsException
    {
        this.checkAccess = true;
        executeWithoutAccessCheck();
    }

    /**
     * The instance method executes the query.
     */
    public void executeWithoutAccessCheck() throws EFapsException
    {
        if (getMainJoinElement().selectSize() > 0) {

            int incSelIndex = 0;
            this.cachedResult = new CachedResult();

            for (final JoinElement joinElement : getJoinElements()) {

                joinElement.setIncSelIndex(incSelIndex);
                // warum diese Ueberpruefung? weil der join jeweils die spalte
                // mit der id zum vergleichen rauschmeisst!!
                if (incSelIndex == 0) {
                    incSelIndex += joinElement.getSelectExpressions().size();
                } else {
                    incSelIndex += joinElement.getSelectExpressions().size() - 1;
                }

                final CompleteStatement completeStatement = new CompleteStatement();

                joinElement.appendStatement(completeStatement, -1, isExpandChildTypes());

                for (final SelectType selectType : getSelectTypesOrder()) {
                    if (selectType.isNullAllowed()) {
                        completeStatement.appendUnion();
                        joinElement.appendStatement(completeStatement, selectType.getOrderIndex(),
                                                        isExpandChildTypes());
                    }
                }

                executeOneCompleteStmt(completeStatement, joinElement.getMatchColumn());
            }

            for (final SelExpr2Attr selExpr : getAllSelExprMap().values()) {
                selExpr.initSelectIndex();
            }
            for (final SelExpr2Attr selExpr : getAllOIDSelExprMap().values()) {
                selExpr.initSelectIndex();
            }
        }
        this.cachedResult.beforeFirst();
    }

    /**
     * The instance method executes exact one complete statement and populates
     * the result in the cached result {@link #cachedResult}.
     *
     * @param _complStmt complete statement instance to execute
     * @param _matchColumn column in the complete statement (result set) used to
     *            as key to compare in the cached result
     */
    private void executeOneCompleteStmt(final CompleteStatement _complStmt, final int _matchColumn)
                    throws EFapsException
    {

        ConnectionResource con = null;
        try {
            con = Context.getThreadContext().getConnectionResource();

            if (AbstractQuery.LOG.isTraceEnabled()) {
                AbstractQuery.LOG.trace(_complStmt.getStatement().toString());
            }

            final Statement stmt = con.getConnection().createStatement();

            final ResultSet rs = stmt.executeQuery(_complStmt.getStatement().toString());

            this.cachedResult.populate(rs, _matchColumn, 0);

            rs.close();
            stmt.close();
            con.commit();
        } catch (final EFapsException e) {
            if (con != null) {
                con.abort();
            }
            throw e;
        } catch (final Throwable e) {
            if (con != null) {
                con.abort();
            }
            // TODO: exception eintragen!
            e.printStackTrace();
            throw new EFapsException(getClass(), "executeOneCompleteStmt.Throwable");
        }
    }

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

    // ///////////////////////////////////////////////////////////////////////////

    /**
     * This is the getter method for instance variable {@link #selectTypesOrder}
     * .
     *
     * @return value of instance variable {@link #selectTypesOrder}
     * @see #selectTypesOrder
     */
    public List getSelectTypesOrder()
    {
        return this.selectTypesOrder;
    }

    /**
     * This is the getter method for the instance variable {@link #type}.
     *
     * @return value of instance variable {@link #type}
     */
    public Type getType()
    {
        return this.type;
    }

    /**
     * This is the getter method for instance variable {@link #joinElements}.
     *
     * @return value of instance variable {@link #joinElements}
     * @see #joinElements
     */
    protected List getJoinElements()
    {
        return this.joinElements;
    }

    /**
     * This is the getter method for instance variable {@link #mapJoinElements}.
     *
     * @return value of instance variable {@link #mapJoinElements}
     * @see #mapJoinElements
     */
    protected Map getMapJoinElements()
    {
        return this.mapJoinElements;
    }

    /**
     * This is the getter method for instance variable {@link #mainJoinElement}.
     *
     * @return value of instance variable {@link #mainJoinElement}
     * @see #mainJoinElement
     */
    protected JoinElement getMainJoinElement()
    {
        return this.mainJoinElement;
    }

    /**
     * This is the getter method for instance variable {@link #mainSelectTypes}.
     *
     * @return value of instance variable {@link #mainSelectTypes}
     * @see #mainSelectTypes
     */
    private Map getMainSelectTypes()
    {
        return this.mainSelectTypes;
    }

    /**
     * This is the getter method for instance variable {@link #mainWhereClauses}
     * .
     *
     * @return value of instance variable {@link #mainWhereClauses}
     * @see #mainWhereClauses
     */
    protected List getMainWhereClauses()
    {
        return this.mainWhereClauses;
    }

    /**
     * This is the getter method for instance variable {@link #expandChildTypes}
     * .
     *
     * @return value of instance variable {@link #expandChildTypes}
     * @see #expandChildTypes
     * @see #setExpandChildTypes
     */
    protected boolean isExpandChildTypes()
    {
        return this.expandChildTypes;
    }

    /**
     * This is the setter method for instance variable {@link #expandChildTypes}
     * .
     *
     * @param _expandChildTypes new value for instance variable
     *            {@link #expandChildTypes}
     * @see #expandChildTypes
     * @see #isExpandChildTypes
     */
    public void setExpandChildTypes(final boolean _expandChildTypes)
    {
        this.expandChildTypes = _expandChildTypes;
    }

    /**
     * This is the getter method for instance variable {@link #allSelExprMap}.
     *
     * @return value of instance variable {@link #allSelExprMap}
     * @see #allSelExprMap
     */
    protected Map getAllSelExprMap()
    {
        return this.allSelExprMap;
    }

    /**
     * This is the getter method for instance variable {@link #allOIDSelExprMap}
     * .
     *
     * @return value of instance variable {@link #allOIDSelExprMap}
     * @see #allOIDSelExprMap
     */
    protected Map getAllOIDSelExprMap()
    {
        return this.allOIDSelExprMap;
    }

    /**
     * The class is used to make one join select.
     */
    public class JoinElement
    {

        private JoinElement()
        {
            if (getMainSelectTypes() != null) {
                getSelectTypes().addAll(getMainJoinElement().getSelectTypes());
            }
            getJoinElements().add(this);
        }

        protected void appendStatement(final CompleteStatement _completeStatement, final int _orderIndex,
                        final boolean _childTypes) throws EFapsException
        {
            _completeStatement.append("select distinct ");
            appendSelectExpressions(_completeStatement, _orderIndex);
            appendFrom(_completeStatement, _orderIndex);
            appendWhereClause(_completeStatement, _orderIndex, _childTypes);

            for (final SelectType selectType : getSelectTypesOrder()) {
                if (selectType.isNullAllowed() && (_orderIndex < 0 || selectType.getOrderIndex() < _orderIndex)) {
                    _completeStatement.appendUnion();
                    _completeStatement.append("select distinct ");
                    appendSelectExpressions(_completeStatement, selectType.getOrderIndex());
                    appendFrom(_completeStatement, selectType.getOrderIndex());
                    appendWhereClause(_completeStatement, selectType.getOrderIndex(), _childTypes);
                }
            }
        }

        /**
         * Appends all select expressions from this one join element to the
         * comlete statement.
         *
         * @param _completeStatement complete SQL statement to select values
         * @param _orderIndex ????????????????????
         */
        private void appendSelectExpressions(final CompleteStatement _completeStatement, final int _orderIndex)
        {
            final Iterator iter = getSelectExpressions().iterator();
            while (iter.hasNext()) {
                final SQLSelectExpression selectExpr = iter.next();
                if ((_orderIndex < 0) || selectExpr.getSelectType().getOrderIndex() < _orderIndex) {
                    _completeStatement.append(selectExpr.getExpression());
                } else {
                    _completeStatement.append(selectExpr.getNullString());
                }
                if (iter.hasNext()) {
                    _completeStatement.append(",");
                }
            }
        }

        private void appendFrom(final CompleteStatement _completeStatement, final int _orderIndex)
        {
            for (final SelectType selectType : getSelectTypes()) {
                if ((_orderIndex < 0) || (selectType.getOrderIndex() < _orderIndex)) {
                    selectType.appendFrom(_completeStatement);
                }
            }
        }

        private void appendWhereClause(final CompleteStatement _completeStatement, final int _orderIndex,
                        final boolean _childTypes) throws EFapsException
        {
            final Iterator typeIter = getSelectTypes().iterator();
            while (typeIter.hasNext()) {
                final SelectType selectType = typeIter.next();
                if (_orderIndex < 0 || selectType.getOrderIndex() < _orderIndex) {
                    _completeStatement.appendWhereAnd();
                    selectType.appendTypeWhereClause(_completeStatement, _childTypes);
                }
            }
            for (final WhereClause whereClause : this.whereClauses) {
                whereClause.appendWhereClause(_completeStatement, _orderIndex);
            }

            if (AbstractQuery.this.companyClause != null) {
                AbstractQuery.this.companyClause.appendWhereClause(_completeStatement, _orderIndex);
            }

            if (getMainWhereClauses().size() > 0) {
                _completeStatement.appendWhereAnd();
                _completeStatement.appendWhere();
                _completeStatement.append(" (");
                for (final WhereClause whereClause : getMainWhereClauses()) {
                    whereClause.appendWhereClause(_completeStatement, _orderIndex);
                }
                _completeStatement.append(" )");
            }

        }

        /**
         * The method returns the size of the select expressions.
         *
         * @return size of the select expressions
         * @see #getExpressions
         */
        public int selectSize()
        {
            return getExpressions().size();
        }

        /**
         * Returns for the given expression the select expression. The select
         * expression is tested for uniqueness (and if defined already reused).
         *
         * @param _selectType instance of SelectType
         * @param _sqlTable SQL table which is selected
         * @param _aliasTableName alias table name (defined in the from clause)
         * @param _columnNAme column name within the SQL table
         * @param _isId is the selected column an internal eFaps id? if true,
         *            the null value select is "0", otherwise the null value
         *            select is direct evaluated from the table information
         * @return new select expression
         */
        private SQLSelectExpression getSelectExpression(final SelectType _selectType, final SQLTable _sqlTable,
                        final int _aliasIndex, final String _columnName, final boolean _isId)
        {
            final String sqlExpr = new StringBuilder().append(_sqlTable.getSqlTable()).append(_aliasIndex).append('.')
                            .append(_columnName).toString();
            SQLSelectExpression selectExpr = getExpressions().get(sqlExpr);
            if (selectExpr == null) {
                final String nullString = _isId ? "0" : _sqlTable.getTableInformation().getColInfo(_columnName)
                                .getNullValueSelect();
                selectExpr = new SQLSelectExpression(getExpressions().size() + 1, sqlExpr, this, _selectType,
                                nullString);
                getExpressions().put(sqlExpr, selectExpr);
                getSelectExpressions().add(selectExpr);
            }
            return selectExpr;
        }

        /**
         * @param _aliasIndex index used to create the sql prefix
         * @param _selectType instance of SelectType
         * @param _isOID the select statement is an OID select and must be
         *            stored in the OID map
         * @param _key key used to store in the (OID) map
         * @param _attribute attribute to select
         * @see #getSelectExpression
         */
        private void addSelectAttribute(final int _aliasIndex, final SelectType _selectType, final boolean _isOID,
                        final Object _key, final Attribute _attr)
        {
            final ArrayList selectExprs = new ArrayList();

            if (_attr.getTable() != null) {
                _selectType.getTypeTableNames().add(_attr.getTable());
                for (final String _sqlColName : _attr.getSqlColNames()) {
                    final SQLSelectExpression selectExpr = getSelectExpression(_selectType, _attr.getTable(),
                                    _aliasIndex, _sqlColName, false);
                    // System.out.println("selectExprs.add="+selectExpr);
                    selectExprs.add(selectExpr);
                }
            }
            final SelExpr2Attr selExpr2Attr = new SelExpr2Attr(_attr, selectExprs);
            // System.out.println("selectExprs="+selExpr2Attr);
            if (_isOID) {
                getAllOIDSelExprMap().put(_key, selExpr2Attr);
            } else {
                getAllSelExprMap().put(_key, selExpr2Attr);
            }
        }

        /**
         * The instance method creates a new instance of {@link #SelectType} add
         * adds them to {@link #selectTypesOrder}.
         *
         * @param _type type to add in the correct order
         * @param _nullAllowed type can be null
         * @return new created instance of {@link #SelectType}
         * @see #selectTypesOrder
         */
        protected SelectType getNewSelectType(final Type _type, final boolean _nullAllowed)
        {
            final SelectType selectType = new SelectType(this, _type, (getSelectTypesOrder().size() + 1000));
            selectType.setOrderIndex(getSelectTypesOrder().size() + 1000);
            selectType.setNullAllowed(_nullAllowed);
            getSelectTypesOrder().add(selectType);
            addSelectType(selectType);
            return selectType;
        }

        private void addWhere(final SelectType _selectType1, final Attribute _attr1, final SelectType _selectType2,
                        final Attribute _attr2) throws EFapsException
        {
            this.whereClauses.add(new WhereClauseAttrEqAttr(_selectType1, _attr1, _selectType2, _attr2));
        }

        private void addSelectType(final SelectType _selectType)
        {
            getSelectTypes().add(_selectType);
        }

        // /////////////////////////////////////////////////////////////////////////
        private final List whereClauses = new ArrayList();

        /**
         * The instance variable stores all select types of the select
         * statement.
         *
         * @see #getTableNames
         */
        private final Set selectTypes = new HashSet();

        /**
         * This is the instance variable to hold all expressions. The SQL
         * statement is stores as key, the value is the index of the expression
         * in the select statement. This is used that an expression is only once
         * in a select statement (uniqueness)!.
         *
         * @see #getExpressions
         */
        private final Map expressions = new HashMap();

        /**
         * The instance variable stores all select expressions.
         *
         * @see #getSelectExpressions
         */
        private final List selectExpressions = new ArrayList();

        /**
         * The instance variable stores the order of the select types. The
         * information is needed if an expand is made (and in an expand a null
         * value is possible!).
         *
         * @see #getSelectTypesOrder
         */
        private final List selectTypesOrder = new ArrayList();

        /**
         * The instance variable stores the column index of this join element.
         * The index is the select expression used to join with other select
         * statements. The default value is 1 for the first column.
         *
         * @see #getMatchColumn
         * @see #setMatchColumn
         */
        private int matchColumn = 1;

        /**
         * The instance variable stores the number of previous select
         * epxressions used to calculate the index of select expressions of this
         * join element in the complete join.
         *
         * @see #getIncSelIndex
         * @see #setIncSelIndex
         */
        private int incSelIndex = 0;

        // /////////////////////////////////////////////////////////////////////////

        /**
         * This is the getter method for instance variable {@link #selectTypes}.
         *
         * @return value of instance variable {@link #selectTypes}
         * @see #selectTypes
         */
        private Set getSelectTypes()
        {
            return this.selectTypes;
        }

        /**
         * This is the getter method for instance variable {@link #expressions}.
         *
         * @return value of instance variable {@link #expressions}
         * @see #expressions
         */
        protected Map getExpressions()
        {
            return this.expressions;
        }

        /**
         * This is the getter method for instance variable
         * {@link #selectExpressions}.
         *
         * @return value of instance variable {@link #selectExpressions}
         * @see #selectExpressions
         */
        protected List getSelectExpressions()
        {
            return this.selectExpressions;
        }

        /**
         * This is the getter method for instance variable
         * {@link #selectTypesOrder}.
         *
         * @return value of instance variable {@link #selectTypesOrder}
         * @see #selectTypesOrder
         */
        public List getSelectTypesOrder()
        {
            return this.selectTypesOrder;
        }

        /**
         * This is the setter method for instance variable {@link #matchColumn}.
         *
         * @param _orderIndex new value for instance variable
         *            {@link #matchColumn}
         * @see #matchColumn
         * @see #getMatchColumn
         */
        private void setMatchColumn(final int _matchColumn)
        {
            this.matchColumn = _matchColumn;
        }

        /**
         * This is the getter method for instance variable {@link #matchColumn}.
         *
         * @return value of instance variable {@link #matchColumn}
         * @see #matchColumn
         * @see #setMatchColumn
         */
        public int getMatchColumn()
        {
            return this.matchColumn;
        }

        /**
         * This is the setter method for instance variable {@link #incSelIndex}.
         *
         * @param _orderIndex new value for instance variable
         *            {@link #incSelIndex}
         * @see #incSelIndex
         * @see #getIncSelIndex
         */
        private void setIncSelIndex(final int _incSelIndex)
        {
            this.incSelIndex = _incSelIndex;
        }

        /**
         * This is the getter method for instance variable {@link #incSelIndex}.
         *
         * @return value of instance variable {@link #incSelIndex}
         * @see #incSelIndex
         * @see #setIncSelIndex
         */
        private int getIncSelIndex()
        {
            return this.incSelIndex;
        }
    }

    /**
     * The class stores the relation between an select expression and an
     * attribute.
     */
    private class SelExpr2Attr
    {

        /**
         * Stores the attribute.
         *
         * @see #getAttribute
         * @see #setAttribute
         */
        private Attribute attribute = null;

        /**
         * Stores all select expression.
         *
         * @see #getSelExpr
         * @see #setSelExpr
         */
        private ArrayList selExprs = null;

        /**
         * Stores all the indexes of the SQL select expression where the values
         * of the attribute are found (in the same order than defined in the
         * attribute).
         *
         * @see #getIndexes
         */
        private final ArrayList indexes = new ArrayList();

        // /////////////////////////////////////////////////////////////////////////

        /**
         * Constructor
         *
         * @param _attr attribute
         * @param _selExprs select expressions
         */
        private SelExpr2Attr(final Attribute _attr, final ArrayList _selExprs)
        {
            setAttribute(_attr);
            setSelExprs(_selExprs);
        }

        /**
         * After execution of the query, the indexes where that attribute values
         * stands, could be initialised and used by {@link #getAttrValue}.
         */
        protected void initSelectIndex()
        {
            // System.out.println("~~~~~~~~~~~~++initSelectIndex+"+getSelExprs());
            for (final SQLSelectExpression selExpr : getSelExprs()) {
                final int index = selExpr.getJoinElement().getIncSelIndex() + selExpr.getIndex();
                // System.out.println("~~~~~~~~~~~~++index="+index);
                getIndexes().add(new Integer(index));
            }
            // System.out.println("~~~~~~~~~~~~++getIndexes()="+getIndexes());
        }

        /**
         * @return attribute value with the value returned from the select
         *         expression
         */
        protected Object getAttrValue() throws EFapsException
        {
            if (getAttribute() == null) {
                throw new EFapsException(getClass(), "SelectExpression.get.NoAttribute");
            }
            Object ret = null;
            try {
                ret = getAttribute().readDBValue(AbstractQuery.this.cachedResult, getIndexes());
            } catch (final Exception e) {
                throw new EFapsException(getClass(), "getAttrValue.CouldNotReadValue", e);
            }
            return ret;
        }

        // /////////////////////////////////////////////////////////////////////////

        /**
         * This is the getter method for instance variable {@link #attribute}.
         *
         * @return value of instance variable {@link #attribute}
         * @see #attribute
         * @see #setAttribute
         */
        public Attribute getAttribute()
        {
            return this.attribute;
        }

        /**
         * This is the setter method for instance variable {@link #attribute}.
         *
         * @param _attribute new value for instance variable {@link #attribute}
         * @see #attribute
         * @see #getAttribute
         */
        private void setAttribute(final Attribute _attribute)
        {
            this.attribute = _attribute;
        }

        /**
         * This is the getter method for instance variable {@link #selExprs}.
         *
         * @return value of instance variable {@link #selExprs}
         * @see #selExprs
         * @see #setSelExprs
         */
        public ArrayList getSelExprs()
        {
            return this.selExprs;
        }

        /**
         * This is the setter method for instance variable {@link #selExprs}.
         *
         * @param _selExpr new value for instance variable {@link #selExprs}
         * @see #selExprs
         * @see #getSelExprs
         */
        private void setSelExprs(final ArrayList _selExprs)
        {
            this.selExprs = _selExprs;
        }

        /**
         * This is the getter method for instance variable {@link #indexes}.
         *
         * @return value of instance variable {@link #indexes}
         * @see #indexes
         */
        public ArrayList getIndexes()
        {
            return this.indexes;
        }
    }

    // ###########################################################################
    // ###########################################################################
    // ###########################################################################
    // ###########################################################################
    // ###########################################################################

    private class SQLSelectExpression
    {

        /**
     *
     */
        private final int index;

        /**
     *
     */
        private final String expression;

        /**
     *
     */
        private final JoinElement joinElement;

        /**
     *
     */
        private final SelectType selectType;

        /**
     *
     */
        private final String nullString;

        /**
     *
     */
        protected SQLSelectExpression(final int _index, final String _expression, final JoinElement _joinElement,
                        final SelectType _selectType, final String _nullString)
        {
            this.index = _index;
            this.expression = _expression;
            this.joinElement = _joinElement;
            this.selectType = _selectType;
            this.nullString = _nullString;
        }

        // /////////////////////////////////////////////////////////////////////////

        /**
         * This is the getter method for instance variable {@link #index}.
         *
         * @return value of instance variable {@link #index}
         * @see #index
         */
        public int getIndex()
        {
            return this.index;
        }

        /**
         * This is the getter method for instance variable {@link #expression}.
         *
         * @return value of instance variable {@link #expression}
         * @see #expression
         */
        public String getExpression()
        {
            return this.expression;
        }

        /**
         * This is the getter method for instance variable {@link #joinElement}.
         *
         * @return value of instance variable {@link #joinElement}
         * @see #joinElement
         */
        public JoinElement getJoinElement()
        {
            return this.joinElement;
        }

        /**
         * This is the getter method for instance variable {@link #selectType}.
         *
         * @return value of instance variable {@link #selectType}
         * @see #selectType
         */
        public SelectType getSelectType()
        {
            return this.selectType;
        }

        /**
         * This is the getter method for instance variable {@link #nullString}.
         *
         * @return value of instance variable {@link #nullString}
         * @see #nullString
         */
        public String getNullString()
        {
            return this.nullString;
        }
    }

    // ###########################################################################
    // ###########################################################################
    // ###########################################################################
    // ###########################################################################
    // ###########################################################################

    public class SelectType
    {

        /**
         * The string instance variable stores the table names of the select
         * statement of this selected type.
         *
         * @see #getTableNames
         */
        private final Set typeTableNames = new HashSet();

        /**
         * The instance variable stores the index of the order.
         *
         * @see #getOrderIndex
         * @see #setOrderIndex
         */
        private int orderIndex = 0;

        final JoinElement joinElement;

        /**
         * The instance variable stores the type this class instance is
         * representing.
         *
         * @see #getType
         */
        private final Type type;

        /**
         * The instance variable stores the index number of the type in the
         * select expressions of the table. The index number is the number of
         * the SQL table (from TABLENAME TABLENAME+INDEX_NUMBER)
         * defined in the from statement of the complete SQL select statement.
         */
        private final int typeIndex;

        /**
         * The instance method stores the index of the id of this type in the
         * SQL table within the SQL select statement.
         *
         * @see #getIndexId
         * @see #setIndexId
         */
        private final Integer indexId;

        /**
         * The instance method stores the index of the type id of this type in
         * the SQL table within the SQL select statement.
         *
         * @see #getIndexId
         */
        private final Integer indexType;

        /**
         * The instance variable stores if the type can be null (and so the link
         * to a type must not be defined...).
         *
         * @see #isNullAllowed
         * @see #setNullAllowed
         */
        private boolean nullAllowed = false;

        private SelectType(final JoinElement _joinElement, final Type _type, final int _typeIndex)
        {
            this.joinElement = _joinElement;
            this.type = _type;
            this.typeIndex = _typeIndex;
            getTypeTableNames().add(getType().getMainTable());
            SQLSelectExpression selectExpr = this.joinElement.getSelectExpression(this, getType().getMainTable(),
                            this.typeIndex, getType().getMainTable().getSqlColId(), true);
            this.indexId = selectExpr.getIndex();
            this.joinElement.setMatchColumn(selectExpr.getIndex());

            if (getType().getMainTable().getSqlColType() != null) {
                selectExpr = this.joinElement.getSelectExpression(this, getType().getMainTable(), this.typeIndex,
                                getType().getMainTable().getSqlColType(), true);
                this.indexType = selectExpr.getIndex();
            } else {
                this.indexType = null;
            }
        }

        /**
         * @param _isOID must be set to true is select expression selects
         *            the OID of the object.
         * @param _key key to store the select expression in the select map
         *            expression
         * @param _attr attribute itself which must be selected
         */
        protected void addSelect(final boolean _isOID, final Object _key, final Attribute _attr)
        {
            this.joinElement.addSelectAttribute(this.typeIndex, this, _isOID, _key, _attr);
        }

        /**
         * @param _isOID must be set to true is select expression selects
         *            the OID of the business object.
         * @param _key key to store the select expression in the select map
         *            expression
         * @param _expression expression itself which must be selected
         * TODO:  EFapsException Property
         */
        protected void addSelect(final boolean _isOID,
                                 final Object _key,
                                 final String _expression)
            throws EFapsException
        {
            // System.out.println("AbstractQuery.addSelect("+_isOID+","+_key+","+_expression+")");
            if ((_expression != null) && !"".equals(_expression)) {
                if (_expression.indexOf('.') >= 0) {
                    final JoinElement elm = new JoinElement();
                    final StringTokenizer tokens = new StringTokenizer(_expression, ".");
                    final String link = tokens.nextToken();
                    final Attribute attr = getType().getAttribute(link);
                    if (attr == null) {
                        AbstractQuery.LOG.error("Link for '" + link
                                + "' does not exists on type " + "'" + getType().getName() + "'");
                        throw new EFapsException(getClass(), "addSelect.LinkDoesNotExists", link, getType().getName());
                    }

                    // add new link type
                    final Type linkType = attr.getLink();

                    if (linkType == null) {
                        AbstractQuery.LOG.error("For Link '" + link + "' of type " + "'" + getType().getName() + "' "
                                        + "the type is not defined.");
                        throw new EFapsException(getClass(), "addSelect.LinkDoesNotExists", link, getType().getName());
                    }
                    final SelectType selectType = elm.getNewSelectType(linkType, !attr.isRequired());
                    final Attribute attrFromLink = linkType.getAttribute(tokens.nextToken());

                    selectType.addSelect(_isOID, _key, attrFromLink);

                    elm.addWhere(this, attr, selectType, linkType.getAttribute("ID"));

                    // System.out.println("selectType.index="+selectType.getTypeIndex());

                    // for ID selection
                    final SQLSelectExpression selectExpr = elm.getSelectExpression(this, getType().getMainTable(),
                                    this.typeIndex, getType().getMainTable().getSqlColId(), true);
                    elm.setMatchColumn(selectExpr.getIndex());

                    getTypeTableNames().add(attr.getTable());

                    getMapJoinElements().put(_expression, elm);

                } else {
                    final Attribute attr = getType().getAttribute(_expression);
                    if (attr == null) {
                        AbstractQuery.LOG.error("attribute '" + _expression + "' for type " + "'" + getType().getName()
                                        + "' not found");
                        throw new EFapsException(getClass(), "addSelect.AttributeNotFound", _expression, getType()
                                        .getName());
                    }
                    addSelect(_isOID, _key, attr);
                }
            }
        }

        /**
         * Adds the tables from this attribute in a where clause.
         */
        public void add4Where(final Attribute _attr)
        {
            for (final String sqlColName : _attr.getSqlColNames()) {
                getTypeTableNames().add(_attr.getTable());
                this.joinElement.getSelectExpression(this, _attr.getTable(), this.typeIndex, sqlColName, false);
            }
        }

        protected void appendFrom(final CompleteStatement _completeStatement)
        {
            for (final SQLTable table : getTypeTableNames()) {
                _completeStatement.appendFrom(table.getSqlTable()).append(" ").append(table.getSqlTable()).append(
                                this.typeIndex);
            }
        }

        /**
         * @param _childTypes also child types are allowed
         */
        protected void appendTypeWhereClause(final CompleteStatement _completeStatement, final boolean _childTypes)
        {
            if (getType().getMainTable().getSqlColType() != null) {

                if (_childTypes) {
                    _completeStatement.appendWhereAnd();
                    _completeStatement.appendWhere(getType().getMainTable().getSqlTable()).appendWhere(this.typeIndex)
                                    .appendWhere(".");
                    _completeStatement.appendWhere(getType().getMainTable().getSqlColType());
                    _completeStatement.appendWhere(" in (");
                    _completeStatement.appendWhere(getType().getId());
                    for (final Type child : getType().getChildTypes()) {
                        _completeStatement.appendWhere(",").appendWhere(child.getId());
                    }
                    _completeStatement.appendWhere(")");
                } else {
                    _completeStatement.appendWhereAnd();
                    _completeStatement.appendWhere(getType().getMainTable().getSqlTable()).appendWhere(this.typeIndex)
                                    .appendWhere(".");
                    _completeStatement.appendWhere(getType().getMainTable().getSqlColType());
                    _completeStatement.appendWhere("=");
                    _completeStatement.appendWhere(getType().getId());
                }
            }

            final Iterator iter = getTypeTableNames().iterator();
            final SQLTable table = iter.next();
            while (iter.hasNext()) {
                _completeStatement.appendWhereAnd();
                _completeStatement.appendWhere(table.getSqlTable()).appendWhere(this.typeIndex).appendWhere(".")
                                .appendWhere(table.getSqlColId());
                _completeStatement.appendWhere("=");
                final SQLTable nextTable = iter.next();
                _completeStatement.appendWhere(nextTable.getSqlTable()).appendWhere(this.typeIndex).appendWhere(".")
                                .appendWhere(nextTable.getSqlColId());
            }
        }

        /**
         * This is the getter method for instance variable {@link #typeIndex}.
         *
         * @return value of instance variable {@link #typeIndex}
         * @see #typeIndex
         */
        public int getTypeIndex()
        {
            return this.typeIndex;
        }

        /**
         * This is the getter method for instance variable {@link #type}.
         *
         * @return value of instance variable {@link #type}
         * @see #type
         * @see #setType
         */
        public Type getType()
        {
            return this.type;
        }

        /**
         * This is the getter method for instance variable {@link #indexType}.
         *
         * @return value of instance variable {@link #indexType}
         * @see #indexType
         * @see #setIndexType
         */
        protected Integer getIndexType()
        {
            return this.indexType;
        }

        /**
         * This is the getter method for instance variable {@link #indexId}.
         *
         * @return value of instance variable {@link #indexId}
         * @see #indexId
         * @see #setIndexId
         */
        protected Integer getIndexId()
        {
            return this.indexId;
        }

        /**
         * This is the getter method for instance variable
         * {@link #typeTableNames}.
         *
         * @return value of instance variable {@link #typeTableNames}
         * @see #typeTableNames
         */
        protected Set getTypeTableNames()
        {
            return this.typeTableNames;
        }

        /**
         * This is the getter method for instance variable {@link #nullAllowed}.
         *
         * @return value of instance variable {@link #nullAllowed}
         * @see #nullAllowed
         * @see #setNullAllowed
         */
        public boolean isNullAllowed()
        {
            return this.nullAllowed;
        }

        /**
         * This is the setter method for instance variable {@link #nullAllowed}.
         *
         * @param _nullAllowed new value for instance variable
         *            {@link #nullAllowed}
         * @see #nullAllowed
         * @see #isNullAllowed
         */
        private void setNullAllowed(final boolean _nullAllowed)
        {
            this.nullAllowed = _nullAllowed;
        }

        /**
         * This is the getter method for instance variable {@link #orderIndex}.
         *
         * @return value of instance variable {@link #orderIndex}
         * @see #orderIndex
         * @see #setOrderIndex
         */
        public int getOrderIndex()
        {
            return this.orderIndex;
        }

        /**
         * This is the setter method for instance variable {@link #orderIndex}.
         *
         * @param _orderIndex new value for instance variable
         *            {@link #orderIndex}
         * @see #orderIndex
         * @see #getOrderIndex
         */
        private void setOrderIndex(final int _orderIndex)
        {
            this.orderIndex = _orderIndex;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy