diff --git a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/mock/MockProxyFactory.java b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/mock/MockProxyFactory.java index 3de2e3a9833..cd78366c00b 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/mock/MockProxyFactory.java +++ b/dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/mock/MockProxyFactory.java @@ -27,6 +27,11 @@ public T getProxy(Invoker invoker) throws RpcException { return null; } + @Override + public T getProxy(Invoker invoker, boolean generic) throws RpcException { + return null; + } + @Override public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { return null; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/ProxyFactory.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/ProxyFactory.java index 6ba705717ba..fb03d6bda44 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/ProxyFactory.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/ProxyFactory.java @@ -36,6 +36,15 @@ public interface ProxyFactory { @Adaptive({Constants.PROXY_KEY}) T getProxy(Invoker invoker) throws RpcException; + /** + * create proxy. + * + * @param invoker + * @return proxy + */ + @Adaptive({Constants.PROXY_KEY}) + T getProxy(Invoker invoker, boolean generic) throws RpcException; + /** * create invoker. * diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericFilter.java index d393822625a..8404a99f3ca 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericFilter.java @@ -32,10 +32,12 @@ import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.RpcInvocation; import com.alibaba.dubbo.rpc.RpcResult; import com.alibaba.dubbo.rpc.service.GenericException; +import com.alibaba.dubbo.rpc.service.GenericService; import com.alibaba.dubbo.rpc.support.ProtocolUtils; import java.io.IOException; @@ -52,7 +54,7 @@ public Result invoke(Invoker invoker, Invocation inv) throws RpcException { if (inv.getMethodName().equals(Constants.$INVOKE) && inv.getArguments() != null && inv.getArguments().length == 3 - && !ProtocolUtils.isGeneric(invoker.getUrl().getParameter(Constants.GENERIC_KEY))) { + && !invoker.getInterface().equals(GenericService.class)) { String name = ((String) inv.getArguments()[0]).trim(); String[] types = (String[]) inv.getArguments()[1]; Object[] args = (Object[]) inv.getArguments()[2]; @@ -63,6 +65,11 @@ public Result invoke(Invoker invoker, Invocation inv) throws RpcException { args = new Object[params.length]; } String generic = inv.getAttachment(Constants.GENERIC_KEY); + + if (StringUtils.isBlank(generic)) { + generic = RpcContext.getContext().getAttachment(Constants.GENERIC_KEY); + } + if (StringUtils.isEmpty(generic) || ProtocolUtils.isDefaultGenericSerialization(generic)) { args = PojoUtils.realize(args, params, method.getGenericParameterTypes()); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericImplFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericImplFilter.java index 99bced54e74..6be08fef47c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericImplFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/filter/GenericImplFilter.java @@ -155,13 +155,13 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept for (Object arg : args) { if (!(byte[].class == arg.getClass())) { - error(byte[].class.getName(), arg.getClass().getName()); + error(generic, byte[].class.getName(), arg.getClass().getName()); } } } else if (ProtocolUtils.isBeanGenericSerialization(generic)) { for (Object arg : args) { if (!(arg instanceof JavaBeanDescriptor)) { - error(JavaBeanDescriptor.class.getName(), arg.getClass().getName()); + error(generic, JavaBeanDescriptor.class.getName(), arg.getClass().getName()); } } } @@ -172,10 +172,10 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept return invoker.invoke(invocation); } - private void error(String expected, String actual) throws RpcException { + private void error(String generic, String expected, String actual) throws RpcException { throw new RpcException( "Generic serialization [" + - Constants.GENERIC_SERIALIZATION_NATIVE_JAVA + + generic + "] only support message type " + expected + " and your message type is " + diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java index 8136cc02165..561520c49e7 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractProxyProtocol.java @@ -68,7 +68,7 @@ public Exporter export(final Invoker invoker) throws RpcException { if (exporter != null) { return exporter; } - final Runnable runnable = doExport(proxyFactory.getProxy(invoker), invoker.getInterface(), invoker.getUrl()); + final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl()); exporter = new AbstractExporter(invoker) { @Override public void unexport() { @@ -89,12 +89,12 @@ public void unexport() { @Override public Invoker refer(final Class type, final URL url) throws RpcException { - final Invoker tagert = proxyFactory.getInvoker(doRefer(type, url), type, url); + final Invoker target = proxyFactory.getInvoker(doRefer(type, url), type, url); Invoker invoker = new AbstractInvoker(type, url) { @Override protected Result doInvoke(Invocation invocation) throws Throwable { try { - Result result = tagert.invoke(invocation); + Result result = target.invoke(invocation); Throwable e = result.getException(); if (e != null) { for (Class rpcException : rpcExceptions) { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java index 21c350da9c1..d27f6089709 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/AbstractProxyFactory.java @@ -22,6 +22,7 @@ import com.alibaba.dubbo.rpc.ProxyFactory; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.service.EchoService; +import com.alibaba.dubbo.rpc.service.GenericService; /** * AbstractProxyFactory @@ -30,6 +31,11 @@ public abstract class AbstractProxyFactory implements ProxyFactory { @Override public T getProxy(Invoker invoker) throws RpcException { + return getProxy(invoker, false); + } + + @Override + public T getProxy(Invoker invoker, boolean generic) throws RpcException { Class[] interfaces = null; String config = invoker.getUrl().getParameter("interfaces"); if (config != null && config.length() > 0) { @@ -46,6 +52,15 @@ public T getProxy(Invoker invoker) throws RpcException { if (interfaces == null) { interfaces = new Class[]{invoker.getInterface(), EchoService.class}; } + + if (!invoker.getInterface().equals(GenericService.class) && generic) { + int len = interfaces.length; + Class[] temp = interfaces; + interfaces = new Class[len + 1]; + System.arraycopy(temp, 0, interfaces, 0, len); + interfaces[len] = GenericService.class; + } + return getProxy(invoker, interfaces); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java index ec3db16ceba..3f3ed3ff493 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/proxy/wrapper/StubProxyFactoryWrapper.java @@ -54,6 +54,11 @@ public void setProtocol(Protocol protocol) { this.protocol = protocol; } + @Override + public T getProxy(Invoker invoker, boolean generic) throws RpcException { + return proxyFactory.getProxy(invoker, generic); + } + @Override @SuppressWarnings({"unchecked", "rawtypes"}) public T getProxy(Invoker invoker) throws RpcException { diff --git a/dubbo-rpc/dubbo-rpc-hessian/pom.xml b/dubbo-rpc/dubbo-rpc-hessian/pom.xml index 00ca28cf2a3..98ad82de8f5 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/pom.xml +++ b/dubbo-rpc/dubbo-rpc-hessian/pom.xml @@ -48,5 +48,11 @@ org.apache.httpcomponents httpclient + + com.alibaba + dubbo-serialization-jdk + ${project.parent.version} + test + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/DubboHessianURLConnectionFactory.java b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/DubboHessianURLConnectionFactory.java new file mode 100644 index 00000000000..8fe2f14de44 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/DubboHessianURLConnectionFactory.java @@ -0,0 +1,40 @@ +/* + * 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 com.alibaba.dubbo.rpc.protocol.hessian; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.rpc.RpcContext; +import com.caucho.hessian.client.HessianConnection; +import com.caucho.hessian.client.HessianURLConnectionFactory; + +import java.io.IOException; +import java.net.URL; + +public class DubboHessianURLConnectionFactory extends HessianURLConnectionFactory { + + @Override + public HessianConnection open(URL url) throws IOException { + HessianConnection connection = super.open(url); + RpcContext context = RpcContext.getContext(); + for (String key : context.getAttachments().keySet()) { + connection.addHeader(Constants.DEFAULT_EXCHANGER + key, context.getAttachment(key)); + } + + return connection; + } +} diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java index f1eae5cf63c..9733307d629 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java +++ b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocol.java @@ -25,8 +25,11 @@ import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol; +import com.alibaba.dubbo.rpc.service.GenericService; +import com.alibaba.dubbo.rpc.support.ProtocolUtils; import com.caucho.hessian.HessianException; import com.caucho.hessian.client.HessianConnectionException; +import com.caucho.hessian.client.HessianConnectionFactory; import com.caucho.hessian.client.HessianProxyFactory; import com.caucho.hessian.io.HessianMethodSerializationException; import com.caucho.hessian.server.HessianSkeleton; @@ -37,6 +40,7 @@ import java.io.IOException; import java.net.SocketTimeoutException; import java.util.ArrayList; +import java.util.Enumeration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -73,12 +77,17 @@ protected Runnable doExport(T impl, Class type, URL url) throws RpcExcept serverMap.put(addr, server); } final String path = url.getAbsolutePath(); - HessianSkeleton skeleton = new HessianSkeleton(impl, type); + final HessianSkeleton skeleton = new HessianSkeleton(impl, type); skeletonMap.put(path, skeleton); + + final String genericPath = path + "/" + Constants.GENERIC_KEY; + skeletonMap.put(genericPath, new HessianSkeleton(impl, GenericService.class)); + return new Runnable() { @Override public void run() { skeletonMap.remove(path); + skeletonMap.remove(genericPath); } }; } @@ -86,6 +95,13 @@ public void run() { @Override @SuppressWarnings("unchecked") protected T doRefer(Class serviceType, URL url) throws RpcException { + String generic = url.getParameter(Constants.GENERIC_KEY); + boolean isGeneric = ProtocolUtils.isGeneric(generic) || serviceType.equals(GenericService.class); + if (isGeneric) { + RpcContext.getContext().setAttachment(Constants.GENERIC_KEY, generic); + url = url.setPath(url.getPath() + "/" + Constants.GENERIC_KEY); + } + HessianProxyFactory hessianProxyFactory = new HessianProxyFactory(); boolean isHessian2Request = url.getParameter(Constants.HESSIAN2_REQUEST_KEY, Constants.DEFAULT_HESSIAN2_REQUEST); hessianProxyFactory.setHessian2Request(isHessian2Request); @@ -96,6 +112,10 @@ protected T doRefer(Class serviceType, URL url) throws RpcException { hessianProxyFactory.setConnectionFactory(new HttpClientConnectionFactory()); } else if (client != null && client.length() > 0 && !Constants.DEFAULT_HTTP_CLIENT.equals(client)) { throw new IllegalStateException("Unsupported http protocol client=\"" + client + "\"!"); + } else { + HessianConnectionFactory factory = new DubboHessianURLConnectionFactory(); + factory.setHessianProxyFactory(hessianProxyFactory); + hessianProxyFactory.setConnectionFactory(factory); } int timeout = url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); hessianProxyFactory.setConnectTimeout(timeout); @@ -148,6 +168,16 @@ public void handle(HttpServletRequest request, HttpServletResponse response) response.setStatus(500); } else { RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); + + Enumeration enumeration = request.getHeaderNames(); + while (enumeration.hasMoreElements()) { + String key = enumeration.nextElement(); + if (key.startsWith(Constants.DEFAULT_EXCHANGER)) { + RpcContext.getContext().setAttachment(key.substring(Constants.DEFAULT_EXCHANGER.length()), + request.getHeader(key)); + } + } + try { skeleton.invoke(request.getInputStream(), response.getOutputStream()); } catch (Throwable e) { diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HttpClientConnectionFactory.java b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HttpClientConnectionFactory.java index 033277d02e6..b19cd275c8a 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HttpClientConnectionFactory.java +++ b/dubbo-rpc/dubbo-rpc-hessian/src/main/java/com/alibaba/dubbo/rpc/protocol/hessian/HttpClientConnectionFactory.java @@ -16,6 +16,8 @@ */ package com.alibaba.dubbo.rpc.protocol.hessian; +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.rpc.RpcContext; import com.caucho.hessian.client.HessianConnection; import com.caucho.hessian.client.HessianConnectionFactory; import com.caucho.hessian.client.HessianProxyFactory; @@ -41,7 +43,12 @@ public void setHessianProxyFactory(HessianProxyFactory factory) { @Override public HessianConnection open(URL url) throws IOException { - return new HttpClientConnection(httpClient, url); + HttpClientConnection httpClientConnection = new HttpClientConnection(httpClient, url); + RpcContext context = RpcContext.getContext(); + for (String key : context.getAttachments().keySet()) { + httpClientConnection.addHeader(Constants.DEFAULT_EXCHANGER + key, context.getAttachment(key)); + } + return httpClientConnection; } } diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java index 877ecd38842..bae03335c5c 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianProtocolTest.java @@ -17,17 +17,29 @@ package com.alibaba.dubbo.rpc.protocol.hessian; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.beanutil.JavaBeanDescriptor; +import com.alibaba.dubbo.common.beanutil.JavaBeanSerializeUtil; import com.alibaba.dubbo.common.extension.ExtensionLoader; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.common.serialize.nativejava.NativeJavaSerialization; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Protocol; import com.alibaba.dubbo.rpc.ProxyFactory; +import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.protocol.hessian.HessianServiceImpl.MyException; +import com.alibaba.dubbo.rpc.service.GenericService; import org.junit.Assert; import org.junit.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + import static org.junit.Assert.fail; /** @@ -52,6 +64,87 @@ public void testHessianProtocol() { exporter.unexport(); } + @Test + public void testGenericInvoke() { + HessianServiceImpl server = new HessianServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("hessian://127.0.0.1:5342/" + HessianService.class.getName() + "?version=1.0.0"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HessianService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxyFactory.getProxy(invoker, true); + String result = (String) client.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"haha"}); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", result); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testGenericInvokeWithNativeJava() throws IOException, ClassNotFoundException { + HessianServiceImpl server = new HessianServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("hessian://127.0.0.1:5342/" + HessianService.class.getName() + "?version=1.0.0&generic=nativejava"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HessianService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxyFactory.getProxy(invoker); + + Serialization serialization = new NativeJavaSerialization(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject("haha"); + objectOutput.flushBuffer(); + + Object result = client.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{byteArrayOutputStream.toByteArray()}); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream((byte[]) result); + ObjectInput objectInput = serialization.deserialize(url, byteArrayInputStream); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", objectInput.readObject()); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testGenericInvokeWithRpcContext() { + RpcContext.getContext().setAttachment("myContext", "123"); + + HessianServiceImpl server = new HessianServiceImpl(); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("hessian://127.0.0.1:5342/" + HessianService.class.getName() + "?version=1.0.0"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HessianService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxyFactory.getProxy(invoker, true); + String result = (String) client.$invoke("context", new String[]{"java.lang.String"}, new Object[]{"haha"}); + Assert.assertEquals("Hello, haha context, 123", result); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testGenericInvokeWithBean() { + HessianServiceImpl server = new HessianServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("hessian://127.0.0.1:5342/" + HessianService.class.getName() + "?version=1.0.0&generic=bean"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HessianService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxyFactory.getProxy(invoker); + + JavaBeanDescriptor javaBeanDescriptor = JavaBeanSerializeUtil.serialize("haha"); + + Object result = client.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{javaBeanDescriptor}); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", JavaBeanSerializeUtil.deserialize((JavaBeanDescriptor) result)); + invoker.destroy(); + exporter.unexport(); + } + @Test public void testOverload() { HessianServiceImpl server = new HessianServiceImpl(); diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java index 8629425145e..9df4524f1d1 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java +++ b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianService.java @@ -30,4 +30,6 @@ public interface HessianService { String customException(); + String context(String name); + } diff --git a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java index 855de0a28a5..68d14b3f2bb 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java +++ b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/com/alibaba/dubbo/rpc/protocol/hessian/HessianServiceImpl.java @@ -16,6 +16,8 @@ */ package com.alibaba.dubbo.rpc.protocol.hessian; +import com.alibaba.dubbo.rpc.RpcContext; + /** * HessianServiceImpl */ @@ -53,6 +55,10 @@ public String customException() { throw new MyException("custom exception"); } + public String context(String name) { + return "Hello, " + name + " context, " + RpcContext.getContext().getAttachment("myContext"); + } + static class MyException extends RuntimeException { private static final long serialVersionUID = -3051041116483629056L; diff --git a/dubbo-rpc/dubbo-rpc-http/pom.xml b/dubbo-rpc/dubbo-rpc-http/pom.xml index 427b70ba6a3..93d8a0f028f 100644 --- a/dubbo-rpc/dubbo-rpc-http/pom.xml +++ b/dubbo-rpc/dubbo-rpc-http/pom.xml @@ -48,5 +48,11 @@ org.springframework spring-web + + com.alibaba + dubbo-serialization-jdk + ${project.parent.version} + test + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java index 27a59134e8c..3fc908749a8 100644 --- a/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java +++ b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocol.java @@ -24,12 +24,16 @@ import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol; - +import com.alibaba.dubbo.rpc.service.GenericService; +import com.alibaba.dubbo.rpc.support.ProtocolUtils; +import org.aopalliance.intercept.MethodInvocation; import org.springframework.remoting.RemoteAccessException; import org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor; import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean; import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter; import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationFactory; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -74,6 +78,22 @@ protected Runnable doExport(final T impl, Class type, URL url) throws Rpc server = httpBinder.bind(url, new InternalHandler()); serverMap.put(addr, server); } + final String path = url.getAbsolutePath(); + skeletonMap.put(path, createExporter(impl, type)); + + final String genericPath = path + "/" + Constants.GENERIC_KEY; + + skeletonMap.put(genericPath, createExporter(impl, GenericService.class)); + return new Runnable() { + @Override + public void run() { + skeletonMap.remove(path); + skeletonMap.remove(genericPath); + } + }; + } + + private HttpInvokerServiceExporter createExporter(T impl, Class type) { final HttpInvokerServiceExporter httpServiceExporter = new HttpInvokerServiceExporter(); httpServiceExporter.setServiceInterface(type); httpServiceExporter.setService(impl); @@ -82,21 +102,33 @@ protected Runnable doExport(final T impl, Class type, URL url) throws Rpc } catch (Exception e) { throw new RpcException(e.getMessage(), e); } - final String path = url.getAbsolutePath(); - skeletonMap.put(path, httpServiceExporter); - return new Runnable() { - @Override - public void run() { - skeletonMap.remove(path); - } - }; + return httpServiceExporter; } @Override @SuppressWarnings("unchecked") protected T doRefer(final Class serviceType, final URL url) throws RpcException { + final String generic = url.getParameter(Constants.GENERIC_KEY); + final boolean isGeneric = ProtocolUtils.isGeneric(generic) || serviceType.equals(GenericService.class); + final HttpInvokerProxyFactoryBean httpProxyFactoryBean = new HttpInvokerProxyFactoryBean(); - httpProxyFactoryBean.setServiceUrl(url.toIdentityString()); + httpProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() { + @Override + public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { + RemoteInvocation invocation = new HttpRemoteInvocation(methodInvocation); + if (isGeneric) { + invocation.addAttribute(Constants.GENERIC_KEY, generic); + } + return invocation; + } + }); + + String key = url.toIdentityString(); + if (isGeneric) { + key = key + "/" + Constants.GENERIC_KEY; + } + + httpProxyFactoryBean.setServiceUrl(key); httpProxyFactoryBean.setServiceInterface(serviceType); String client = url.getParameter(Constants.CLIENT_KEY); if (client == null || client.length() == 0 || "simple".equals(client)) { @@ -112,7 +144,8 @@ protected void prepareConnection(HttpURLConnection con, httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor); } else if ("commons".equals(client)) { HttpComponentsHttpInvokerRequestExecutor httpInvokerRequestExecutor = new HttpComponentsHttpInvokerRequestExecutor(); - httpInvokerRequestExecutor.setReadTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT)); + httpInvokerRequestExecutor.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT)); + httpInvokerRequestExecutor.setConnectTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT)); httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor); } else { throw new IllegalStateException("Unsupported http protocol client " + client + ", only supported: simple, commons"); diff --git a/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpRemoteInvocation.java b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpRemoteInvocation.java new file mode 100644 index 00000000000..5054c4fded8 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpRemoteInvocation.java @@ -0,0 +1,57 @@ +/* + * 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 com.alibaba.dubbo.rpc.protocol.http; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.rpc.RpcContext; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.remoting.support.RemoteInvocation; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +public class HttpRemoteInvocation extends RemoteInvocation { + + private static final long serialVersionUID = 1L; + private static final String dubboAttachmentsAttrName = "dubbo.attachments"; + + public HttpRemoteInvocation(MethodInvocation methodInvocation) { + super(methodInvocation); + addAttribute(dubboAttachmentsAttrName, new HashMap(RpcContext.getContext().getAttachments())); + } + + @Override + public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + RpcContext context = RpcContext.getContext(); + context.setAttachments((Map) getAttribute(dubboAttachmentsAttrName)); + + String generic = (String) getAttribute(Constants.GENERIC_KEY); + if (StringUtils.isNotEmpty(generic)) { + context.setAttachment(Constants.GENERIC_KEY, generic); + } + try { + return super.invoke(targetObject); + } finally { + context.setAttachments(null); + + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocolTest.java b/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocolTest.java new file mode 100644 index 00000000000..014eed6558a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpProtocolTest.java @@ -0,0 +1,198 @@ +/* + * 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 com.alibaba.dubbo.rpc.protocol.http; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.beanutil.JavaBeanDescriptor; +import com.alibaba.dubbo.common.beanutil.JavaBeanSerializeUtil; +import com.alibaba.dubbo.common.extension.ExtensionLoader; +import com.alibaba.dubbo.common.serialize.ObjectInput; +import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.common.serialize.nativejava.NativeJavaSerialization; +import com.alibaba.dubbo.rpc.*; +import com.alibaba.dubbo.rpc.service.GenericService; +import junit.framework.Assert; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.fail; + +/** + * HttpProtocolTest + */ +public class HttpProtocolTest { + + @Test + public void testHttpProtocol() { + HttpServiceImpl server = new HttpServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(HttpService.class, url); + HttpService client = proxyFactory.getProxy(invoker); + String result = client.sayHello("haha"); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", result); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testGenericInvoke() { + HttpServiceImpl server = new HttpServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxyFactory.getProxy(invoker, true); + String result = (String) client.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"haha"}); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", result); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testGenericInvokeWithNativeJava() throws IOException, ClassNotFoundException { + HttpServiceImpl server = new HttpServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&generic=nativejava"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxyFactory.getProxy(invoker); + + Serialization serialization = new NativeJavaSerialization(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + ObjectOutput objectOutput = serialization.serialize(url, byteArrayOutputStream); + objectOutput.writeObject("haha"); + objectOutput.flushBuffer(); + + Object result = client.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{byteArrayOutputStream.toByteArray()}); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream((byte[]) result); + ObjectInput objectInput = serialization.deserialize(url, byteArrayInputStream); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", objectInput.readObject()); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testGenericInvokeWithBean() { + HttpServiceImpl server = new HttpServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&generic=bean"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(GenericService.class, url); + GenericService client = proxyFactory.getProxy(invoker); + + JavaBeanDescriptor javaBeanDescriptor = JavaBeanSerializeUtil.serialize("haha"); + + Object result = client.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{javaBeanDescriptor}); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", JavaBeanSerializeUtil.deserialize((JavaBeanDescriptor) result)); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testOverload() { + HttpServiceImpl server = new HttpServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&hessian.overload.method=true&hessian2.request=false"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(HttpService.class, url); + HttpService client = proxyFactory.getProxy(invoker); + String result = client.sayHello("haha"); + Assert.assertEquals("Hello, haha", result); + result = client.sayHello("haha", 1); + Assert.assertEquals("Hello, haha. ", result); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testSimpleClient() { + HttpServiceImpl server = new HttpServiceImpl(); + Assert.assertFalse(server.isCalled()); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&client=simple"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(HttpService.class, url); + HttpService client = proxyFactory.getProxy(invoker); + String result = client.sayHello("haha"); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", result); + invoker.destroy(); + exporter.unexport(); + } + + @Test + public void testTimeOut() { + HttpServiceImpl server = new HttpServiceImpl(); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&timeout=10"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(HttpService.class, url); + HttpService client = proxyFactory.getProxy(invoker); + try { + client.timeOut(6000); + fail(); + } catch (RpcException expected) { + Assert.assertEquals(true, expected.isTimeout()); + } finally { + invoker.destroy(); + exporter.unexport(); + } + + } + + @Test + public void testCustomException() { + HttpServiceImpl server = new HttpServiceImpl(); + ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); + Invoker invoker = protocol.refer(HttpService.class, url); + HttpService client = proxyFactory.getProxy(invoker); + try { + client.customException(); + fail(); + } catch (HttpServiceImpl.MyException expected) { + } + invoker.destroy(); + exporter.unexport(); + } + +} diff --git a/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpService.java b/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpService.java new file mode 100644 index 00000000000..0d0d22c1e76 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpService.java @@ -0,0 +1,33 @@ +/* + * 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 com.alibaba.dubbo.rpc.protocol.http; + + +/** + * HttpService + */ +public interface HttpService { + + String sayHello(String name); + + String sayHello(String name, int times); + + void timeOut(int millis); + + String customException(); + +} diff --git a/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpServiceImpl.java b/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpServiceImpl.java new file mode 100644 index 00000000000..1c78b3ba692 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-http/src/test/java/com/alibaba/dubbo/rpc/protocol/http/HttpServiceImpl.java @@ -0,0 +1,64 @@ +/* + * 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 com.alibaba.dubbo.rpc.protocol.http; + +/** + * HttpServiceImpl + */ +public class HttpServiceImpl implements HttpService { + + private boolean called; + + public String sayHello(String name) { + called = true; + return "Hello, " + name; + } + + public String sayHello(String name, int times) { + called = true; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < times; i++) { + sb.append("Hello, " + name + ". "); + } + return sb.toString(); + } + + public boolean isCalled() { + return called; + } + + public void timeOut(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public String customException() { + throw new MyException("custom exception"); + } + + static class MyException extends RuntimeException { + + private static final long serialVersionUID = -3051041116483629056L; + + public MyException(String message) { + super(message); + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-rest/pom.xml b/dubbo-rpc/dubbo-rpc-rest/pom.xml index 026e2c293a9..724ae6dac99 100644 --- a/dubbo-rpc/dubbo-rpc-rest/pom.xml +++ b/dubbo-rpc/dubbo-rpc-rest/pom.xml @@ -105,5 +105,11 @@ netty-all + + com.alibaba + dubbo-serialization-jdk + ${project.parent.version} + test + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestProtocolTest.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestProtocolTest.java new file mode 100644 index 00000000000..4764cf6b66f --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestProtocolTest.java @@ -0,0 +1,48 @@ +/* + * 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 com.alibaba.dubbo.rpc.protol.rest; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extension.ExtensionLoader; +import com.alibaba.dubbo.rpc.*; +import junit.framework.Assert; +import org.junit.Test; + +/** + * RestProtocolTest + */ +public class RestProtocolTest { + + private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + private ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + @Test + public void testRestProtocol() { + ServiceClassHolder.getInstance().pushServiceClass(RestServiceImpl.class); + RestServiceImpl server = new RestServiceImpl(); + Assert.assertFalse(server.isCalled()); + URL url = URL.valueOf("rest://127.0.0.1:5342/rest/say1?version=1.0.0"); + Exporter exporter = protocol.export(proxyFactory.getInvoker(server, RestService.class, url)); + Invoker invoker = protocol.refer(RestService.class, url); + RestService client = proxyFactory.getProxy(invoker); + String result = client.sayHello("haha"); + Assert.assertTrue(server.isCalled()); + Assert.assertEquals("Hello, haha", result); + invoker.destroy(); + exporter.unexport(); + } +} diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestService.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestService.java new file mode 100644 index 00000000000..30441b2a87d --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestService.java @@ -0,0 +1,36 @@ +/* + * 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 com.alibaba.dubbo.rpc.protol.rest; + + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +/** + * RestService + */ +@Path("/rest") +public interface RestService { + + @POST + @Path("/say1") + @Consumes({MediaType.TEXT_PLAIN}) + String sayHello(String name); + +} diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestServiceImpl.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestServiceImpl.java new file mode 100644 index 00000000000..3de80d266ca --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/com/alibaba/dubbo/rpc/protol/rest/RestServiceImpl.java @@ -0,0 +1,36 @@ +/* + * 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 com.alibaba.dubbo.rpc.protol.rest; + +/** + * RestServiceImpl + */ + +public class RestServiceImpl implements RestService { + + private boolean called; + + public String sayHello(String name) { + called = true; + return "Hello, " + name; + } + + + public boolean isCalled() { + return called; + } +}