Merge branch '3.x-dev'

This commit is contained in:
ken.lj 2019-08-30 17:31:01 +08:00
commit 9f5cc83d34
122 changed files with 4729 additions and 1211 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ target/
*.zip
*.tar
*.tar.gz
.flattened-pom.xml
# eclipse ignore
.settings/

View File

@ -48,7 +48,7 @@ public class RouterChain<T> {
private RouterChain(URL url) {
List<RouterFactory> extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class)
.getActivateExtension(url, (String[]) null);
.getActivateExtension(url, "router");
List<Router> routers = extensionFactories.stream()
.map(factory -> factory.getRouter(url))

View File

@ -52,7 +52,7 @@ public class MockInvokersSelector extends AbstractRouter {
if (invocation.getAttachments() == null) {
return getNormalInvokers(invokers);
} else {
String value = invocation.getAttachments().get(INVOCATION_NEED_MOCK);
String value = (String) invocation.getAttachments().get(INVOCATION_NEED_MOCK);
if (value == null) {
return getNormalInvokers(invokers);
} else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {

View File

@ -98,7 +98,7 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
List<Invoker<T>> result = invokers;
String tag = StringUtils.isEmpty(invocation.getAttachment(Constants.TAG_KEY)) ? url.getParameter(Constants.TAG_KEY) :
invocation.getAttachment(Constants.TAG_KEY);
(String) invocation.getAttachment(Constants.TAG_KEY);
// if we are requesting for a Provider with a specific tag
if (StringUtils.isNotEmpty(tag)) {
@ -164,7 +164,7 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
List<Invoker<T>> result = invokers;
// Dynamic param
String tag = StringUtils.isEmpty(invocation.getAttachment(Constants.TAG_KEY)) ? url.getParameter(Constants.TAG_KEY) :
invocation.getAttachment(Constants.TAG_KEY);
(String) invocation.getAttachment(Constants.TAG_KEY);
// Tag request
if (!StringUtils.isEmpty(tag)) {
result = filterInvoker(invokers, invoker -> tag.equals(invoker.getUrl().getParameter(TAG_KEY)));
@ -189,7 +189,7 @@ public class TagRouter extends AbstractRouter implements ConfigurationListener {
}
private boolean isForceUseTag(Invocation invocation) {
return Boolean.valueOf(invocation.getAttachment(FORCE_USE_TAG, url.getParameter(FORCE_USE_TAG, "false")));
return Boolean.valueOf((String) invocation.getAttachment(FORCE_USE_TAG, url.getParameter(FORCE_USE_TAG, "false")));
}
private <T> List<Invoker<T>> filterInvoker(List<Invoker<T>> invokers, Predicate<Invoker<T>> predicate) {

View File

@ -237,7 +237,7 @@ public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
checkWhetherDestroyed();
// binding attachments into invocation.
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
Map<String, Object> contextAttachments = RpcContext.getContext().getAttachments();
if (contextAttachments != null && contextAttachments.size() != 0) {
((RpcInvocation) invocation).addAttachments(contextAttachments);
}

View File

@ -46,8 +46,8 @@ public class MockDirInvocation implements Invocation {
return new Object[]{"aa"};
}
public Map<String, String> getAttachments() {
Map<String, String> attachments = new HashMap<String, String>();
public Map<String, Object> getAttachments() {
Map<String, Object> attachments = new HashMap<String, Object>();
attachments.put(PATH_KEY, "dubbo");
attachments.put(GROUP_KEY, "dubbo");
attachments.put(VERSION_KEY, "1.0.0");
@ -58,12 +58,12 @@ public class MockDirInvocation implements Invocation {
}
@Override
public void setAttachment(String key, String value) {
public void setAttachment(String key, Object value) {
}
@Override
public void setAttachmentIfAbsent(String key, String value) {
public void setAttachmentIfAbsent(String key, Object value) {
}
@ -71,12 +71,27 @@ public class MockDirInvocation implements Invocation {
return null;
}
public String getAttachment(String key) {
@Override
public Object put(Object key, Object value) {
return null;
}
@Override
public Object get(Object key) {
return null;
}
@Override
public Map<Object, Object> getAttributes() {
return null;
}
public Object getAttachment(String key) {
return getAttachments().get(key);
}
public String getAttachment(String key, String defaultValue) {
public Object getAttachment(String key, Object defaultValue) {
return getAttachments().get(key);
}
}
}

View File

@ -150,7 +150,7 @@ public class AbstractClusterInvokerTest {
// setup attachment
RpcContext.getContext().setAttachment(attachKey, attachValue);
Map<String, String> attachments = RpcContext.getContext().getAttachments();
Map<String, Object> attachments = RpcContext.getContext().getAttachments();
Assertions.assertTrue( attachments != null && attachments.size() == 1,"set attachment failed!");
cluster = new AbstractClusterInvoker(dic) {
@ -158,7 +158,7 @@ public class AbstractClusterInvokerTest {
protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
throws RpcException {
// attachment will be bind to invocation
String value = invocation.getAttachment(attachKey);
String value = (String) invocation.getAttachment(attachKey);
Assertions.assertTrue(value != null && value.equals(attachValue),"binding attachment failed!");
return null;
}

View File

@ -1,156 +1,155 @@
/*
* 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.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* ForkingClusterInvokerTest
*/
@SuppressWarnings("unchecked")
public class ForkingClusterInvokerTest {
private List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
private URL url = URL.valueOf("test://test:11/test?forks=2");
private Invoker<ForkingClusterInvokerTest> invoker1 = mock(Invoker.class);
private Invoker<ForkingClusterInvokerTest> invoker2 = mock(Invoker.class);
private Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);
private RpcInvocation invocation = new RpcInvocation();
private Directory<ForkingClusterInvokerTest> dic;
private Result result = new AppResponse();
@BeforeEach
public void setUp() throws Exception {
dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(invokers);
given(dic.getInterface()).willReturn(ForkingClusterInvokerTest.class);
invocation.setMethodName("method1");
invokers.add(invoker1);
invokers.add(invoker2);
invokers.add(invoker3);
}
private void resetInvokerToException() {
given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
given(invoker1.getUrl()).willReturn(url);
given(invoker1.isAvailable()).willReturn(true);
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
given(invoker2.getUrl()).willReturn(url);
given(invoker2.isAvailable()).willReturn(true);
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker3.invoke(invocation)).willThrow(new RuntimeException());
given(invoker3.getUrl()).willReturn(url);
given(invoker3.isAvailable()).willReturn(true);
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
}
private void resetInvokerToNoException() {
given(invoker1.invoke(invocation)).willReturn(result);
given(invoker1.getUrl()).willReturn(url);
given(invoker1.isAvailable()).willReturn(true);
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willReturn(result);
given(invoker2.getUrl()).willReturn(url);
given(invoker2.isAvailable()).willReturn(true);
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker3.invoke(invocation)).willReturn(result);
given(invoker3.getUrl()).willReturn(url);
given(invoker3.isAvailable()).willReturn(true);
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
}
@Test
public void testInvokeException() {
resetInvokerToException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
try {
invoker.invoke(invocation);
Assertions.fail();
} catch (RpcException expected) {
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"));
assertFalse(expected.getCause() instanceof RpcException);
}
}
@Test
public void testClearRpcContext() {
resetInvokerToException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
String attachKey = "attach";
String attachValue = "value";
RpcContext.getContext().setAttachment(attachKey, attachValue);
Map<String, String> attachments = RpcContext.getContext().getAttachments();
Assertions.assertTrue(attachments != null && attachments.size() == 1, "set attachment failed!");
try {
invoker.invoke(invocation);
Assertions.fail();
} catch (RpcException expected) {
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"), "Succeeded to forking invoke provider !");
assertFalse(expected.getCause() instanceof RpcException);
}
Map<String, String> afterInvoke = RpcContext.getContext().getAttachments();
Assertions.assertTrue(afterInvoke != null && afterInvoke.size() == 0, "clear attachment failed!");
}
@Test()
public void testInvokeNoException() {
resetInvokerToNoException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
Result ret = invoker.invoke(invocation);
Assertions.assertSame(result, ret);
}
/*
* 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.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* ForkingClusterInvokerTest
*/
@SuppressWarnings("unchecked")
public class ForkingClusterInvokerTest {
private List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
private URL url = URL.valueOf("test://test:11/test?forks=2");
private Invoker<ForkingClusterInvokerTest> invoker1 = mock(Invoker.class);
private Invoker<ForkingClusterInvokerTest> invoker2 = mock(Invoker.class);
private Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);
private RpcInvocation invocation = new RpcInvocation();
private Directory<ForkingClusterInvokerTest> dic;
private Result result = new AppResponse();
@BeforeEach
public void setUp() throws Exception {
dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(invokers);
given(dic.getInterface()).willReturn(ForkingClusterInvokerTest.class);
invocation.setMethodName("method1");
invokers.add(invoker1);
invokers.add(invoker2);
invokers.add(invoker3);
}
private void resetInvokerToException() {
given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
given(invoker1.getUrl()).willReturn(url);
given(invoker1.isAvailable()).willReturn(true);
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
given(invoker2.getUrl()).willReturn(url);
given(invoker2.isAvailable()).willReturn(true);
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker3.invoke(invocation)).willThrow(new RuntimeException());
given(invoker3.getUrl()).willReturn(url);
given(invoker3.isAvailable()).willReturn(true);
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
}
private void resetInvokerToNoException() {
given(invoker1.invoke(invocation)).willReturn(result);
given(invoker1.getUrl()).willReturn(url);
given(invoker1.isAvailable()).willReturn(true);
given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willReturn(result);
given(invoker2.getUrl()).willReturn(url);
given(invoker2.isAvailable()).willReturn(true);
given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
given(invoker3.invoke(invocation)).willReturn(result);
given(invoker3.getUrl()).willReturn(url);
given(invoker3.isAvailable()).willReturn(true);
given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
}
@Test
public void testInvokeException() {
resetInvokerToException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
try {
invoker.invoke(invocation);
Assertions.fail();
} catch (RpcException expected) {
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"));
assertFalse(expected.getCause() instanceof RpcException);
}
}
@Test
public void testClearRpcContext() {
resetInvokerToException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
String attachKey = "attach";
String attachValue = "value";
RpcContext.getContext().setAttachment(attachKey, attachValue);
Map<String, Object> attachments = RpcContext.getContext().getAttachments();
Assertions.assertTrue(attachments != null && attachments.size() == 1, "set attachment failed!");
try {
invoker.invoke(invocation);
Assertions.fail();
} catch (RpcException expected) {
Assertions.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"), "Succeeded to forking invoke provider !");
assertFalse(expected.getCause() instanceof RpcException);
}
Map<String, Object> afterInvoke = RpcContext.getContext().getAttachments();
Assertions.assertTrue(afterInvoke != null && afterInvoke.size() == 0, "clear attachment failed!");
}
@Test()
public void testInvokeNoException() {
resetInvokerToNoException();
ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
dic);
Result ret = invoker.invoke(invocation);
Assertions.assertSame(result, ret);
}
}

View File

@ -107,7 +107,7 @@ public class MergeableClusterInvokerTest {
given(invocation.getMethodName()).willReturn("getMenu");
given(invocation.getParameterTypes()).willReturn(new Class<?>[]{});
given(invocation.getArguments()).willReturn(new Object[]{});
given(invocation.getAttachments()).willReturn(new HashMap<String, String>())
given(invocation.getAttachments()).willReturn(new HashMap<String, Object>())
;
given(invocation.getInvoker()).willReturn(firstInvoker);
@ -190,7 +190,7 @@ public class MergeableClusterInvokerTest {
new Class<?>[]{String.class, List.class});
given(invocation.getArguments()).willReturn(new Object[]{menu, menuItems})
;
given(invocation.getAttachments()).willReturn(new HashMap<String, String>())
given(invocation.getAttachments()).willReturn(new HashMap<String, Object>())
;
given(invocation.getInvoker()).willReturn(firstInvoker);

View File

@ -16,18 +16,47 @@
*/
package org.apache.dubbo.common.config;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.ConfigUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
/**
* Configuration from system properties and dubbo.properties
*/
public class PropertiesConfiguration extends AbstractPrefixConfiguration {
private static final Logger logger = LoggerFactory.getLogger(PropertiesConfiguration.class);
public PropertiesConfiguration(String prefix, String id) {
super(prefix, id);
ExtensionLoader<OrderedPropertiesProvider> propertiesProviderExtensionLoader = ExtensionLoader.getExtensionLoader(OrderedPropertiesProvider.class);
Set<String> propertiesProviderNames = propertiesProviderExtensionLoader.getSupportedExtensions();
if (propertiesProviderNames == null || propertiesProviderNames.isEmpty()) {
return;
}
List<OrderedPropertiesProvider> orderedPropertiesProviders = new ArrayList<>();
for (String propertiesProviderName : propertiesProviderNames) {
orderedPropertiesProviders.add(propertiesProviderExtensionLoader.getExtension(propertiesProviderName));
}
//order the propertiesProvider according the priority descending
orderedPropertiesProviders.sort((OrderedPropertiesProvider a, OrderedPropertiesProvider b) -> {
return b.priority() - a.priority();
});
//load the default properties
Properties properties = ConfigUtils.getProperties();
//override the properties.
for (OrderedPropertiesProvider orderedPropertiesProvider :
orderedPropertiesProviders) {
properties.putAll(orderedPropertiesProvider.initProperties());
}
ConfigUtils.setProperties(properties);
}
public PropertiesConfiguration() {

View File

@ -0,0 +1,150 @@
/*
* 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.dubbo.common.threadpool;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* The most important difference between this Executor and other normal Executor is that this one doesn't manage
* any thread.
*
* Tasks submitted to this executor through {@link #execute(Runnable)} will not get scheduled to a specific thread, though normal executors always do the schedule.
* Those tasks are stored in a blocking queue and will only be executed when a thead calls {@link #waitAndDrain()}, the thead executing the task
* is exactly the same as the one calling waitAndDrain.
*/
public class ThreadlessExecutor extends AbstractExecutorService {
private static final Logger logger = LoggerFactory.getLogger(ThreadlessExecutor.class.getName());
private final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
private ExecutorService sharedExecutor;
private volatile boolean waiting = true;
private final Object lock = new Object();
public ThreadlessExecutor(ExecutorService sharedExecutor) {
this.sharedExecutor = sharedExecutor;
}
public boolean isWaiting() {
return waiting;
}
/**
* Waits until there is a Runnable, then executes it and all queued Runnables after it.
*/
public void waitAndDrain() throws InterruptedException {
Runnable runnable = queue.take();
synchronized (lock) {
waiting = false;
runnable.run();
}
runnable = queue.poll();
while (runnable != null) {
try {
runnable.run();
} catch (Throwable t) {
logger.info(t);
}
runnable = queue.poll();
}
}
public long waitAndDrain(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
/*long startInMs = System.currentTimeMillis();
Runnable runnable = queue.poll(timeout, unit);
if (runnable == null) {
throw new TimeoutException();
}
runnable.run();
long elapsedInMs = System.currentTimeMillis() - startInMs;
long timeLeft = timeout - elapsedInMs;
if (timeLeft < 0) {
throw new TimeoutException();
}
return timeLeft;*/
throw new UnsupportedOperationException();
}
/**
* If the calling thread is still waiting for a callback task, add the task into the blocking queue to wait for schedule.
* Otherwise, submit to shared callback executor directly.
*
* @param runnable
*/
@Override
public void execute(Runnable runnable) {
synchronized (lock) {
if (!waiting) {
sharedExecutor.execute(runnable);
} else {
queue.add(runnable);
}
}
}
/**
* tells the thread blocking on {@link #waitAndDrain()} to return, despite of the current status, to avoid endless waiting.
*/
public void notifyReturn() {
// an empty runnable task.
execute(() -> {
});
}
/**
* The following methods are still not supported
*/
@Override
public void shutdown() {
}
@Override
public List<Runnable> shutdownNow() {
return null;
}
@Override
public boolean isShutdown() {
return false;
}
@Override
public boolean isTerminated() {
return false;
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return false;
}
}

View File

@ -0,0 +1,107 @@
/*
* 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.dubbo.common.threadpool.manager;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.ThreadPool;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Consider implementing {@link Licycle} to enable executors shutdown when the process stops.
*/
public class DefaultExecutorRepository implements ExecutorRepository {
private static final Logger logger = LoggerFactory.getLogger(DefaultExecutorRepository.class);
private int DEFAULT_SCHEDULER_SIZE = Runtime.getRuntime().availableProcessors();
private final ExecutorService SHARED_EXECUTOR = Executors.newCachedThreadPool(new NamedThreadFactory("DubboSharedHandler", true));
private Ring<ScheduledExecutorService> scheduledExecutors = new Ring<>();
private ScheduledExecutorService reconnectScheduledExecutor;
private ConcurrentMap<String, ConcurrentMap<String, ExecutorService>> data = new ConcurrentHashMap<>();
public DefaultExecutorRepository() {
for (int i = 0; i < DEFAULT_SCHEDULER_SIZE; i++) {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-framework-scheduler"));
scheduledExecutors.addItem(scheduler);
}
reconnectScheduledExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-reconnect-scheduler"));
}
public ExecutorService createExecutorIfAbsent(URL url) {
String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
if (Constants.CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(Constants.SIDE_KEY))) {
componentKey = Constants.CONSUMER_SIDE;
}
Map<String, ExecutorService> executors = data.computeIfAbsent(componentKey, k -> new ConcurrentHashMap<>());
return executors.computeIfAbsent(Integer.toString(url.getPort()), k -> (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url));
}
@Override
public void updateThreadpool(URL url, ExecutorService executor) {
try {
if (url.hasParameter(Constants.THREADS_KEY)
&& executor instanceof ThreadPoolExecutor && !executor.isShutdown()) {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
int threads = url.getParameter(Constants.THREADS_KEY, 0);
int max = threadPoolExecutor.getMaximumPoolSize();
int core = threadPoolExecutor.getCorePoolSize();
if (threads > 0 && (threads != max || threads != core)) {
if (threads < core) {
threadPoolExecutor.setCorePoolSize(threads);
if (core == max) {
threadPoolExecutor.setMaximumPoolSize(threads);
}
} else {
threadPoolExecutor.setMaximumPoolSize(threads);
if (core == max) {
threadPoolExecutor.setCorePoolSize(threads);
}
}
}
}
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
@Override
public ScheduledExecutorService nextScheduledExecutor() {
return scheduledExecutors.pollItem();
}
@Override
public ExecutorService getSharedExecutor() {
return SHARED_EXECUTOR;
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.dubbo.common.threadpool.manager;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.SPI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
/**
*
*/
@SPI("default")
public interface ExecutorRepository {
/**
* Called by both Client and Server. TODO, consider separate these two parts.
* When the Client or Server starts for the first time, generate a new threadpool according to the parameters passed in usr.
*
* @param url
* @return
*/
ExecutorService createExecutorIfAbsent(URL url);
/**
* Modify some of the threadpool's properties according to the url, for example, coreSize, maxSize, ...
*
* @param url
* @param executor
*/
void updateThreadpool(URL url, ExecutorService executor);
/**
* Returns a scheduler from the scheduler list, call this method whenever you need a scheduler for a cron job.
* If your cron cannot burden the possible schedule delay caused by sharing the same scheduler, please consider define a dedicate one.
*
* @return
*/
ScheduledExecutorService nextScheduledExecutor();
/**
* Get the default shared threadpool.
*
* @return
*/
ExecutorService getSharedExecutor();
}

View File

@ -0,0 +1,66 @@
/*
* 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.dubbo.common.threadpool.manager;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
public class Ring<T> {
AtomicInteger count = new AtomicInteger();
private List<T> itemList = new CopyOnWriteArrayList<T>();
public void addItem(T t) {
if (t != null) {
itemList.add(t);
}
}
public T pollItem() {
if (itemList.isEmpty()) {
return null;
}
if (itemList.size() == 1) {
return itemList.get(0);
}
if (count.intValue() > Integer.MAX_VALUE - 10000) {
count.set(count.get() % itemList.size());
}
int index = Math.abs(count.getAndIncrement()) % itemList.size();
return itemList.get(index);
}
public T peekItem() {
if (itemList.isEmpty()) {
return null;
}
if (itemList.size() == 1) {
return itemList.get(0);
}
int index = Math.abs(count.get()) % itemList.size();
return itemList.get(index);
}
public List<T> listItems() {
return Collections.unmodifiableList(itemList);
}
}

View File

@ -0,0 +1 @@
default=org.apache.dubbo.common.threadpool.manager.DefaultExecutorRepository

View File

@ -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 org.apache.dubbo.common.config;
import java.util.Properties;
public class MockOrderedPropertiesProvider2 implements OrderedPropertiesProvider {
@Override
public int priority() {
return 1;
}
@Override
public Properties initProperties() {
Properties properties = new Properties();
properties.put("testKey", "999");
return properties;
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.dubbo.common.config;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class PropertiesConfigurationTest {
@Test
public void testOrderPropertiesProviders() {
PropertiesConfiguration configuration = new PropertiesConfiguration("test", null);
Assertions.assertTrue(configuration.getInternalProperty("testKey").equals("999"));
}
}

View File

@ -0,0 +1,2 @@
mock1=org.apache.dubbo.common.config.MockOrderedPropertiesProvider1
mock2=org.apache.dubbo.common.config.MockOrderedPropertiesProvider2

View File

@ -30,15 +30,15 @@ public interface Invocation extends org.apache.dubbo.rpc.Invocation {
}
@Override
default void setAttachmentIfAbsent(String key, String value) {
default void setAttachmentIfAbsent(String key, Object value) {
}
@Override
default void setAttachment(String key, String value) {
default void setAttachment(String key, Object value) {
}
class CompatibleInvocation implements Invocation, org.apache.dubbo.rpc.Invocation {
class CompatibleInvocation implements Invocation {
private org.apache.dubbo.rpc.Invocation delegate;
@ -62,17 +62,17 @@ public interface Invocation extends org.apache.dubbo.rpc.Invocation {
}
@Override
public Map<String, String> getAttachments() {
public Map<String, Object> getAttachments() {
return delegate.getAttachments();
}
@Override
public String getAttachment(String key) {
public Object getAttachment(String key) {
return delegate.getAttachment(key);
}
@Override
public String getAttachment(String key, String defaultValue) {
public Object getAttachment(String key, Object defaultValue) {
return delegate.getAttachment(key, defaultValue);
}
@ -81,6 +81,21 @@ public interface Invocation extends org.apache.dubbo.rpc.Invocation {
return new Invoker.CompatibleInvoker(delegate.getInvoker());
}
@Override
public Object put(Object key, Object value) {
return delegate.put(key, value);
}
@Override
public Object get(Object key) {
return delegate.get(key);
}
@Override
public Map<Object, Object> getAttributes() {
return delegate.getAttributes();
}
@Override
public org.apache.dubbo.rpc.Invocation getOriginal() {
return delegate;

View File

@ -83,32 +83,32 @@ public interface Result extends org.apache.dubbo.rpc.Result {
}
@Override
public Map<String, String> getAttachments() {
public Map<String, Object> getAttachments() {
return delegate.getAttachments();
}
@Override
public void addAttachments(Map<String, String> map) {
public void addAttachments(Map<String, Object> map) {
delegate.addAttachments(map);
}
@Override
public void setAttachments(Map<String, String> map) {
public void setAttachments(Map<String, Object> map) {
delegate.setAttachments(map);
}
@Override
public String getAttachment(String key) {
public Object getAttachment(String key) {
return delegate.getAttachment(key);
}
@Override
public String getAttachment(String key, String defaultValue) {
public Object getAttachment(String key, Object defaultValue) {
return delegate.getAttachment(key, defaultValue);
}
@Override
public void setAttachment(String key, String value) {
public void setAttachment(String key, Object value) {
delegate.setAttachment(key, value);
}
}

View File

@ -65,17 +65,17 @@ public class CacheTest {
}
@Override
public Map<String, String> getAttachments() {
public Map<String, Object> getAttachments() {
return null;
}
@Override
public String getAttachment(String key) {
public Object getAttachment(String key) {
return null;
}
@Override
public String getAttachment(String key, String defaultValue) {
public Object getAttachment(String key, Object defaultValue) {
return null;
}
@ -83,5 +83,20 @@ public class CacheTest {
public Invoker<?> getInvoker() {
return null;
}
@Override
public Object put(Object key, Object value) {
return null;
}
@Override
public Object get(Object key) {
return null;
}
@Override
public Map<Object, Object> getAttributes() {
return null;
}
}
}

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import org.apache.dubbo.common.Constants;
import java.util.HashMap;
import java.util.Map;
@ -53,8 +54,8 @@ public class LegacyInvocation implements Invocation {
return new Object[]{arg0};
}
public Map<String, String> getAttachments() {
Map<String, String> attachments = new HashMap<String, String>();
public Map<String, Object> getAttachments() {
Map<String, Object> attachments = new HashMap<String, Object>();
attachments.put(PATH_KEY, "dubbo");
attachments.put(GROUP_KEY, "dubbo");
attachments.put(VERSION_KEY, "1.0.0");
@ -68,11 +69,26 @@ public class LegacyInvocation implements Invocation {
return null;
}
public String getAttachment(String key) {
@Override
public Object put(Object key, Object value) {
return null;
}
@Override
public Object get(Object key) {
return null;
}
@Override
public Map<Object, Object> getAttributes() {
return null;
}
public Object getAttachment(String key) {
return getAttachments().get(key);
}
public String getAttachment(String key, String defaultValue) {
public Object getAttachment(String key, Object defaultValue) {
return getAttachments().get(key);
}

View File

@ -1,88 +1,103 @@
/*
* 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.dubbo.service;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
/**
* MockInvocation.java
*/
public class MockInvocation implements Invocation {
private String arg0;
public MockInvocation(String arg0) {
this.arg0 = arg0;
}
public String getMethodName() {
return "echo";
}
public Class<?>[] getParameterTypes() {
return new Class[]{String.class};
}
public Object[] getArguments() {
return new Object[]{arg0};
}
public Map<String, String> getAttachments() {
Map<String, String> attachments = new HashMap<String, String>();
attachments.put(PATH_KEY, "dubbo");
attachments.put(GROUP_KEY, "dubbo");
attachments.put(VERSION_KEY, "1.0.0");
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
attachments.put(TOKEN_KEY, "sfag");
attachments.put(TIMEOUT_KEY, "1000");
return attachments;
}
@Override
public void setAttachment(String key, String value) {
}
@Override
public void setAttachmentIfAbsent(String key, String value) {
}
public Invoker<?> getInvoker() {
return null;
}
public String getAttachment(String key) {
return getAttachments().get(key);
}
public String getAttachment(String key, String defaultValue) {
return getAttachments().get(key);
}
}
/*
* 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.dubbo.service;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
/**
* MockInvocation.java
*/
public class MockInvocation implements Invocation {
private String arg0;
public MockInvocation(String arg0) {
this.arg0 = arg0;
}
public String getMethodName() {
return "echo";
}
public Class<?>[] getParameterTypes() {
return new Class[]{String.class};
}
public Object[] getArguments() {
return new Object[]{arg0};
}
public Map<String, Object> getAttachments() {
Map<String, Object> attachments = new HashMap<String, Object>();
attachments.put(PATH_KEY, "dubbo");
attachments.put(GROUP_KEY, "dubbo");
attachments.put(VERSION_KEY, "1.0.0");
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
attachments.put(TOKEN_KEY, "sfag");
attachments.put(TIMEOUT_KEY, "1000");
return attachments;
}
@Override
public void setAttachment(String key, Object value) {
}
@Override
public void setAttachmentIfAbsent(String key, Object value) {
}
public Invoker<?> getInvoker() {
return null;
}
@Override
public Object put(Object key, Object value) {
return null;
}
@Override
public Object get(Object key) {
return null;
}
@Override
public Map<Object, Object> getAttributes() {
return null;
}
public Object getAttachment(String key) {
return getAttachments().get(key);
}
public Object getAttachment(String key, Object defaultValue) {
return getAttachments().get(key);
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.dubbo.config;
import org.apache.dubbo.common.extension.SPI;
/**
* Dynamically add some parameters / check config
*/
@SPI
public interface AppendParametersComponent {
default void appendReferParameters(ReferenceConfig referenceConfig) {
}
default void appendExportParameters(ServiceConfig serviceConfig) {
}
}

View File

@ -38,7 +38,9 @@ import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
import org.apache.dubbo.rpc.cluster.support.RegistryAwareCluster;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ConsumerMethodModel;
import org.apache.dubbo.rpc.model.ConsumerModel;
import org.apache.dubbo.rpc.model.ServiceMetadata;
import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
import org.apache.dubbo.rpc.service.GenericService;
import org.apache.dubbo.rpc.support.ProtocolUtils;
@ -46,7 +48,6 @@ import org.apache.dubbo.rpc.support.ProtocolUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -172,6 +173,8 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
*/
private transient volatile boolean destroyed;
private ServiceMetadata serviceMetadata;
@SuppressWarnings("unused")
private final Object finalizerGuardian = new Object() {
@Override
@ -193,9 +196,13 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
};
public ReferenceConfig() {
serviceMetadata = new ServiceMetadata();
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
}
public ReferenceConfig(Reference reference) {
serviceMetadata = new ServiceMetadata();
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
appendAnnotation(Reference.class, reference);
setMethods(MethodConfig.constructMethodConfig(reference.methods()));
}
@ -238,6 +245,13 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
resolveFile();
checkApplication();
checkMetadataReport();
appendParameters();
}
private void appendParameters() {
URL appendParametersUrl = URL.valueOf("appendParameters://");
List<AppendParametersComponent> appendParametersComponents = ExtensionLoader.getExtensionLoader(AppendParametersComponent.class).getActivateExtension(appendParametersUrl, (String[]) null);
appendParametersComponents.forEach(component -> component.appendReferParameters(this));
}
public synchronized T get() {
@ -275,11 +289,18 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
}
checkStubAndLocal(interfaceClass);
checkMock(interfaceClass);
//init serivceMetadata
serviceMetadata.setVersion(version);
serviceMetadata.setGroup(group);
serviceMetadata.setDefaultGroup(group);
serviceMetadata.setServiceType(getActualInterface());
serviceMetadata.setServiceInterfaceName(interfaceName);
Map<String, String> map = new HashMap<String, String>();
map.put(SIDE_KEY, CONSUMER_SIDE);
appendRuntimeParameters(map);
if (!isGeneric()) {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
@ -326,13 +347,29 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
}
map.put(REGISTER_IP_KEY, hostToRegistry);
serviceMetadata.getAttachments().putAll(map);
ref = createProxy(map);
String serviceKey = URL.buildKey(interfaceName, group, version);
ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes));
ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes, serviceMetadata));
serviceMetadata.setTarget(ref);
consumerModel.getServiceMetadata().addAttribute(Constants.PROXY_CLASS_REF, ref);
initialized = true;
}
private Class<?> getActualInterface() {
Class actualInterface = interfaceClass;
if (interfaceClass == GenericService.class) {
try {
actualInterface = Class.forName(interfaceName);
} catch (ClassNotFoundException e) {
// ignore
}
}
return actualInterface;
}
private ConsumerModel buildConsumerModel(String serviceKey, Map<String, Object> attributes) {
Method[] methods = interfaceClass.getMethods();
Class serviceInterface = interfaceClass;
@ -622,6 +659,10 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
return invoker;
}
public ServiceMetadata getServiceMetadata() {
return serviceMetadata;
}
@Override
@Parameter(excluded = true)
public String getPrefix() {
@ -661,4 +702,9 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
}
}
}
@Parameter(excluded = true)
public String getUniqueServiceName() {
return URL.buildKey(interfaceName, group, version);
}
}

View File

@ -40,6 +40,7 @@ import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ProviderModel;
import org.apache.dubbo.rpc.model.ServiceMetadata;
import org.apache.dubbo.rpc.service.GenericService;
import org.apache.dubbo.rpc.support.ProtocolUtils;
@ -112,7 +113,7 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
*
* <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
* the protocol is <b>DubboProtocol</b></li>
* <p>
*
* Actuallywhen the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
* layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
*/
@ -194,10 +195,16 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
*/
private volatile String generic;
private ServiceMetadata serviceMetadata;
public ServiceConfig() {
serviceMetadata = new ServiceMetadata();
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
}
public ServiceConfig(Service service) {
serviceMetadata = new ServiceMetadata();
serviceMetadata.addAttribute("ORIGIN_CONFIG", this);
appendAnnotation(Service.class, service);
setMethods(MethodConfig.constructMethodConfig(service.methods()));
}
@ -354,6 +361,13 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
}
checkStubAndLocal(interfaceClass);
checkMock(interfaceClass);
appendParameters();
}
private void appendParameters() {
URL appendParametersUrl = URL.valueOf("appendParameters://");
List<AppendParametersComponent> appendParametersComponents = ExtensionLoader.getExtensionLoader(AppendParametersComponent.class).getActivateExtension(appendParametersUrl, (String[]) null);
appendParametersComponents.forEach(component -> component.appendExportParameters(this));
}
/**
@ -368,6 +382,14 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
public synchronized void export() {
checkAndUpdateSubConfigs();
//init serviceMetadata
serviceMetadata.setVersion(version);
serviceMetadata.setGroup(group);
serviceMetadata.setDefaultGroup(group);
serviceMetadata.setServiceType(interfaceClass);
serviceMetadata.setServiceInterfaceName(interfaceName);
serviceMetadata.setTarget(ref);
if (!shouldExport()) {
return;
}
@ -556,6 +578,9 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
map.put(TOKEN_KEY, token);
}
}
//init serviceMetadata attachments
serviceMetadata.getAttachments().putAll(map);
// export service
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
@ -1032,6 +1057,10 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
return urls;
}
public ServiceMetadata getServiceMetadata() {
return serviceMetadata;
}
/**
* @deprecated Replace to getProtocols()
*/
@ -1053,4 +1082,9 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
public String getPrefix() {
return DUBBO + ".service." + interfaceName;
}
@Parameter(excluded = true)
public String getUniqueServiceName() {
return URL.buildKey(interfaceName, group, version);
}
}

View File

@ -128,6 +128,5 @@
<artifactId>tomcat-embed-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -48,7 +48,7 @@ public interface DynamicConfiguration extends Configuration {
}
/**
/*
* {@link #removeListener(String, String, ConfigurationListener)}
*
* @param key the key to represent a configuration

View File

@ -24,6 +24,8 @@ import org.apache.dubbo.demo.DemoService;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
@Component("demoServiceComponent")
public class DemoServiceComponent implements DemoService {
@Reference
@ -33,4 +35,9 @@ public class DemoServiceComponent implements DemoService {
public String sayHello(String name) {
return demoService.sayHello(name);
}
@Override
public CompletableFuture<String> sayHelloAsync(String name) {
return null;
}
}

View File

@ -25,6 +25,8 @@ import org.apache.dubbo.rpc.RpcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
@Service
public class DemoServiceImpl implements DemoService {
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@ -35,4 +37,9 @@ public class DemoServiceImpl implements DemoService {
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
}
@Override
public CompletableFuture<String> sayHelloAsync(String name) {
return null;
}
}

View File

@ -22,6 +22,8 @@ import org.apache.dubbo.rpc.RpcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
public class DemoServiceImpl implements DemoService {
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@ -31,4 +33,9 @@ public class DemoServiceImpl implements DemoService {
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
}
@Override
public CompletableFuture<String> sayHelloAsync(String name) {
return null;
}
}

View File

@ -16,8 +16,11 @@
*/
package org.apache.dubbo.demo;
import java.util.concurrent.CompletableFuture;
public interface DemoService {
String sayHello(String name);
CompletableFuture<String> sayHelloAsync(String name);
}

View File

@ -22,6 +22,8 @@ import org.apache.dubbo.rpc.RpcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
public class DemoServiceImpl implements DemoService {
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@ -31,4 +33,14 @@ public class DemoServiceImpl implements DemoService {
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
}
@Override
public CompletableFuture<String> sayHelloAsync(String name) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture("future return value!");
}
}

View File

@ -35,6 +35,12 @@ public interface JValidatorTestTarget {
void someMethod5(Map<String, String> map);
public void someMethod3(ValidationParameter[] parameters);
public void someMethod4(List<String> strings);
public void someMethod5(Map<String, String> map);
@interface Test2 {
}

View File

@ -88,5 +88,4 @@ public interface MonitorService {
*/
List<URL> lookup(URL query);
}

View File

@ -0,0 +1,35 @@
/*
* 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.dubbo.registry;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.SPI;
import java.util.List;
@SPI
public interface AddressListener {
/**
* processing when receiving the address list
*
* @param addresses provider address list
* @param registryDirectoryUrl
*/
List<URL> notify(List<URL> addresses, URL registryDirectoryUrl);
}

View File

@ -28,6 +28,7 @@ import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.configcenter.DynamicConfiguration;
import org.apache.dubbo.registry.AddressListener;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.remoting.Constants;
@ -230,6 +231,16 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
// providers
List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());
/**
* 3.x added for extend URL address
*/
ExtensionLoader<AddressListener> addressListenerExtensionLoader = ExtensionLoader.getExtensionLoader(AddressListener.class);
List<AddressListener> supportedListeners = addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);
if (supportedListeners != null && !supportedListeners.isEmpty()) {
for (AddressListener addressListener : supportedListeners) {
providerURLs = addressListener.notify(providerURLs, getUrl());
}
}
refreshOverrideAndInvoker(providerURLs);
}

View File

@ -24,6 +24,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
public class MockChannel implements ExchangeChannel {
@ -93,6 +94,16 @@ public class MockChannel implements ExchangeChannel {
return null;
}
@Override
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
return null;
}
@Override
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
return null;
}
public ExchangeHandler getExchangeHandler() {
return null;
}

View File

@ -29,6 +29,7 @@ import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeoutException;
/**
@ -81,13 +82,23 @@ public class MockedClient implements ExchangeClient {
}
public CompletableFuture<Object> request(Object msg) throws RemotingException {
return request(msg, 0);
return request(msg, null);
}
public CompletableFuture<Object> request(Object msg, int timeout) throws RemotingException {
return this.request(msg, timeout, null);
}
@Override
public CompletableFuture<Object> request(Object msg, ExecutorService executor) throws RemotingException {
return this.request(msg, 0, executor);
}
@Override
public CompletableFuture<Object> request(Object msg, int timeout, ExecutorService executor) throws RemotingException {
this.invoked = msg;
return new CompletableFuture<Object>() {
public Object get() throws InterruptedException, ExecutionException {
public Object get() throws InterruptedException, ExecutionException {
return received;
}

View File

@ -33,20 +33,17 @@
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-api</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<optional>true</optional>
</dependency>
<!-- Test Libraries -->

View File

@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.RemotingException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
/**
* ExchangeChannel. (API/SPI, Prototype, ThreadSafe)
@ -33,6 +34,7 @@ public interface ExchangeChannel extends Channel {
* @return response future
* @throws RemotingException
*/
@Deprecated
CompletableFuture<Object> request(Object request) throws RemotingException;
/**
@ -43,8 +45,28 @@ public interface ExchangeChannel extends Channel {
* @return response future
* @throws RemotingException
*/
@Deprecated
CompletableFuture<Object> request(Object request, int timeout) throws RemotingException;
/**
* send request.
*
* @param request
* @return response future
* @throws RemotingException
*/
CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException;
/**
* send request.
*
* @param request
* @param timeout
* @return response future
* @throws RemotingException
*/
CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException;
/**
* get message handler.
*

View File

@ -16,6 +16,16 @@
*/
package org.apache.dubbo.remoting.exchange;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.Codec;
import org.apache.dubbo.remoting.Decodeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* Response
*/
@ -173,4 +183,55 @@ public class Response {
return "Response [id=" + mId + ", version=" + mVersion + ", status=" + mStatus + ", event=" + mEvent
+ ", error=" + mErrorMsg + ", result=" + (mResult == this ? "this" : mResult) + "]";
}
public static class AppResult {
protected Map<String, String> attachments = new HashMap<String, String>();
protected Object result;
protected Throwable exception;
public Map<String, String> getAttachments() {
return attachments;
}
public void setAttachments(Map<String, String> attachments) {
this.attachments = attachments;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
public Throwable getException() {
return exception;
}
public void setException(Throwable exception) {
this.exception = exception;
}
}
public static class DecodeableAppResult implements Codec, Decodeable {
@Override
public void decode() throws Exception {
}
@Override
public void encode(Channel channel, OutputStream output, Object message) throws IOException {
}
@Override
public Object decode(Channel channel, InputStream input) throws IOException {
return null;
}
}
}

View File

@ -31,9 +31,7 @@ import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import java.util.concurrent.ExecutorService;
/**
* ExchangeReceiver
@ -100,11 +98,21 @@ final class HeaderExchangeChannel implements ExchangeChannel {
@Override
public CompletableFuture<Object> request(Object request) throws RemotingException {
return request(request, channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT));
return request(request, null);
}
@Override
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
return request(request, timeout, null);
}
@Override
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
return request(request, channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT), executor);
}
@Override
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
if (closed) {
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
}
@ -113,7 +121,7 @@ final class HeaderExchangeChannel implements ExchangeChannel {
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
req.setData(request);
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
try {
channel.send(req);
} catch (RemotingException e) {

View File

@ -31,6 +31,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.remoting.utils.UrlUtils.getHeartbeat;
@ -84,6 +85,16 @@ public class HeaderExchangeClient implements ExchangeClient {
return channel.request(request, timeout);
}
@Override
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
return channel.request(request, executor);
}
@Override
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
return channel.request(request, timeout, executor);
}
@Override
public ChannelHandler getChannelHandler() {
return channel.getChannelHandler();

View File

@ -21,7 +21,7 @@ import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.store.DataStore;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.common.utils.ExecutorUtil;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.remoting.Channel;
@ -50,6 +50,7 @@ public abstract class AbstractClient extends AbstractEndpoint implements Client
private final Lock connectLock = new ReentrantLock();
private final boolean needReconnect;
protected volatile ExecutorService executor;
private ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
public AbstractClient(URL url, ChannelHandler handler) throws RemotingException {
super(url, handler);
@ -84,11 +85,7 @@ public abstract class AbstractClient extends AbstractEndpoint implements Client
"Failed to start " + getClass().getSimpleName() + " " + NetUtils.getLocalAddress()
+ " connect to the server " + getRemoteAddress() + ", cause: " + t.getMessage(), t);
}
executor = (ExecutorService) ExtensionLoader.getExtensionLoader(DataStore.class)
.getDefaultExtension().get(CONSUMER_SIDE, Integer.toString(url.getPort()));
ExtensionLoader.getExtensionLoader(DataStore.class)
.getDefaultExtension().remove(CONSUMER_SIDE, Integer.toString(url.getPort()));
executor = executorRepository.createExecutorIfAbsent(url);
}
protected static ChannelHandler wrapChannelHandler(URL url, ChannelHandler handler) {

View File

@ -20,7 +20,7 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.store.DataStore;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.common.utils.ExecutorUtil;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.remoting.Channel;
@ -32,7 +32,6 @@ import org.apache.dubbo.remoting.Server;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
@ -55,6 +54,8 @@ public abstract class AbstractServer extends AbstractEndpoint implements Server
private int accepts;
private int idleTimeout;
private ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
super(url, handler);
localAddress = getUrl().toInetSocketAddress();
@ -76,9 +77,7 @@ public abstract class AbstractServer extends AbstractEndpoint implements Server
throw new RemotingException(url.toInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName()
+ " on " + getLocalAddress() + ", cause: " + t.getMessage(), t);
}
//fixme replace this with better method
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
executor = executorRepository.createExecutorIfAbsent(url);
}
protected abstract void doOpen() throws Throwable;
@ -110,30 +109,7 @@ public abstract class AbstractServer extends AbstractEndpoint implements Server
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
try {
if (url.hasParameter(THREADS_KEY)
&& executor instanceof ThreadPoolExecutor && !executor.isShutdown()) {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
int threads = url.getParameter(THREADS_KEY, 0);
int max = threadPoolExecutor.getMaximumPoolSize();
int core = threadPoolExecutor.getCorePoolSize();
if (threads > 0 && (threads != max || threads != core)) {
if (threads < core) {
threadPoolExecutor.setCorePoolSize(threads);
if (core == max) {
threadPoolExecutor.setMaximumPoolSize(threads);
}
} else {
threadPoolExecutor.setMaximumPoolSize(threads);
if (core == max) {
threadPoolExecutor.setCorePoolSize(threads);
}
}
}
}
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
executorRepository.updateThreadpool(url, executor);
super.setUrl(getUrl().addParameters(url.getParameters()));
}

View File

@ -40,6 +40,7 @@ public class CodecSupport {
private static final Logger logger = LoggerFactory.getLogger(CodecSupport.class);
private static Map<Byte, Serialization> ID_SERIALIZATION_MAP = new HashMap<Byte, Serialization>();
private static Map<Byte, String> ID_SERIALIZATIONNAME_MAP = new HashMap<Byte, String>();
private static Map<String, Byte> SERIALIZATIONNAME_ID_MAP = new HashMap<String, Byte>();
static {
Set<String> supportedExtensions = ExtensionLoader.getExtensionLoader(Serialization.class).getSupportedExtensions();
@ -55,6 +56,7 @@ public class CodecSupport {
}
ID_SERIALIZATION_MAP.put(idByte, serialization);
ID_SERIALIZATIONNAME_MAP.put(idByte, name);
SERIALIZATIONNAME_ID_MAP.put(name, idByte);
}
}
@ -65,6 +67,10 @@ public class CodecSupport {
return ID_SERIALIZATION_MAP.get(id);
}
public static byte getIDByName(String name) {
return SERIALIZATIONNAME_ID_MAP.get(name);
}
public static Serialization getSerialization(URL url) {
return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(
url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION));

View File

@ -20,29 +20,21 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.store.DataStore;
import org.apache.dubbo.common.threadpool.ThreadPool;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.Constants;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
import org.apache.dubbo.remoting.transport.ChannelHandlerDelegate;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
public class WrappedChannelHandler implements ChannelHandlerDelegate {
protected static final Logger logger = LoggerFactory.getLogger(WrappedChannelHandler.class);
protected static final ExecutorService SHARED_EXECUTOR = Executors.newCachedThreadPool(new NamedThreadFactory("DubboSharedHandler", true));
protected final ExecutorService executor;
protected final ChannelHandler handler;
protected final URL url;
@ -50,24 +42,10 @@ public class WrappedChannelHandler implements ChannelHandlerDelegate {
public WrappedChannelHandler(ChannelHandler handler, URL url) {
this.handler = handler;
this.url = url;
executor = (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url);
String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
componentKey = CONSUMER_SIDE;
}
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
dataStore.put(componentKey, Integer.toString(url.getPort()), executor);
}
public void close() {
try {
if (executor != null) {
executor.shutdown();
}
} catch (Throwable t) {
logger.warn("fail to destroy thread pool of server: " + t.getMessage(), t);
}
}
@Override
@ -95,8 +73,16 @@ public class WrappedChannelHandler implements ChannelHandlerDelegate {
handler.caught(channel, exception);
}
public ExecutorService getExecutor() {
return executor;
protected void sendFeedback(Channel channel, Request request, Throwable t) throws RemotingException {
if (request.isTwoWay()) {
String msg = "Server side(" + url.getIp() + "," + url.getPort()
+ ") thread pool is exhausted, detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
}
@Override
@ -112,8 +98,45 @@ public class WrappedChannelHandler implements ChannelHandlerDelegate {
return url;
}
/**
* Currently, this method is mainly customized to facilitate the thread model on consumer side.
* 1. Use ThreadlessExecutor, aka., delegate callback directly to the thread initiating the call.
* 2. Use shared executor to execute the callback.
*
* @param msg
* @return
*/
public ExecutorService getPreferredExecutorService(Object msg) {
if (msg instanceof Response) {
Response response = (Response) msg;
DefaultFuture responseFuture = DefaultFuture.getFuture(response.getId());
// a typical scenario is the response returned after timeout, the timeout response may has completed the future
if (responseFuture == null) {
return getSharedExecutorService();
} else {
ExecutorService executor = responseFuture.getExecutor();
if (executor == null || executor.isShutdown()) {
executor = getSharedExecutorService();
}
return executor;
}
} else {
return getSharedExecutorService();
}
}
/**
* get the shared executor for current Server or Client
*
* @return
*/
public ExecutorService getSharedExecutorService() {
return ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension().createExecutorIfAbsent(url);
}
@Deprecated
public ExecutorService getExecutorService() {
return executor == null || executor.isShutdown() ? SHARED_EXECUTOR : executor;
return getSharedExecutorService();
}

View File

@ -22,7 +22,6 @@ import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.ExecutionException;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
@ -58,22 +57,13 @@ public class AllChannelHandler extends WrappedChannelHandler {
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getExecutorService();
ExecutorService executor = getPreferredExecutorService(message);
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
//TODO A temporary solution to the problem that the exception information can not be sent to the opposite end after the thread pool is full. Need a refactoring
//fix The thread pool is full, refuses to call, does not return, and causes the consumer to wait for time out
if(message instanceof Request && t instanceof RejectedExecutionException){
Request request = (Request)message;
if(request.isTwoWay()){
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
sendFeedback(channel, (Request) message, t);
return;
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}

View File

@ -24,7 +24,6 @@ import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.ExecutionException;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
@ -80,21 +79,13 @@ public class ConnectionOrderedChannelHandler extends WrappedChannelHandler {
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getExecutorService();
ExecutorService executor = getPreferredExecutorService(message);
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
//fix, reject exception can not be sent to consumer because thread pool is full, resulting in consumers waiting till timeout.
if (message instanceof Request && t instanceof RejectedExecutionException) {
Request request = (Request) message;
if (request.isTwoWay()) {
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
sendFeedback(channel, (Request) message, t);
return;
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}

View File

@ -0,0 +1,51 @@
/*
* 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.dubbo.remoting.transport.dispatcher.direct;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.threadpool.ThreadlessExecutor;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.ExecutionException;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
import java.util.concurrent.ExecutorService;
public class DirectChannelHandler extends WrappedChannelHandler {
public DirectChannelHandler(ChannelHandler handler, URL url) {
super(handler, url);
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getPreferredExecutorService(message);
if (executor instanceof ThreadlessExecutor) {
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
} else {
handler.received(channel, message);
}
}
}

View File

@ -29,7 +29,7 @@ public class DirectDispatcher implements Dispatcher {
@Override
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
return handler;
return new DirectChannelHandler(handler, url);
}
}

View File

@ -17,12 +17,12 @@
package org.apache.dubbo.remoting.transport.dispatcher.execution;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.threadpool.ThreadlessExecutor;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.ExecutionException;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable;
import org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.ChannelState;
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
@ -42,7 +42,8 @@ public class ExecutionChannelHandler extends WrappedChannelHandler {
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getExecutorService();
ExecutorService executor = getPreferredExecutorService(message);
if (message instanceof Request) {
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
@ -51,19 +52,12 @@ public class ExecutionChannelHandler extends WrappedChannelHandler {
// therefore the consumer side has to wait until gets timeout. This is a temporary solution to prevent
// this scenario from happening, but a better solution should be considered later.
if (t instanceof RejectedExecutionException) {
Request request = (Request) message;
if (request.isTwoWay()) {
String msg = "Server side(" + url.getIp() + "," + url.getPort()
+ ") thread pool is exhausted, detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
sendFeedback(channel, (Request) message, t);
}
throw new ExecutionException(message, channel, getClass() + " error when process received event.", t);
}
} else if (executor instanceof ThreadlessExecutor) {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} else {
handler.received(channel, message);
}

View File

@ -35,7 +35,7 @@ public class MessageOnlyChannelHandler extends WrappedChannelHandler {
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getExecutorService();
ExecutorService executor = getPreferredExecutorService(message);
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.handler.MockedChannel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
@ -59,6 +60,7 @@ public class DefaultFutureTest {
* start time: 2018-06-21 15:13:02.215, end time: 2018-06-21 15:13:07.231...
*/
@Test
@Disabled
public void timeoutNotSend() throws Exception {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println("before a future is create , time is : " + LocalDateTime.now().format(formatter));
@ -89,13 +91,14 @@ public class DefaultFutureTest {
* start time: 2018-06-21 15:12:38.337, end time: 2018-06-21 15:12:43.354...
*/
@Test
@Disabled
public void timeoutSend() throws Exception {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println("before a future is create , time is : " + LocalDateTime.now().format(formatter));
// timeout after 5 seconds.
Channel channel = new MockedChannel();
Request request = new Request(10);
DefaultFuture f = DefaultFuture.newFuture(channel, request, 5000);
DefaultFuture f = DefaultFuture.newFuture(channel, request, 5000, null);
//mark the future is sent
DefaultFuture.sent(channel, request);
while (!f.isDone()) {
@ -119,7 +122,7 @@ public class DefaultFutureTest {
private DefaultFuture defaultFuture(int timeout) {
Channel channel = new MockedChannel();
Request request = new Request(index.getAndIncrement());
return DefaultFuture.newFuture(channel, request, timeout);
return DefaultFuture.newFuture(channel, request, timeout, null);
}
}
}

View File

@ -17,23 +17,21 @@
package org.apache.dubbo.remoting.exchange.support.header;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.exchange.Request;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.util.List;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class HeaderExchangeChannelTest {
@ -193,7 +191,7 @@ public class HeaderExchangeChannelTest {
public void closeWithTimeoutTest02() {
Assertions.assertFalse(channel.isClosed());
Request request = new Request();
DefaultFuture.newFuture(channel, request, 100);
DefaultFuture.newFuture(channel, request, 100, null);
header.close(100);
//return directly
header.close(1000);

View File

@ -51,7 +51,7 @@ public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest {
handler.disconnected(new MockedChannel());
Assertions.assertTrue(executor.getActiveCount() <= 1, executor.getActiveCount() + " must <=1");
}
//queue.size
//queue.size
Assertions.assertEquals(taskCount - 1, executor.getQueue().size());
for (int i = 0; i < taskCount; i++) {
@ -107,6 +107,7 @@ public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest {
}
@Test
@Disabled("FIXME")
public void test_Received_InvokeInExecuter() throws RemotingException {
Assertions.assertThrows(ExecutionException.class, () -> {
handler = new ConnectionOrderedChannelHandler(new BizChannelHander(false), url);
@ -142,4 +143,4 @@ public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest {
}, req);
Assertions.assertEquals(1, count.get(), "channel.send must be invoke");
}
}
}

View File

@ -17,6 +17,9 @@
package org.apache.dubbo.rpc;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@ -49,7 +52,7 @@ public class AppResponse extends AbstractResult implements Serializable {
private Throwable exception;
private Map<String, String> attachments = new HashMap<String, String>();
private Map<String, Object> attachments = new HashMap<String, Object>();
public AppResponse() {
}
@ -113,7 +116,7 @@ public class AppResponse extends AbstractResult implements Serializable {
}
@Override
public Map<String, String> getAttachments() {
public Map<String, Object> getAttachments() {
return attachments;
}
@ -122,38 +125,35 @@ public class AppResponse extends AbstractResult implements Serializable {
*
* @param map contains all key-value pairs to append
*/
@Override
public void setAttachments(Map<String, String> map) {
this.attachments = map == null ? new HashMap<String, String>() : map;
public void setAttachments(Map<String, Object> map) {
this.attachments = map == null ? new HashMap<String, Object>() : map;
}
@Override
public void addAttachments(Map<String, String> map) {
public void addAttachments(Map<String, Object> map) {
if (map == null) {
return;
}
if (this.attachments == null) {
this.attachments = new HashMap<String, String>();
this.attachments = new HashMap<String, Object>();
}
this.attachments.putAll(map);
}
@Override
public String getAttachment(String key) {
public Object getAttachment(String key) {
return attachments.get(key);
}
@Override
public String getAttachment(String key, String defaultValue) {
String result = attachments.get(key);
if (result == null || result.length() == 0) {
public Object getAttachment(String key, Object defaultValue) {
Object result = attachments.get(key);
if (result == null) {
result = defaultValue;
}
return result;
}
@Override
public void setAttachment(String key, String value) {
public void setAttachment(String key, Object value) {
attachments.put(key, value);
}

View File

@ -47,6 +47,7 @@ public class AsyncRpcResult extends AbstractResult {
*/
private RpcContext storedContext;
private RpcContext storedServerContext;
private Executor executor;
private Invocation invocation;
@ -136,6 +137,30 @@ public class AsyncRpcResult extends AbstractResult {
return new AppResponse();
}
/**
* This method will always return after a maximum 'timeout' waiting:
* 1. if value returns before timeout, return normally.
* 2. if no value returns after timeout, throw TimeoutException.
*
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
@Override
public Result get() throws InterruptedException, ExecutionException {
if (executor != null) {
ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
threadlessExecutor.waitAndDrain();
}
return super.get();
}
@Override
public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return this.get();
}
@Override
public Object recreate() throws Throwable {
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
@ -172,32 +197,32 @@ public class AsyncRpcResult extends AbstractResult {
}
@Override
public Map<String, String> getAttachments() {
public Map<String, Object> getAttachments() {
return getAppResponse().getAttachments();
}
@Override
public void setAttachments(Map<String, String> map) {
public void setAttachments(Map<String, Object> map) {
getAppResponse().setAttachments(map);
}
@Override
public void addAttachments(Map<String, String> map) {
public void addAttachments(Map<String, Object> map) {
getAppResponse().addAttachments(map);
}
@Override
public String getAttachment(String key) {
public Object getAttachment(String key) {
return getAppResponse().getAttachment(key);
}
@Override
public String getAttachment(String key, String defaultValue) {
public Object getAttachment(String key, Object defaultValue) {
return getAppResponse().getAttachment(key, defaultValue);
}
@Override
public void setAttachment(String key, String value) {
public void setAttachment(String key, Object value) {
getAppResponse().setAttachment(key, value);
}
@ -213,6 +238,14 @@ public class AsyncRpcResult extends AbstractResult {
return invocation;
}
public Executor getExecutor() {
return executor;
}
public void setExecutor(Executor executor) {
this.executor = executor;
}
/**
* tmp context to use when the thread switch to Dubbo thread.
*/

View File

@ -1,90 +1,95 @@
/*
* 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.dubbo.rpc;
import java.util.Map;
/**
* Invocation. (API, Prototype, NonThreadSafe)
*
* @serial Don't change the class name and package name.
* @see org.apache.dubbo.rpc.Invoker#invoke(Invocation)
* @see org.apache.dubbo.rpc.RpcInvocation
*/
public interface Invocation {
/**
* get method name.
*
* @return method name.
* @serial
*/
String getMethodName();
/**
* get parameter types.
*
* @return parameter types.
* @serial
*/
Class<?>[] getParameterTypes();
/**
* get arguments.
*
* @return arguments.
* @serial
*/
Object[] getArguments();
/**
* get attachments.
*
* @return attachments.
* @serial
*/
Map<String, String> getAttachments();
void setAttachment(String key, String value);
void setAttachmentIfAbsent(String key, String value);
/**
* get attachment by key.
*
* @return attachment value.
* @serial
*/
String getAttachment(String key);
/**
* get attachment by key with default value.
*
* @return attachment value.
* @serial
*/
String getAttachment(String key, String defaultValue);
/**
* get the invoker in current context.
*
* @return invoker.
* @transient
*/
Invoker<?> getInvoker();
/*
* 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.dubbo.rpc;
import java.util.Map;
/**
* Invocation. (API, Prototype, NonThreadSafe)
*
* @serial Don't change the class name and package name.
* @see org.apache.dubbo.rpc.Invoker#invoke(Invocation)
* @see org.apache.dubbo.rpc.RpcInvocation
*/
public interface Invocation {
/**
* get method name.
*
* @return method name.
* @serial
*/
String getMethodName();
/**
* get parameter types.
*
* @return parameter types.
* @serial
*/
Class<?>[] getParameterTypes();
/**
* get arguments.
*
* @return arguments.
* @serial
*/
Object[] getArguments();
/**
* get attachments.
*
* @return attachments.
* @serial
*/
Map<String, Object> getAttachments();
void setAttachment(String key, Object value);
void setAttachmentIfAbsent(String key, Object value);
/**
* get attachment by key.
*
* @return attachment value.
* @serial
*/
Object getAttachment(String key);
/**
* get attachment by key with default value.
*
* @return attachment value.
* @serial
*/
Object getAttachment(String key, Object defaultValue);
/**
* get the invoker in current context.
*
* @return invoker.
* @transient
*/
Invoker<?> getInvoker();
Object put(Object key, Object value);
Object get(Object key);
Map<Object, Object> getAttributes();
}

View File

@ -18,6 +18,6 @@ package org.apache.dubbo.rpc;
public enum InvokeMode {
SYNC, ASYNC, FUTURE
SYNC, ASYNC, FUTURE;
}

View File

@ -86,37 +86,37 @@ public interface Result extends CompletionStage<Result>, Future<Result>, Seriali
*
* @return attachments.
*/
Map<String, String> getAttachments();
Map<String, Object> getAttachments();
/**
* Add the specified map to existing attachments in this instance.
*
* @param map
*/
void addAttachments(Map<String, String> map);
void addAttachments(Map<String, Object> map);
/**
* Replace the existing attachments with the specified param.
*
* @param map
*/
void setAttachments(Map<String, String> map);
void setAttachments(Map<String, Object> map);
/**
* get attachment by key.
*
* @return attachment value.
*/
String getAttachment(String key);
Object getAttachment(String key);
/**
* get attachment by key with default value.
*
* @return attachment value.
*/
String getAttachment(String key, String defaultValue);
Object getAttachment(String key, Object defaultValue);
void setAttachment(String key, String value);
void setAttachment(String key, Object value);
/**
* Returns the specified {@code valueIfAbsent} when not complete, or

View File

@ -73,7 +73,7 @@ public class RpcContext {
}
};
private final Map<String, String> attachments = new HashMap<String, String>();
private final Map<String, Object> attachments = new HashMap<String, Object>();
private final Map<String, Object> values = new HashMap<String, Object>();
private List<URL> urls;
@ -105,7 +105,6 @@ public class RpcContext {
private Object response;
private AsyncContext asyncContext;
protected RpcContext() {
}
@ -467,7 +466,7 @@ public class RpcContext {
* @param key
* @return attachment
*/
public String getAttachment(String key) {
public Object getAttachment(String key) {
return attachments.get(key);
}
@ -478,7 +477,7 @@ public class RpcContext {
* @param value
* @return context
*/
public RpcContext setAttachment(String key, String value) {
public RpcContext setAttachment(String key, Object value) {
if (value == null) {
attachments.remove(key);
} else {
@ -503,7 +502,7 @@ public class RpcContext {
*
* @return attachments
*/
public Map<String, String> getAttachments() {
public Map<String, Object> getAttachments() {
return attachments;
}
@ -513,7 +512,7 @@ public class RpcContext {
* @param attachment
* @return context
*/
public RpcContext setAttachments(Map<String, String> attachment) {
public RpcContext setAttachments(Map<String, Object> attachment) {
this.attachments.clear();
if (attachment != null && attachment.size() > 0) {
this.attachments.putAll(attachment);

View File

@ -17,7 +17,6 @@
package org.apache.dubbo.rpc;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.StringUtils;
import java.io.Serializable;
import java.lang.reflect.Method;
@ -48,7 +47,9 @@ public class RpcInvocation implements Invocation, Serializable {
private Object[] arguments;
private Map<String, String> attachments;
private Map<String, Object> attachments;
private Map<Object, Object> attributes = new HashMap<Object, Object>();
private transient Invoker<?> invoker;
@ -61,7 +62,7 @@ public class RpcInvocation implements Invocation, Serializable {
public RpcInvocation(Invocation invocation, Invoker<?> invoker) {
this(invocation.getMethodName(), invocation.getParameterTypes(),
invocation.getArguments(), new HashMap<String, String>(invocation.getAttachments()),
invocation.getArguments(), new HashMap<String, Object>(invocation.getAttachments()),
invocation.getInvoker());
if (invoker != null) {
URL url = invoker.getUrl();
@ -96,24 +97,25 @@ public class RpcInvocation implements Invocation, Serializable {
this(method, arguments, null);
}
public RpcInvocation(Method method, Object[] arguments, Map<String, String> attachment) {
public RpcInvocation(Method method, Object[] arguments, Map<String, Object> attachment, Map<Object, Object> attributes) {
this(method.getName(), method.getParameterTypes(), arguments, attachment, null);
this.returnType = method.getReturnType();
this.attributes = attributes == null ? new HashMap<>() : attributes;
}
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments) {
this(methodName, parameterTypes, arguments, null, null);
}
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, String> attachments) {
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, Object> attachments) {
this(methodName, parameterTypes, arguments, attachments, null);
}
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, String> attachments, Invoker<?> invoker) {
public RpcInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments, Map<String, Object> attachments, Invoker<?> invoker) {
this.methodName = methodName;
this.parameterTypes = parameterTypes == null ? new Class<?>[0] : parameterTypes;
this.arguments = arguments == null ? new Object[0] : arguments;
this.attachments = attachments == null ? new HashMap<String, String>() : attachments;
this.attachments = attachments == null ? new HashMap<String, Object>() : attachments;
this.invoker = invoker;
}
@ -126,6 +128,19 @@ public class RpcInvocation implements Invocation, Serializable {
this.invoker = invoker;
}
public Object put(Object key, Object value) {
return attributes.put(key, value);
}
public Object get(Object key) {
return attributes.get(key);
}
@Override
public Map<Object, Object> getAttributes() {
return attributes;
}
@Override
public String getMethodName() {
return methodName;
@ -154,53 +169,53 @@ public class RpcInvocation implements Invocation, Serializable {
}
@Override
public Map<String, String> getAttachments() {
public Map<String, Object> getAttachments() {
return attachments;
}
public void setAttachments(Map<String, String> attachments) {
this.attachments = attachments == null ? new HashMap<String, String>() : attachments;
public void setAttachments(Map<String, Object> attachments) {
this.attachments = attachments == null ? new HashMap<String, Object>() : attachments;
}
@Override
public void setAttachment(String key, String value) {
public void setAttachment(String key, Object value) {
if (attachments == null) {
attachments = new HashMap<String, String>();
attachments = new HashMap<String, Object>();
}
attachments.put(key, value);
}
@Override
public void setAttachmentIfAbsent(String key, String value) {
public void setAttachmentIfAbsent(String key, Object value) {
if (attachments == null) {
attachments = new HashMap<String, String>();
attachments = new HashMap<String, Object>();
}
if (!attachments.containsKey(key)) {
attachments.put(key, value);
}
}
public void addAttachments(Map<String, String> attachments) {
public void addAttachments(Map<String, Object> attachments) {
if (attachments == null) {
return;
}
if (this.attachments == null) {
this.attachments = new HashMap<String, String>();
this.attachments = new HashMap<String, Object>();
}
this.attachments.putAll(attachments);
}
public void addAttachmentsIfAbsent(Map<String, String> attachments) {
public void addAttachmentsIfAbsent(Map<String, Object> attachments) {
if (attachments == null) {
return;
}
for (Map.Entry<String, String> entry : attachments.entrySet()) {
for (Map.Entry<String, Object> entry : attachments.entrySet()) {
setAttachmentIfAbsent(entry.getKey(), entry.getValue());
}
}
@Override
public String getAttachment(String key) {
public Object getAttachment(String key) {
if (attachments == null) {
return null;
}
@ -208,12 +223,12 @@ public class RpcInvocation implements Invocation, Serializable {
}
@Override
public String getAttachment(String key, String defaultValue) {
public Object getAttachment(String key, Object defaultValue) {
if (attachments == null) {
return defaultValue;
}
String value = attachments.get(key);
if (StringUtils.isEmpty(value)) {
Object value = attachments.get(key);
if (null == value) {
return defaultValue;
}
return value;

View File

@ -0,0 +1,27 @@
/*
* 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.dubbo.rpc.model;
import org.apache.dubbo.common.extension.SPI;
@SPI
public interface ApplicationInitListener {
/**
* init the application
*/
void init();
}

View File

@ -16,20 +16,23 @@
*/
package org.apache.dubbo.rpc.model;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Represent a application which is using Dubbo and store basic metadata info for using
* during the processing of RPC invoking.
*
* <p>
* ApplicationModel includes many ProviderModel which is about published services
* and many Consumer Model which is about subscribed services.
*
* <p>
* adjust project structure in order to fully utilize the methods introduced here.
*/
public class ApplicationModel {
@ -47,6 +50,8 @@ public class ApplicationModel {
private static String application;
private static AtomicBoolean INIT_FLAG = new AtomicBoolean(false);
public static Collection<ConsumerModel> allConsumerModels() {
return CONSUMED_SERVICES.values();
}
@ -63,6 +68,16 @@ public class ApplicationModel {
return CONSUMED_SERVICES.get(serviceName);
}
public static void init() {
if (INIT_FLAG.compareAndSet(false, true)) {
ExtensionLoader<ApplicationInitListener> extensionLoader = ExtensionLoader.getExtensionLoader(ApplicationInitListener.class);
Set<String> listenerNames = extensionLoader.getSupportedExtensions();
for (String listenerName : listenerNames) {
extensionLoader.getExtension(listenerName).init();
}
}
}
public static void initConsumerModel(String serviceName, ConsumerModel consumerModel) {
if (CONSUMED_SERVICES.putIfAbsent(serviceName, consumerModel) != null) {
LOGGER.warn("Already register the same consumer:" + serviceName);

View File

@ -18,7 +18,8 @@ package org.apache.dubbo.rpc.model;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static org.apache.dubbo.rpc.Constants.$INVOKE;
@ -32,10 +33,9 @@ public class ConsumerMethodModel {
private final String methodName;
private final boolean generic;
private final AsyncMethodInfo asyncInfo;
private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();
public ConsumerMethodModel(Method method, Map<String, Object> attributes) {
public ConsumerMethodModel(Method method) {
this.method = method;
this.parameterClasses = method.getParameterTypes();
this.returnClass = method.getReturnType();
@ -43,24 +43,32 @@ public class ConsumerMethodModel {
this.methodName = method.getName();
this.generic = methodName.equals($INVOKE) && parameterTypes != null && parameterTypes.length == 3;
if (attributes != null) {
asyncInfo = (AsyncMethodInfo) attributes.get(methodName);
} else {
asyncInfo = null;
}
}
public Method getMethod() {
return method;
}
// public ConcurrentMap<String, Object> getAttributeMap() {
// return attributeMap;
// }
public void addAttribute(String key, Object value) {
this.attributeMap.put(key, value);
}
public Object getAttribute(String key) {
return this.attributeMap.get(key);
}
public Class<?> getReturnClass() {
return returnClass;
}
public AsyncMethodInfo getAsyncInfo() {
return asyncInfo;
}
// public AsyncMethodInfo getAsyncInfo() {
// return (AsyncMethodInfo) attributeMap.get(Constants.ASYNC_KEY);
// }
public String getMethodName() {
return methodName;

View File

@ -16,10 +16,9 @@
*/
package org.apache.dubbo.rpc.model;
import org.apache.dubbo.common.utils.Assert;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@ -29,47 +28,31 @@ import java.util.Optional;
* Consumer Model which is about subscribed services.
*/
public class ConsumerModel {
private final Object proxyObject;
private final String serviceName;
private final Class<?> serviceInterfaceClass;
private final ServiceMetadata serviceMetadata;
private final Map<Method, ConsumerMethodModel> methodModels = new IdentityHashMap<Method, ConsumerMethodModel>();
/**
* This constructor create an instance of ConsumerModel and passed objects should not be null.
* If service name, service instance, proxy object,methods should not be null. If these are null
* then this constructor will throw {@link IllegalArgumentException}
* @param serviceName Name of the service.
* @param serviceInterfaceClass Service interface class.
* @param proxyObject Proxy object.
* @param methods Methods of service class
* @param attributes Attributes of methods.
*/
public ConsumerModel(String serviceName
, Class<?> serviceInterfaceClass
, Object proxyObject
, Method[] methods
, Map<String, Object> attributes) {
public ConsumerModel(String serviceName, String group, String version, Class<?> interfaceClass) {
this.serviceMetadata = new ServiceMetadata(serviceName, group, version, interfaceClass);
Assert.notEmptyString(serviceName, "Service name can't be null or blank");
Assert.notNull(serviceInterfaceClass, "Service interface class can't null");
Assert.notNull(proxyObject, "Proxy object can't be null");
Assert.notNull(methods, "Methods can't be null");
this.serviceName = serviceName;
this.serviceInterfaceClass = serviceInterfaceClass;
this.proxyObject = proxyObject;
Method[] methods = interfaceClass.getMethods();
for (Method method : methods) {
methodModels.put(method, new ConsumerMethodModel(method, attributes));
methodModels.put(method, new ConsumerMethodModel(method));
}
}
public ConsumerModel(ServiceMetadata serviceMetadata) {
this.serviceMetadata = serviceMetadata;
Method[] methods = serviceMetadata.getServiceType().getMethods();
for (Method method : methods) {
methodModels.put(method, new ConsumerMethodModel(method));
}
}
/**
* Return the proxy object used by called while creating instance of ConsumerModel
* @return
* @return serviceMetadata
*/
public Object getProxyObject() {
return proxyObject;
public ServiceMetadata getServiceMetadata() {
return serviceMetadata;
}
/**
@ -93,6 +76,27 @@ public class ConsumerModel {
return consumerMethodModelEntry.map(Map.Entry::getValue).orElse(null);
}
/**
* @param method metodName
* @param argsType method arguments type
* @return
*/
public ConsumerMethodModel getMethodModel(String method, String[] argsType) {
Optional<ConsumerMethodModel> consumerMethodModel = methodModels.entrySet().stream()
.filter(entry -> entry.getKey().getName().equals(method))
.map(Map.Entry::getValue).filter(methodModel -> Arrays.equals(argsType, methodModel.getParameterTypes()))
.findFirst();
return consumerMethodModel.orElse(null);
}
/**
* @return
*/
public Class<?> getServiceInterfaceClass() {
return serviceMetadata.getServiceType();
}
/**
* Return all method models for the current service
*
@ -102,11 +106,7 @@ public class ConsumerModel {
return new ArrayList<ConsumerMethodModel>(methodModels.values());
}
public Class<?> getServiceInterfaceClass() {
return serviceInterfaceClass;
}
public String getServiceName() {
return serviceName;
return this.serviceMetadata.getServiceKey();
}
}

View File

@ -17,19 +17,24 @@
package org.apache.dubbo.rpc.model;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ProviderMethodModel {
private transient final Method method;
private final Method method;
private final String methodName;
private final Class<?>[] parameterClasses;
private final String[] methodArgTypes;
private final String serviceName;
private final Type[] genericParameterTypes;
private final ConcurrentMap<String, Object> attributeMap = new ConcurrentHashMap<>();
public ProviderMethodModel(Method method, String serviceName) {
public ProviderMethodModel(Method method) {
this.method = method;
this.serviceName = serviceName;
this.methodName = method.getName();
this.parameterClasses = method.getParameterTypes();
this.methodArgTypes = getArgTypes(method);
this.genericParameterTypes = method.getGenericParameterTypes();
}
public Method getMethod() {
@ -44,8 +49,8 @@ public class ProviderMethodModel {
return methodArgTypes;
}
public String getServiceName() {
return serviceName;
public ConcurrentMap<String, Object> getAttributeMap() {
return attributeMap;
}
private static String[] getArgTypes(Method method) {
@ -60,4 +65,12 @@ public class ProviderMethodModel {
}
return methodArgTypes;
}
public Class<?>[] getParameterClasses() {
return parameterClasses;
}
public Type[] getGenericParameterTypes() {
return genericParameterTypes;
}
}

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.model;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -27,30 +28,35 @@ import java.util.Map;
* ProviderModel which is about published services
*/
public class ProviderModel {
private final String serviceName;
private final Object serviceInstance;
private final Class<?> serviceInterfaceClass;
private final ServiceMetadata serviceMetadata;
private final String serivceKey;
private final Map<String, List<ProviderMethodModel>> methods = new HashMap<String, List<ProviderMethodModel>>();
public ProviderModel(String serviceName, Object serviceInstance, Class<?> serviceInterfaceClass) {
public ProviderModel(String serviceName, String group, String version, Object serviceInstance, Class<?> serviceInterfaceClass) {
if (null == serviceInstance) {
throw new IllegalArgumentException("Service[" + serviceName + "]Target is NULL.");
}
this.serviceName = serviceName;
this.serviceInstance = serviceInstance;
this.serviceInterfaceClass = serviceInterfaceClass;
initMethod();
this.serviceMetadata = new ServiceMetadata(serviceName, group, version, serviceInterfaceClass);
this.serivceKey = serviceMetadata.getServiceKey();
initMethod(serviceInterfaceClass);
}
public ProviderModel(Object serviceInstance, ServiceMetadata serviceMetadata) {
this.serviceInstance = serviceInstance;
this.serviceMetadata = serviceMetadata;
this.serivceKey = serviceMetadata.getServiceKey();
initMethod(serviceMetadata.getServiceType());
}
public String getServiceName() {
return serviceName;
return this.serviceMetadata.getServiceKey();
}
public Class<?> getServiceInterfaceClass() {
return serviceInterfaceClass;
return this.serviceMetadata.getServiceType();
}
public Object getServiceInstance() {
@ -77,20 +83,32 @@ public class ProviderModel {
return null;
}
private void initMethod() {
Method[] methodsToExport = null;
methodsToExport = this.serviceInterfaceClass.getMethods();
public List<ProviderMethodModel> getMethodModelList(String methodName) {
List<ProviderMethodModel> resultList = methods.get(methodName);
return resultList == null ? Collections.emptyList() : resultList;
}
private void initMethod(Class<?> serviceInterfaceClass) {
Method[] methodsToExport;
methodsToExport = serviceInterfaceClass.getMethods();
for (Method method : methodsToExport) {
method.setAccessible(true);
List<ProviderMethodModel> methodModels = methods.get(method.getName());
if (methodModels == null) {
methodModels = new ArrayList<ProviderMethodModel>(1);
methodModels = new ArrayList<ProviderMethodModel>();
methods.put(method.getName(), methodModels);
}
methodModels.add(new ProviderMethodModel(method, serviceName));
methodModels.add(new ProviderMethodModel(method));
}
}
/**
* @return serviceMetadata
*/
public ServiceMetadata getServiceMetadata() {
return serviceMetadata;
}
}

View File

@ -0,0 +1,130 @@
/*
* 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.dubbo.rpc.model;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* data related to service level such as name, version, classloader of business service,
* security info, etc. Also with a AttributeMap for extension.
*/
public class ServiceMetadata {
private String serviceKey;
private String serviceInterfaceName;
private String defaultGroup;
private String version;
private Class<?> serviceType;
private volatile String group;
private Object target;
/* will be transferred to remote side */
private final Map<String, Object> attachments = new ConcurrentHashMap<String, Object>();
/* used locally*/
private final Map<String, Object> attributeMap = new ConcurrentHashMap<String, Object>();
public ServiceMetadata(String serviceInterfaceName, String group, String version, Class<?> serviceType) {
this.serviceInterfaceName = serviceInterfaceName;
this.defaultGroup = group;
this.group = group;
this.version = version;
this.serviceKey = serviceInterfaceName + ":" + version;
this.serviceType = serviceType;
}
public ServiceMetadata() {
}
public String getServiceKey() {
return serviceInterfaceName + ":" + version;
}
public Map<String, Object> getAttachments() {
return attachments;
}
public Map<String, Object> getAttributeMap() {
return attributeMap;
}
public Object getAttribute(String key) {
return attributeMap.get(key);
}
public void addAttribute(String key, Object value) {
this.attributeMap.put(key, value);
}
public void addAttachment(String key, Object value) {
this.attributeMap.put(key, value);
}
public Class<?> getServiceType() {
return serviceType;
}
public String getServiceInterfaceName() {
return serviceInterfaceName;
}
public String getDefaultGroup() {
return defaultGroup;
}
public String getVersion() {
return version;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public void setServiceInterfaceName(String serviceInterfaceName) {
this.serviceInterfaceName = serviceInterfaceName;
}
public void setDefaultGroup(String defaultGroup) {
this.defaultGroup = defaultGroup;
}
public void setVersion(String version) {
this.version = version;
}
public void setServiceType(Class<?> serviceType) {
this.serviceType = serviceType;
}
public void setServiceKey(String serviceKey) {
this.serviceKey = serviceKey;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
}

View File

@ -18,13 +18,18 @@ package org.apache.dubbo.rpc.protocol;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.ThreadlessExecutor;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.FutureAdapter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.InvokeMode;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
@ -36,6 +41,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@ -49,21 +55,21 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
private final URL url;
private final Map<String, String> attachment;
private final Map<String, Object> attachment;
private volatile boolean available = true;
private AtomicBoolean destroyed = new AtomicBoolean(false);
public AbstractInvoker(Class<T> type, URL url) {
this(type, url, (Map<String, String>) null);
this(type, url, (Map<String, Object>) null);
}
public AbstractInvoker(Class<T> type, URL url, String[] keys) {
this(type, url, convertAttachment(url, keys));
}
public AbstractInvoker(Class<T> type, URL url, Map<String, String> attachment) {
public AbstractInvoker(Class<T> type, URL url, Map<String, Object> attachment) {
if (type == null) {
throw new IllegalArgumentException("service type == null");
}
@ -75,11 +81,11 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
this.attachment = attachment == null ? null : Collections.unmodifiableMap(attachment);
}
private static Map<String, String> convertAttachment(URL url, String[] keys) {
private static Map<String, Object> convertAttachment(URL url, String[] keys) {
if (ArrayUtils.isEmpty(keys)) {
return null;
}
Map<String, String> attachment = new HashMap<String, String>();
Map<String, Object> attachment = new HashMap<String, Object>();
for (String key : keys) {
String value = url.getParameter(key);
if (value != null && value.length() > 0) {
@ -137,11 +143,11 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
if (CollectionUtils.isNotEmptyMap(attachment)) {
invocation.addAttachmentsIfAbsent(attachment);
}
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
Map<String, Object> contextAttachments = RpcContext.getContext().getAttachments();
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
/**
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
* because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered
* because the {@link RpcContext#setAttachment(String, Object)} is passed in the Filter when the call is triggered
* by the built-in retry mechanism of the Dubbo. The attachment to update RpcContext will no longer work, which is
* a mistake in most cases (for example, through Filter to RpcContext output traceId and spanId and other information).
*/
@ -151,26 +157,38 @@ public abstract class AbstractInvoker<T> implements Invoker<T> {
invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation));
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
AsyncRpcResult asyncResult;
try {
return doInvoke(invocation);
asyncResult = (AsyncRpcResult) doInvoke(invocation);
} catch (InvocationTargetException e) { // biz exception
Throwable te = e.getTargetException();
if (te == null) {
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
if (te instanceof RpcException) {
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
}
return AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
}
} catch (RpcException e) {
if (e.isBiz()) {
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
throw e;
}
} catch (Throwable e) {
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
}
RpcContext.getContext().setFuture(new FutureAdapter(asyncResult, inv));
return asyncResult;
}
protected ExecutorService getCallbackExecutor(URL url, Invocation inv) {
ExecutorService sharedExecutor = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension().createExecutorIfAbsent(url);
if (InvokeMode.SYNC == RpcUtils.getInvokeMode(getUrl(), inv)) {
return new ThreadlessExecutor(sharedExecutor);
} else {
return sharedExecutor;
}
}

View File

@ -1,203 +1,200 @@
/*
* 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.dubbo.rpc.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.InvokeMode;
import org.apache.dubbo.rpc.RpcInvocation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import static org.apache.dubbo.rpc.Constants.$INVOKE;
import static org.apache.dubbo.rpc.Constants.$INVOKE_ASYNC;
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
import static org.apache.dubbo.rpc.Constants.ID_KEY;
import static org.apache.dubbo.rpc.Constants.RETURN_KEY;
/**
* RpcUtils
*/
public class RpcUtils {
private static final Logger logger = LoggerFactory.getLogger(RpcUtils.class);
private static final AtomicLong INVOKE_ID = new AtomicLong(0);
public static Class<?> getReturnType(Invocation invocation) {
try {
if (invocation != null && invocation.getInvoker() != null
&& invocation.getInvoker().getUrl() != null
&& !invocation.getMethodName().startsWith("$")) {
String service = invocation.getInvoker().getUrl().getServiceInterface();
if (StringUtils.isNotEmpty(service)) {
Class<?> invokerInterface = invocation.getInvoker().getInterface();
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
: ReflectUtils.forName(service);
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
if (method.getReturnType() == void.class) {
return null;
}
return method.getReturnType();
}
}
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
return null;
}
public static Type[] getReturnTypes(Invocation invocation) {
try {
if (invocation != null && invocation.getInvoker() != null
&& invocation.getInvoker().getUrl() != null
&& !invocation.getMethodName().startsWith("$")) {
String service = invocation.getInvoker().getUrl().getServiceInterface();
if (StringUtils.isNotEmpty(service)) {
Class<?> invokerInterface = invocation.getInvoker().getInterface();
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
: ReflectUtils.forName(service);
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
if (method.getReturnType() == void.class) {
return null;
}
return ReflectUtils.getReturnTypes(method);
}
}
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
return null;
}
public static Long getInvocationId(Invocation inv) {
String id = inv.getAttachment(ID_KEY);
return id == null ? null : new Long(id);
}
/**
* Idempotent operation: invocation id will be added in async operation by default
*
* @param url
* @param inv
*/
public static void attachInvocationIdIfAsync(URL url, Invocation inv) {
if (isAttachInvocationId(url, inv) && getInvocationId(inv) == null && inv instanceof RpcInvocation) {
((RpcInvocation) inv).setAttachment(ID_KEY, String.valueOf(INVOKE_ID.getAndIncrement()));
}
}
private static boolean isAttachInvocationId(URL url, Invocation invocation) {
String value = url.getMethodParameter(invocation.getMethodName(), AUTO_ATTACH_INVOCATIONID_KEY);
if (value == null) {
// add invocationid in async operation by default
return isAsync(url, invocation);
} else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
return true;
} else {
return false;
}
}
public static String getMethodName(Invocation invocation) {
if ($INVOKE.equals(invocation.getMethodName())
&& invocation.getArguments() != null
&& invocation.getArguments().length > 0
&& invocation.getArguments()[0] instanceof String) {
return (String) invocation.getArguments()[0];
}
return invocation.getMethodName();
}
public static Object[] getArguments(Invocation invocation) {
if ($INVOKE.equals(invocation.getMethodName())
&& invocation.getArguments() != null
&& invocation.getArguments().length > 2
&& invocation.getArguments()[2] instanceof Object[]) {
return (Object[]) invocation.getArguments()[2];
}
return invocation.getArguments();
}
public static Class<?>[] getParameterTypes(Invocation invocation) {
if ($INVOKE.equals(invocation.getMethodName())
&& invocation.getArguments() != null
&& invocation.getArguments().length > 1
&& invocation.getArguments()[1] instanceof String[]) {
String[] types = (String[]) invocation.getArguments()[1];
if (types == null) {
return new Class<?>[0];
}
Class<?>[] parameterTypes = new Class<?>[types.length];
for (int i = 0; i < types.length; i++) {
parameterTypes[i] = ReflectUtils.forName(types[0]);
}
return parameterTypes;
}
return invocation.getParameterTypes();
}
public static boolean isAsync(URL url, Invocation inv) {
boolean isAsync;
if (Boolean.TRUE.toString().equals(inv.getAttachment(ASYNC_KEY))) {
isAsync = true;
} else {
isAsync = url.getMethodParameter(getMethodName(inv), ASYNC_KEY, false);
}
return isAsync;
}
public static boolean isReturnTypeFuture(Invocation inv) {
Class<?> clazz;
if (inv instanceof RpcInvocation) {
clazz = ((RpcInvocation) inv).getReturnType();
} else {
clazz = getReturnType(inv);
}
return (clazz != null && CompletableFuture.class.isAssignableFrom(clazz)) || isGenericAsync(inv);
}
public static InvokeMode getInvokeMode(URL url, Invocation inv) {
if (isReturnTypeFuture(inv)) {
return InvokeMode.FUTURE;
} else if (isAsync(url, inv)) {
return InvokeMode.ASYNC;
} else {
return InvokeMode.SYNC;
}
}
public static boolean isGenericAsync(Invocation inv) {
return $INVOKE_ASYNC.equals(inv.getMethodName());
}
public static boolean isOneway(URL url, Invocation inv) {
boolean isOneway;
if (Boolean.FALSE.toString().equals(inv.getAttachment(RETURN_KEY))) {
isOneway = true;
} else {
isOneway = !url.getMethodParameter(getMethodName(inv), RETURN_KEY, true);
}
return isOneway;
}
}
/*
* 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.dubbo.rpc.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.InvokeMode;
import org.apache.dubbo.rpc.RpcInvocation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import static org.apache.dubbo.rpc.Constants.$INVOKE;
import static org.apache.dubbo.rpc.Constants.$INVOKE_ASYNC;
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
import static org.apache.dubbo.rpc.Constants.ID_KEY;
import static org.apache.dubbo.rpc.Constants.RETURN_KEY;
/**
* RpcUtils
*/
public class RpcUtils {
private static final Logger logger = LoggerFactory.getLogger(RpcUtils.class);
private static final AtomicLong INVOKE_ID = new AtomicLong(0);
public static Class<?> getReturnType(Invocation invocation) {
try {
if (invocation != null && invocation.getInvoker() != null
&& invocation.getInvoker().getUrl() != null
&& !invocation.getMethodName().startsWith("$")) {
String service = invocation.getInvoker().getUrl().getServiceInterface();
if (StringUtils.isNotEmpty(service)) {
Class<?> invokerInterface = invocation.getInvoker().getInterface();
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
: ReflectUtils.forName(service);
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
if (method.getReturnType() == void.class) {
return null;
}
return method.getReturnType();
}
}
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
return null;
}
public static Type[] getReturnTypes(Invocation invocation) {
try {
if (invocation != null && invocation.getInvoker() != null
&& invocation.getInvoker().getUrl() != null
&& !invocation.getMethodName().startsWith("$")) {
String service = invocation.getInvoker().getUrl().getServiceInterface();
if (StringUtils.isNotEmpty(service)) {
Class<?> invokerInterface = invocation.getInvoker().getInterface();
Class<?> cls = invokerInterface != null ? ReflectUtils.forName(invokerInterface.getClassLoader(), service)
: ReflectUtils.forName(service);
Method method = cls.getMethod(invocation.getMethodName(), invocation.getParameterTypes());
if (method.getReturnType() == void.class) {
return null;
}
return ReflectUtils.getReturnTypes(method);
}
}
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
return null;
}
public static Long getInvocationId(Invocation inv) {
String id = (String)inv.getAttachment(ID_KEY);
return id == null ? null : new Long(id);
}
/**
* Idempotent operation: invocation id will be added in async operation by default
*
* @param url
* @param inv
*/
public static void attachInvocationIdIfAsync(URL url, Invocation inv) {
if (isAttachInvocationId(url, inv) && getInvocationId(inv) == null && inv instanceof RpcInvocation) {
((RpcInvocation) inv).setAttachment(ID_KEY, String.valueOf(INVOKE_ID.getAndIncrement()));
}
}
private static boolean isAttachInvocationId(URL url, Invocation invocation) {
String value = url.getMethodParameter(invocation.getMethodName(), AUTO_ATTACH_INVOCATIONID_KEY);
if (value == null) {
// add invocationid in async operation by default
return isAsync(url, invocation);
} else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
return true;
} else {
return false;
}
}
public static String getMethodName(Invocation invocation) {
if ($INVOKE.equals(invocation.getMethodName())
&& invocation.getArguments() != null
&& invocation.getArguments().length > 0
&& invocation.getArguments()[0] instanceof String) {
return (String) invocation.getArguments()[0];
}
return invocation.getMethodName();
}
public static Object[] getArguments(Invocation invocation) {
if ($INVOKE.equals(invocation.getMethodName())
&& invocation.getArguments() != null
&& invocation.getArguments().length > 2
&& invocation.getArguments()[2] instanceof Object[]) {
return (Object[]) invocation.getArguments()[2];
}
return invocation.getArguments();
}
public static Class<?>[] getParameterTypes(Invocation invocation) {
if ($INVOKE.equals(invocation.getMethodName())
&& invocation.getArguments() != null
&& invocation.getArguments().length > 1
&& invocation.getArguments()[1] instanceof String[]) {
String[] types = (String[]) invocation.getArguments()[1];
if (types == null) {
return new Class<?>[0];
}
Class<?>[] parameterTypes = new Class<?>[types.length];
for (int i = 0; i < types.length; i++) {
parameterTypes[i] = ReflectUtils.forName(types[0]);
}
return parameterTypes;
}
return invocation.getParameterTypes();
}
public static boolean isAsync(URL url, Invocation inv) {
boolean isAsync;
if (Boolean.TRUE.toString().equals(inv.getAttachment(ASYNC_KEY))) {
isAsync = true;
} else {
isAsync = url.getMethodParameter(getMethodName(inv), ASYNC_KEY, false);
}
return isAsync;
}
public static boolean isReturnTypeFuture(Invocation inv) {
Class<?> clazz = getReturnType(inv);
return (clazz != null && CompletableFuture.class.isAssignableFrom(clazz)) || isGenericAsync(inv);
}
public static boolean isGenericAsync(Invocation inv) {
return $INVOKE_ASYNC.equals(inv.getMethodName());
public static InvokeMode getInvokeMode(URL url, Invocation inv) {
if (isReturnTypeFuture(inv)) {
return InvokeMode.FUTURE;
} else if (isAsync(url, inv)) {
return InvokeMode.ASYNC;
} else {
return InvokeMode.SYNC;
}
}
public static boolean isGenericAsync(Invocation inv) {
return Constants.$INVOKE_ASYNC.equals(inv.getMethodName());
}
public static boolean isOneway(URL url, Invocation inv) {
boolean isOneway;
if (Boolean.FALSE.toString().equals(inv.getAttachment(RETURN_KEY))) {
isOneway = true;
} else {
isOneway = !url.getMethodParameter(getMethodName(inv), RETURN_KEY, true);
}
return isOneway;
}
}

View File

@ -86,7 +86,7 @@ public class RpcContextTest {
public void testAttachments() {
RpcContext context = RpcContext.getContext();
Map<String, String> map = new HashMap<String, String>();
Map<String, Object> map = new HashMap<String, Object>();
map.put("_11", "1111");
map.put("_22", "2222");
map.put(".33", "3333");

View File

@ -1,82 +1,97 @@
/*
* 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.dubbo.rpc.support;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
/**
* MockInvocation.java
*/
public class MockInvocation implements Invocation {
public String getMethodName() {
return "echo";
}
public Class<?>[] getParameterTypes() {
return new Class[]{String.class};
}
public Object[] getArguments() {
return new Object[]{"aa"};
}
public Map<String, String> getAttachments() {
Map<String, String> attachments = new HashMap<String, String>();
attachments.put(PATH_KEY, "dubbo");
attachments.put(GROUP_KEY, "dubbo");
attachments.put(VERSION_KEY, "1.0.0");
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
attachments.put(TOKEN_KEY, "sfag");
attachments.put(TIMEOUT_KEY, "1000");
return attachments;
}
@Override
public void setAttachment(String key, String value) {
}
@Override
public void setAttachmentIfAbsent(String key, String value) {
}
public Invoker<?> getInvoker() {
return null;
}
public String getAttachment(String key) {
return getAttachments().get(key);
}
public String getAttachment(String key, String defaultValue) {
return getAttachments().get(key);
}
}
/*
* 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.dubbo.rpc.support;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
/**
* MockInvocation.java
*/
public class MockInvocation implements Invocation {
public String getMethodName() {
return "echo";
}
public Class<?>[] getParameterTypes() {
return new Class[]{String.class};
}
public Object[] getArguments() {
return new Object[]{"aa"};
}
public Map<String, Object> getAttachments() {
Map<String, Object> attachments = new HashMap<String, Object>();
attachments.put(PATH_KEY, "dubbo");
attachments.put(GROUP_KEY, "dubbo");
attachments.put(VERSION_KEY, "1.0.0");
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
attachments.put(TOKEN_KEY, "sfag");
attachments.put(TIMEOUT_KEY, "1000");
return attachments;
}
@Override
public void setAttachment(String key, Object value) {
}
@Override
public void setAttachmentIfAbsent(String key, Object value) {
}
public Invoker<?> getInvoker() {
return null;
}
@Override
public Object put(Object key, Object value) {
return null;
}
@Override
public Object get(Object key) {
return null;
}
@Override
public Map<Object, Object> getAttributes() {
return null;
}
public Object getAttachment(String key) {
return getAttachments().get(key);
}
public Object getAttachment(String key, Object defaultValue) {
return getAttachments().get(key);
}
}

View File

@ -1,152 +1,152 @@
/*
* 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.dubbo.rpc.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
public class RpcUtilsTest {
/**
* regular scenario: async invocation in URL
* verify: 1. whether invocationId is set correctly, 2. idempotent or not
*/
@Test
public void testAttachInvocationIdIfAsync_normal() {
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
Map<String, String> attachments = new HashMap<String, String>();
attachments.put("aa", "bb");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{}, attachments);
RpcUtils.attachInvocationIdIfAsync(url, inv);
long id1 = RpcUtils.getInvocationId(inv);
RpcUtils.attachInvocationIdIfAsync(url, inv);
long id2 = RpcUtils.getInvocationId(inv);
assertEquals(id1, id2); // verify if it's idempotent
assertTrue(id1 >= 0);
assertEquals("bb", attachments.get("aa"));
}
/**
* scenario: sync invocation, no attachment added by default
* verify: no id attribute added in attachment
*/
@Test
public void testAttachInvocationIdIfAsync_sync() {
URL url = URL.valueOf("dubbo://localhost/");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertNull(RpcUtils.getInvocationId(inv));
}
/**
* scenario: async invocation, add attachment by default
* verify: no error report when the original attachment is null
*/
@Test
public void testAttachInvocationIdIfAsync_nullAttachments() {
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertTrue(RpcUtils.getInvocationId(inv) >= 0L);
}
/**
* scenario: explicitly configure to not add attachment
* verify: no id attribute added in attachment
*/
@Test
public void testAttachInvocationIdIfAsync_forceNotAttache() {
URL url = URL.valueOf("dubbo://localhost/?test.async=true&" + AUTO_ATTACH_INVOCATIONID_KEY + "=false");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertNull(RpcUtils.getInvocationId(inv));
}
/**
* scenario: explicitly configure to add attachment
* verify: id attribute added in attachment
*/
@Test
public void testAttachInvocationIdIfAsync_forceAttache() {
URL url = URL.valueOf("dubbo://localhost/?" + AUTO_ATTACH_INVOCATIONID_KEY + "=true");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertNotNull(RpcUtils.getInvocationId(inv));
}
@Test
public void testGetReturnTypes() throws Exception {
Invoker invoker = mock(Invoker.class);
given(invoker.getUrl()).willReturn(URL.valueOf("test://127.0.0.1:1/org.apache.dubbo.rpc.support.DemoService?interface=org.apache.dubbo.rpc.support.DemoService"));
Invocation inv = new RpcInvocation("testReturnType", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types = RpcUtils.getReturnTypes(inv);
Assertions.assertEquals(2, types.length);
Assertions.assertEquals(String.class, types[0]);
Assertions.assertEquals(String.class, types[1]);
Invocation inv1 = new RpcInvocation("testReturnType1", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types1 = RpcUtils.getReturnTypes(inv1);
Assertions.assertEquals(2, types1.length);
Assertions.assertEquals(List.class, types1[0]);
Assertions.assertEquals(DemoService.class.getMethod("testReturnType1", new Class<?>[]{String.class}).getGenericReturnType(), types1[1]);
Invocation inv2 = new RpcInvocation("testReturnType2", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types2 = RpcUtils.getReturnTypes(inv2);
Assertions.assertEquals(2, types2.length);
Assertions.assertEquals(String.class, types2[0]);
Assertions.assertEquals(String.class, types2[1]);
Invocation inv3 = new RpcInvocation("testReturnType3", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types3 = RpcUtils.getReturnTypes(inv3);
Assertions.assertEquals(2, types3.length);
Assertions.assertEquals(List.class, types3[0]);
java.lang.reflect.Type genericReturnType3 = DemoService.class.getMethod("testReturnType3", new Class<?>[]{String.class}).getGenericReturnType();
Assertions.assertEquals(((ParameterizedType) genericReturnType3).getActualTypeArguments()[0], types3[1]);
Invocation inv4 = new RpcInvocation("testReturnType4", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types4 = RpcUtils.getReturnTypes(inv4);
Assertions.assertEquals(2, types4.length);
Assertions.assertNull(types4[0]);
Assertions.assertNull(types4[1]);
Invocation inv5 = new RpcInvocation("testReturnType5", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types5 = RpcUtils.getReturnTypes(inv5);
Assertions.assertEquals(2, types5.length);
Assertions.assertEquals(Map.class, types5[0]);
java.lang.reflect.Type genericReturnType5 = DemoService.class.getMethod("testReturnType5", new Class<?>[]{String.class}).getGenericReturnType();
Assertions.assertEquals(((ParameterizedType) genericReturnType5).getActualTypeArguments()[0], types5[1]);
}
}
/*
* 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.dubbo.rpc.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.apache.dubbo.rpc.Constants.AUTO_ATTACH_INVOCATIONID_KEY;
public class RpcUtilsTest {
/**
* regular scenario: async invocation in URL
* verify: 1. whether invocationId is set correctly, 2. idempotent or not
*/
@Test
public void testAttachInvocationIdIfAsync_normal() {
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
Map<String, Object> attachments = new HashMap<String, Object>();
attachments.put("aa", "bb");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{}, attachments);
RpcUtils.attachInvocationIdIfAsync(url, inv);
long id1 = RpcUtils.getInvocationId(inv);
RpcUtils.attachInvocationIdIfAsync(url, inv);
long id2 = RpcUtils.getInvocationId(inv);
assertEquals(id1, id2); // verify if it's idempotent
assertTrue(id1 >= 0);
assertEquals("bb", attachments.get("aa"));
}
/**
* scenario: sync invocation, no attachment added by default
* verify: no id attribute added in attachment
*/
@Test
public void testAttachInvocationIdIfAsync_sync() {
URL url = URL.valueOf("dubbo://localhost/");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertNull(RpcUtils.getInvocationId(inv));
}
/**
* scenario: async invocation, add attachment by default
* verify: no error report when the original attachment is null
*/
@Test
public void testAttachInvocationIdIfAsync_nullAttachments() {
URL url = URL.valueOf("dubbo://localhost/?test.async=true");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertTrue(RpcUtils.getInvocationId(inv) >= 0L);
}
/**
* scenario: explicitly configure to not add attachment
* verify: no id attribute added in attachment
*/
@Test
public void testAttachInvocationIdIfAsync_forceNotAttache() {
URL url = URL.valueOf("dubbo://localhost/?test.async=true&" + AUTO_ATTACH_INVOCATIONID_KEY + "=false");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertNull(RpcUtils.getInvocationId(inv));
}
/**
* scenario: explicitly configure to add attachment
* verify: id attribute added in attachment
*/
@Test
public void testAttachInvocationIdIfAsync_forceAttache() {
URL url = URL.valueOf("dubbo://localhost/?" + AUTO_ATTACH_INVOCATIONID_KEY + "=true");
Invocation inv = new RpcInvocation("test", new Class[]{}, new String[]{});
RpcUtils.attachInvocationIdIfAsync(url, inv);
assertNotNull(RpcUtils.getInvocationId(inv));
}
@Test
public void testGetReturnTypes() throws Exception {
Invoker invoker = mock(Invoker.class);
given(invoker.getUrl()).willReturn(URL.valueOf("test://127.0.0.1:1/org.apache.dubbo.rpc.support.DemoService?interface=org.apache.dubbo.rpc.support.DemoService"));
Invocation inv = new RpcInvocation("testReturnType", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types = RpcUtils.getReturnTypes(inv);
Assertions.assertEquals(2, types.length);
Assertions.assertEquals(String.class, types[0]);
Assertions.assertEquals(String.class, types[1]);
Invocation inv1 = new RpcInvocation("testReturnType1", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types1 = RpcUtils.getReturnTypes(inv1);
Assertions.assertEquals(2, types1.length);
Assertions.assertEquals(List.class, types1[0]);
Assertions.assertEquals(DemoService.class.getMethod("testReturnType1", new Class<?>[]{String.class}).getGenericReturnType(), types1[1]);
Invocation inv2 = new RpcInvocation("testReturnType2", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types2 = RpcUtils.getReturnTypes(inv2);
Assertions.assertEquals(2, types2.length);
Assertions.assertEquals(String.class, types2[0]);
Assertions.assertEquals(String.class, types2[1]);
Invocation inv3 = new RpcInvocation("testReturnType3", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types3 = RpcUtils.getReturnTypes(inv3);
Assertions.assertEquals(2, types3.length);
Assertions.assertEquals(List.class, types3[0]);
java.lang.reflect.Type genericReturnType3 = DemoService.class.getMethod("testReturnType3", new Class<?>[]{String.class}).getGenericReturnType();
Assertions.assertEquals(((ParameterizedType) genericReturnType3).getActualTypeArguments()[0], types3[1]);
Invocation inv4 = new RpcInvocation("testReturnType4", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types4 = RpcUtils.getReturnTypes(inv4);
Assertions.assertEquals(2, types4.length);
Assertions.assertNull(types4[0]);
Assertions.assertNull(types4[1]);
Invocation inv5 = new RpcInvocation("testReturnType5", new Class<?>[]{String.class}, null, null, invoker);
java.lang.reflect.Type[] types5 = RpcUtils.getReturnTypes(inv5);
Assertions.assertEquals(2, types5.length);
Assertions.assertEquals(Map.class, types5[0]);
java.lang.reflect.Type genericReturnType5 = DemoService.class.getMethod("testReturnType5", new Class<?>[]{String.class}).getGenericReturnType();
Assertions.assertEquals(((ParameterizedType) genericReturnType5).getActualTypeArguments()[0], types5[1]);
}
}

View File

@ -288,14 +288,14 @@ class CallbackServiceCodec {
switch (callbackstatus) {
case CallbackServiceCodec.CALLBACK_CREATE:
try {
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt(inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), true);
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt((String) inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), true);
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new IOException(StringUtils.toString(e));
}
case CallbackServiceCodec.CALLBACK_DESTROY:
try {
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt(inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), false);
return referOrDestroyCallbackService(channel, url, pts[paraIndex], inv, Integer.parseInt((String) inv.getAttachment(INV_ATT_CALLBACK_KEY + paraIndex)), false);
} catch (Exception e) {
throw new IOException(StringUtils.toString(e));
}

View File

@ -125,9 +125,9 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
Map<String, String> map = (Map<String, String>) in.readObject(Map.class);
if (map != null && map.size() > 0) {
Map<String, String> attachment = getAttachments();
Map<String, Object> attachment = getAttachments();
if (attachment == null) {
attachment = new HashMap<String, String>();
attachment = new HashMap<String, Object>();
}
attachment.putAll(map);
setAttachments(attachment);

View File

@ -72,6 +72,7 @@ public class DecodeableRpcResult extends AppResponse implements Codec, Decodeabl
@Override
public Object decode(Channel channel, InputStream input) throws IOException {
log.debug("Decoding in thread -- " + Thread.currentThread().getName());
ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType)
.deserialize(channel.getUrl(), input);
@ -153,7 +154,7 @@ public class DecodeableRpcResult extends AppResponse implements Codec, Decodeabl
private void handleAttachment(ObjectInput in) throws IOException {
try {
setAttachments((Map<String, String>) in.readObject(Map.class));
setAttachments((Map<String, Object>) in.readObject(Map.class));
} catch (ClassNotFoundException e) {
rethrow(e);
}

View File

@ -175,8 +175,8 @@ public class DubboCodec extends ExchangeCodec {
RpcInvocation inv = (RpcInvocation) data;
out.writeUTF(version);
out.writeUTF(inv.getAttachment(PATH_KEY));
out.writeUTF(inv.getAttachment(VERSION_KEY));
out.writeUTF((String) inv.getAttachment(PATH_KEY));
out.writeUTF((String) inv.getAttachment(VERSION_KEY));
out.writeUTF(inv.getMethodName());
out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes()));

View File

@ -243,7 +243,7 @@ public class DubboProtocol extends AbstractProtocol {
boolean isCallBackServiceInvoke = false;
boolean isStubServiceInvoke = false;
int port = channel.getLocalAddress().getPort();
String path = inv.getAttachments().get(PATH_KEY);
String path = (String) inv.getAttachments().get(PATH_KEY);
// if it's callback service on client side
isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getAttachments().get(STUB_EVENT_KEY));
@ -258,7 +258,7 @@ public class DubboProtocol extends AbstractProtocol {
inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString());
}
String serviceKey = serviceKey(port, path, inv.getAttachments().get(VERSION_KEY), inv.getAttachments().get(GROUP_KEY));
String serviceKey = serviceKey(port, path, (String) inv.getAttachments().get(VERSION_KEY), (String) inv.getAttachments().get(GROUP_KEY));
DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
if (exporter == null) {

View File

@ -29,6 +29,7 @@ import org.apache.dubbo.remoting.exchange.Exchangers;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ -114,6 +115,20 @@ final class LazyConnectExchangeClient implements ExchangeClient {
return client.request(request, timeout);
}
@Override
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
warning();
initClient();
return client.request(request, executor);
}
@Override
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
warning();
initClient();
return client.request(request, timeout, executor);
}
/**
* If {@link #REQUEST_WITH_WARNING_KEY} is configured, then warn once every 5000 invocations.
*/

View File

@ -27,6 +27,7 @@ import org.apache.dubbo.remoting.exchange.ExchangeHandler;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import static org.apache.dubbo.remoting.Constants.RECONNECT_KEY;
@ -80,6 +81,16 @@ final class ReferenceCountExchangeClient implements ExchangeClient {
return client.request(request, timeout);
}
@Override
public CompletableFuture<Object> request(Object request, ExecutorService executor) throws RemotingException {
return client.request(request, executor);
}
@Override
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
return client.request(request, timeout, executor);
}
@Override
public boolean isConnected() {
return client.isConnected();

View File

@ -111,8 +111,9 @@ public class ImplicitCallBackTest {
ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
asyncMethodInfo.setOnthrowInstance(notify);
asyncMethodInfo.setOnthrowMethod(onThrowMethod);
attitudes.put("get", asyncMethodInfo);
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), new ConsumerModel(consumerUrl.getServiceKey(), IDemoService.class, demoProxy, IDemoService.class.getMethods(), attitudes));
ConsumerModel consumerModel = new ConsumerModel(consumerUrl.getServiceInterface(), "Dubbo", "1.0.0", IDemoService.class);
consumerModel.getMethodModel("get").addAttribute(Constants.ASYNC_KEY, asyncMethodInfo);
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), consumerModel);
}
//================================================================================================
@ -122,8 +123,9 @@ public class ImplicitCallBackTest {
ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
asyncMethodInfo.setOnreturnInstance(notify);
asyncMethodInfo.setOnreturnMethod(onReturnMethod);
attitudes.put("get", asyncMethodInfo);
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), new ConsumerModel(consumerUrl.getServiceKey(), IDemoService.class, demoProxy, IDemoService.class.getMethods(), attitudes));
ConsumerModel consumerModel = new ConsumerModel(consumerUrl.getServiceInterface(), "Dubbo", "1.0.0", IDemoService.class);
consumerModel.getMethodModel("get").addAttribute(Constants.ASYNC_KEY, asyncMethodInfo);
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), consumerModel);
}
public void initImplicitCallBackURL_onlyOninvoke() throws Exception {
@ -131,8 +133,9 @@ public class ImplicitCallBackTest {
ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
asyncMethodInfo.setOninvokeInstance(notify);
asyncMethodInfo.setOninvokeMethod(onInvokeMethod);
attitudes.put("get", asyncMethodInfo);
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), new ConsumerModel(consumerUrl.getServiceKey(), IDemoService.class, demoProxy, IDemoService.class.getMethods(), attitudes));
ConsumerModel consumerModel = new ConsumerModel(consumerUrl.getServiceInterface(), "Dubbo", "1.0.0", IDemoService.class);
consumerModel.getMethodModel("get").addAttribute(Constants.ASYNC_KEY, asyncMethodInfo);
ApplicationModel.initConsumerModel(consumerUrl.getServiceKey(), consumerModel);
}
@Test

View File

@ -27,6 +27,7 @@ import org.apache.dubbo.rpc.model.ProviderModel;
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoService;
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl;
import org.apache.dubbo.rpc.protocol.dubbo.support.ProtocolUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -68,7 +69,7 @@ public class InvokerTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
String result = invoke.telnet(mockChannel, "echo(\"ok\")");
@ -83,8 +84,8 @@ public class InvokerTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = invoke.telnet(mockChannel, "DemoService.echo(\"ok\")");
assertTrue(result.contains("result: \"ok\""));
@ -98,8 +99,9 @@ public class InvokerTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
try {
invoke.telnet(mockChannel, "sayHello(null)");
} catch (Exception ex) {
@ -114,8 +116,8 @@ public class InvokerTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = invoke.telnet(mockChannel, "getType(\"High\")");
assertTrue(result.contains("result: \"High\""));
@ -130,8 +132,9 @@ public class InvokerTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = invoke.telnet(mockChannel, "getPerson({\"name\":\"zhangsan\",\"age\":12,\"class\":\"org.apache.dubbo.rpc.protocol.dubbo.support.Person\"})");
assertTrue(result.contains("result: 12"));
}
@ -144,8 +147,9 @@ public class InvokerTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String param = "{\"name\":\"Dubbo\",\"age\":8}";
String result = invoke.telnet(mockChannel, "getPerson(" + param + ")");
assertTrue(result.contains("Please use the select command to select the method you want to invoke. eg: select 1"));
@ -161,8 +165,9 @@ public class InvokerTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String param = "{\"name\":\"Dubbo\",\"age\":8},{\"name\":\"Apache\",\"age\":20}";
String result = invoke.telnet(mockChannel, "getPerson(" + param + ")");
assertTrue(result.contains("result: 28"));

View File

@ -66,7 +66,7 @@ public class ListTelnetHandlerTest {
mockChannel = mock(Channel.class);
given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = list.telnet(mockChannel, "-l DemoService");
@ -80,7 +80,7 @@ public class ListTelnetHandlerTest {
mockChannel = mock(Channel.class);
given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = list.telnet(mockChannel, "DemoService");
@ -94,11 +94,11 @@ public class ListTelnetHandlerTest {
mockChannel = mock(Channel.class);
given(mockChannel.getAttribute("telnet.service")).willReturn(null);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = list.telnet(mockChannel, "");
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService\r\n", result);
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService:1.0.0\r\n", result);
}
@Test
@ -106,11 +106,11 @@ public class ListTelnetHandlerTest {
mockChannel = mock(Channel.class);
given(mockChannel.getAttribute("telnet.service")).willReturn(null);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = list.telnet(mockChannel, "-l");
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService -> published: N\r\n", result);
assertEquals("PROVIDER:\r\norg.apache.dubbo.rpc.protocol.dubbo.support.DemoService:1.0.0 -> published: N\r\n", result);
}
@Test
@ -118,12 +118,12 @@ public class ListTelnetHandlerTest {
mockChannel = mock(Channel.class);
given(mockChannel.getAttribute("telnet.service")).willReturn("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService");
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", "Dubbo", "1.0.0", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel("org.apache.dubbo.rpc.protocol.dubbo.support.DemoService", providerModel);
String result = list.telnet(mockChannel, "");
assertTrue(result.startsWith("Use default service org.apache.dubbo.rpc.protocol.dubbo.support.DemoService.\r\n" +
"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService (as provider):\r\n"));
"org.apache.dubbo.rpc.protocol.dubbo.support.DemoService:1.0.0 (as provider):\r\n"));
for (Method method : DemoService.class.getMethods()) {
assertTrue(result.contains(method.getName()));
}

View File

@ -25,6 +25,7 @@ import org.apache.dubbo.rpc.model.ProviderModel;
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoService;
import org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl;
import org.apache.dubbo.rpc.protocol.dubbo.support.ProtocolUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -71,7 +72,7 @@ public class SelectTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), "", "", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
String result = select.telnet(mockChannel, "1");
@ -86,7 +87,7 @@ public class SelectTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), "", "", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
String result = select.telnet(mockChannel, "index");
@ -107,7 +108,7 @@ public class SelectTelnetHandlerTest {
given(mockChannel.getLocalAddress()).willReturn(NetUtils.toAddress("127.0.0.1:5555"));
given(mockChannel.getRemoteAddress()).willReturn(NetUtils.toAddress("127.0.0.1:20886"));
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), new DemoServiceImpl(), DemoService.class);
ProviderModel providerModel = new ProviderModel(DemoService.class.getName(), "", "", new DemoServiceImpl(), DemoService.class);
ApplicationModel.initProviderModel(DemoService.class.getName(), providerModel);
String result = select.telnet(mockChannel, null);

View File

@ -33,7 +33,7 @@ public class DubboHessianURLConnectionFactory extends HessianURLConnectionFactor
HessianConnection connection = super.open(url);
RpcContext context = RpcContext.getContext();
for (String key : context.getAttachments().keySet()) {
connection.addHeader(Constants.DEFAULT_EXCHANGER + key, context.getAttachment(key));
connection.addHeader(Constants.DEFAULT_EXCHANGER + key, (String) context.getAttachment(key));
}
return connection;

View File

@ -1,56 +1,55 @@
/*
* 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.dubbo.rpc.protocol.hessian;
import org.apache.dubbo.remoting.Constants;
import org.apache.dubbo.rpc.RpcContext;
import com.caucho.hessian.client.HessianConnection;
import com.caucho.hessian.client.HessianConnectionFactory;
import com.caucho.hessian.client.HessianProxyFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import java.net.URL;
/**
* HttpClientConnectionFactory
*/
public class HttpClientConnectionFactory implements HessianConnectionFactory {
private HttpClient httpClient;
@Override
public void setHessianProxyFactory(HessianProxyFactory factory) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout((int) factory.getConnectTimeout())
.setSocketTimeout((int) factory.getReadTimeout())
.build();
httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
}
@Override
public HessianConnection open(URL 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;
}
}
/*
* 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.dubbo.rpc.protocol.hessian;
import com.caucho.hessian.client.HessianConnection;
import com.caucho.hessian.client.HessianConnectionFactory;
import com.caucho.hessian.client.HessianProxyFactory;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import java.net.URL;
/**
* HttpClientConnectionFactory
*/
public class HttpClientConnectionFactory implements HessianConnectionFactory {
private HttpClient httpClient;
@Override
public void setHessianProxyFactory(HessianProxyFactory factory) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout((int) factory.getConnectTimeout())
.setSocketTimeout((int) factory.getReadTimeout())
.build();
httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
}
@Override
public HessianConnection open(URL url) {
HttpClientConnection httpClientConnection = new HttpClientConnection(httpClient, url);
RpcContext context = RpcContext.getContext();
for (String key : context.getAttachments().keySet()) {
httpClientConnection.addHeader(Constants.DEFAULT_EXCHANGER + key, (String) context.getAttachment(key));
}
return httpClientConnection;
}
}

View File

@ -36,14 +36,14 @@ public class HttpRemoteInvocation extends RemoteInvocation {
public HttpRemoteInvocation(MethodInvocation methodInvocation) {
super(methodInvocation);
addAttribute(DUBBO_ATTACHMENTS_ATTR_NAME, new HashMap<String, String>(RpcContext.getContext().getAttachments()));
addAttribute(DUBBO_ATTACHMENTS_ATTR_NAME, new HashMap<String, Object>(RpcContext.getContext().getAttachments()));
}
@Override
public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
RpcContext context = RpcContext.getContext();
context.setAttachments((Map<String, String>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
context.setAttachments((Map<String, Object>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
String generic = (String) getAttribute(GENERIC_KEY);
if (StringUtils.isNotEmpty(generic)) {

View File

@ -0,0 +1,61 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dubbo-rpc</artifactId>
<groupId>org.apache.dubbo</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-rpc-jsonrpc</artifactId>
<description>The JSON-RPC module of dubbo project</description>
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-http</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>com.github.briandilley.jsonrpc4j</groupId>
<artifactId>jsonrpc4j</artifactId>
</dependency>
<dependency>
<groupId>javax.portlet</groupId>
<artifactId>portlet-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -137,7 +137,7 @@ public class RestProtocol extends AbstractProxyProtocol {
}
@Override
protected <T> T doRefer(Class<T> serviceType, URL url) throws RpcException {
protected <T> T getFrameworkProxy(Class<T> serviceType, URL url) throws RpcException {
// TODO more configs to add
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();

View File

@ -69,16 +69,18 @@ public class RpcContextFilter implements ContainerRequestFilter, ClientRequestFi
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
int size = 0;
for (Map.Entry<String, String> entry : RpcContext.getContext().getAttachments().entrySet()) {
for (Map.Entry<String, Object> entry : RpcContext.getContext().getAttachments().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
Object value = entry.getValue();
if (illegalForRest(key) || illegalForRest(value)) {
throw new IllegalArgumentException("The attachments of " + RpcContext.class.getSimpleName() + " must not contain ',' or '=' when using rest protocol");
}
String stringValue = (String) value;
// TODO for now we don't consider the differences of encoding and server limit
if (value != null) {
size += value.getBytes(StandardCharsets.UTF_8).length;
size += stringValue.getBytes(StandardCharsets.UTF_8).length;
}
if (size > MAX_HEADER_SIZE) {
throw new IllegalArgumentException("The attachments of " + RpcContext.class.getSimpleName() + " is too big");
@ -95,9 +97,9 @@ public class RpcContextFilter implements ContainerRequestFilter, ClientRequestFi
* @param v string value
* @return true for illegal
*/
private boolean illegalForRest(String v) {
if (StringUtils.isNotEmpty(v)) {
return v.contains(",") || v.contains("=");
private boolean illegalForRest(Object v) {
if (v instanceof String && StringUtils.isNotEmpty((String) v)) {
return ((String) v).contains(",") || ((String) v).contains("=");
}
return false;
}

View File

@ -56,7 +56,7 @@ public class RestProtocolTest {
public void testRestProtocol() {
URL url = URL.valueOf("rest://127.0.0.1:5342/rest/say?version=1.0.0&interface=org.apache.dubbo.rpc.protocol.rest.DemoService");
DemoServiceImpl server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(url.getPathKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(url.getPathKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(url.getPathKey(), providerModel);
Exporter<DemoService> exporter = protocol.export(proxy.getInvoker(server, DemoService.class, url));
@ -76,7 +76,7 @@ public class RestProtocolTest {
DemoServiceImpl server = new DemoServiceImpl();
Assertions.assertFalse(server.isCalled());
URL url = URL.valueOf("rest://127.0.0.1:5341/a/b/c?version=1.0.0&interface=org.apache.dubbo.rpc.protocol.rest.DemoService");
ProviderModel providerModel = new ProviderModel(url.getPathKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(url.getPathKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(url.getPathKey(), providerModel);
Exporter<DemoService> exporter = protocol.export(proxy.getInvoker(server, DemoService.class, url));
@ -94,7 +94,7 @@ public class RestProtocolTest {
@Test
public void testExport() {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
RpcContext.getContext().setAttachment("timeout", "200");
@ -111,7 +111,7 @@ public class RestProtocolTest {
@Test
public void testNettyServer() {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
URL nettyUrl = exportUrl.addParameter(SERVER_KEY, "netty");
@ -129,7 +129,7 @@ public class RestProtocolTest {
public void testServletWithoutWebConfig() {
Assertions.assertThrows(RpcException.class, () -> {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getPathKey(), providerModel);
URL servletUrl = exportUrl.addParameter(SERVER_KEY, "servlet");
@ -142,7 +142,7 @@ public class RestProtocolTest {
public void testErrorHandler() {
Assertions.assertThrows(RpcException.class, () -> {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
URL nettyUrl = exportUrl.addParameter(SERVER_KEY, "netty");
@ -157,7 +157,7 @@ public class RestProtocolTest {
@Test
public void testInvoke() {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
@ -172,7 +172,7 @@ public class RestProtocolTest {
@Test
public void testFilter() {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
URL nettyUrl = exportUrl.addParameter(SERVER_KEY, "netty")
@ -191,7 +191,7 @@ public class RestProtocolTest {
@Test
public void testRpcContextFilter() {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
// use RpcContextFilter
@ -215,7 +215,7 @@ public class RestProtocolTest {
public void testRegFail() {
Assertions.assertThrows(RuntimeException.class, () -> {
DemoService server = new DemoServiceImpl();
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), server, DemoService.class);
ProviderModel providerModel = new ProviderModel(exportUrl.getServiceKey(), "", "", server, DemoService.class);
ApplicationModel.initProviderModel(exportUrl.getServiceKey(), providerModel);
URL nettyUrl = exportUrl.addParameter(EXTENSION_KEY, "com.not.existing.Filter");

View File

@ -72,7 +72,7 @@ public class RmiProtocol extends AbstractProxyProtocol {
@Override
@SuppressWarnings("unchecked")
protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException {
protected <T> T getFrameworkProxy(final Class<T> serviceType, final URL url) throws RpcException {
final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
final String generic = url.getParameter(GENERIC_KEY);
final boolean isGeneric = ProtocolUtils.isGeneric(generic) || serviceType.equals(GenericService.class);

View File

@ -50,7 +50,7 @@ public class RmiRemoteInvocation extends RemoteInvocation {
public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
RpcContext context = RpcContext.getContext();
context.setAttachments((Map<String, String>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
context.setAttachments((Map<String, Object>) getAttribute(DUBBO_ATTACHMENTS_ATTR_NAME));
String generic = (String) getAttribute(GENERIC_KEY);
if (StringUtils.isNotEmpty(generic)) {
context.setAttachment(GENERIC_KEY, generic);

View File

@ -0,0 +1,123 @@
<!--
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.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc</artifactId>
<version>${revision}</version>
</parent>
<artifactId>dubbo-rpc-rsocket</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>The default rpc module of dubbo project</description>
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-multicast</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.rsocket</groupId>
<artifactId>rsocket-core</artifactId>
<version>0.11.14</version>
</dependency>
<dependency>
<groupId>io.rsocket</groupId>
<artifactId>rsocket-transport-netty</artifactId>
<version>0.11.14</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-container-api</artifactId>
<version>${project.parent.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-jdk</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>javax.validation</groupId>-->
<!--<artifactId>validation-api</artifactId>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.hibernate</groupId>-->
<!--<artifactId>hibernate-validator</artifactId>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.glassfish</groupId>-->
<!--<artifactId>javax.el</artifactId>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
</dependencies>
</project>

View File

@ -0,0 +1,98 @@
/*
* 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.dubbo.rpc.protocol.rsocket;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.Serialization;
import org.apache.dubbo.rpc.AppResponse;
import io.rsocket.Payload;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class FutureSubscriber extends CompletableFuture<AppResponse> implements Subscriber<Payload> {
private final Serialization serialization;
private final Class<?> retType;
public FutureSubscriber(Serialization serialization, Class<?> retType) {
this.serialization = serialization;
this.retType = retType;
}
@Override
public void onSubscribe(Subscription subscription) {
subscription.request(1);
}
@Override
public void onNext(Payload payload) {
try {
AppResponse appResponse = new AppResponse();
ByteBuffer dataBuffer = payload.getData();
byte[] dataBytes = new byte[dataBuffer.remaining()];
dataBuffer.get(dataBytes, dataBuffer.position(), dataBuffer.remaining());
InputStream dataInputStream = new ByteArrayInputStream(dataBytes);
ObjectInput in = serialization.deserialize(null, dataInputStream);
int flag = in.readByte();
if ((flag & RSocketConstants.FLAG_ERROR) != 0) {
Throwable t = (Throwable) in.readObject();
appResponse.setException(t);
} else {
Object value = null;
if ((flag & RSocketConstants.FLAG_NULL_VALUE) == 0) {
if (retType == null) {
value = in.readObject();
} else {
value = in.readObject(retType);
}
appResponse.setValue(value);
}
}
if ((flag & RSocketConstants.FLAG_HAS_ATTACHMENT) != 0) {
Map<String, Object> attachment = in.readObject(Map.class);
appResponse.setAttachments(attachment);
}
this.complete(appResponse);
} catch (Throwable t) {
this.completeExceptionally(t);
}
}
@Override
public void onError(Throwable throwable) {
this.completeExceptionally(throwable);
}
@Override
public void onComplete() {
}
}

View File

@ -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 org.apache.dubbo.rpc.protocol.rsocket;
import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public class MetadataCodec {
public static Map<String, Object> decodeMetadata(byte[] bytes) throws IOException {
return JSON.parseObject(new String(bytes, StandardCharsets.UTF_8), Map.class);
}
public static byte[] encodeMetadata(Map<String, Object> metadata) throws IOException {
String jsonStr = JSON.toJSONString(metadata);
return jsonStr.getBytes(StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.dubbo.rpc.protocol.rsocket;
public class RSocketConstants {
public static final String SERVICE_NAME_KEY = "_service_name";
public static final String SERVICE_VERSION_KEY = "_service_version";
public static final String METHOD_NAME_KEY = "_method_name";
public static final String PARAM_TYPE_KEY = "_param_type";
public static final String SERIALIZE_TYPE_KEY = "_serialize_type";
public static final String TIMEOUT_KEY = "_timeout";
public static final int FLAG_ERROR = 0x01;
public static final int FLAG_NULL_VALUE = 0x02;
public static final int FLAG_HAS_ATTACHMENT = 0x04;
}

Some files were not shown because too many files have changed in this diff Show More