Author: sergeyb Date: Thu Jul 2 11:37:39 2009 New Revision: 790553 URL: http://svn.apache.org/viewvc?rev=790553&view=rev Log: [CXF-2323] : Support for features in JAX-RS clients (patch from Eamonn with minor modifications, thanks)
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientConfiguration.java (with props) Modified: cxf/trunk/api/src/main/java/org/apache/cxf/feature/AbstractFeature.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/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBeanTest.java cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java Modified: cxf/trunk/api/src/main/java/org/apache/cxf/feature/AbstractFeature.java URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/feature/AbstractFeature.java?rev=790553&r1=790552&r2=790553&view=diff ============================================================================== --- cxf/trunk/api/src/main/java/org/apache/cxf/feature/AbstractFeature.java (original) +++ cxf/trunk/api/src/main/java/org/apache/cxf/feature/AbstractFeature.java Thu Jul 2 11:37:39 2009 @@ -43,6 +43,10 @@ initializeProvider(client, bus); } + public void initialize(InterceptorProvider interceptorProvider, Bus bus) { + initializeProvider(interceptorProvider, bus); + } + public void initialize(Bus bus) { initializeProvider(bus, bus); } @@ -71,4 +75,4 @@ } return active; } -} \ No newline at end of file +} 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=790553&r1=790552&r2=790553&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 Thu Jul 2 11:37:39 2009 @@ -50,7 +50,6 @@ import org.apache.cxf.BusFactory; import org.apache.cxf.common.i18n.BundleUtils; import org.apache.cxf.common.logging.LogUtils; -import org.apache.cxf.common.util.ModCountCopyOnWriteArrayList; import org.apache.cxf.endpoint.ConduitSelector; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.helpers.IOUtils; @@ -75,23 +74,17 @@ * */ public class AbstractClient implements Client, InvocationHandlerAware { - private static final Logger LOG = LogUtils.getL7dLogger(AbstractClient.class); private static final ResourceBundle BUNDLE = BundleUtils.getBundle(AbstractClient.class); - - protected List<Interceptor> inInterceptors = new ModCountCopyOnWriteArrayList<Interceptor>(); - protected List<Interceptor> outInterceptors = new ModCountCopyOnWriteArrayList<Interceptor>(); - protected ConduitSelector conduitSelector; - protected Bus bus; + protected ClientConfiguration cfg = new ClientConfiguration(); + private MultivaluedMap<String, String> requestHeaders = new MetadataMap<String, String>(); private ResponseBuilder responseBuilder; private URI baseURI; private UriBuilder currentBuilder; - - protected AbstractClient(URI baseURI, URI currentURI) { this.baseURI = baseURI; this.currentBuilder = new UriBuilderImpl(currentURI); @@ -485,31 +478,31 @@ } } - protected void setConduitSelector(ConduitSelector cs) { - this.conduitSelector = cs; + protected ClientConfiguration getConfiguration() { + return cfg; } - protected void setBus(Bus bus) { - this.bus = bus; + protected void setConfiguration(ClientConfiguration config) { + cfg = config; } protected void prepareConduitSelector(Message message) { - conduitSelector.prepare(message); - message.getExchange().put(ConduitSelector.class, conduitSelector); + cfg.getConduitSelector().prepare(message); + message.getExchange().put(ConduitSelector.class, cfg.getConduitSelector()); } protected PhaseInterceptorChain setupOutInterceptorChain(Endpoint endpoint) { - PhaseManager pm = bus.getExtension(PhaseManager.class); - List<Interceptor> i1 = bus.getOutInterceptors(); - List<Interceptor> i2 = outInterceptors; + PhaseManager pm = cfg.getBus().getExtension(PhaseManager.class); + List<Interceptor> i1 = cfg.getBus().getOutInterceptors(); + List<Interceptor> i2 = cfg.getOutInterceptors(); List<Interceptor> i3 = endpoint.getOutInterceptors(); return new PhaseChainCache().get(pm.getOutPhases(), i1, i2, i3); } protected PhaseInterceptorChain setupInInterceptorChain(Endpoint endpoint) { - PhaseManager pm = bus.getExtension(PhaseManager.class); - List<Interceptor> i1 = bus.getInInterceptors(); - List<Interceptor> i2 = inInterceptors; + PhaseManager pm = cfg.getBus().getExtension(PhaseManager.class); + List<Interceptor> i1 = cfg.getBus().getInInterceptors(); + List<Interceptor> i2 = cfg.getInInterceptors(); List<Interceptor> i3 = endpoint.getInInterceptors(); return new PhaseChainCache().get(pm.getInPhases(), i1, i2, i3); } @@ -523,7 +516,7 @@ protected Message createMessage(String httpMethod, MultivaluedMap<String, String> headers, URI currentURI) { - Message m = conduitSelector.getEndpoint().getBinding().createMessage(); + Message m = cfg.getConduitSelector().getEndpoint().getBinding().createMessage(); m.put(Message.REQUESTOR_ROLE, Boolean.TRUE); m.put(Message.INBOUND_MESSAGE, Boolean.FALSE); @@ -538,13 +531,13 @@ Exchange exchange = new ExchangeImpl(); exchange.setSynchronous(true); exchange.setOutMessage(m); - exchange.put(Bus.class, bus); + exchange.put(Bus.class, cfg.getBus()); exchange.put(MessageObserver.class, new ClientMessageObserver()); - exchange.put(Endpoint.class, conduitSelector.getEndpoint()); + exchange.put(Endpoint.class, cfg.getConduitSelector().getEndpoint()); exchange.setOneWay(false); m.setExchange(exchange); - PhaseInterceptorChain chain = setupOutInterceptorChain(conduitSelector.getEndpoint()); + PhaseInterceptorChain chain = setupOutInterceptorChain(cfg.getConduitSelector().getEndpoint()); m.setInterceptorChain(chain); //setup conduit selector @@ -553,26 +546,18 @@ return m; } - protected void setInInterceptors(List<Interceptor> interceptors) { - inInterceptors = interceptors; - } - - protected void setOutInterceptors(List<Interceptor> interceptors) { - outInterceptors = interceptors; - } - private class ClientMessageObserver implements MessageObserver { public void onMessage(Message m) { - Message message = conduitSelector.getEndpoint().getBinding().createMessage(m); + Message message = cfg.getConduitSelector().getEndpoint().getBinding().createMessage(m); message.put(Message.REQUESTOR_ROLE, Boolean.FALSE); message.put(Message.INBOUND_MESSAGE, Boolean.TRUE); - PhaseInterceptorChain chain = setupInInterceptorChain(conduitSelector.getEndpoint()); + PhaseInterceptorChain chain = setupInInterceptorChain(cfg.getConduitSelector().getEndpoint()); message.setInterceptorChain(chain); message.getExchange().setInMessage(message); Bus origBus = BusFactory.getThreadDefaultBus(false); - BusFactory.setThreadDefaultBus(bus); + BusFactory.setThreadDefaultBus(cfg.getBus()); // execute chain try { @@ -587,4 +572,6 @@ public Object getInvocationHandler() { return this; } + + } Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientConfiguration.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientConfiguration.java?rev=790553&view=auto ============================================================================== --- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientConfiguration.java (added) +++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientConfiguration.java Thu Jul 2 11:37:39 2009 @@ -0,0 +1,85 @@ +/** + * 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.client; + +import java.util.List; + +import org.apache.cxf.Bus; +import org.apache.cxf.common.util.ModCountCopyOnWriteArrayList; +import org.apache.cxf.endpoint.ConduitSelector; +import org.apache.cxf.interceptor.Interceptor; +import org.apache.cxf.interceptor.InterceptorProvider; + +public class ClientConfiguration implements InterceptorProvider { + + private List<Interceptor> inInterceptors = new ModCountCopyOnWriteArrayList<Interceptor>(); + private List<Interceptor> outInterceptors = new ModCountCopyOnWriteArrayList<Interceptor>(); + private List<Interceptor> outFault = new ModCountCopyOnWriteArrayList<Interceptor>(); + private List<Interceptor> inFault = new ModCountCopyOnWriteArrayList<Interceptor>(); + private ConduitSelector conduitSelector; + private Bus bus; + + public void setConduitSelector(ConduitSelector cs) { + this.conduitSelector = cs; + } + + public ConduitSelector getConduitSelector() { + return conduitSelector; + } + + public void setBus(Bus bus) { + this.bus = bus; + } + + public Bus getBus() { + return bus; + } + + public List<Interceptor> getInFaultInterceptors() { + return inFault; + } + + public List<Interceptor> getInInterceptors() { + return inInterceptors; + } + + public List<Interceptor> getOutFaultInterceptors() { + return outFault; + } + + public List<Interceptor> getOutInterceptors() { + return outInterceptors; + } + + public void setInInterceptors(List<Interceptor> interceptors) { + inInterceptors = interceptors; + } + + public void setOutInterceptors(List<Interceptor> interceptors) { + outInterceptors = interceptors; + } + + public void setInFaultInterceptors(List<Interceptor> interceptors) { + inFault = interceptors; + } + + public void setOutFaultInterceptors(List<Interceptor> interceptors) { + outFault = interceptors; + } +} Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientConfiguration.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientConfiguration.java ------------------------------------------------------------------------------ svn:keywords = Rev Date 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=790553&r1=790552&r2=790553&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 Thu Jul 2 11:37:39 2009 @@ -145,10 +145,7 @@ reportInvalidResourceMethod(m, "INVALID_SUBRESOURCE"); } ClientProxyImpl proxyImpl = new ClientProxyImpl(getBaseURI(), uri, subCri, false, inheritHeaders); - proxyImpl.setBus(bus); - proxyImpl.setConduitSelector(conduitSelector); - proxyImpl.setInInterceptors(inInterceptors); - proxyImpl.setOutInterceptors(outInterceptors); + proxyImpl.setConfiguration(getConfiguration()); Object proxy = JAXRSClientFactory.create(m.getReturnType(), proxyImpl); if (inheritHeaders) { 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=790553&r1=790552&r2=790553&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 Thu Jul 2 11:37:39 2009 @@ -29,6 +29,7 @@ import org.apache.cxf.endpoint.ConduitSelector; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.endpoint.UpfrontConduitSelector; +import org.apache.cxf.feature.AbstractFeature; import org.apache.cxf.jaxrs.AbstractJAXRSFactoryBean; import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean; import org.apache.cxf.jaxrs.JAXRSServiceImpl; @@ -167,14 +168,22 @@ ep.getEndpointInfo().addExtensor(authPolicy); } - - client.setConduitSelector(getConduitSelector(ep)); - client.setBus(getBus()); - client.setOutInterceptors(getOutInterceptors()); - client.setInInterceptors(getInInterceptors()); + applyFeatures(client); + client.getConfiguration().setConduitSelector(getConduitSelector(ep)); + client.getConfiguration().setBus(getBus()); + client.getConfiguration().getOutInterceptors().addAll(getOutInterceptors()); + client.getConfiguration().getInInterceptors().addAll(getInInterceptors()); if (headers != null) { client.headers(headers); } setupFactory(ep); } + + protected void applyFeatures(AbstractClient client) { + if (getFeatures() != null) { + for (AbstractFeature feature : getFeatures()) { + feature.initialize(client.getConfiguration(), getBus()); + } + } + } } 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=790553&r1=790552&r2=790553&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 Thu Jul 2 11:37:39 2009 @@ -536,10 +536,7 @@ static void copyProperties(Client toClient, Client fromClient) { AbstractClient newClient = toAbstractClient(toClient); AbstractClient oldClient = toAbstractClient(fromClient); - newClient.bus = oldClient.bus; - newClient.conduitSelector = oldClient.conduitSelector; - newClient.inInterceptors = oldClient.inInterceptors; - newClient.outInterceptors = oldClient.outInterceptors; + newClient.setConfiguration(oldClient.getConfiguration()); } private static AbstractClient toAbstractClient(Client client) { Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBeanTest.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBeanTest.java?rev=790553&r1=790552&r2=790553&view=diff ============================================================================== --- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBeanTest.java (original) +++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBeanTest.java Thu Jul 2 11:37:39 2009 @@ -19,8 +19,18 @@ package org.apache.cxf.jaxrs.client; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cxf.Bus; +import org.apache.cxf.feature.AbstractFeature; +import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.interceptor.InterceptorProvider; import org.apache.cxf.jaxrs.resources.BookStore; import org.apache.cxf.jaxrs.resources.BookStoreSubresourcesOnly; +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.AbstractPhaseInterceptor; +import org.apache.cxf.phase.Phase; import org.junit.Assert; import org.junit.Test; @@ -68,4 +78,57 @@ WebClient.client(store2).getCurrentURI().toString()); } + @Test + public void testAddLoggingToClient() throws Exception { + JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); + bean.setAddress("http://bar"); + bean.setResourceClass(BookStoreSubresourcesOnly.class); + TestFeature testFeature = new TestFeature(); + List<AbstractFeature> features = new ArrayList<AbstractFeature>(); + features.add((AbstractFeature)testFeature); + bean.setFeatures(features); + + BookStoreSubresourcesOnly store = bean.create(BookStoreSubresourcesOnly.class, 1, 2, 3); + assertTrue("TestFeature wasn't initialized", testFeature.isInitialized()); + BookStoreSubresourcesOnly store2 = store.getItself3("id4"); + assertEquals("http://bar/bookstore/1/2/3/id4/sub3", + WebClient.client(store2).getCurrentURI().toString()); + } + + + private class TestFeature extends AbstractFeature { + private TestInterceptor testInterceptor; + + @Override + protected void initializeProvider(InterceptorProvider provider, Bus bus) { + testInterceptor = new TestInterceptor(); + provider.getOutInterceptors().add(testInterceptor); + } + + protected boolean isInitialized() { + return testInterceptor.isInitialized(); + } + } + + private class TestInterceptor extends AbstractPhaseInterceptor<Message> { + private boolean isInitialized; + + public TestInterceptor() { + this(Phase.PRE_STREAM); + } + + public TestInterceptor(String s) { + super(Phase.PRE_STREAM); + isInitialized = true; + } + + public void handleMessage(Message message) throws Fault { + } + + protected boolean isInitialized() { + return isInitialized; + } + + } + } Modified: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java URL: http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java?rev=790553&r1=790552&r2=790553&view=diff ============================================================================== --- cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java (original) +++ cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java Thu Jul 2 11:37:39 2009 @@ -24,6 +24,7 @@ import java.io.InputStream; import java.net.URL; import java.net.URLConnection; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -40,8 +41,11 @@ import org.apache.commons.httpclient.methods.FileRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.cxf.Bus; +import org.apache.cxf.feature.AbstractFeature; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.interceptor.Fault; +import org.apache.cxf.interceptor.InterceptorProvider; import org.apache.cxf.io.CachedOutputStream; import org.apache.cxf.jaxrs.client.JAXRSClientFactory; import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; @@ -389,6 +393,23 @@ getStringFromInputStream(getHttpInputStream("http://localhost:9092/test/services")); assertNotNull(listings); } + + @Test + public void testAddFeatureToClient() throws Exception { + String baseAddress = "http://localhost:9092/test/services/rest"; + JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); + bean.setAddress(baseAddress); + bean.setResourceClass(BookStoreJaxrsJaxws.class); + TestFeature testFeature = new TestFeature(); + List<AbstractFeature> features = new ArrayList<AbstractFeature>(); + features.add((AbstractFeature)testFeature); + bean.setFeatures(features); + BookStoreJaxrsJaxws proxy = (BookStoreJaxrsJaxws)bean.create(); + Book b = proxy.getBook(new Long("123")); + assertTrue("Interceptor not invoked", testFeature.handleMessageCalled()); + assertEquals(123, b.getId()); + assertEquals("CXF in Action", b.getName()); + } private String getStringFromInputStream(InputStream in) throws Exception { CachedOutputStream bos = new CachedOutputStream(); @@ -427,7 +448,7 @@ } } - + @Ignore public class TestStreamDrainInterptor extends AbstractPhaseInterceptor<Message> { public TestStreamDrainInterptor() { @@ -444,7 +465,7 @@ // input stream will be closed by readBytesFromStream() payload = IOUtils.readBytesFromStream(is); assertTrue("payload was null", payload != null); - assertTrue("payload was EMPTYR", payload.length > 0); + assertTrue("payload was EMPTY", payload.length > 0); message.setContent(InputStream.class, new ByteArrayInputStream(payload)); } catch (Exception e) { String error = "Failed to read the stream properly due to " + e.getMessage(); @@ -453,4 +474,41 @@ } } + + @Ignore + private class TestFeature extends AbstractFeature { + private TestInterceptor testInterceptor; + + @Override + protected void initializeProvider(InterceptorProvider provider, Bus bus) { + testInterceptor = new TestInterceptor(); + provider.getOutInterceptors().add(testInterceptor); + } + + protected boolean handleMessageCalled() { + return testInterceptor.handleMessageCalled(); + } + } + + @Ignore + private class TestInterceptor extends AbstractPhaseInterceptor<Message> { + private boolean handleMessageCalled; + public TestInterceptor() { + this(Phase.PRE_STREAM); + } + + public TestInterceptor(String s) { + super(Phase.PRE_STREAM); + + } + + public void handleMessage(Message message) throws Fault { + handleMessageCalled = true; + } + + protected boolean handleMessageCalled() { + return handleMessageCalled; + } + + } }