/* * Copyright (C) NetStruxr, Inc. All rights reserved. * * This software is published under the terms of the NetStruxr * Public Software License version 0.5, a copy of which has been * included with this distribution in the LICENSE.NPL file. */ package er.directtoweb.assignments.delayed; import java.util.Enumeration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.directtoweb.D2WContext; import com.webobjects.eocontrol.EOKeyValueUnarchiver; import com.webobjects.eocontrol.EOQualifier; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSKeyValueCoding; import com.webobjects.foundation.NSMutableArray; import er.directtoweb.assignments.ERDComputingAssignmentInterface; /** * DelayedConditionalAssignment expects a value dictionary that contains the * following keys: * - qualifierFormat (see EOQualifier for more info) * - args: the arguments used by the qualifier format * - trueValue: the value used if the condition returns true * - falseValue: the value used if the condition returns false * To specify a null value for true and false values simply ommit the * corresponding key. * The condition is evaluated * every time that the propertyKey is requested thus making the rule system * a lot more dynamic. */ public class ERDDelayedConditionalAssignment extends ERDDelayedAssignment implements ERDComputingAssignmentInterface { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; private final static Logger log = LoggerFactory.getLogger("er.directtoweb.rules.DelayedConditionalAssignment"); /** * Static constructor required by the EOKeyValueUnarchiver * interface. If this isn't implemented then the default * behavior is to construct the first super class that does * implement this method. Very lame. * @param eokeyvalueunarchiver to be unarchived * @return decoded assignment of this class */ public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver eokeyvalueunarchiver) { return new ERDDelayedConditionalAssignment(eokeyvalueunarchiver); } /** * Public constructor * @param u key-value unarchiver used when unarchiving * from rule files. */ public ERDDelayedConditionalAssignment(EOKeyValueUnarchiver u) { super(u); } /** * Public constructor * @param key context key * @param value of the assignment */ public ERDDelayedConditionalAssignment(String key, Object value) { super(key,value); } public NSArray _dependentKeys; /** * Implementation of the {@link er.directtoweb.assignments.ERDComputingAssignmentInterface}. This * assignment depends upon all of the qualifier keys from the formed * qualifier of the value of this assignment. This array of keys is * used when constructing the significant keys for the passed in keyPath. * @param keyPath to compute significant keys for. * @return array of context keys this assignment depends upon. */ public NSArray dependentKeys(String keyPath) { if (_dependentKeys==null) { NSDictionary conditionAssignment; try { conditionAssignment = (NSDictionary)value(); } catch (ClassCastException e) { log.error("expected a NSDictionary object but received {}", value(), e); throw e; } String qualFormat = (String)conditionAssignment.objectForKey("qualifierFormat"); NSArray args = (NSArray)conditionAssignment.objectForKey("args"); log.debug("parsing {}", qualFormat); EOQualifier qualifier = EOQualifier.qualifierWithQualifierFormat(qualFormat, args); if (log.isDebugEnabled()) log.debug("Qualifier keys: {}", qualifier.allQualifierKeys()); _dependentKeys=qualifier.allQualifierKeys().allObjects(); } return _dependentKeys; } /** * This method is called whenever the propertyKey is requested, * but the value in the cache is actually a rule. */ @Override public Object fireNow(D2WContext c) { Object result = null; NSDictionary conditionAssignment = (NSDictionary)value(); String qualFormat = (String)conditionAssignment.objectForKey("qualifierFormat"); NSArray args = (NSArray)conditionAssignment.objectForKey("args"); if (args != null && args.count() > 0) { // Need to resolve the args from the context. NSMutableArray argHolder = new NSMutableArray(args.count()); for (Enumeration argEnumerator = args.objectEnumerator(); argEnumerator.hasMoreElements();) { Object arg = argEnumerator.nextElement(); if (arg instanceof String && ((String)arg).length() > 1 && ((String)arg).charAt(0) == '^') { Object value = c.valueForKeyPath(((String)arg).substring(1, ((String)arg).length())); if (value == null) value = NSKeyValueCoding.NullValue; argHolder.addObject(value); } else { argHolder.addObject(arg); } } } if (log.isDebugEnabled()) { log.debug("Entity '{}'", c.entity().name()); log.debug("Object {}", c.valueForKey("object")); log.debug("qualifierFormat {}", qualFormat); log.debug("args {}", args); } EOQualifier qualifier = EOQualifier.qualifierWithQualifierFormat(qualFormat, args); if (log.isDebugEnabled()) { log.debug("Qualifier keys: {}", qualifier.allQualifierKeys()); log.debug("Qualifier: {}", qualifier); log.debug("DelayedConditonalQualifier: {}", qualifier); } if (qualifier.evaluateWithObject(c)) { result = conditionAssignment.objectForKey("trueValue"); log.debug("trueValue = {}", result); } else { result = conditionAssignment.objectForKey("falseValue"); log.debug("falseValue = {}", result); } return result; } }