You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2011/06/04 18:06:07 UTC
svn commit: r1131422 - in /cxf/trunk:
api/src/main/java/org/apache/cxf/endpoint/
rt/core/src/main/java/org/apache/cxf/clustering/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ rt/fron...
Author: sergeyb
Date: Sat Jun 4 16:06:06 2011
New Revision: 1131422
URL: http://svn.apache.org/viewvc?rev=1131422&view=rev
Log:
[CXF-3561] Initial support for failover feature
Added:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/FailoverFeature.java (with props)
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/FailoverTest.java (with props)
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/Server.java (with props)
Modified:
cxf/trunk/api/src/main/java/org/apache/cxf/endpoint/AbstractConduitSelector.java
cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverFeature.java
cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverTargetSelector.java
cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/LoadDistributorFeature.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSBindingFactory.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
Modified: cxf/trunk/api/src/main/java/org/apache/cxf/endpoint/AbstractConduitSelector.java
URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/endpoint/AbstractConduitSelector.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/endpoint/AbstractConduitSelector.java (original)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/endpoint/AbstractConduitSelector.java Sat Jun 4 16:06:06 2011
@@ -27,6 +27,7 @@ import org.apache.cxf.common.util.String
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.transport.Conduit;
import org.apache.cxf.transport.ConduitInitiator;
@@ -41,7 +42,8 @@ import org.apache.cxf.ws.addressing.Endp
* that retreives a Conduit from the ConduitInitiator.
*/
public abstract class AbstractConduitSelector implements ConduitSelector {
-
+ protected static final String KEEP_CONDUIT_ALIVE = "KeepConduitAlive";
+
protected Conduit selectedConduit;
protected Endpoint endpoint;
@@ -126,6 +128,13 @@ public abstract class AbstractConduitSel
* @param exchange represents the completed MEP
*/
public void complete(Exchange exchange) {
+ // Clients expecting explicit InputStream responses
+ // will need to keep low level conduits operating on InputStreams open
+ // and will be responsible for closing the streams
+
+ if (MessageUtils.isTrue(exchange.get(KEEP_CONDUIT_ALIVE))) {
+ return;
+ }
try {
if (exchange.getInMessage() != null) {
getSelectedConduit(exchange.getInMessage()).close(exchange.getInMessage());
Modified: cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverFeature.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverFeature.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverFeature.java (original)
+++ cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverFeature.java Sat Jun 4 16:06:06 2011
@@ -21,6 +21,8 @@ package org.apache.cxf.clustering;
import org.apache.cxf.Bus;
import org.apache.cxf.common.injection.NoJSR250Annotations;
import org.apache.cxf.endpoint.Client;
+import org.apache.cxf.endpoint.ConduitSelector;
+import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.feature.AbstractFeature;
/**
@@ -35,13 +37,22 @@ public class FailoverFeature extends Abs
@Override
public void initialize(Client client, Bus bus) {
- FailoverTargetSelector selector =
- new FailoverTargetSelector();
- selector.setEndpoint(client.getEndpoint());
- selector.setStrategy(getStrategy());
+ ConduitSelector selector = initTargetSelector(client.getConduitSelector().getEndpoint());
client.setConduitSelector(selector);
}
+ protected ConduitSelector initTargetSelector(Endpoint endpoint) {
+ FailoverTargetSelector selector = getTargetSelector();
+ selector.setEndpoint(endpoint);
+ selector.setStrategy(getStrategy());
+ return selector;
+ }
+
+ protected FailoverTargetSelector getTargetSelector() {
+ return new FailoverTargetSelector();
+ }
+
+
public void setStrategy(FailoverStrategy strategy) {
failoverStrategy = strategy;
}
Modified: cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverTargetSelector.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverTargetSelector.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverTargetSelector.java (original)
+++ cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/FailoverTargetSelector.java Sat Jun 4 16:06:06 2011
@@ -207,9 +207,11 @@ public class FailoverTargetSelector exte
failover = curr instanceof java.io.IOException;
curr = curr.getCause();
}
- getLogger().log(Level.INFO,
- "CHECK_FAILURE_IN_TRANSPORT",
- new Object[] {ex, failover});
+ if (ex != null) {
+ getLogger().log(Level.INFO,
+ "CHECK_FAILURE_IN_TRANSPORT",
+ new Object[] {ex, failover});
+ }
return failover;
}
Modified: cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/LoadDistributorFeature.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/LoadDistributorFeature.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/LoadDistributorFeature.java (original)
+++ cxf/trunk/rt/core/src/main/java/org/apache/cxf/clustering/LoadDistributorFeature.java Sat Jun 4 16:06:06 2011
@@ -18,9 +18,7 @@
*/
package org.apache.cxf.clustering;
-import org.apache.cxf.Bus;
import org.apache.cxf.common.injection.NoJSR250Annotations;
-import org.apache.cxf.endpoint.Client;
/**
* This feature may be applied to a Client so as to enable
@@ -32,12 +30,7 @@ import org.apache.cxf.endpoint.Client;
public class LoadDistributorFeature extends FailoverFeature {
@Override
- public void initialize(Client client, Bus bus) {
- LoadDistributorTargetSelector selector =
- new LoadDistributorTargetSelector();
- selector.setEndpoint(client.getEndpoint());
- selector.setStrategy(getStrategy());
- client.setConduitSelector(selector);
+ protected FailoverTargetSelector getTargetSelector() {
+ return new LoadDistributorTargetSelector();
}
-
}
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSBindingFactory.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSBindingFactory.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSBindingFactory.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSBindingFactory.java Sat Jun 4 16:06:06 2011
@@ -19,6 +19,8 @@
package org.apache.cxf.jaxrs;
+import javax.xml.namespace.QName;
+
import org.apache.cxf.Bus;
import org.apache.cxf.binding.AbstractBaseBindingFactory;
import org.apache.cxf.binding.Binding;
@@ -65,7 +67,7 @@ public class JAXRSBindingFactory extends
*/
public BindingInfo createBindingInfo(Service service, String namespace, Object obj) {
BindingInfo info = new BindingInfo(null, JAXRSBindingFactory.JAXRS_BINDING_ID);
-
+ info.setName(new QName(JAXRSBindingFactory.JAXRS_BINDING_ID, "binding"));
return info;
}
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java Sat Jun 4 16:06:06 2011
@@ -24,7 +24,6 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URI;
-import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -53,6 +52,8 @@ import org.apache.cxf.common.i18n.Bundle
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.endpoint.ConduitSelector;
import org.apache.cxf.endpoint.Endpoint;
+import org.apache.cxf.endpoint.Retryable;
+import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.jaxrs.impl.MetadataMap;
@@ -65,22 +66,27 @@ import org.apache.cxf.jaxrs.utils.Inject
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.ExchangeImpl;
import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.phase.PhaseChainCache;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.phase.PhaseManager;
import org.apache.cxf.service.Service;
+import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.transport.MessageObserver;
+import org.apache.cxf.transport.http.HTTPConduit;
/**
* Common proxy and http-centric client implementation
*
*/
-public class AbstractClient implements Client {
+public abstract class AbstractClient implements Client, Retryable {
+ protected static final String REQUEST_CONTEXT = "RequestContext";
+ protected static final String RESPONSE_CONTEXT = "ResponseContext";
+ protected static final String KEEP_CONDUIT_ALIVE = "KeepConduitAlive";
+
private static final Logger LOG = LogUtils.getL7dLogger(AbstractClient.class);
private static final ResourceBundle BUNDLE = BundleUtils.getBundle(AbstractClient.class);
- private static final String REQUEST_CONTEXT = "RequestContext";
- private static final String RESPONSE_CONTEXT = "ResponseContext";
protected ClientConfiguration cfg = new ClientConfiguration();
private ClientState state;
@@ -308,27 +314,15 @@ public class AbstractClient implements C
return null;
}
- protected ResponseBuilder setResponseBuilder(HttpURLConnection conn, Exchange exchange) throws Throwable {
- Message inMessage = exchange.getInMessage();
+ protected ResponseBuilder setResponseBuilder(Message outMessage, Exchange exchange) throws Exception {
+ HttpURLConnection conn = (HttpURLConnection)outMessage.get(HTTPConduit.KEY_HTTP_CONNECTION);
+
if (conn == null) {
- // unlikely to occur
throw new ClientWebApplicationException("HTTP Connection is null");
}
- Integer responseCode = (Integer)exchange.get(Message.RESPONSE_CODE);
- if (responseCode == null) {
- //Invocation was never made to server, something stopped the outbound
- //interceptor chain, we dont have a response code.
- //Do not call conn.getResponseCode() as that will
- //result in a call to the server when we have already decided not to.
- //Throw an exception if we have one
- Exception ex = exchange.getOutMessage().getContent(Exception.class);
- if (ex != null) {
- throw ex;
- } else {
- throw new RuntimeException("Unknown client side exception");
- }
- }
- int status = responseCode.intValue();
+ checkClientException(exchange.getOutMessage(), exchange.getOutMessage().getContent(Exception.class));
+
+ int status = (Integer)exchange.get(Message.RESPONSE_CODE);
ResponseBuilder currentResponseBuilder = Response.status(status);
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
@@ -363,6 +357,8 @@ public class AbstractClient implements C
}
}
InputStream mStream = null;
+
+ Message inMessage = exchange.getInMessage();
if (inMessage != null) {
mStream = inMessage.getContent(InputStream.class);
}
@@ -450,6 +446,92 @@ public class AbstractClient implements C
return null;
}
+ protected void completeExchange(Object response, Exchange exchange) {
+ // higher level conduits such as FailoverTargetSelector need to
+ // clear the request state but a fair number of response objects
+ // depend on InputStream being still open thus lower-level conduits
+ // operating on InputStream don't have to close streams pro-actively
+ exchange.put(KEEP_CONDUIT_ALIVE, true);
+ getConfiguration().getConduitSelector().complete(exchange);
+ }
+
+ protected Object[] preProcessResult(Message message) throws Exception {
+
+ Exchange exchange = message.getExchange();
+
+ Exception ex = null;
+ // Check to see if there is a Fault from the outgoing chain if it's an out Message
+ if (!message.get(Message.INBOUND_MESSAGE).equals(Boolean.TRUE)) {
+ ex = message.getContent(Exception.class);
+ }
+ if (ex != null) {
+ getConfiguration().getConduitSelector().complete(exchange);
+ checkClientException(message, message.getContent(Exception.class));
+ }
+ checkClientException(message, message.getExchange().get(Exception.class));
+
+ List result = message.getExchange().get(List.class);
+ return result != null ? result.toArray() : null;
+ }
+
+ protected void checkClientException(Message message, Exception ex) throws Exception {
+ if (message.getExchange().get(Message.RESPONSE_CODE) == null) {
+ if (ex instanceof ClientWebApplicationException) {
+ throw ex;
+ } else if (ex != null) {
+ throw new ClientWebApplicationException(ex);
+ } else {
+ throw new ClientWebApplicationException();
+ }
+ }
+ }
+
+ protected URI calculateNewRequestURI(Map<String, Object> reqContext) {
+ URI newBaseURI = URI.create(reqContext.get(Message.ENDPOINT_ADDRESS).toString());
+ String baseURIPath = newBaseURI.getRawPath();
+
+ URI requestURI = URI.create(reqContext.get(Message.REQUEST_URI).toString());
+ String reqURIPath = requestURI.getRawPath();
+
+ UriBuilder builder = UriBuilder.fromUri(newBaseURI);
+ String basePath = reqURIPath.startsWith(baseURIPath) ? baseURIPath : getBaseURI().getRawPath();
+ builder.path(reqURIPath.equals(basePath) ? "" : reqURIPath.substring(basePath.length()));
+ URI newRequestURI = builder.replaceQuery(requestURI.getRawQuery()).build();
+
+ resetBaseAddress(newBaseURI);
+ resetCurrentBuilder(newRequestURI);
+
+ return newRequestURI;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object[] invoke(BindingOperationInfo oi, Object[] params, Map<String, Object> context,
+ Exchange exchange) throws Exception {
+
+ try {
+ Object body = params.length == 0 ? null : params[0];
+ Map<String, Object> reqContext = CastUtils.cast((Map)context.get(REQUEST_CONTEXT));
+ MultivaluedMap<String, String> headers =
+ (MultivaluedMap<String, String>)reqContext.get(Message.PROTOCOL_HEADERS);
+
+ URI newRequestURI = calculateNewRequestURI(reqContext);
+
+ Object response = retryInvoke(newRequestURI, headers, body, exchange, context);
+ exchange.put(List.class, getContentsList(response));
+ return new Object[]{response};
+ } catch (Throwable t) {
+ Exception ex = t instanceof Exception ? (Exception)t : new Exception(t);
+ exchange.put(Exception.class, ex);
+ return null;
+ }
+ }
+
+ protected abstract Object retryInvoke(URI newRequestURI,
+ MultivaluedMap<String, String> headers,
+ Object body,
+ Exchange exchange,
+ Map<String, Object> invContext) throws Throwable;
+
// TODO : shall we just do the reflective invocation here ?
protected static void addParametersToBuilder(UriBuilder ub, String paramName, Object pValue,
ParameterType pt) {
@@ -509,18 +591,6 @@ public class AbstractClient implements C
return MediaType.WILDCARD_TYPE;
}
- protected static HttpURLConnection createHttpConnection(URI uri, String methodName) {
- try {
- URL url = uri.toURL();
- HttpURLConnection connect = (HttpURLConnection)url.openConnection();
- connect.setDoOutput(true);
- connect.setRequestMethod(methodName);
- return connect;
- } catch (Exception ex) {
- throw new ClientWebApplicationException("REMOTE_CONNECTION_PROBLEM", ex, null);
- }
- }
-
protected static void setAllHeaders(MultivaluedMap<String, String> headers, HttpURLConnection conn) {
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
StringBuilder b = new StringBuilder();
@@ -601,6 +671,7 @@ public class AbstractClient implements C
LOG.warning("Failure to prepare a message from conduit selector");
}
message.getExchange().put(ConduitSelector.class, cfg.getConduitSelector());
+ message.getExchange().put(Service.class, cfg.getConduitSelector().getEndpoint().getService());
}
protected static PhaseInterceptorChain setupOutInterceptorChain(ClientConfiguration cfg) {
@@ -626,9 +697,12 @@ public class AbstractClient implements C
return m;
}
- protected Message createMessage(String httpMethod,
+ protected Message createMessage(Object body,
+ String httpMethod,
MultivaluedMap<String, String> headers,
- URI currentURI) {
+ URI currentURI,
+ Exchange exchange,
+ Map<String, Object> invocationContext) {
Message m = cfg.getConduitSelector().getEndpoint().getBinding().createMessage();
m.put(Message.REQUESTOR_ROLE, Boolean.TRUE);
m.put(Message.INBOUND_MESSAGE, Boolean.FALSE);
@@ -640,39 +714,79 @@ public class AbstractClient implements C
m.put(Message.CONTENT_TYPE, headers.getFirst(HttpHeaders.CONTENT_TYPE));
- Exchange exchange = new ExchangeImpl();
- exchange.setSynchronous(true);
- exchange.setOutMessage(m);
- exchange.put(Bus.class, cfg.getBus());
- exchange.put(MessageObserver.class, new ClientMessageObserver(cfg));
- exchange.put(Endpoint.class, cfg.getConduitSelector().getEndpoint());
- exchange.setOneWay("true".equals(headers.getFirst(Message.ONE_WAY_REQUEST)));
- // no need for the underlying conduit to throw the IO exceptions in case of
- // client requests returning error HTTP code, it can be overridden if really needed
- exchange.put("org.apache.cxf.http.no_io_exceptions", true);
- m.setExchange(exchange);
+ m.setContent(List.class, getContentsList(body));
+ if (body == null) {
+ setEmptyRequestProperty(m, httpMethod);
+ }
+
+ m.put(URITemplate.TEMPLATE_PARAMETERS, getState().getTemplates());
PhaseInterceptorChain chain = setupOutInterceptorChain(cfg);
m.setInterceptorChain(chain);
+ exchange = createExchange(m, exchange);
+ exchange.setOneWay("true".equals(headers.getFirst(Message.ONE_WAY_REQUEST)));
+ exchange.put(Retryable.class, this);
+
// context
- if (cfg.getRequestContext().size() > 0 || cfg.getResponseContext().size() > 0) {
- Map<String, Object> context = new HashMap<String, Object>();
- context.put(REQUEST_CONTEXT, cfg.getRequestContext());
- context.put(RESPONSE_CONTEXT, cfg.getResponseContext());
- m.put(Message.INVOCATION_CONTEXT, context);
- m.putAll(cfg.getRequestContext());
- exchange.putAll(cfg.getRequestContext());
- exchange.putAll(cfg.getResponseContext());
- }
+ setContexts(m, exchange, invocationContext);
//setup conduit selector
prepareConduitSelector(m);
- exchange.put(Service.class, cfg.getConduitSelector().getEndpoint().getService());
return m;
}
-
+
+ protected Map<String, Object> getRequestContext(Message outMessage) {
+ Map<String, Object> invContext = CastUtils.cast((Map)outMessage.get(Message.INVOCATION_CONTEXT));
+ return CastUtils.cast((Map)invContext.get(REQUEST_CONTEXT));
+ }
+
+ protected List getContentsList(Object body) {
+ return body == null ? new MessageContentsList() : new MessageContentsList(body);
+ }
+
+ protected Exchange createExchange(Message m, Exchange exchange) {
+ if (exchange == null) {
+ exchange = new ExchangeImpl();
+ }
+ exchange.setSynchronous(true);
+ exchange.setOutMessage(m);
+ exchange.put(Bus.class, cfg.getBus());
+ exchange.put(MessageObserver.class, new ClientMessageObserver(cfg));
+ exchange.put(Endpoint.class, cfg.getConduitSelector().getEndpoint());
+ exchange.put("org.apache.cxf.http.no_io_exceptions", true);
+ m.setExchange(exchange);
+ return exchange;
+ }
+
+ protected void setContexts(Message message, Exchange exchange,
+ Map<String, Object> context) {
+ Map<String, Object> reqContext = null;
+ Map<String, Object> resContext = null;
+ if (context == null) {
+ context = new HashMap<String, Object>();
+ }
+ reqContext = CastUtils.cast((Map)context.get(REQUEST_CONTEXT));
+ resContext = CastUtils.cast((Map)context.get(RESPONSE_CONTEXT));
+ if (reqContext == null) {
+ reqContext = new HashMap<String, Object>(cfg.getRequestContext());
+ context.put(REQUEST_CONTEXT, reqContext);
+ }
+ reqContext.put(Message.PROTOCOL_HEADERS, message.get(Message.PROTOCOL_HEADERS));
+ reqContext.put(Message.REQUEST_URI, message.get(Message.REQUEST_URI));
+ reqContext.put(Message.ENDPOINT_ADDRESS, message.get(Message.ENDPOINT_ADDRESS));
+
+ if (resContext == null) {
+ resContext = new HashMap<String, Object>();
+ context.put(RESPONSE_CONTEXT, resContext);
+ }
+
+ message.put(Message.INVOCATION_CONTEXT, context);
+ message.putAll(reqContext);
+ exchange.putAll(reqContext);
+ }
+
protected void setEmptyRequestProperty(Message outMessage, String httpMethod) {
if ("POST".equals(httpMethod)) {
outMessage.put("org.apache.cxf.post.empty", true);
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java Sat Jun 4 16:06:06 2011
@@ -23,7 +23,6 @@ import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.net.HttpURLConnection;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
@@ -45,6 +44,7 @@ import javax.xml.stream.XMLStreamWriter;
import org.apache.cxf.common.i18n.BundleUtils;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.endpoint.Endpoint;
+import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.InterceptorProvider;
@@ -53,20 +53,20 @@ import org.apache.cxf.jaxrs.model.ClassR
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.jaxrs.model.Parameter;
import org.apache.cxf.jaxrs.model.ParameterType;
-import org.apache.cxf.jaxrs.model.URITemplate;
import org.apache.cxf.jaxrs.provider.ProviderFactory;
import org.apache.cxf.jaxrs.utils.FormUtils;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
+import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.Phase;
-import org.apache.cxf.transport.http.HTTPConduit;
/**
* Proxy-based client implementation
*
*/
-public class ClientProxyImpl extends AbstractClient implements InvocationHandlerAware, InvocationHandler {
+public class ClientProxyImpl extends AbstractClient implements
+ InvocationHandlerAware, InvocationHandler {
private static final Logger LOG = LogUtils.getL7dLogger(ClientProxyImpl.class);
private static final ResourceBundle BUNDLE = BundleUtils.getBundle(ClientProxyImpl.class);
@@ -174,7 +174,14 @@ public class ClientProxyImpl extends Abs
setRequestHeaders(headers, ori, types.containsKey(ParameterType.FORM),
bodyIndex == -1 ? null : params[bodyIndex].getClass(), m.getReturnType());
- return doChainedInvocation(uri, headers, ori, params, bodyIndex, types, pathParams);
+ getState().setTemplates(getTemplateParametersMap(ori.getURITemplate(), pathParams));
+
+ Object body = null;
+ boolean isForm = types.containsKey(ParameterType.FORM);
+ if (bodyIndex != -1 || isForm) {
+ body = isForm ? handleForm(types, params) : params[bodyIndex];
+ }
+ return doChainedInvocation(uri, headers, ori, body, bodyIndex, null, null);
}
@@ -409,47 +416,77 @@ public class ClientProxyImpl extends Abs
}
}
- private Object doChainedInvocation(URI uri, MultivaluedMap<String, String> headers,
- OperationResourceInfo ori, Object[] params, int bodyIndex,
- MultivaluedMap<ParameterType, Parameter> types,
- List<Object> pathParams) throws Throwable {
- Message outMessage = createMessage(ori.getHttpMethod(), headers, uri);
- outMessage.getExchange().setOneWay(ori.isOneway());
+ private Object doChainedInvocation(URI uri,
+ MultivaluedMap<String, String> headers,
+ OperationResourceInfo ori,
+ Object body,
+ int bodyIndex,
+ Exchange exchange,
+ Map<String, Object> invocationContext) throws Throwable {
- getState().setTemplates(getTemplateParametersMap(ori.getURITemplate(), pathParams));
- outMessage.put(URITemplate.TEMPLATE_PARAMETERS, getState().getTemplates());
+ Message outMessage = createMessage(body, ori.getHttpMethod(), headers, uri,
+ exchange, invocationContext);
+ outMessage.getExchange().setOneWay(ori.isOneway());
outMessage.setContent(OperationResourceInfo.class, ori);
setPlainOperationNameProperty(outMessage, ori.getMethodToInvoke().getName());
outMessage.getExchange().put(Method.class, ori.getMethodToInvoke());
- boolean isForm = types.containsKey(ParameterType.FORM);
- if (bodyIndex != -1 || isForm) {
+
+ if (body != null) {
outMessage.put("BODY_INDEX", bodyIndex);
- Object body = isForm ? handleForm(types, params) : params[bodyIndex];
- MessageContentsList contents = new MessageContentsList(new Object[]{body});
- outMessage.setContent(List.class, contents);
outMessage.getInterceptorChain().add(new BodyWriter());
- } else {
- setEmptyRequestProperty(outMessage, ori.getHttpMethod());
}
+
+ Map<String, Object> reqContext = getRequestContext(outMessage);
+ reqContext.put(OperationResourceInfo.class.getName(), ori);
+ reqContext.put("BODY_INDEX", bodyIndex);
// execute chain
try {
outMessage.getInterceptorChain().doIntercept(outMessage);
- } catch (Throwable ex) {
- // we'd like a user to get the whole Response anyway if needed
+ } catch (Exception ex) {
+ outMessage.setContent(Exception.class, ex);
+ }
+
+ Object[] results = preProcessResult(outMessage);
+ if (results != null && results.length == 1) {
+ // this can happen if a connection exception has occurred and
+ // failover feature used this client to invoke on a different address
+ return results[0];
+ }
+
+ Object response = null;
+ try {
+ response = handleResponse(outMessage);
+ return response;
+ } catch (Exception ex) {
+ response = ex;
+ throw ex;
+ } finally {
+ completeExchange(response, outMessage.getExchange());
}
- // TODO : this needs to be done in an inbound chain instead
- HttpURLConnection connect = (HttpURLConnection)outMessage.get(HTTPConduit.KEY_HTTP_CONNECTION);
- return handleResponse(connect, outMessage, ori);
+ }
+
+ @Override
+ protected Object retryInvoke(URI newRequestURI,
+ MultivaluedMap<String, String> headers,
+ Object body,
+ Exchange exchange,
+ Map<String, Object> invContext) throws Throwable {
+ Map<String, Object> reqContext = CastUtils.cast((Map)invContext.get(REQUEST_CONTEXT));
+ int bodyIndex = body != null ? (Integer)reqContext.get("BODY_INDEX") : -1;
+ OperationResourceInfo ori =
+ (OperationResourceInfo)reqContext.get(OperationResourceInfo.class.getName());
+ return doChainedInvocation(newRequestURI, headers, ori,
+ body, bodyIndex, exchange, invContext);
}
- protected Object handleResponse(HttpURLConnection connect, Message outMessage, OperationResourceInfo ori)
+ protected Object handleResponse(Message outMessage)
throws Throwable {
- Response r = setResponseBuilder(connect, outMessage.getExchange()).build();
- Method method = ori.getMethodToInvoke();
+ Response r = setResponseBuilder(outMessage, outMessage.getExchange()).build();
+ Method method = outMessage.getExchange().get(Method.class);
checkResponse(method, r, outMessage);
if (method.getReturnType() == Void.class) {
return null;
@@ -526,6 +563,5 @@ public class ClientProxyImpl extends Abs
}
}
-
}
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java Sat Jun 4 16:06:06 2011
@@ -37,6 +37,7 @@ import org.apache.cxf.jaxrs.JAXRSService
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.service.Service;
+import org.apache.cxf.service.factory.FactoryBeanListener;
public class JAXRSClientFactoryBean extends AbstractJAXRSFactoryBean {
@@ -186,6 +187,8 @@ public class JAXRSClientFactoryBean exte
WebClient client = actualState == null ? new WebClient(getAddress())
: new WebClient(actualState);
initClient(client, ep, actualState == null);
+
+ this.getServiceFactory().sendEvent(FactoryBeanListener.Event.CLIENT_CREATED, client, ep);
return client;
} catch (Exception ex) {
@@ -267,17 +270,20 @@ public class JAXRSClientFactoryBean exte
}
initClient(proxyImpl, ep, actualState == null);
+ Client actualClient = null;
try {
- return (Client)ProxyHelper.getProxy(cri.getServiceClass().getClassLoader(),
+ actualClient = (Client)ProxyHelper.getProxy(cri.getServiceClass().getClassLoader(),
new Class[]{cri.getServiceClass(), Client.class,
InvocationHandlerAware.class},
proxyImpl);
} catch (Exception ex) {
- return (Client)ProxyHelper.getProxy(Thread.currentThread().getContextClassLoader(),
+ actualClient = (Client)ProxyHelper.getProxy(Thread.currentThread().getContextClassLoader(),
new Class[]{cri.getServiceClass(), Client.class,
InvocationHandlerAware.class},
proxyImpl);
}
+ this.getServiceFactory().sendEvent(FactoryBeanListener.Event.CLIENT_CREATED, actualClient, ep);
+ return actualClient;
} catch (IllegalArgumentException ex) {
String message = ex.getLocalizedMessage();
if (cri != null) {
@@ -312,7 +318,6 @@ public class JAXRSClientFactoryBean exte
ep.getEndpointInfo().addExtensor(authPolicy);
}
- applyFeatures(client);
client.getConfiguration().setConduitSelector(getConduitSelector(ep));
client.getConfiguration().setBus(getBus());
client.getConfiguration().getOutInterceptors().addAll(getOutInterceptors());
@@ -320,6 +325,8 @@ public class JAXRSClientFactoryBean exte
client.getConfiguration().getInInterceptors().addAll(getInInterceptors());
client.getConfiguration().getInInterceptors().addAll(ep.getInInterceptors());
+ applyFeatures(client);
+
if (headers != null && addHeaders) {
client.headers(headers);
}
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java Sat Jun 4 16:06:06 2011
@@ -22,7 +22,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
-import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
@@ -53,10 +52,10 @@ import org.apache.cxf.jaxrs.model.URITem
import org.apache.cxf.jaxrs.utils.HttpUtils;
import org.apache.cxf.jaxrs.utils.JAXRSUtils;
import org.apache.cxf.jaxrs.utils.ParameterizedCollectionType;
+import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.Phase;
-import org.apache.cxf.transport.http.HTTPConduit;
/**
@@ -65,6 +64,9 @@ import org.apache.cxf.transport.http.HTT
*/
public class WebClient extends AbstractClient {
+ private static final String RESPONSE_CLASS = "response.class";
+ private static final String RESPONSE_TYPE = "response.type";
+
protected WebClient(String baseAddress) {
this(URI.create(baseAddress));
}
@@ -629,46 +631,80 @@ public class WebClient extends AbstractC
headers.putSingle(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_TYPE.toString());
}
resetResponse();
- return doChainedInvocation(httpMethod, headers, body, responseClass, genericType);
+ return doChainedInvocation(httpMethod, headers, body, responseClass, genericType, null, null);
}
+ @Override
+ protected Object retryInvoke(URI newRequestURI,
+ MultivaluedMap<String, String> headers,
+ Object body,
+ Exchange exchange,
+ Map<String, Object> invContext) throws Throwable {
+
+ Map<String, Object> reqContext = CastUtils.cast((Map)invContext.get(REQUEST_CONTEXT));
+ String httpMethod = (String)reqContext.get(Message.HTTP_REQUEST_METHOD);
+ Class<?> respClass = (Class)reqContext.get(RESPONSE_CLASS);
+ Type type = (Type)reqContext.get(RESPONSE_TYPE);
+ return doChainedInvocation(httpMethod, headers, body, respClass, type, exchange, invContext);
+ }
+
protected Response doChainedInvocation(String httpMethod,
- MultivaluedMap<String, String> headers, Object body, Class<?> responseClass, Type genericType) {
- Throwable primaryError = null;
+ MultivaluedMap<String, String> headers,
+ Object body,
+ Class<?> responseClass,
+ Type genericType,
+ Exchange exchange,
+ Map<String, Object> invContext) {
URI uri = getCurrentURI();
- Message m = createMessage(httpMethod, headers, uri);
- m.put(URITemplate.TEMPLATE_PARAMETERS, getState().getTemplates());
+ Message m = createMessage(body, httpMethod, headers, uri, exchange, invContext);
+
+ Map<String, Object> reqContext = getRequestContext(m);
+ reqContext.put(Message.HTTP_REQUEST_METHOD, httpMethod);
+ reqContext.put(RESPONSE_CLASS, responseClass);
+ reqContext.put(RESPONSE_TYPE, genericType);
+
if (body != null) {
- MessageContentsList contents = new MessageContentsList(body);
- m.setContent(List.class, contents);
m.getInterceptorChain().add(new BodyWriter());
- } else {
- setEmptyRequestProperty(m, httpMethod);
}
setPlainOperationNameProperty(m, httpMethod + ":" + uri.toString());
try {
m.getInterceptorChain().doIntercept(m);
- primaryError = m.getExchange().get(Exception.class);
- } catch (Throwable ex) {
- primaryError = ex;
+ } catch (Exception ex) {
+ m.setContent(Exception.class, ex);
+ }
+ try {
+ Object[] results = preProcessResult(m);
+ if (results != null && results.length == 1) {
+ // this can happen if a connection exception has occurred and
+ // failover feature used this client to invoke on a different address
+ return (Response)results[0];
+ }
+ } catch (Exception ex) {
+ throw ex instanceof ServerWebApplicationException
+ ? (ServerWebApplicationException)ex
+ : ex instanceof ClientWebApplicationException
+ ? new ClientWebApplicationException(ex) : new RuntimeException(ex);
}
-
- // TODO : this needs to be done in an inbound chain instead
- HttpURLConnection connect = (HttpURLConnection)m.get(HTTPConduit.KEY_HTTP_CONNECTION);
- if (connect == null && primaryError != null) {
- /** do we have a pre-connect error ? */
- throw new ClientWebApplicationException(primaryError);
+ Response response = null;
+ Object entity = null;
+ try {
+ response = handleResponse(m, responseClass, genericType);
+ entity = response.getEntity();
+ return response;
+ } catch (RuntimeException ex) {
+ entity = ex;
+ throw ex;
+ } finally {
+ completeExchange(entity, m.getExchange());
}
- return handleResponse(connect, m, responseClass, genericType);
}
- protected Response handleResponse(HttpURLConnection conn, Message outMessage,
- Class<?> responseClass, Type genericType) {
+ protected Response handleResponse(Message outMessage, Class<?> responseClass, Type genericType) {
try {
- ResponseBuilder rb = setResponseBuilder(conn, outMessage.getExchange());
+ ResponseBuilder rb = setResponseBuilder(outMessage, outMessage.getExchange());
Response currentResponse = rb.clone().build();
Object entity = readBody(currentResponse, outMessage, responseClass, genericType,
@@ -678,13 +714,11 @@ public class WebClient extends AbstractC
return rb.build();
} catch (Throwable ex) {
- throw new ClientWebApplicationException(ex);
+ throw (ex instanceof ClientWebApplicationException) ? (ClientWebApplicationException)ex
+ : new ClientWebApplicationException(ex);
}
}
- protected HttpURLConnection getConnection(String methodName) {
- return createHttpConnection(getCurrentBuilder().clone().buildFromEncoded(), methodName);
- }
private class BodyWriter extends AbstractOutDatabindingInterceptor {
@@ -725,7 +759,7 @@ public class WebClient extends AbstractC
newClient.setConfiguration(oldClient.getConfiguration());
}
- private static AbstractClient toAbstractClient(Client client) {
+ private static AbstractClient toAbstractClient(Object client) {
if (client instanceof AbstractClient) {
return (AbstractClient)client;
} else {
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/FailoverFeature.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/FailoverFeature.java?rev=1131422&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/FailoverFeature.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/FailoverFeature.java Sat Jun 4 16:06:06 2011
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cxf.jaxrs.features.clustering;
+
+import java.util.List;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.clustering.AbstractStaticFailoverStrategy;
+import org.apache.cxf.clustering.FailoverStrategy;
+import org.apache.cxf.clustering.FailoverTargetSelector;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.endpoint.ConduitSelector;
+import org.apache.cxf.interceptor.InterceptorProvider;
+import org.apache.cxf.jaxrs.client.ClientConfiguration;
+
+/**
+ * This feature may be applied to proxy or HTTP-centric clients
+ */
+@NoJSR250Annotations
+public class FailoverFeature extends org.apache.cxf.clustering.FailoverFeature {
+
+ private FailoverTargetSelector customSelector;
+
+ @Override
+ public void initialize(InterceptorProvider interceptorProvider, Bus bus) {
+ initialize((ClientConfiguration)interceptorProvider, bus);
+ }
+
+ public void initialize(ClientConfiguration client, Bus bus) {
+ ConduitSelector selector = initTargetSelector(client.getConduitSelector().getEndpoint());
+ client.setConduitSelector(selector);
+ }
+
+ @Override
+ protected FailoverTargetSelector getTargetSelector() {
+ if (customSelector != null) {
+ return customSelector;
+ } else {
+ return super.getTargetSelector();
+ }
+ }
+
+ @Override
+ public FailoverStrategy getStrategy() {
+ FailoverStrategy strategy = super.getStrategy();
+
+ if (strategy == null) {
+ throw new IllegalStateException("Default Strategies are not supported");
+ }
+
+ if (strategy instanceof AbstractStaticFailoverStrategy) {
+ List<String> altAdresses = ((AbstractStaticFailoverStrategy)strategy).getAlternateAddresses(null);
+ if (altAdresses == null || altAdresses.isEmpty()) {
+ throw new IllegalStateException("Strategy is not initialized");
+ }
+ }
+ return strategy;
+ }
+}
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/FailoverFeature.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/features/clustering/FailoverFeature.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java Sat Jun 4 16:06:06 2011
@@ -47,6 +47,7 @@ import org.apache.commons.httpclient.met
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.jaxrs.client.ClientWebApplicationException;
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
import org.apache.cxf.jaxrs.client.ResponseReader;
@@ -71,6 +72,18 @@ public class JAXRSClientServerBookTest e
}
@Test
+ public void testProxyWrongAddress() throws Exception {
+ BookStore store = JAXRSClientFactory.create("http://localhost:8080/wrongaddress",
+ BookStore.class);
+ try {
+ store.getBook("123");
+ fail("ClientWebApplicationException expected");
+ } catch (ClientWebApplicationException ex) {
+ // expected
+ }
+ }
+
+ @Test
public void testGetBookWithCustomHeader() throws Exception {
String endpointAddress =
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java Sat Jun 4 16:06:06 2011
@@ -65,7 +65,7 @@ public class JAXRSMultipartTest extends
@BeforeClass
public static void startServers() throws Exception {
assertTrue("server did not launch correctly",
- launchServer(MultipartServer.class));
+ launchServer(MultipartServer.class, true));
}
@Test
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java?rev=1131422&r1=1131421&r2=1131422&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java Sat Jun 4 16:06:06 2011
@@ -89,7 +89,7 @@ public class JAXRSSoapBookTest extends A
@BeforeClass
public static void startServers() throws Exception {
assertTrue("server did not launch correctly",
- launchServer(BookServerRestSoap.class, true));
+ launchServer(BookServerRestSoap.class));
}
@Test
@@ -285,7 +285,7 @@ public class JAXRSSoapBookTest extends A
Book b = new Book("CXF", 1L);
// Just to make sure it is enforced
- Map<String, Object> props = WebClient.getConfig(client).getResponseContext();
+ Map<String, Object> props = WebClient.getConfig(client).getRequestContext();
props.put(FIStaxOutInterceptor.FI_ENABLED, Boolean.TRUE);
Book b2 = client.addFastinfoBook(b);
@@ -800,7 +800,8 @@ public class JAXRSSoapBookTest extends A
} catch (Exception e) {
assertTrue("Out Interceptor not invoked", testFeature.handleMessageOnOutInterceptorCalled());
assertTrue("In Interceptor not invoked", !testFeature.handleMessageOnInInterceptorCalled());
- assertTrue("Wrong exception caught", "fault from bad interceptor".equals(e.getMessage()));
+ assertTrue("Wrong exception caught",
+ "fault from bad interceptor".equals(e.getCause().getMessage()));
assertTrue("Client In Fault In Interceptor was invoked",
!testFeature.faultInInterceptorCalled());
}
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/FailoverTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/FailoverTest.java?rev=1131422&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/FailoverTest.java (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/FailoverTest.java Sat Jun 4 16:06:06 2011
@@ -0,0 +1,278 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cxf.systest.jaxrs.failover;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.clustering.FailoverTargetSelector;
+import org.apache.cxf.clustering.RandomStrategy;
+import org.apache.cxf.clustering.SequentialStrategy;
+import org.apache.cxf.endpoint.ConduitSelector;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.jaxrs.client.ClientWebApplicationException;
+import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
+import org.apache.cxf.jaxrs.client.ServerWebApplicationException;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.features.clustering.FailoverFeature;
+import org.apache.cxf.systest.jaxrs.Book;
+import org.apache.cxf.systest.jaxrs.BookStore;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Tests failover within a static cluster.
+ */
+public class FailoverTest extends AbstractBusClientServerTestBase {
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ assertTrue("server did not launch correctly",
+ launchServer(Server.class, true));
+ boolean activeReplica1Started = false;
+ boolean activeReplica2Started = false;
+ for (int i = 0; i < 60; i++) {
+ if (!activeReplica1Started) {
+ activeReplica1Started = checkReplica(Server.ADDRESS2);
+ }
+ if (!activeReplica2Started) {
+ activeReplica2Started = checkReplica(Server.ADDRESS3);
+ }
+ if (activeReplica1Started && activeReplica2Started) {
+ break;
+ }
+ Thread.sleep(1000);
+ }
+ }
+ private static boolean checkReplica(String address) {
+ try {
+ Response r = WebClient.create(address).query("_wadl").get();
+ return r.getStatus() == 200;
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
+ @Test
+ public void testSequentialStrategy() throws Exception {
+ FailoverFeature feature =
+ getFeature(false, Server.ADDRESS2, Server.ADDRESS3);
+ strategyTest(Server.ADDRESS1, feature, Server.ADDRESS2, null, false, false);
+ }
+
+ @Test
+ public void testSequentialStrategyWebClient() throws Exception {
+ FailoverFeature feature =
+ getFeature(false, Server.ADDRESS3, Server.ADDRESS2);
+ strategyTestWebClient(Server.ADDRESS1, feature, Server.ADDRESS3, null, false, false);
+ }
+
+ @Test
+ public void testRandomStrategy() throws Exception {
+ FailoverFeature feature =
+ getFeature(true, Server.ADDRESS2, Server.ADDRESS3);
+ strategyTest(Server.ADDRESS1, feature, Server.ADDRESS2, Server.ADDRESS3, false, true);
+ }
+
+ @Test
+ public void testSequentialStrategyWithDiffBaseAddresses() throws Exception {
+ FailoverFeature feature =
+ getFeature(false, Server.ADDRESS3, null);
+ strategyTest(Server.ADDRESS1, feature, Server.ADDRESS3, Server.ADDRESS2, false, false);
+ }
+
+ @Test(expected = ServerWebApplicationException.class)
+ public void testSequentialStrategyWithServerException() throws Exception {
+ FailoverFeature feature =
+ getFeature(false, Server.ADDRESS2, Server.ADDRESS3);
+ strategyTest(Server.ADDRESS1, feature, Server.ADDRESS2, Server.ADDRESS3, true, false);
+ }
+
+ @Test(expected = ClientWebApplicationException.class)
+ public void testSequentialStrategyFailure() throws Exception {
+ FailoverFeature feature =
+ getFeature(false, "http://localhost:8080/non-existent");
+ strategyTest(Server.ADDRESS1, feature, null, null, false, false);
+ }
+
+ private FailoverFeature getFeature(boolean random, String ...address) {
+ FailoverFeature feature = new FailoverFeature();
+ List<String> alternateAddresses = new ArrayList<String>();
+ for (String s : address) {
+ alternateAddresses.add(s);
+ }
+ if (!random) {
+ SequentialStrategy strategy = new SequentialStrategy();
+ strategy.setAlternateAddresses(alternateAddresses);
+ feature.setStrategy(strategy);
+ } else {
+ RandomStrategy strategy = new RandomStrategy();
+ strategy.setAlternateAddresses(alternateAddresses);
+ feature.setStrategy(strategy);
+ }
+ return feature;
+ }
+
+ protected BookStore getBookStore(String address,
+ FailoverFeature feature) throws Exception {
+ JAXRSClientFactoryBean bean = createBean(address, feature);
+ bean.setServiceClass(BookStore.class);
+ return bean.create(BookStore.class);
+ }
+
+ protected WebClient getWebClient(String address,
+ FailoverFeature feature) throws Exception {
+ JAXRSClientFactoryBean bean = createBean(address, feature);
+
+ return bean.createWebClient();
+ }
+
+ protected JAXRSClientFactoryBean createBean(String address,
+ FailoverFeature feature) {
+ JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+ bean.setAddress(address);
+ List<AbstractFeature> features = new ArrayList<AbstractFeature>();
+ features.add(feature);
+ bean.setFeatures(features);
+
+ return bean;
+ }
+
+ protected void strategyTest(String inactiveReplica,
+ FailoverFeature feature,
+ String activeReplica1,
+ String activeReplica2,
+ boolean expectServerException,
+ boolean expectRandom) throws Exception {
+ boolean randomized = false;
+ String prevEndpoint = null;
+ for (int i = 0; i < 20; i++) {
+ BookStore bookStore = getBookStore(inactiveReplica, feature);
+ verifyStrategy(bookStore, expectRandom
+ ? RandomStrategy.class
+ : SequentialStrategy.class);
+ String bookId = expectServerException ? "9999" : "123";
+ Exception ex = null;
+ try {
+ Book book = bookStore.getBook(bookId);
+ assertNotNull("expected non-null response", book);
+ assertEquals("unexpected id", 123L, book.getId());
+ } catch (Exception error) {
+ if (!expectServerException) {
+ //String currEndpoint = getCurrentEndpointAddress(bookStore);
+ //assertTrue(currEndpoint.equals(inactiveReplica));
+ throw error;
+ }
+ ex = error;
+ }
+ String currEndpoint = getCurrentEndpointAddress(bookStore);
+ assertFalse(currEndpoint.equals(inactiveReplica));
+ if (expectRandom) {
+ assertTrue(currEndpoint.equals(activeReplica1) || currEndpoint.equals(activeReplica2));
+ } else {
+ assertTrue(currEndpoint.equals(activeReplica1));
+ }
+ if (expectServerException) {
+ assertNotNull(ex);
+ throw ex;
+ }
+
+ if (!(prevEndpoint == null || currEndpoint.equals(prevEndpoint))) {
+ randomized = true;
+ }
+ prevEndpoint = currEndpoint;
+ }
+ assertEquals("unexpected random/sequential distribution of failovers",
+ expectRandom,
+ randomized);
+ }
+
+ protected void strategyTestWebClient(String inactiveReplica,
+ FailoverFeature feature,
+ String activeReplica1,
+ String activeReplica2,
+ boolean expectServerException,
+ boolean expectRandom) throws Exception {
+ boolean randomized = false;
+ String prevEndpoint = null;
+ for (int i = 0; i < 20; i++) {
+ WebClient bookStore = getWebClient(inactiveReplica, feature);
+ verifyStrategy(bookStore, expectRandom
+ ? RandomStrategy.class
+ : SequentialStrategy.class);
+ String bookId = expectServerException ? "9999" : "123";
+ bookStore.path("bookstore/books").path(bookId);
+ Exception ex = null;
+ try {
+ Book book = bookStore.get(Book.class);
+ assertNotNull("expected non-null response", book);
+ assertEquals("unexpected id", 123L, book.getId());
+ } catch (Exception error) {
+ if (!expectServerException) {
+ throw error;
+ }
+ ex = error;
+ }
+ String currEndpoint = getCurrentEndpointAddress(bookStore);
+ assertFalse(currEndpoint.equals(inactiveReplica));
+ if (expectRandom) {
+ assertTrue(currEndpoint.equals(activeReplica1) || currEndpoint.equals(activeReplica2));
+ } else {
+ assertTrue(currEndpoint.equals(activeReplica1));
+ }
+ if (expectServerException) {
+ assertNotNull(ex);
+ throw ex;
+ }
+
+ if (!(prevEndpoint == null || currEndpoint.equals(prevEndpoint))) {
+ randomized = true;
+ }
+ prevEndpoint = currEndpoint;
+ }
+ assertEquals("unexpected random/sequential distribution of failovers",
+ expectRandom,
+ randomized);
+ }
+
+
+ protected String getCurrentEndpointAddress(Object client) {
+ return WebClient.client(client).getBaseURI().toString();
+ }
+
+
+ protected void verifyStrategy(Object proxy, Class clz) {
+ ConduitSelector conduitSelector =
+ WebClient.getConfig(proxy).getConduitSelector();
+ if (conduitSelector instanceof FailoverTargetSelector) {
+ Object strategy =
+ ((FailoverTargetSelector)conduitSelector).getStrategy();
+ assertTrue("unexpected strategy", clz.isInstance(strategy));
+ } else {
+ fail("unexpected conduit selector: " + conduitSelector);
+ }
+ }
+
+}
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/FailoverTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/FailoverTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/Server.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/Server.java?rev=1131422&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/Server.java (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/Server.java Sat Jun 4 16:06:06 2011
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cxf.systest.jaxrs.failover;
+
+
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.systest.jaxrs.BookStore;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+
+public class Server extends AbstractBusTestServerBase {
+ public static final String PORT1 = allocatePort(Server.class, 0);
+ public static final String PORT2 = allocatePort(Server.class, 1);
+ public static final String PORT3 = allocatePort(Server.class, 3);
+
+ public static final String ADDRESS1 = "http://localhost:" + PORT1 + "/rest";
+ public static final String ADDRESS2 = "http://localhost:" + PORT2 + "/rest";
+ public static final String ADDRESS3 = "http://localhost:" + PORT3 + "/work/rest";
+
+
+ protected void run() {
+ createEndpoint(ADDRESS2);
+ createEndpoint(ADDRESS3);
+ }
+
+ private void createEndpoint(String address) {
+ JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setResourceClasses(BookStore.class);
+ sf.setResourceProvider(BookStore.class, new SingletonResourceProvider(new BookStore(), false));
+ sf.setAddress(address);
+ sf.create();
+ }
+
+ public static void main(String[] args) {
+ try {
+ Server s = new Server();
+ s.start();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.exit(-1);
+ } finally {
+ System.out.println("done!");
+ }
+ }
+}
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/Server.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/failover/Server.java
------------------------------------------------------------------------------
svn:keywords = Rev Date