/*
* 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;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import com.webobjects.directtoweb.Assignment;
import com.webobjects.directtoweb.D2WContext;
import com.webobjects.eocontrol.EOKeyValueUnarchiver;
import er.extensions.foundation.ERXUtilities;
import er.extensions.foundation.ERXValueUtilities;
import er.extensions.localization.ERXLocalizer;
/**
* Abstact super class of most assignments found in
* the ERDirectToWeb framework. This class provides
* default implementations for localization support
* and dynamic method lookup for firing rules.
*/
// ENHANCEME: Should have a default static implementation of decoding an assignment from an unarchiver
// that way all of the subclasses don't have to implement decodeWithKeyValueUnarchiver
// ENHANCEME: Also should have a weak hash map implementation for caching created assignments.
public abstract class ERDAssignment extends Assignment 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;
/** logging supprt */
public final static Logger log = Logger.getLogger("er.directtoweb.rules.ERDAssignment");
/** Cached context class array */
// MOVEME: ERDConstants
public final static Class[] D2WContextClassArray = new Class[] { D2WContext.class };
/**
* Public constructor
* @param u key-value unarchiver used when unarchiving
* from rule files.
*/
public ERDAssignment(EOKeyValueUnarchiver u) { super(u); }
/**
* Public constructor
* @param key context key
* @param value of the assignment
*/
public ERDAssignment(String key, Object value) { super(key,value); }
protected boolean booleanContextValueForKey(D2WContext c, String key, boolean defaultValue) {
return ERXValueUtilities.booleanValueWithDefault(c.valueForKey(key), defaultValue);
}
protected static void logDeprecatedMessage(Class oldClass, Class newClass) {
log.error(oldClass.getName() + " is deprecated, please fix your rules to use " + newClass.getName() + " instead");
}
/**
* Gets the localizer for a given context.
* The default implementation just returns
* the localizer for the current session of
* the given context.
* @param c current context
* @return localizer for the preferred language
* of the session.
*/
public ERXLocalizer localizerForContext(D2WContext c) {
return ERXLocalizer.currentLocalizer();
}
/**
* Returns a localized value for a given key in a given
* context if localization is enabled. This implementation
* calls <code>localizedStringForKeyWithDefault</code> on the
* localizer for the given context.
* @param key to be looked up on the context
* @param c current context
* @return localized version of the given key returning the key
* as the default if a localized version isn't found.
*/
public Object localizedValueForKeyWithDefaultInContext(String key, D2WContext c) {
if (key != null && ERXLocalizer.isLocalizationEnabled()) {
return ERXLocalizer.currentLocalizer().localizedStringForKeyWithDefault(key);
} else {
return key;
}
}
/**
* Returns a localized value for a given key in a given
* context if localization is enabled. This implementation
* calls <code>valueForKeyPath</code> on the
* localizer for the given context.
* @param key to be looked up on the context
* @param c current context
* @return localized version of the given key if localization .
*/
public Object localizedValueForKeyInContext(String key, D2WContext c) {
if(key != null && ERXLocalizer.isLocalizationEnabled()) {
return ERXLocalizer.currentLocalizer().valueForKeyPath(key);
} else {
return key;
}
}
public Object localizedTemplateStringForKeyInContext(String key, D2WContext c) {
if( key != null && ERXLocalizer.isLocalizationEnabled()) {
return ERXLocalizer.currentLocalizer().localizedTemplateStringForKeyWithObject(key, c);
} else {
return key;
}
}
/**
* There are basically two choices to lookup the method to
* be called when an assignment is fired. The first is to
* use the keypath that is being requested to lookup the
* method, i.e. if the context is being asked for the key:
* displayNameForProperty then that method will be called
* on the particular assignment. The second method is to
* use the value of the assignment as the method to be called.
* Using the value of the assignment allows the passing of a
* parameter to your assignment method, this gives the flexibility
* to have several methods for the same key path.
* @param c current context
* @return the name of the method to be called, by default the
* key path of the assignmnet is returned.
*/
public String keyForMethodLookup(D2WContext c) {
return keyPath();
}
/**
* Method called to fire an assignment. This method
* has been enhanced to dynamicly lookup the real
* method to call based on the return value of
* <code>keyForMethodLookup</code>. The default
* implementation will lookup the method based on the
* key path of the assignment. If you are building a
* generic assignment like a BooleanAssignment you
* should override this method seeing as you wouldn't
* care what the key path of the assignment is. If you
* would like to provide a different methodology for the
* method to be fired override the method keyForMethodLookup.
* @param c current D2W context
* @return result of firing the assignment.
*/
@Override
public Object fire(D2WContext c) {
Object result = null;
try {
// ENHANCEME: This method lookup should be staticly cached, something along the
// lines of className-keyForMethod.
Method m = getClass().getMethod(keyForMethodLookup(c), D2WContextClassArray);
result = m.invoke(this, new Object[] { c });
} catch (InvocationTargetException e) {
log.error("InvocationTargetException occurred in ERAssignment: " + e.toString()
+ " keyForMethodLookup(): " + keyForMethodLookup(c) + " target exception: "
+ e.getTargetException()+ " assignment was " + this + "\n\n" + "Target exception backtrace: "
+ ERXUtilities.stackTrace(e.getTargetException()));
} catch (Exception e) {
log.error("Exception occurred in ERDAssignment of class: " + getClass().getName()
+ ": " + e.toString() + " keyForMethodLookup(): " + keyForMethodLookup(c) + " assignment was " + this);
}
return result;
}
}