Java tutorial
/** * 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 } }