use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class LatestDagBase method doEvaluateTriggerables.
protected Set<QuickTriggerable> doEvaluateTriggerables(FormInstance mainInstance, EvaluationContext evalContext, Set<QuickTriggerable> tv, TreeReference anchorRef, Set<QuickTriggerable> alreadyEvaluated) {
// tv should now contain all of the triggerable components which are
// going
// to need to be addressed
// by this update.
// 'triggerables' is topologically-ordered by dependencies, so evaluate
// the triggerables in 'tv'
// in the order they appear in 'triggerables'
Set<QuickTriggerable> fired = new HashSet<QuickTriggerable>();
Map<TreeReference, List<TreeReference>> firedAnchors = new LinkedHashMap<TreeReference, List<TreeReference>>();
for (QuickTriggerable qt : triggerablesDAG) {
if (tv.contains(qt) && !alreadyEvaluated.contains(qt)) {
List<TreeReference> affectedTriggers = qt.t.findAffectedTriggers(firedAnchors);
if (affectedTriggers.isEmpty()) {
affectedTriggers.add(anchorRef);
}
List<EvaluationResult> evaluationResults = evaluateTriggerable(mainInstance, evalContext, qt, affectedTriggers);
if (evaluationResults.size() > 0) {
fired.add(qt);
for (EvaluationResult evaluationResult : evaluationResults) {
TreeReference affectedRef = evaluationResult.getAffectedRef();
TreeReference key = affectedRef.genericize();
List<TreeReference> values = firedAnchors.get(key);
if (values == null) {
values = new ArrayList<TreeReference>();
firedAnchors.put(key, values);
}
values.add(affectedRef);
}
}
fired.add(qt);
}
}
return fired;
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class LatestDagBase method evaluateTriggerable.
/**
* Step 3 in DAG cascade. evaluate the individual triggerable expressions
* against the anchor (the value that changed which triggered recomputation)
*
* @param qt
* The triggerable to be updated
* @param anchorRefs
*/
private List<EvaluationResult> evaluateTriggerable(FormInstance mainInstance, EvaluationContext evalContext, QuickTriggerable qt, List<TreeReference> anchorRefs) {
List<EvaluationResult> evaluationResults = new ArrayList<EvaluationResult>(0);
// Contextualize the reference used by the triggerable against the
// anchor
Set<TreeReference> updatedContextRef = new HashSet<TreeReference>();
for (TreeReference anchorRef : anchorRefs) {
TreeReference contextRef = qt.t.contextualizeContextRef(anchorRef);
if (updatedContextRef.contains(contextRef)) {
continue;
}
try {
// Now identify all of the fully qualified nodes which this
// triggerable
// updates. (Multiple nodes can be updated by the same trigger)
List<TreeReference> qualifiedList = evalContext.expandReference(contextRef);
// Go through each one and evaluate the trigger expression
for (TreeReference qualified : qualifiedList) {
EvaluationContext ec = new EvaluationContext(evalContext, qualified);
evaluationResults.addAll(qt.t.apply(mainInstance, ec, qualified));
}
boolean fired = evaluationResults.size() > 0;
if (fired) {
accessor.getEventNotifier().publishEvent(new Event(qt.t.getClass().getSimpleName(), evaluationResults));
}
updatedContextRef.add(contextRef);
} catch (Exception e) {
throw new RuntimeException("Error evaluating field '" + contextRef.getNameLast() + "': " + e.getMessage(), e);
}
}
return evaluationResults;
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class Safe2014DagImpl method evaluateChildrenTriggerables.
private void evaluateChildrenTriggerables(FormInstance mainInstance, EvaluationContext evalContext, TreeElement newNode, boolean createdOrDeleted, Set<QuickTriggerable> alreadyEvaluated) {
// iterate into the group children and evaluate any triggerables that
// depend one them, if they are not already calculated.
int numChildren = newNode.getNumChildren();
for (int i = 0; i < numChildren; i++) {
TreeReference anchorRef = newNode.getChildAt(i).getRef();
Set<QuickTriggerable> childTriggerables = triggerTriggerables(mainInstance, evalContext, anchorRef, alreadyEvaluated);
publishSummary((createdOrDeleted ? "Created" : "Deleted"), anchorRef, childTriggerables);
}
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class Safe2014DagImpl method finalizeTriggerables.
/**
* Finalize the DAG associated with the form's triggered conditions. This
* will create the appropriate ordering and dependencies to ensure the
* conditions will be evaluated in the appropriate orders.
*
* @throws IllegalStateException
* - If the trigger ordering contains an illegal cycle and the
* triggers can't be laid out appropriately
*/
@Override
public void finalizeTriggerables(FormInstance mainInstance, EvaluationContext evalContext) throws IllegalStateException {
//
// DAGify the triggerables based on dependencies and sort them so that
// triggerables come only after the triggerables they depend on
//
ArrayList<QuickTriggerable> vertices = new ArrayList<QuickTriggerable>(unorderedTriggerables);
triggerablesDAG.clear();
ArrayList<QuickTriggerable[]> partialOrdering = new ArrayList<QuickTriggerable[]>();
HashSet<QuickTriggerable> newDestinationSet = new HashSet<QuickTriggerable>();
for (QuickTriggerable qt : vertices) {
HashSet<QuickTriggerable> deps = new HashSet<QuickTriggerable>();
newDestinationSet.clear();
fillTriggeredElements(mainInstance, evalContext, qt, deps, newDestinationSet);
// remove any self-reference if we have one...
deps.remove(qt);
for (QuickTriggerable qu : deps) {
QuickTriggerable[] edge = { qt, qu };
partialOrdering.add(edge);
}
// save for aggressive 2014 behavior
qt.t.setImmediateCascades(deps);
}
ArrayList<QuickTriggerable> orderedRoots = new ArrayList<QuickTriggerable>();
HashSet<QuickTriggerable> roots = new HashSet<QuickTriggerable>(vertices.size());
int waveCount = -1;
while (vertices.size() > 0) {
++waveCount;
// determine root nodes
roots.clear();
roots.addAll(vertices);
for (int i = 0; i < partialOrdering.size(); i++) {
QuickTriggerable[] edge = partialOrdering.get(i);
roots.remove(edge[1]);
}
// if no root nodes while graph still has nodes, graph has cycles
if (roots.size() == 0) {
String hints = "";
for (QuickTriggerable qt : vertices) {
for (TreeReference r : qt.t.getTargets()) {
hints += "\n" + r.toString(true);
}
}
String message = "Cycle detected in form's relevant and calculation logic!";
if (!hints.equals("")) {
message += "\nThe following nodes are likely involved in the loop:" + hints;
}
throw new IllegalStateException(message);
}
// order the root nodes - so the order is fixed
orderedRoots.clear();
orderedRoots.addAll(roots);
Collections.sort(orderedRoots, QuickTriggerable.quickTriggerablesRootOrdering);
// add them to the triggerablesDAG.
for (int i = 0; i < orderedRoots.size(); i++) {
QuickTriggerable root = orderedRoots.get(i);
root.t.setWaveCount(waveCount);
triggerablesDAG.add(root);
vertices.remove(root);
}
for (int i = partialOrdering.size() - 1; i >= 0; i--) {
QuickTriggerable[] edge = partialOrdering.get(i);
if (roots.contains(edge[0]))
partialOrdering.remove(i);
}
}
//
// build the condition index for repeatable nodes
//
conditionRepeatTargetIndex.clear();
for (QuickTriggerable qt : triggerablesDAG) {
if (qt.t instanceof Condition) {
List<TreeReference> targets = qt.t.getTargets();
for (TreeReference target : targets) {
if (mainInstance.getTemplate(target) != null) {
conditionRepeatTargetIndex.put(target, qt);
}
}
}
}
// printTriggerables();
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class Safe2014DagImpl method addChildrenOfReference.
/**
* This is a utility method to get all of the references of a node. It can
* be replaced when we support dependent XPath Steps (IE: /path/to//)
*/
private void addChildrenOfReference(FormInstance mainInstance, EvaluationContext evalContext, TreeReference original, Set<TreeReference> toAdd, boolean expandRepeatables) {
// original has already been added to the 'toAdd' list.
TreeElement repeatTemplate = expandRepeatables ? mainInstance.getTemplatePath(original) : null;
if (repeatTemplate != null) {
for (int i = 0; i < repeatTemplate.getNumChildren(); ++i) {
TreeElement child = repeatTemplate.getChildAt(i);
toAdd.add(child.getRef().genericize());
addChildrenOfElement(mainInstance, evalContext, child, toAdd, expandRepeatables);
}
} else {
List<TreeReference> refSet = evalContext.expandReference(original);
for (TreeReference ref : refSet) {
addChildrenOfElement(mainInstance, evalContext, evalContext.resolveReference(ref), toAdd, expandRepeatables);
}
}
}
Aggregations