/* * Copyright (C) 2009 JavaRosa * * 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.openrosa.client.jr.core.model.condition; import java.io.IOException; import java.util.Vector; import org.openrosa.client.java.io.DataInputStream; import org.openrosa.client.java.io.DataOutputStream; import org.openrosa.client.jr.core.model.FormDef; import org.openrosa.client.jr.core.model.instance.FormInstance; import org.openrosa.client.jr.core.model.instance.TreeReference; import org.openrosa.client.jr.core.util.externalizable.DeserializationException; import org.openrosa.client.jr.core.util.externalizable.ExtUtil; import org.openrosa.client.jr.core.util.externalizable.ExtWrapList; import org.openrosa.client.jr.core.util.externalizable.ExtWrapTagged; import org.openrosa.client.jr.core.util.externalizable.Externalizable; import org.openrosa.client.jr.core.util.externalizable.PrototypeFactory; public abstract class Triggerable implements Externalizable { public IConditionExpr expr; public Vector targets; public TreeReference contextRef; //generic ref used to turn triggers into absolute references public Triggerable () { } public Triggerable (IConditionExpr expr, TreeReference contextRef) { this.expr = expr; this.contextRef = contextRef; this.targets = new Vector(); } protected abstract Object eval (FormInstance instance, EvaluationContext ec); protected abstract void apply (TreeReference ref, Object result, FormInstance instance, FormDef f); public abstract boolean canCascade (); public void apply (FormInstance instance, EvaluationContext evalContext, FormDef f) { Object result = eval(instance, evalContext); for (int i = 0; i < targets.size(); i++) { TreeReference targetRef = ((TreeReference)targets.elementAt(i)).contextualize(evalContext.getContextRef()); Vector v = instance.expandReference(targetRef); for (int j = 0; j < v.size(); j++) { TreeReference affectedRef = (TreeReference)v.elementAt(j); apply(affectedRef, result, instance, f); } } } public void addTarget (TreeReference target) { if (targets.indexOf(target) == -1) targets.addElement(target); } public Vector getTargets () { return targets; } public Vector getTriggers () { Vector relTriggers = expr.getTriggers(); Vector absTriggers = new Vector(); for (int i = 0; i < relTriggers.size(); i++) { absTriggers.addElement(((TreeReference)relTriggers.elementAt(i)).anchor(contextRef)); } return absTriggers; } public boolean equals (Object o) { if (o instanceof Triggerable) { Triggerable t = (Triggerable)o; if (this == t) return true; if (this.expr.equals(t.expr)) { //check triggers Vector Atriggers = this.getTriggers(); Vector Btriggers = t.getTriggers(); //order and quantity don't matter; all that matters is every trigger in A exists in B and vice versa for (int k = 0; k < 2; k++) { Vector v1 = (k == 0 ? Atriggers : Btriggers); Vector v2 = (k == 0 ? Btriggers : Atriggers); for (int i = 0; i < v1.size(); i++) { if (v2.indexOf(v1.elementAt(i)) == -1) { return false; } } } return true; } else { return false; } } else { return false; } } public void readExternal(DataInputStream in, PrototypeFactory pf) throws IOException, DeserializationException { expr = (IConditionExpr)ExtUtil.read(in, new ExtWrapTagged(), pf); contextRef = (TreeReference)ExtUtil.read(in, TreeReference.class, pf); targets = (Vector)ExtUtil.read(in, new ExtWrapList(TreeReference.class), pf); } public void writeExternal(DataOutputStream out) throws IOException { ExtUtil.write(out, new ExtWrapTagged(expr)); ExtUtil.write(out, contextRef); ExtUtil.write(out, new ExtWrapList(targets)); } }