/** * Copyright 2010 JBoss Inc * * 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. */ package org.drools.ide.common.client.modeldriven.brl; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class RuleModel implements PortableObject { /** * This name is generally not used - the asset name or the * file name is preferred (ie it could get out of sync with the name of the file it is in). */ public String name; public String parentName; public String modelVersion = "1.0"; public RuleAttribute[] attributes = new RuleAttribute[0]; public RuleMetadata[] metadataList = new RuleMetadata[0]; public IPattern[] lhs = new IPattern[0]; public IAction[] rhs = new IAction[0]; public RuleModel() { } /** * This will return the fact pattern that a variable is bound to. * * @param var The bound fact variable (NOT bound field). * @return null or the FactPattern found. */ public FactPattern getBoundFact(final String var) { if (this.lhs == null) { return null; } for (int i = 0; i < this.lhs.length; i++) { if (this.lhs[i] instanceof FactPattern) { final FactPattern p = (FactPattern) this.lhs[i]; if (p.boundName != null && var.equals(p.boundName)) { return p; } } } return null; } public String getBindingType(final String var) { if (this.lhs == null) { return null; } for (int i = 0; i < this.lhs.length; i++) { if (this.lhs[i] instanceof FactPattern) { final FactPattern p = (FactPattern) this.lhs[i]; if (p.isBound() && var.equals(p.boundName) ) { return p.factType; } for (FieldConstraint z : p.getFieldConstraints()) { String type = giveFieldBinding(z, var); if (type != null) { return type; } } } } return null; } private String giveFieldBinding(FieldConstraint f, String var) { if (f instanceof SingleFieldConstraint) { SingleFieldConstraint s = (SingleFieldConstraint) f; if (s.isBound() && var.equals(s.getFieldBinding())) { return s.getFieldType(); } } if (f instanceof CompositeFieldConstraint) { CompositeFieldConstraint s = (CompositeFieldConstraint) f; //If the user didn't add any constraint yet, s.constraints is null if (s.constraints != null){ for (FieldConstraint ss : s.constraints) { return giveFieldBinding(ss, var); } } } return null; } /* * Get the bound fact of a rhs action * Fix nheron */ public ActionInsertFact getRhsBoundFact(final String var) { if (this.rhs == null) { return null; } for (int i = 0; i < this.rhs.length; i++) { if (this.rhs[i] instanceof ActionInsertFact) { final ActionInsertFact p = (ActionInsertFact) this.rhs[i]; if (p.getBoundName() != null && var.equals(p.getBoundName())) { return p; } } } return null; } /** * @return A list of bound facts (String). Or empty list if none are found. */ public List<String> getBoundFacts() { if (this.lhs == null) { return Collections.emptyList(); } final List<String> list = new ArrayList<String>(); for (int i = 0; i < this.lhs.length; i++) { if (this.lhs[i] instanceof FactPattern) { final FactPattern p = (FactPattern) this.lhs[i]; if (p.boundName != null) { list.add(p.boundName); } list.addAll(getListFieldBinding(p)); } } return list; } private List<String> getListFieldBinding(FactPattern fact) { List<String> result = new ArrayList<String>(); for (int j = 0; j < fact.getFieldConstraints().length; j++) { FieldConstraint fc = fact.getFieldConstraints()[j]; List<String> s = getFieldBinding(fc); result.addAll(s); } return result; } private List<String> getFieldBinding(FieldConstraint f) { List<String> result = new ArrayList<String>(); if (f instanceof SingleFieldConstraint) { SingleFieldConstraint sfc = (SingleFieldConstraint) f; if (sfc.isBound()) { result.add(sfc.getFieldBinding()); } } if (f instanceof CompositeFieldConstraint) { CompositeFieldConstraint cfc = (CompositeFieldConstraint) f; //If the user didn't add any constraint yet, s.constraints is null if (cfc.constraints != null){ for (FieldConstraint ss : cfc.constraints) { List<String> t = getFieldBinding(ss); result.addAll(t); } } } return result; } /** * @return A list of bound facts of the rhs(String). Or empty list if none are found. * Fix nheron */ public List<String> getRhsBoundFacts() { if (this.rhs == null) { return null; } final List<String> list = new ArrayList<String>(); for (int i = 0; i < this.rhs.length; i++) { if (this.rhs[i] instanceof ActionInsertFact) { final ActionInsertFact p = (ActionInsertFact) this.rhs[i]; if (p.getBoundName() != null) { list.add(p.getBoundName()); } } } return list; } /** * @param idx Remove this index from the LHS. * returns false if it was NOT allowed to remove this item (ie * it is used on the RHS). */ public boolean removeLhsItem(final int idx) { final IPattern[] newList = new IPattern[this.lhs.length - 1]; int newIdx = 0; for (int i = 0; i < this.lhs.length; i++) { if (i != idx) { newList[newIdx] = this.lhs[i]; newIdx++; } else { if (this.lhs[i] instanceof FactPattern) { final FactPattern p = (FactPattern) this.lhs[i]; if (p.boundName != null && isBoundFactUsed(p.boundName)) { return false; } } } } this.lhs = newList; return true; } /** * @param binding The name of the LHS fact binding. * @return Returns true if the specified binding is used on the RHS. */ public boolean isBoundFactUsed(final String binding) { if (this.rhs == null) { return false; } for (int i = 0; i < this.rhs.length; i++) { if (this.rhs[i] instanceof ActionSetField) { final ActionSetField set = (ActionSetField) this.rhs[i]; if (set.variable.equals(binding)) { return true; } } else if (this.rhs[i] instanceof ActionRetractFact) { final ActionRetractFact ret = (ActionRetractFact) this.rhs[i]; if (ret.variableName.equals(binding)) { return true; } } } return false; } public void addLhsItem(final IPattern pat) { this.addLhsItem(pat, true); } public void addLhsItem(final IPattern pat, boolean append) { this.addLhsItem(pat, append ? this.lhs.length : 0); } public void addLhsItem(final IPattern pat, int position) { if (this.lhs == null) { this.lhs = new IPattern[0]; } if (position < 0){ position = 0; }else if(position > this.lhs.length){ position = this.lhs.length; } final IPattern[] list = this.lhs; final IPattern[] newList = new IPattern[list.length + 1]; for (int i = 0; i < newList.length; i++) { if (i < position) { newList[i] = list[i]; } else if (i > position) { newList[i] = list[i - 1]; } else { newList[i] = pat; } } this.lhs = newList; } public void moveLhsItemDown(int itemIndex) { if (this.lhs == null) { this.lhs = new IPattern[0]; } this.moveItemDown(this.lhs, itemIndex); } public void moveLhsItemUp(int itemIndex) { if (this.lhs == null) { this.lhs = new IPattern[0]; } this.moveItemUp(this.lhs, itemIndex); } public void moveRhsItemDown(int itemIndex) { if (this.rhs == null) { this.rhs = new IAction[0]; } this.moveItemDown(this.rhs, itemIndex); } public void moveRhsItemUp(int itemIndex) { if (this.rhs == null) { this.rhs = new IAction[0]; } this.moveItemUp(this.rhs, itemIndex); } private void moveItemDown(Object[] array,int itemIndex) { for (int i = 0; i < array.length; i++) { if (i == itemIndex) { if (array.length > (i + 1)) { Object tmp = array[i + 1]; array[i + 1] = array[i]; array[i] = tmp; i++; } } } } private void moveItemUp(Object[] array,int itemIndex){ if (itemIndex==0){ return; } for (int i = 0; i < array.length; i++) { if (i == itemIndex) { Object tmp = array[i - 1]; array[i - 1] = array[i]; array[i] = tmp; } } } public void addRhsItem(final IAction action) { this.addRhsItem(action, true); } public void addRhsItem(final IAction action, boolean append) { this.addRhsItem(action, append ? this.rhs.length : 0); } public void addRhsItem(final IAction action, int position) { if (this.rhs == null) { this.rhs = new IAction[0]; } if (position < 0){ position = 0; }else if(position > this.rhs.length){ position = this.rhs.length; } final IAction[] list = this.rhs; final IAction[] newList = new IAction[list.length + 1]; for (int i = 0; i < newList.length; i++) { if (i < position) { newList[i] = list[i]; } else if (i > position) { newList[i] = list[i - 1]; } else { newList[i] = action; } } this.rhs = newList; } public void removeRhsItem(final int idx) { final IAction[] newList = new IAction[this.rhs.length - 1]; int newIdx = 0; for (int i = 0; i < this.rhs.length; i++) { if (i != idx) { newList[newIdx] = this.rhs[i]; newIdx++; } } this.rhs = newList; } public void addAttribute(final RuleAttribute attribute) { final RuleAttribute[] list = this.attributes; final RuleAttribute[] newList = new RuleAttribute[list.length + 1]; for (int i = 0; i < list.length; i++) { newList[i] = list[i]; } newList[list.length] = attribute; this.attributes = newList; } public void removeAttribute(final int idx) { final RuleAttribute[] newList = new RuleAttribute[this.attributes.length - 1]; int newIdx = 0; for (int i = 0; i < this.attributes.length; i++) { if (i != idx) { newList[newIdx] = this.attributes[i]; newIdx++; } } this.attributes = newList; } /** * Add metaData * * @param metadata */ public void addMetadata(final RuleMetadata metadata) { final RuleMetadata[] newList = new RuleMetadata[this.metadataList.length + 1]; for (int i = 0; i < this.metadataList.length; i++) { newList[i] = this.metadataList[i]; } newList[this.metadataList.length] = metadata; this.metadataList = newList; } public void removeMetadata(final int idx) { final RuleMetadata[] newList = new RuleMetadata[this.metadataList.length - 1]; int newIdx = 0; for (int i = 0; i < this.metadataList.length; i++) { if (i != idx) { newList[newIdx] = this.metadataList[i]; newIdx++; } } this.metadataList = newList; } /** * Locate metadata element * * @param attributeName - value to look for * @return null if not found */ public RuleMetadata getMetaData(String attributeName) { if (metadataList != null && attributeName != null) { for (int i = 0; i < metadataList.length; i++) { if (attributeName.equals(metadataList[i].attributeName)) { return metadataList[i]; } } } return null; } /** * Update metaData element if it exists or add it otherwise * * @param target * @return true on update of existing element * false on added of element */ public boolean updateMetadata(final RuleMetadata target) { RuleMetadata metaData = getMetaData(target.attributeName); if (metaData != null) { metaData.value = target.value; return true; } addMetadata(target); return false; } /** * This uses a deceptively simple algorithm to determine * what bound variables are in scope for a given constraint (including connectives). * Does not take into account globals. */ public List<String> getBoundVariablesInScope(final BaseSingleFieldConstraint con) { final List<String> result = new ArrayList<String>(); for (int i = 0; i < this.lhs.length; i++) { final IPattern pat = this.lhs[i]; if (pat instanceof FactPattern) { final FactPattern fact = (FactPattern) pat; if (fact.constraintList != null) { final FieldConstraint[] cons = fact.constraintList.constraints; if (cons != null) { for (int k = 0; k < cons.length; k++) { FieldConstraint fc = cons[k]; if (fc instanceof SingleFieldConstraint) { final SingleFieldConstraint c = (SingleFieldConstraint) fc; if (c == con) { return result; } if (c.connectives != null) { for (int j = 0; j < c.connectives.length; j++) { if (con == c.connectives[j]) { return result; } } } if (c.isBound()) { result.add(c.getFieldBinding()); } } } } if (fact.isBound()) { result.add(fact.boundName); } } else { if (fact.isBound()) { result.add(fact.boundName); } } } } return result; } /** * This will get a list of all bound variables, including bound fields. */ public List<String> getAllVariables() { List<String> result = new ArrayList<String>(); for (int i = 0; i < this.lhs.length; i++) { IPattern pat = this.lhs[i]; if (pat instanceof FactPattern) { FactPattern fact = (FactPattern) pat; if (fact.isBound()) { result.add(fact.boundName); } for (int j = 0; j < fact.getFieldConstraints().length; j++) { FieldConstraint fc = fact.getFieldConstraints()[j]; if (fc instanceof SingleFieldConstraint) { SingleFieldConstraint con = (SingleFieldConstraint) fc; if (con.isBound()) { result.add(con.getFieldBinding()); } if (con.getExpressionValue() != null && con.getExpressionValue().isBound()) { result.add(con.getExpressionValue().getBinding()); } if (con instanceof SingleFieldConstraintEBLeftSide) { SingleFieldConstraintEBLeftSide exp = (SingleFieldConstraintEBLeftSide) con; if (exp.getExpressionLeftSide() != null && exp.getExpressionLeftSide().isBound()) { result.add(exp.getExpressionLeftSide().getBinding()); } } } } } } for (int i = 0; i < this.rhs.length; i++) { IAction pat = this.rhs[i]; if (pat instanceof ActionInsertFact) { ActionInsertFact fact = (ActionInsertFact) pat; if (fact.isBound()) { result.add(fact.getBoundName()); } } } return result; } /** * Checks to see if a variable is used or not, includes fields * as well as facts. */ public boolean isVariableNameUsed(String s) { return getAllVariables().contains(s); } /** * Returns true if any DSLSentences are used. */ public boolean hasDSLSentences() { if (this.lhs != null) { for (IPattern pattern : this.lhs) { if (pattern instanceof DSLSentence) { return true; } } } if (this.rhs != null) { for (IAction action : this.rhs) { if (action instanceof DSLSentence) { return true; } } } return false; } }