Saturday, June 09, 2007

XWORK external reference resolver

XWORK external reference resolver


Sometimes xwork action classes needs to be wired with external references, for example spring maintained resources. In such cases the dependencies are defined using a <external-ref> tag. For example: see below a sample xwork configuration wherein an action class needs to be wired with a spring maintained datasource:



<package name="auditIntegration" extends="auditResultRun">
<action name="executeAllAudits" class="com.xxx.AllSchemasAuditAction">
<external-ref name="dataSource" required="true">/db/dw/DataSource</external-ref>
<param name="nestedActionName">executeAudit</param>
</action>
</package>


In such cases external resolvers need to be specified which perform the property setting. XWORK provides a specification using com.opensymphony.xwork.config.ExternalReferenceResolver and provides a default implementation com.opensymphony.xwork.spring.SpringExternalReferenceResolver for spring reference resolver. Custom implementation can be provided to resolve other external references like JNDI dependencies into xwork etc. In any case these external resolvers must be explicitly declared to be used by XWORK. See below for a sample declaration (extends the webwork default config):



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">
<xwork>
<include file="webwork-default.xml"/>
<package name="xwork-common" extends="webwork-default"
externalReferenceResolver="com.xxx.SpringExternalReferenceResolver">
</package>
</xwork>



Sample implementation for the external resolver (code adapted from XWORK com.opensymphony.xwork.spring.SpringExternalReferenceResolver implementation):



public class SpringExternalReferenceResolver implements com.opensymphony.xwork.config.ExternalReferenceResolver
{
private static final Logger log = Logger.getLogger(SpringExternalReferenceResolver.class);

/**
* resolve the references for this invocation
* @param invocation the invocation to resolve
* @throws ReferenceResolverException if we had issues.
*/
public void resolveReferences(ActionInvocation invocation) throws ReferenceResolverException
{
ApplicationContext ctx = {{get app context handle here}};
if (ctx == null)
throw new IllegalStateException("application context has not been set for this "
+ "external reference resolver!");

List externalRefs = invocation.getProxy().getConfig().getExternalRefs();
for (Iterator iter = externalRefs.iterator(); iter.hasNext(); )
{
ExternalReference reference = (ExternalReference) iter.next();
if (log.isDebugEnabled())
log.debug("resolving " + reference.getName() + " to " + reference.getExternalRef());
if (reference.getExternalRef() == null)
{
throw new ReferenceResolverException(
"reference " + reference.getName() + " has no external ref");
}

Object bean = null;
try
{
// no such bean exception
bean = ctx.getBean(reference.getExternalRef());
if (log.isDebugEnabled())
log.debug("resolved " + reference.getExternalRef() + " to " +
(bean != null ? bean.getClass().toString() : "null"));

// other exceptions
Map context = Ognl.createDefaultContext(invocation.getAction());
if (log.isDebugEnabled())
log.debug("setting bean into property " + reference.getName() + " of " +
invocation.getAction().getClass());

// unbelievably, this actually throws a RuntimeException! Unbelievable
OgnlUtil.setProperty(reference.getName(), bean, invocation.getAction(),
context, true);
if (log.isDebugEnabled())
log.debug("resolved " + reference.getName() + " to " +
reference.getExternalRef() + ": " + bean);
}
catch (NoSuchBeanDefinitionException e)
{
if (reference.isRequired())
{
//if a dependency is required but wasn't found throw an exception
throw new ReferenceResolverException(
"Failed to find external reference: " + reference.getExternalRef(), e);
}
else
{
log.warn("Bean '" + reference.getExternalRef() +
"' could not be found in spring");
// just keep going
continue;
}
}
catch (Exception e)
{
throw new ReferenceResolverException(
"Failed to set external reference: " + reference.getExternalRef()
+ " for bean attribute: " + reference.getName() + ": " + e.getMessage() +
" bean hashcode: " + (bean != null ? bean.getClass().hashCode() : -1), e);
}
}
if (log.isDebugEnabled())
log.debug("external reference resolution for " + invocation.getAction() + " complete.");
}


}

No comments:

Post a Comment