001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.xwork.spring;
006:
007: import com.opensymphony.xwork.ActionInvocation;
008: import com.opensymphony.xwork.config.ExternalReferenceResolver;
009: import com.opensymphony.xwork.config.ReferenceResolverException;
010: import com.opensymphony.xwork.config.entities.ExternalReference;
011: import com.opensymphony.xwork.util.OgnlUtil;
012: import ognl.Ognl;
013: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
014: import org.springframework.context.ApplicationContext;
015: import org.springframework.context.ApplicationContextAware;
016:
017: import java.lang.reflect.Method;
018: import java.util.Iterator;
019: import java.util.List;
020: import java.util.Map;
021:
022: /**
023: * Resolves an xwork external-ref references to a component available from Spring application
024: * context.
025: *
026: * @author Ross
027: */
028: public class SpringExternalReferenceResolver implements
029: ExternalReferenceResolver, ApplicationContextAware {
030: protected ApplicationContext applicationContext;
031:
032: public void setApplicationContext(
033: ApplicationContext applicationContext) {
034: this .applicationContext = applicationContext;
035: }
036:
037: public void resolveReferences(ActionInvocation invocation)
038: throws ReferenceResolverException {
039: if (applicationContext == null)
040: throw new IllegalStateException(
041: "The application context has not been set on this resolver");
042:
043: List externalRefs = invocation.getProxy().getConfig()
044: .getExternalRefs();
045: Object bean;
046: ExternalReference reference;
047:
048: Iterator iter = externalRefs.iterator();
049: while (iter.hasNext()) {
050: reference = (ExternalReference) iter.next();
051: //IF the reference name is null we can can try and look up the
052: // reference based on the type
053: if (reference.getExternalRef() == null) {
054: Class[] types = getParameterTypes(invocation
055: .getAction(), reference.getName());
056: if (types == null || types.length == 0
057: || types.length > 1) {
058: throw new ReferenceResolverException(
059: "Unable to find a method on the action called "
060: + reference.getName()
061: + " that takes a single parameter");
062: } else {
063: String names[] = applicationContext
064: .getBeanNamesForType(types[0]);
065: if (names == null || names.length == 0
066: || names.length > 1) {
067: throw new ReferenceResolverException(
068: "The container is unable to resolve single instance of "
069: + types[0]);
070: } else {
071: reference.setExternalRef(names[0]);
072: }
073: }
074: }
075:
076: try {
077: bean = applicationContext.getBean(reference
078: .getExternalRef());
079: } catch (NoSuchBeanDefinitionException e) {
080: if (reference.isRequired()) {
081: //if a dependacy is required but wasn't found throw an
082: // exception
083: throw new ReferenceResolverException(
084: "Failed to find external reference: "
085: + reference.getExternalRef(), e);
086: } else {
087: return;
088: }
089: }
090:
091: try {
092: Map context = Ognl.createDefaultContext(invocation
093: .getAction());
094: OgnlUtil.setProperty(reference.getName(), bean,
095: invocation.getAction(), context);
096: } catch (Exception e) {
097: throw new ReferenceResolverException(
098: "Failed to set external reference: "
099: + reference.getExternalRef()
100: + " for bean attribute: "
101: + reference.getName() + ". "
102: + e.getMessage(), e);
103: }
104: }
105: }
106:
107: //TODO find a utility class that does this or put it in a utility class
108: //TODO We will also want to cache this info somewhere so we dont execute
109: // each time a request is made
110: private Class[] getParameterTypes(Object bean, String methodName) {
111: if (!methodName.startsWith("set")) {
112: methodName = "set"
113: + methodName.substring(0, 1).toUpperCase()
114: + methodName.substring(1);
115: }
116: Method methods[] = bean.getClass().getMethods();
117:
118: for (int i = 0; i < methods.length; i++) {
119: if (methods[i].getName().equals(methodName)) {
120: return methods[i].getParameterTypes();
121: }
122: }
123: return null;
124: }
125: }
|