Moved MethodEndpoint functionality to core-tiger module. (Fixed #SWS-20)

This commit is contained in:
Arjen Poutsma
2007-04-11 13:21:04 +00:00
parent f07ea88b35
commit 68347ecdd2
28 changed files with 264 additions and 192 deletions

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.server.endpoint;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.util.Assert;
/**
* Represents a bean method that will be invoked as part of an incoming Web service message.
* <p/>
* Consists of a {@link Method}, and a bean {@link Object}.
*
* @author Arjen Poutsma
*/
public final class MethodEndpoint {
private Object bean;
private Method method;
/**
* Constructs a new method endpoint with the given bean and method.
*
* @param bean the object bean
* @param method the method
*/
public MethodEndpoint(Object bean, Method method) {
Assert.notNull(bean, "bean must not be null");
Assert.notNull(method, "method must not be null");
this.bean = bean;
this.method = method;
}
/**
* Constructs a new method endpoint with the given bean, method name and parameters.
*
* @param bean the object bean
* @param methodName the method name
* @param parameterTypes the method parameter types
*/
public MethodEndpoint(Object bean, String methodName, Class[] parameterTypes) throws NoSuchMethodException {
Assert.notNull(bean, "bean must not be null");
Assert.notNull(methodName, "method must not be null");
this.bean = bean;
method = bean.getClass().getMethod(methodName, parameterTypes);
}
/** Returns the object bean for this method endpoint. */
public Object getBean() {
return bean;
}
/** Returns the method for this method endpoint. */
public Method getMethod() {
return method;
}
/**
* Invokes this method endpoint with the given arguments.
*
* @param args the arguments
* @return the invocation result
* @throws IllegalAccessException when there is insufficient access to invoke the method
* @throws InvocationTargetException when the method invocation results in an exception
*/
public Object invoke(Object[] args) throws IllegalAccessException, InvocationTargetException {
return method.invoke(bean, args);
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o != null && o instanceof MethodEndpoint) {
MethodEndpoint other = (MethodEndpoint) o;
return bean.equals(other.bean) && method.equals(other.method);
}
return false;
}
public int hashCode() {
return 31 * bean.hashCode() + method.hashCode();
}
public String toString() {
return method.toString();
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointAdapter;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Abstract base class for {@link EndpointAdapter} implementations that support {@link MethodEndpoint}s. Contains
* template methods for handling these method endpoints.
*
* @author Arjen Poutsma
*/
public abstract class AbstractMethodEndpointAdapter extends TransformerObjectSupport implements EndpointAdapter {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
/**
* Delegates to {@link #supportsInternal(org.springframework.ws.server.endpoint.MethodEndpoint)}.
*
* @param endpoint endpoint object to check
* @return whether or not this adapter can adapt the given endpoint
*/
public final boolean supports(Object endpoint) {
return endpoint instanceof MethodEndpoint && supportsInternal((MethodEndpoint) endpoint);
}
/**
* Delegates to {@link #invokeInternal(org.springframework.ws.context.MessageContext,MethodEndpoint)}.
*
* @param messageContext the current message context
* @param endpoint the endpoint to use. This object must have previously been passed to the
* <code>supportsInternal</code> method of this interface, which must have returned
* <code>true</code>
* @throws Exception in case of errors
*/
public final void invoke(MessageContext messageContext, Object endpoint) throws Exception {
invokeInternal(messageContext, (MethodEndpoint) endpoint);
}
/**
* Given a method endpoint, return whether or not this adapter can support it.
*
* @param methodEndpoint method endpoint to check
* @return whether or not this adapter can adapt the given method
*/
protected abstract boolean supportsInternal(MethodEndpoint methodEndpoint);
/**
* Use the given method endpoint to handle the request.
*
* @param messageContext the current message context
* @param methodEndpoint the method endpoint to use
* @throws Exception in case of errors
*/
protected abstract void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint)
throws Exception;
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.mapping;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContextException;
import org.springframework.core.JdkVersion;
import org.springframework.util.StringUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
/**
* Abstract base class for {@link MethodEndpoint} mappings.
* <p/>
* Subclasses typically implement {@link org.springframework.beans.factory.config.BeanPostProcessor} to look for beans
* that qualify as enpoint. The methods of this bean are then registered under a specific key with {@link
* #registerEndpoint(String,MethodEndpoint)}.
*
* @author Arjen Poutsma
*/
public abstract class AbstractMethodEndpointMapping extends AbstractEndpointMapping {
/** Keys are Strings, values are {@link MethodEndpoint}s. */
private final Map endpointMap = new HashMap();
/**
* Lookup an endpoint for the given message. The extraction of the endpoint key is delegated to the concrete
* subclass.
*
* @return the looked up endpoint, or <code>null</code>
* @see #getLookupKeyForMessage(MessageContext)
*/
protected Object getEndpointInternal(MessageContext messageContext) throws Exception {
String key = getLookupKeyForMessage(messageContext);
if (!StringUtils.hasLength(key)) {
return null;
}
if (logger.isDebugEnabled()) {
logger.debug("Looking up endpoint for [" + key + "]");
}
return lookupEndpoint(key);
}
/**
* Returns the the endpoint keys for the given message context.
*
* @return the registration keys
*/
protected abstract String getLookupKeyForMessage(MessageContext messageContext) throws Exception;
/**
* Looks up an endpoint instance for the given keys. All keys are tried in order.
*
* @param key key the beans are mapped to
* @return the associated endpoint instance, or <code>null</code> if not found
*/
protected MethodEndpoint lookupEndpoint(String key) {
return (MethodEndpoint) endpointMap.get(key);
}
/**
* Register the given endpoint instance under the key.
*
* @param key the lookup key
* @param endpoint the method endpoint instance
* @throws BeansException if the endpoint could not be registered
*/
protected void registerEndpoint(String key, MethodEndpoint endpoint) throws BeansException {
Object mappedEndpoint = endpointMap.get(key);
if (mappedEndpoint != null) {
throw new ApplicationContextException("Cannot map endpoint [" + endpoint + "] on registration key [" + key +
"]: there's already endpoint [" + mappedEndpoint + "] mapped");
}
if (endpoint == null) {
throw new ApplicationContextException("Could not find endpoint for key [" + key + "]");
}
endpointMap.put(key, endpoint);
if (logger.isDebugEnabled()) {
logger.debug("Mapped key [" + key + "] onto endpoint [" + endpoint + "]");
}
}
/**
* Helper method that registers the methods of the given bean. This method iterates over the methods of the bean,
* and calls {@link #getLookupKeyForMethod(Method)} for each. If this returns a string, the method is registered
* using {@link #registerEndpoint(String,MethodEndpoint)}.
*
* @see #getLookupKeyForMethod(Method)
*/
protected void registerMethods(Object endpoint) {
Method[] methods = getEndpointClass(endpoint).getMethods();
for (int i = 0; i < methods.length; i++) {
if (JdkVersion.isAtLeastJava15() && methods[i].isSynthetic() ||
methods[i].getDeclaringClass().equals(Object.class)) {
continue;
}
String key = getLookupKeyForMethod(methods[i]);
if (StringUtils.hasLength(key)) {
registerEndpoint(key, new MethodEndpoint(endpoint, methods[i]));
}
}
}
/**
* Returns the the endpoint keys for the given method. Returns <code>null</code> if the method is not to be
* registered, which is the default.
*
* @param method the method
* @return a registration key, or <code>null</code> if the method is not to be registered
*/
protected String getLookupKeyForMethod(Method method) {
return null;
}
/**
* Return the class or interface to use for method reflection.
* <p/>
* Default implementation returns the target class for a CGLIB proxy, and the class of the given bean else (for a
* JDK proxy or a plain bean class).
*
* @param endpoint the bean instance (might be an AOP proxy)
* @return the bean class to expose
*/
protected Class getEndpointClass(Object endpoint) {
if (AopUtils.isCglibProxy(endpoint)) {
return endpoint.getClass().getSuperclass();
}
return endpoint.getClass();
}
}

View File

@@ -17,13 +17,11 @@
package org.springframework.ws.server.endpoint.mapping;
import javax.xml.namespace.QName;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.xml.dom.DomUtils;
import org.springframework.xml.namespace.QNameUtils;
import org.w3c.dom.Element;
@@ -56,15 +54,10 @@ public class PayloadRootQNameEndpointMapping extends AbstractQNameEndpointMappin
}
protected QName resolveQName(MessageContext messageContext) throws TransformerException {
Element payloadElement = getMessagePayloadElement(messageContext.getRequest());
Element payloadElement =
DomUtils.getRootElement(messageContext.getRequest().getPayloadSource(), transformerFactory);
return QNameUtils.getQNameForNode(payloadElement);
}
private Element getMessagePayloadElement(WebServiceMessage message) throws TransformerException {
Transformer transformer = transformerFactory.newTransformer();
DOMResult domResult = new DOMResult();
transformer.transform(message.getPayloadSource(), domResult);
return (Element) domResult.getNode().getFirstChild();
}
}

View File

@@ -31,7 +31,6 @@ import org.springframework.ws.transport.WebServiceConnection;
* Commons HttpClient</a> to execute POST requests.
* <p/>
* Allows to use a preconfigured HttpClient instance, potentially with authentication, HTTP connection pooling, etc.
* Also designed for easy subclassing, customizing specific template methods.
*
* @author Arjen Poutsma
* @see org.springframework.ws.transport.http.HttpUrlConnectionMessageSender

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.server.endpoint;
import java.lang.reflect.Method;
import junit.framework.TestCase;
public class MethodEndpointTest extends TestCase {
private MethodEndpoint endpoint;
private boolean myMethodInvoked;
private Method method;
protected void setUp() throws Exception {
myMethodInvoked = false;
method = getClass().getMethod("myMethod", new Class[]{String.class});
endpoint = new MethodEndpoint(this, method);
}
public void testGetters() throws Exception {
assertEquals("Invalid bean", this, endpoint.getBean());
assertEquals("Invalid bean", method, endpoint.getMethod());
}
public void testInvoke() throws Exception {
assertFalse("Method invoked before invocation", myMethodInvoked);
endpoint.invoke(new Object[]{"arg"});
assertTrue("Method invoked before invocation", myMethodInvoked);
}
public void testEquals() throws Exception {
assertEquals("Not equal", endpoint, endpoint);
assertEquals("Not equal", new MethodEndpoint(this, method), endpoint);
Method otherMethod = getClass().getMethod("testEquals", new Class[0]);
assertFalse("Equal", new MethodEndpoint(this, otherMethod).equals(endpoint));
}
public void testHashCode() throws Exception {
assertEquals("Not equal", new MethodEndpoint(this, method).hashCode(), endpoint.hashCode());
Method otherMethod = getClass().getMethod("testEquals", new Class[0]);
assertFalse("Equal", new MethodEndpoint(this, otherMethod).hashCode() == endpoint.hashCode());
}
public void myMethod(String arg) {
assertEquals("Invalid argument", "arg", arg);
myMethodInvoked = true;
}
public void testToString() throws Exception {
assertNotNull("Na valid toString", endpoint.toString());
}
}