com.pureinfo.ark.auth2.model.RuleDef.java Source code

Java tutorial

Introduction

Here is the source code for com.pureinfo.ark.auth2.model.RuleDef.java

Source

/**
 * PureInfo Ark
 * @(#)RuleDef.java   1.0 2006-9-29
 * 
 * Copyright(c) 2004-2005, PureInfo Information Technology Corp. Ltd. 
 * All rights reserved, see the license file.
 * 
 * www.pureinfo.com.cn
 */

package com.pureinfo.ark.auth2.model;

import java.util.ArrayList;
import java.util.List;

import org.dom4j.Element;

import com.pureinfo.ark.auth.model.IUser;
import com.pureinfo.ark.content.model.ArkContent;
import com.pureinfo.dolphin.DolphinConstants;
import com.pureinfo.dolphin.context.LocalContextHelper;
import com.pureinfo.dolphin.mapping.EntityMetadata;
import com.pureinfo.dolphin.mapping.EntityRelative;
import com.pureinfo.dolphin.mapping.PropertyType;
import com.pureinfo.dolphin.model.DolphinObject;
import com.pureinfo.dolphin.persister.ISession;
import com.pureinfo.dolphin.persister.IStatement;
import com.pureinfo.dolphin.persister.util.RelativeUtil;
import com.pureinfo.dolphin.query.logic.ISQLLogic;
import com.pureinfo.dolphin.query.logic.SQLComparison;
import com.pureinfo.dolphin.query.logic.SQLCondition;
import com.pureinfo.dolphin.query.logic.SQLLogicBuilder;
import com.pureinfo.dolphin.query.logic.SQLLogicString;
import com.pureinfo.dolphin.script.ScriptOperator;
import com.pureinfo.dolphin.script.util.CompareUtil;
import com.pureinfo.force.exception.PureException;
import com.pureinfo.force.object.DataTypes;
import com.pureinfo.force.object.Values;
import com.pureinfo.force.xml.IXMLSupporter;
import com.pureinfo.force.xml.XMLUtil;

/**
 * <P>
 * Created on 2006-9-29 22:04:43 <BR>
 * Last modified on 2006-9-29
 * </P>
 * RuleDef: definition for rules.
 * 
 * @author Why
 * @version 1.0, 2006-9-29
 * @since Ark 1.2
 */
public class RuleDef implements IXMLSupporter {
    public final static String NULL_VALUE = "null";

    private EntityMetadata m_resourceMetadata;

    private String m_sResProperty;

    private String m_sResProperty4sql;

    private String m_sUserProperty;

    private int m_nValueType;

    private Values m_values;

    private int m_nTestOp;

    private RuleDef[] m_children;

    //cached data
    private String m_sAlias;

    private String m_sMyProperty;

    /**
     * Constructor: default
     */
    public RuleDef(EntityMetadata _resourceMetadata) {
        super();
        this.setResourceMetadata(_resourceMetadata);
    }

    /**
     * Returns the resourceMetata.
     * 
     * @return the resourceMetata.
     */
    public EntityMetadata getResourceMetadata() {
        return m_resourceMetadata;
    }

    /**
     * Sets the resourceMetata.
     * 
     * @param _resourceMetata
     *            the resourceMetata to set.
     */
    public void setResourceMetadata(EntityMetadata _resourceMetata) {
        m_resourceMetadata = _resourceMetata;
    }

    /**
     * Returns the resProperty.
     * 
     * @return the resProperty.
     */
    public String getResProperty() {
        return m_sResProperty;
    }

    /**
     * Sets the resProperty.
     * 
     * @param _sResProperty
     *            the resProperty to set.
     */
    public void setResProperty(String _sResProperty) {
        m_sResProperty = _sResProperty;

        int nPos = _sResProperty.indexOf('.');
        if (nPos < 1) {
            m_sMyProperty = _sResProperty;
        } else {
            m_sMyProperty = _sResProperty.substring(0, nPos);
        }
    }

    /**
     * Returns the resProperty4sql.
     * 
     * @return the resProperty4sql.
     */
    public String getResProperty4sql() {
        String sProperty = (m_sResProperty4sql != null) ? m_sResProperty4sql : "this." + m_sResProperty;
        return "{" + sProperty + "}";
    }

    /**
     * Sets the resProperty4sql.
     * 
     * @param _sResProperty4sql
     *            the resProperty4sql to set.
     */
    public void setResProperty4sql(String _sResProperty4sql) {
        m_sResProperty4sql = _sResProperty4sql;
        if (_sResProperty4sql == null) {
            m_sAlias = null;
        } else {
            m_sAlias = _sResProperty4sql.substring(0, _sResProperty4sql.indexOf('.'));
        }
    }

    /**
     * Returns the userProperty.
     * 
     * @return the userProperty.
     */
    public String getUserProperty() {
        return m_sUserProperty;
    }

    /**
     * Sets the userProperty.
     * 
     * @param _sUserProperty
     *            the userProperty to set.
     */
    public void setUserProperty(String _sUserProperty) {
        m_sUserProperty = _sUserProperty;
    }

    /**
     * Returns the valueType.
     * 
     * @return the valueType.
     */
    public int getValueType() {
        return m_nValueType;
    }

    /**
     * Sets the valueType.
     * 
     * @param _nValueType
     *            the valueType to set.
     */
    public void setValueType(int _nValueType) {
        m_nValueType = _nValueType;
    }

    /**
     * Returns the values.
     * 
     * @return the values.
     */
    public Values getValues() {
        return m_values;
    }

    /**
     * Sets the values.
     * 
     * @param _sValue
     *            the values to set.
     * @param _nDataType
     *            data type of each value
     */
    public void setValue(String _sValue, int _nDataType) {
        if (_sValue == null) {
            m_values = null;
        } else {
            if (m_values == null) {
                m_values = new Values();
            }
            m_values.fromString(_sValue, _nDataType);
        }
    }

    /**
     * Returns the testOp.
     * 
     * @return the testOp.
     */
    public int getTestOp() {
        return (m_nTestOp == ScriptOperator.UNKNOWN) ? ScriptOperator.STR_EQ : m_nTestOp;
    }

    /**
     * Sets the testOp.
     * 
     * @param _nTestOp
     *            the testOp to set.
     */
    public void setTestOp(int _nTestOp) {
        m_nTestOp = _nTestOp;
    }

    /**
     * Returns the children.
     * 
     * @return the children.
     */
    public RuleDef[] getChildren() {
        return m_children;
    }

    /**
     * Sets the children.
     * 
     * @param _sChildren
     *            the children to set.
     */
    public void setChildren(RuleDef[] _sChildren) {
        m_children = _sChildren;
    }

    //=========================================================================
    //logic interface for authorization

    /**
     * Returns <code>true</code> if the speicified resource and user match the
     * rule.
     * 
     * @param _user
     *            the specified user
     * @param _resource
     *            the specified resource
     * @return <code>true</code> if the speicified resource and user match the
     *         rule, <code>false</code> otherwise.
     */
    public boolean test(IUser _user, ArkContent _resource) throws PureException {
        boolean bResult;
        if (m_sResProperty.equals("#has")) {
            bResult = testHas(_user, _resource);
        } else {
            Object resValue = _resource.getRefProperty(m_sResProperty);
            Object[] value;
            if (m_values != null) {
                value = m_values.getValues();
            } else {
                value = new Object[] { ((DolphinObject) _user).getRefProperty(m_sUserProperty) };
            }

            bResult = CompareUtil.compare(resValue, value, m_nTestOp);
        }

        if (bResult && m_children != null) {
            //check if any of the children matchs
            for (int i = 0; i < m_children.length; i++) {
                if (m_children[i].test(_user, _resource))
                    return true;
            }
            bResult = false;
        }

        return bResult;
    }

    /**
     * Returns <code>true</code> if there is path to pass the rule.
     * 
     * @param _nActionIndex
     *            index of the action
     * @return <code>true</code> if there is path to pass the rule;
     *         <code>false</code>, otherwise.
     * @throws PureException
     *             if failed.
     */
    public boolean hasPath(IUser _user, ArkContent _resource) throws PureException {
        boolean bResult = true;
        if (m_sResProperty.charAt(0) != '#') {
            if (_resource.hasProperty(m_sMyProperty)) {
                Object resValue = _resource.getRefProperty(m_sResProperty);
                Object[] value;
                if (m_values != null) {
                    value = m_values.getValues();
                } else {
                    value = new Object[] { ((DolphinObject) _user).getRefProperty(m_sUserProperty) };
                }

                bResult = CompareUtil.compare(resValue, value, m_nTestOp);
            }
        }

        if (bResult && m_children != null) {
            // check if any of the children matchs
            for (int i = 0; i < m_children.length; i++) {
                if (m_children[i].hasPath(_user, _resource))
                    return true;
            }
            bResult = false;
        }

        return bResult;
    }

    /**
     * Tests the has logic rule.
     * 
     * @param _user
     *            the current user
     * @param _resource
     *            the resource to test
     * @return <code>true</code> if the "#has" rule is matched;
     *         <code>false</code> otherwise.
     * @throws PureException
     * @since 1.2
     */
    public boolean testHas(IUser _user, ArkContent _resource) throws PureException {
        //1. to find the rule logic
        EntityMetadata metadata = _resource.getMetadata(true);
        ISQLLogic logic = this.getSQLLogicBase(_user);

        IStatement query = null;
        ISession session = null;
        StringBuffer sbuff = null;
        List params = new ArrayList(2);
        try {
            // 2. to parse the logic condition
            String sCondition = logic.toSQL(params);
            sCondition = RelativeUtil.parseJoinCondition(sCondition, _resource, params);

            // 3. to find the relatives in rule condition
            String[] aliases = logic.getAliases();
            int nRelativeNum = (aliases == null) ? 0 : aliases.length;
            EntityRelative relatives[] = new EntityRelative[nRelativeNum];

            // 4. to render the query SQL
            sbuff = new StringBuffer("SELECT 1 FROM ");
            if (nRelativeNum == 0) {
                sbuff.append(_resource.isFromFormal() ? metadata.getTable() : metadata.getTempTable());
            } else {
                for (int i = 0; i < nRelativeNum; i++) {
                    relatives[i] = metadata.getRelative(aliases[i], true);
                    if (i > 0)
                        sbuff.append(',');
                    sbuff.append('{').append(relatives[i].getAlias()).append('}');
                }
            }

            sbuff.append(" WHERE ").append(sCondition);
            for (int i = 0; i < nRelativeNum; i++) {
                sbuff.append(" AND ");
                sbuff.append(RelativeUtil.parseJoinCondition(relatives[i].getJoinCondition(), _resource, params));
            }

            // 5. to execute the query
            session = LocalContextHelper.currentSession();
            query = session.createQuery(sbuff.toString(), _resource.getClass(), 1);
            for (int i = 0; i < nRelativeNum; i++) {
                query.registerAlias(relatives[i].getAlias(), relatives[i].getTypeClass());
            }
            query.setParameters(0, params);
            return query.executeStat() != null;
        } finally {
            params.clear();
            if (sbuff != null)
                sbuff.setLength(0);
            if (query != null)
                query.clear();
            if (session != null)
                LocalContextHelper.closeSession();
        }
    }

    /**
     * Returns the restriction rule as SQL logic when the user do the specified
     * action on the resource.
     * 
     * @param _user
     *            the current user
     * @return the restriction rule as SQL logic when the user do the specified
     *         action on the resource.
     * @throws PureException
     *             if failed to render the logic.
     */
    public ISQLLogic getSQLLogicRule(IUser _user) throws PureException {
        return getSQLLogicRule0(_user, true);
    }

    /**
     * Returns the restriction rule as SQL logic when the user do the specified
     * action on the resource.
     * 
     * @param _user
     *            the current user
     * @param _bIncludingChildren
     *            <code>true</code>, including the children logic; otherwise,
     *            excluding.
     * @return the restriction rule as SQL logic when the user do the specified
     *         action on the resource.
     * @throws PureException
     *             if failed to render the logic.
     */
    private ISQLLogic getSQLLogicRule0(IUser _user, boolean _bIncludingChildren) throws PureException {
        ISQLLogic logic;

        //1. to render the logic of mine
        if (m_sResProperty.equals("#has")) {
            logic = getSQLLogic4Has(_user);
        } else {
            logic = getSQLLogicBase(_user);
        }

        //2. to render the logic in the children
        if (m_children != null && m_children.length > 0 && _bIncludingChildren) {
            ISQLLogic childrenLogic = getSQLLogicRule(_user, m_children);
            logic = SQLLogicBuilder.and(logic, childrenLogic);
        }
        return logic;
    }

    /**
     * Renders the base SQL logic of current rule.
     * 
     * @param _user
     *            the current user
     * @return the base SQL logic of current rule.
     * @throws PureException
     *             if failed.
     * @since 1.2
     */
    private ISQLLogic getSQLLogicBase(IUser _user) throws PureException {
        ISQLLogic logic;
        int nType = this.getValueType();
        int nOp = ScriptOperator.toSQLType(m_nTestOp);
        if (m_values != null) {
            logic = SQLLogicBuilder.build(this.getResProperty4sql(), nOp, nType, m_values.getValues());
        } else {
            Object value = ((DolphinObject) _user).getRefProperty(m_sUserProperty);
            logic = new SQLComparison(this.getResProperty4sql(), nOp, nType, value);
        }

        if (m_sAlias != null) {
            logic.addAlias(m_sAlias);
        }

        return logic;
    }

    /**
     * Renders the SQL logic for #has rule.
     * 
     * @param _user
     *            the current user.
     * @return the SQL logic for #has rule.
     * @throws PureException
     *             if failed.
     * @since 1.2
     */
    private ISQLLogic getSQLLogic4Has(IUser _user) throws PureException {
        StringBuffer sbuffSQL = new StringBuffer("EXISTS(SELECT 1 FROM {");
        StringBuffer sbuffCondition = new StringBuffer();
        try {
            //1. to render "select 1 from X"
            sbuffSQL.append(m_sAlias).append('}');

            //2. to add the base logic in this rule
            ISQLLogic logic = getSQLLogicBase(_user);
            List params = new ArrayList(0);
            sbuffCondition.append(logic.toSQL(params));
            logic.clear();

            //3. to render the logic for relative, including all its depends.
            EntityRelative relative = m_resourceMetadata.getRelative(m_sAlias, true);
            sbuffCondition.append(" AND (").append(relative.getJoinCondition()).append(')');

            // to check the relative depends
            String[] depends = relative.getDepends();
            if (depends != null && depends.length > 0) {
                for (int i = 0; i < depends.length; i++) {
                    relative = m_resourceMetadata.getRelative(depends[i], true);
                    sbuffSQL.append(",{").append(relative.getAlias()).append(')'); //from
                    sbuffCondition.append(" AND ").append('(').append(relative.getJoinCondition()).append(')');
                }
            }

            //4. finally, to concat the SQL like "EXISTS(SELECT 1 FROM R1,R2 WHERE C1 AND C2)"
            sbuffSQL.append(" WHERE ").append(sbuffCondition).append(')');
            logic = new SQLLogicString(sbuffSQL.toString(), params);
            logic.addAlias(DolphinConstants.ALIAS_FLAG_4JOIN_EXISTS + m_sAlias);
            return logic;
        } finally {
            sbuffSQL.setLength(0);
            sbuffCondition.setLength(0);
        }
    }

    /**
     * Gets the SQL logic rule by the specified rules.
     * 
     * @param _user
     *            the specified user
     * @param _rules
     *            the rules
     * @return the SQL logic
     * @throws PureException
     *             if failed.
     */
    public static ISQLLogic getSQLLogicRule(IUser _user, RuleDef[] _rules) throws PureException {
        if (_rules.length == 1) {
            return _rules[0].getSQLLogicRule(_user);
        }

        //else
        SQLCondition condition = new SQLCondition(false, _rules.length);
        ISQLLogic logic;
        for (int i = 0; i < _rules.length; i++) {
            logic = _rules[i].getSQLLogicRule(_user);
            if (logic == SQLLogicString.TRUE) {
                return logic;
            }
            //else
            if (logic != SQLLogicString.FALSE) {
                condition.append(logic);
            }
        } //endfor

        return condition.shrink();
    }

    //=========================================================================
    //implementation for IXMLSupporter

    /**
     * @see com.pureinfo.force.xml.IXMLSupporter#toXMLElement(org.dom4j.Element)
     */
    public void toXMLElement(Element _element) throws PureException {
        _element.addAttribute("res-property", m_sResProperty);
        if (m_sResProperty4sql != null) {
            _element.addAttribute("res-property4sql", m_sResProperty4sql);
            _element.addAttribute("type", DataTypes.getName(m_nValueType));
        }
        if (m_sUserProperty != null) {
            _element.addAttribute("user-property", m_sUserProperty);
        }
        if (m_values != null) {
            _element.addAttribute("value", m_values.toString());
        }
        _element.addAttribute("test", ScriptOperator.getSymbol(m_nTestOp));

        //to export children
        if (m_children != null) {
            for (int i = 0; i < m_children.length; i++) {
                _element.add(XMLUtil.toXMLElement(m_children[i], "rule"));
            }
        }
    }

    /**
     * @see com.pureinfo.force.xml.IXMLSupporter#fromXML(org.dom4j.Element)
     */
    public void fromXML(Element _element) throws PureException {
        this.setResProperty(XMLUtil.getAttributeValueTrim(_element, "res-property"));
        this.setUserProperty(XMLUtil.getAttributeValueTrim(_element, "user-property"));
        this.setResProperty4sql(XMLUtil.getAttributeValueTrim(_element, "res-property4sql"));

        //read value type
        String sTypeName = XMLUtil.getAttributeValueTrim(_element, "type");
        if (sTypeName != null) {
            this.setValueType(PropertyType.lookupByName(sTypeName).getDataType());
        } else {
            this.setValueType(m_resourceMetadata.getProperty(m_sResProperty, true).getDataType());
        }

        this.setValue(XMLUtil.getAttributeValueTrim(_element, "value"), m_nValueType);
        this.setTestOp(ScriptOperator.getType(XMLUtil.getAttributeValueTrim(_element, "test")));

        //to import children
        List list = _element.elements("rule");
        if (list == null || list.isEmpty()) {
            m_children = null;
        } else {
            try {
                m_children = new RuleDef[list.size()];
                RuleDef ruleDef;
                for (int i = 0; i < list.size(); i++) {
                    ruleDef = new RuleDef(m_resourceMetadata);
                    ruleDef.fromXML((Element) list.get(i));
                    m_children[i] = ruleDef;
                }
            } finally {
                list.clear();
            }
        } //endif
    }
}