package er.extensions.components;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOAssociation;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOElement;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSKeyValueCodingAdditions;
import com.webobjects.foundation.NSMutableArray;
/**
* Sets a keypath to a value. This is useful when you want a part of the page
* rendered with different settings. The value is changed before its children
* will be processed and is re-set to the old value after their processing.<br>
* One way to use it would be in a D2W app, where <code>source="edit"</code>
* and <code>destination=d2wContext.task</code> when you are on a list page.
* Another would be the typical scenario where you iterate over keys of a
* dictionary and you want the corresponding entry. Normally you'd need an
* accessor for that, but using this component you would set
* <code>source=myDict</code>, <code>sourceKeypath=currentyKey</code> and
* <code>destination=currentEntry</code>.
*
* @binding source the source object
* @binding sourceKeypath (optional) the key path off the source object. If
* omitted, the source itself is used.
* @binding destination the destination of the value
* @binding destinationKeypath (optional) the key path off the destination
* object. If omitted, the source itself is used.
* @author ak
*/
public class ERXKeyValueSetter extends ERXDynamicElement {
public ERXKeyValueSetter(String name, NSDictionary<String, WOAssociation> associations, NSMutableArray<WOElement> children) {
super(name, associations, children);
}
private Object setNewValue(WOContext context) {
WOComponent component = context.component();
Object newValue = valueForBinding("source", component);
String sourceKey = stringValueForBinding("sourceKeypath", component);
if (sourceKey != null) {
newValue = NSKeyValueCodingAdditions.Utility.valueForKeyPath(newValue, sourceKey);
}
Object oldValue = valueForBinding("destination", component);
String destinationKey = stringValueForBinding("destinationKeypath", component);
if (destinationKey != null) {
Object destinationTarget = oldValue;
oldValue = NSKeyValueCodingAdditions.Utility.valueForKeyPath(destinationTarget, destinationKey);
NSKeyValueCodingAdditions.Utility.takeValueForKeyPath(destinationTarget, newValue, destinationKey);
} else {
setValueForBinding(newValue, "destination", component);
}
return oldValue;
}
private void restoreOldValue(Object oldValue, WOContext context) {
WOComponent component = context.component();
String destinationKey = stringValueForBinding("destinationKeypath", component);
if (destinationKey != null) {
Object destinationTarget = oldValue;
oldValue = NSKeyValueCodingAdditions.Utility.valueForKeyPath(destinationTarget, destinationKey);
NSKeyValueCodingAdditions.Utility.takeValueForKeyPath(destinationTarget, oldValue, destinationKey);
} else {
setValueForBinding(oldValue, "destination", component);
}
}
@Override
public void takeValuesFromRequest(WORequest request, WOContext context) {
Object oldValue = setNewValue(context);
super.takeValuesFromRequest(request, context);
restoreOldValue(oldValue, context);
}
@Override
public WOActionResults invokeAction(WORequest request, WOContext context) {
Object oldValue = setNewValue(context);
WOActionResults result = super.invokeAction(request, context);
restoreOldValue(oldValue, context);
return result;
}
@Override
public void appendToResponse(WOResponse response, WOContext context) {
Object oldValue = setNewValue(context);
super.appendToResponse(response, context);
restoreOldValue(oldValue, context);
}
}