
org.directwebremoting.fluent.FluentConfigurator Maven / Gradle / Ivy
package org.directwebremoting.fluent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.directwebremoting.AjaxFilter;
import org.directwebremoting.Container;
import org.directwebremoting.extend.AccessControl;
import org.directwebremoting.extend.AjaxFilterManager;
import org.directwebremoting.extend.Configurator;
import org.directwebremoting.extend.Converter;
import org.directwebremoting.extend.ConverterManager;
import org.directwebremoting.extend.Creator;
import org.directwebremoting.extend.CreatorManager;
import org.directwebremoting.impl.SignatureParser;
import org.directwebremoting.util.LocalUtil;
import org.directwebremoting.util.Logger;
/**
* A {@link Configurator} that used the FluentInterface style as
* described by
* Martin Fowler.
*
* To wire up the configuration programatically rather than having to use
* dwr.xml
. In order to use this style, you'll need to:
*
*
* - Create a concrete implementation of {@link FluentConfigurator} which
* implements the {@link #configure()} method.
* - Add an init param '
customConfigurator
' to the DWR servlet in
* web.xml
to point at your new class.
*
*
* The implementation of {@link #configure()} will look something like
* this:
*
*
* public void configure() {
* withConverterType("dog", "com.yourcompany.beans.Dog");
* withCreatorType("ejb", "com.yourcompany.dwr.creator.EJBCreator");
* withCreator("new", "ApartmentDAO")
* .addParam("scope", "session")
* .addParam("class", "com.yourcompany.dao.ApartmentDAO")
* .exclude("saveApartment")
* .withAuth("method", "role");
* withCreator("struts", "DogDAO")
* .addParam("clas", "com.yourcompany.dao.DogDAO")
* .include("getDog")
* .include("getColor");
* withConverter("dog", "*.Dog")
* .addParam("name", "value");
* withSignature()
* .addLine("import java.util.List;")
* .addLine("import com.example.Check;")
* .addLine("Check.setLotteryResults(List nos);");
* }
*
* @author Aaron Johnson [ajohnson at cephas dot net / http://cephas.net/blog]
* @author Joe Walker [joe at getahead dot ltd dot uk]
*/
public abstract class FluentConfigurator implements Configurator
{
/**
* This method is used to configure DWR using the fluent style.
*/
public abstract void configure();
/**
* Add a new {@link Converter} definition.
* @param id The id referred to by the {@link #withConverter(String, String)}
* @param converterClassName The implementation of {@link Converter} to instansitate.
* @return this
to continue the fluency
*/
public FluentConfigurator withConverterType(String id, String converterClassName)
{
setState(STATE_INIT_CONVERT);
converterManager.addConverterType(id, converterClassName);
return this;
}
/**
* Use a {@link Converter} to instansiate a class
* @param newConverter A predefined {@link Converter} or one defined by
* {@link #withConverterType(String, String)}.
* @param newMatch The javascript name of this component
* @return this
to continue the fluency
*/
public FluentConfigurator withConverter(String newConverter, String newMatch)
{
setState(STATE_ALLOW_CONVERT);
this.converter = newConverter;
this.match = newMatch;
return this;
}
/**
* Add a new {@link Creator} definition.
* @param id The id referred to by the {@link #withCreator(String, String)}
* @param creatorClassName The implementation of {@link Creator} to instansitate.
* @return this
to continue the fluency
*/
public FluentConfigurator withCreatorType(String id, String creatorClassName)
{
setState(STATE_INIT_CREATE);
creatorManager.addCreatorType(id, creatorClassName);
return this;
}
/**
* Use a {@link Creator} to instansiate a class
* @param newTypeName A predefined {@link Creator} or one defined by
* {@link #withCreatorType(String, String)}.
* @param newScriptName The javascript name of this component
* @return this
to continue the fluency
*/
public FluentConfigurator withCreator(String newTypeName, String newScriptName)
{
setState(STATE_ALLOW_CREATE);
this.typeName = newTypeName;
this.scriptName = newScriptName;
return this;
}
/**
* @param newFilterClassName filter class name
* @return this
to continue the fluency
*/
public FluentConfigurator withFilter(String newFilterClassName)
{
setState(STATE_ALLOW_FILTER);
this.filterClassName = newFilterClassName;
return this;
}
/**
* Add a parameter to whatever is being configured.
* @param name The name of the parameter
* @param value The value of the parameter
* @return this
to continue the fluency
*/
public FluentConfigurator addParam(String name, String value)
{
if (params == null)
{
params = new HashMap();
}
params.put(name, value);
return this;
}
/**
* Add a filter to whatever is being configured.
* @param newFilterClassName The class to add as a filter
* @return this
to continue the fluency
*/
public FluentConfigurator addFilter(String newFilterClassName)
{
if (filters == null)
{
filters = new ArrayList();
}
filters.add(newFilterClassName);
return this;
}
/**
* Add an include rule to a {@link Creator}.
* This should be used during a {@link #withCreator(String, String)} call.
* @param methodName The method name to be allowed
* @return this
to continue the fluency
*/
public FluentConfigurator include(String methodName)
{
accessControl.addIncludeRule(scriptName, methodName);
return this;
}
/**
* Add an exclude rule to a {@link Creator}
* This should be used during a {@link #withCreator(String, String)} call.
* @param methodName The method name to be dis-allowed
* @return this
to continue the fluency
*/
public FluentConfigurator exclude(String methodName)
{
accessControl.addExcludeRule(scriptName, methodName);
return this;
}
/**
* Add an authorization rule to a {@link Creator}
* This should be used during a {@link #withCreator(String, String)} call.
* @param methodName The method name to have a required role
* @param role The required role for the given method
* @return this
to continue the fluency
*/
public FluentConfigurator withAuth(String methodName, String role)
{
accessControl.addRoleRestriction(scriptName, methodName, role);
return this;
}
/**
* Add lines to a signature.
* @return this
to continue the fluency
*/
public FluentConfigurator withSignature()
{
setState(STATE_SIGNATURE);
return this;
}
/**
* Add lines to a signature.
* @param line The line of text to add to the signature configuration
* @return this
to continue the fluency
*/
public FluentConfigurator addLine(String line)
{
if (null == line)
{
return this;
}
if (null == signature)
{
signature = new StringBuffer();
}
signature.append(line);
signature.append(System.getProperty("line.separator"));
return this;
}
/**
* Because some parts of the configuration require multiple steps, the instance
* needs to maintain a state across invocations. Whenever the state is changed
* by calling this method, the instance will 'flush' anything in the queue
* applicable to that state EVEN IF the state itself doesn't change. Thus, it's
* important that the child methods don't call setState() when being invoked.
* @param state The new state. See the STATE_* constants.
*/
private void setState(int state)
{
flush();
this.state = state;
}
/**
* Takes and configuration that is in progress and calls methods on the
* various objects to enable that configuration.
*/
private void flush()
{
switch (state)
{
case STATE_INIT_CONVERT:
// do nothing;
break;
case STATE_INIT_CREATE:
// do nothing;
break;
case STATE_ALLOW_CONVERT:
try
{
if (params == null)
{
converterManager.addConverter(match, converter, EMPTY_MAP);
}
else
{
converterManager.addConverter(match, converter, params);
}
}
catch (Exception e)
{
log.warn("Failed to add converter of type='" + converter + "', match=" + match + ": ", e);
}
params = null;
match = null;
converter = null;
break;
case STATE_ALLOW_CREATE:
try
{
if (params == null)
{
creatorManager.addCreator(scriptName, typeName, EMPTY_MAP);
}
else
{
creatorManager.addCreator(scriptName, typeName, params);
}
if (filters != null)
{
for (Iterator it = filters.iterator(); it.hasNext();)
{
String className = (String) it.next();
AjaxFilter filter = (AjaxFilter) LocalUtil.classNewInstance(scriptName, className, AjaxFilter.class);
if (filter != null)
{
LocalUtil.setParams(filter, Collections.EMPTY_MAP, Collections.EMPTY_LIST);
ajaxFilterManager.addAjaxFilter(filter, scriptName);
}
}
}
}
catch (Exception e)
{
log.warn("Failed to add creator of type='" + typeName + "', scriptName=" + scriptName + ": ", e);
}
params = null;
scriptName = null;
typeName = null;
filters = null;
break;
case STATE_ALLOW_FILTER:
try
{
Class impl = LocalUtil.classForName(filterClassName);
AjaxFilter object = (AjaxFilter) impl.newInstance();
if (params != null) {
LocalUtil.setParams(object, params, Collections.EMPTY_LIST);
}
ajaxFilterManager.addAjaxFilter(object);
}
catch (ClassCastException ex)
{
log.error(filterClassName + " does not implement " + AjaxFilter.class.getName(), ex);
}
catch (NoClassDefFoundError ex)
{
log.info("Missing class for filter (class='" + filterClassName + "'). Cause: " + ex.getMessage());
}
catch (Exception ex)
{
log.error("Failed to add filter: class=" + filterClassName, ex);
}
params = null;
filterClassName = null;
break;
case STATE_SIGNATURE:
if (signature != null && signature.length() > 0)
{
SignatureParser sigp = new SignatureParser(converterManager, creatorManager);
sigp.parse(signature.toString());
}
break;
default:
break;
}
}
/* (non-Javadoc)
* @see org.directwebremoting.Configurator#configure(org.directwebremoting.Container)
*/
public void configure(Container container)
{
converterManager = (ConverterManager) container.getBean(ConverterManager.class.getName());
ajaxFilterManager = (AjaxFilterManager) container.getBean(AjaxFilterManager.class.getName());
accessControl = (AccessControl) container.getBean(AccessControl.class.getName());
creatorManager = (CreatorManager) container.getBean(CreatorManager.class.getName());
configure();
setState(STATE_COMPLETE);
}
/**
* Used for
*/
private String typeName = null;
/**
* Used for
*/
private String scriptName = null;
/**
* Used for
*/
private String filterClassName = null;
/**
* Used for
*/
private String converter = null;
/**
* Used for
*/
private String match = null;
/**
* holds name / value pairs used in
*/
private Map params = null;
/**
* holds classNames of filters used in
*/
private List filters = null;
/**
* holds signature lines
*/
private StringBuffer signature = null;
/**
* What section of a configuration are we in?
*/
private int state = -1;
/**
* JDK5: we can convert this to Collections.emptyMap();
*/
private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap());
/**
* What AjaxFilters apply to which Ajax calls?
*/
private AjaxFilterManager ajaxFilterManager = null;
/**
* The ConverterManager that we are configuring
*/
private ConverterManager converterManager = null;
/**
* The AccessControl that we are configuring
*/
private AccessControl accessControl = null;
/**
* The CreatorManager that we are configuring
*/
private CreatorManager creatorManager = null;
/**
* {@link #state} to say we are working in {@link #withCreatorType(String, String)}
*/
private static final int STATE_INIT_CREATE = 0;
/**
* {@link #state} to say we are working in {@link #withConverterType(String, String)}
*/
private static final int STATE_INIT_CONVERT = 1;
/**
* {@link #state} to say we are working in {@link #withCreator(String, String)}
*/
private static final int STATE_ALLOW_CREATE = 2;
/**
* {@link #state} to say we are working in {@link #withFilter(String)}
*/
private static final int STATE_ALLOW_FILTER = 3;
/**
* {@link #state} to say we are working in {@link #withConverter(String, String)}
*/
private static final int STATE_ALLOW_CONVERT = 4;
/**
* {@link #state} to say we are working in {@link #withSignature()}
*/
private static final int STATE_SIGNATURE = 5;
/**
* {@link #state} to say {@link #configure()} has completed
*/
private static final int STATE_COMPLETE = 6;
/**
* The log stream
*/
private static final Logger log = Logger.getLogger(FluentConfigurator.class);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy