import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import javax.servlet.http.HttpSession;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.directive.DirectiveConstants;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.runtime.parser.node.Node;
/**
* Example of a velocity directive which can be used to load a JavaBean into a velocity context
* so that it can be accessed in a template.
* Note: this needs to be added to the properties of the velocity engine before it is initialised using:
*
* ve.setProperty("userdirective", ?UseBeanDirective?);
*
* @author Jason R Briggs
*/
public class UseBeanDirective extends Directive {
private static final String APPLICATION_SCOPE = "application";
private static final String EMPTY = "";
private static final String PAGE_SCOPE = "page";
private static final String QUOTES = "\"'";
private static final String SESSION_SCOPE = "session";
private static final String USEBEAN = "usebean";
private static final int APPLICATION = 1;
private static final int SESSION = 2;
private static final int PAGE = 3;
private static HashMap beanClasses = new HashMap();
private static HashMap beanNames = new HashMap();
private static HashMap appScopeBeans = new HashMap();
public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException {
int count = node.jjtGetNumChildren();
String name = node.jjtGetChild(0).getFirstToken().toString();
String className = node.jjtGetChild(1).getFirstToken().toString();
int scope;
String tmp;
if (count >= 3) {
tmp = node.jjtGetChild(2).getFirstToken().toString();
}
else {
tmp = EMPTY;
}
// set the scope variable
if (tmp.equals(APPLICATION_SCOPE)) {
scope = APPLICATION;
}
else if (tmp.equals(SESSION_SCOPE)) {
scope = SESSION;
}
else {
scope = PAGE;
}
// cache the classnames, so we don't try to load the classes every time
if (!beanClasses.containsKey(className)) {
synchronized (beanClasses) {
if (!beanClasses.containsKey(className)) {
try {
String cn = remove(className, QUOTES);
Class c = Class.forName(cn);
beanClasses.put(className, c);
}
catch (Exception e) {
e.printStackTrace();
throw new MethodInvocationException(e.getMessage(), e, getName());
}
}
}
}
HttpSession session = null;
try {
Object obj = null;
// if application scope, we use a hashmap to store the beans
if (scope == APPLICATION && appScopeBeans.containsKey(name)) {
obj = appScopeBeans.get(name);
}
// if session scope, try to get the bean from the user's session
// (note: stored in the velocity context)
else if (scope == SESSION) {
session = (HttpSession)context.get(SESSION_SCOPE);
obj = session.getAttribute(name);
}
// if we haven't managed to get an object by now, we'll
// just instantiate it using the class
if (obj == null) {
Class c = (Class)beanClasses.get(className);
obj = c.newInstance();
}
// put the object into the context
context.put(name, obj);
// depending upon the scope, put it in the cache of app beans
// or into the session
if (scope == APPLICATION && !appScopeBeans.containsKey(name)) {
appScopeBeans.put(name, obj);
}
else if (scope == SESSION) {
session.setAttribute(name, obj);
}
}
catch (Exception e) {
throw new MethodInvocationException(e.getMessage(), e, getName());
}
return true;
}
public int getType() {
return DirectiveConstants.LINE;
}
public String getName() {
return USEBEAN;
}
private static final String remove(String s, String chars) {
if (s == null) {
return EMPTY;
}
else {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (chars.indexOf(c) < 0) {
sb.append(c);
}
}
return sb.toString();
}
}
}