| /*
|
| * Copyright 1999-2011 Alibaba Group.
|
| *
|
| * Licensed under the Apache License, Version 2.0 (the "License");
|
| * you may not use this file except in compliance with the License.
|
| * You may obtain a copy of the License at
|
| *
|
| * http://www.apache.org/licenses/LICENSE-2.0
|
| *
|
| * Unless required by applicable law or agreed to in writing, software
|
| * distributed under the License is distributed on an "AS IS" BASIS,
|
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| * See the License for the specific language governing permissions and
|
| * limitations under the License.
|
| */
|
| package com.alibaba.dubbo.rpc; |
| |
| import java.net.InetSocketAddress;
|
| import java.util.ArrayList;
|
| import java.util.Arrays;
|
| import java.util.HashMap;
|
| import java.util.List;
|
| import java.util.Map;
|
| import java.util.concurrent.Callable;
|
| import java.util.concurrent.ExecutionException;
|
| import java.util.concurrent.Future;
|
| import java.util.concurrent.FutureTask;
|
| import java.util.concurrent.TimeUnit;
|
| import java.util.concurrent.TimeoutException;
|
|
|
| import com.alibaba.dubbo.common.Constants;
|
| import com.alibaba.dubbo.common.URL;
|
| import com.alibaba.dubbo.common.utils.NetUtils;
|
| |
| /** |
| * Thread local context. (API, ThreadLocal, ThreadSafe)
|
| *
|
| * 注意:RpcContext是一个临时状态记录器,当接收到RPC请求,或发起RPC请求时,RpcContext的状态都会变化。
|
| * 比如:A调B,B再调C,则B机器上,在B调C之前,RpcContext记录的是A调B的信息,在B调C之后,RpcContext记录的是B调C的信息。 |
| * |
| * @see com.alibaba.dubbo.rpc.filter.ContextFilter |
| * @author qian.lei |
| * @author william.liangf |
| */ |
| public class RpcContext { |
| |
| private static final ThreadLocal<RpcContext> LOCAL = new ThreadLocal<RpcContext>() { |
| @Override |
| protected RpcContext initialValue() { |
| return new RpcContext(); |
| } |
| }; |
| |
| /** |
| * get context. |
| * |
| * @return context |
| */ |
| public static RpcContext getContext() { |
| return LOCAL.get(); |
| } |
| |
| /** |
| * remove context. |
| * |
| * @see com.alibaba.dubbo.rpc.filter.ContextFilter |
| */ |
| public static void removeContext() { |
| LOCAL.remove(); |
| } |
|
|
| private Future<?> future;
|
|
|
| private List<URL> urls;
|
|
|
| private URL url;
|
|
|
| private String methodName;
|
|
|
| private Class<?>[] parameterTypes;
|
|
|
| private Object[] arguments;
|
| |
| private InetSocketAddress localAddress; |
| |
| private InetSocketAddress remoteAddress; |
|
|
| private final Map<String, String> attachments = new HashMap<String, String>();
|
|
|
| private final Map<String, Object> values = new HashMap<String, Object>();
|
|
|
| @Deprecated
|
| private List<Invoker<?>> invokers;
|
|
|
| @Deprecated
|
| private Invoker<?> invoker;
|
|
|
| @Deprecated
|
| private Invocation invocation;
|
| |
| protected RpcContext() { |
| } |
|
|
| /**
|
| * is provider side.
|
| *
|
| * @return provider side.
|
| */
|
| public boolean isProviderSide() {
|
| URL url = getUrl();
|
| if (url == null) {
|
| return false;
|
| }
|
| InetSocketAddress address = getRemoteAddress();
|
| if (address == null) {
|
| return false;
|
| }
|
| String host;
|
| if (address.getAddress() == null) {
|
| host = address.getHostName();
|
| } else {
|
| host = address.getAddress().getHostAddress();
|
| }
|
| return url.getPort() != address.getPort() ||
|
| ! NetUtils.filterLocalHost(url.getIp()).equals(NetUtils.filterLocalHost(host));
|
| } |
|
|
| /**
|
| * is consumer side.
|
| *
|
| * @return consumer side.
|
| */
|
| public boolean isConsumerSide() {
|
| URL url = getUrl();
|
| if (url == null) {
|
| return false;
|
| }
|
| InetSocketAddress address = getRemoteAddress();
|
| if (address == null) {
|
| return false;
|
| }
|
| String host;
|
| if (address.getAddress() == null) {
|
| host = address.getHostName();
|
| } else {
|
| host = address.getAddress().getHostAddress();
|
| }
|
| return url.getPort() == address.getPort() &&
|
| NetUtils.filterLocalHost(url.getIp()).equals(NetUtils.filterLocalHost(host));
|
| }
|
|
|
| /**
|
| * get future.
|
| *
|
| * @param <T>
|
| * @return future
|
| */
|
| @SuppressWarnings("unchecked")
|
| public <T> Future<T> getFuture() {
|
| return (Future<T>) future;
|
| }
|
|
|
| /**
|
| * set future.
|
| *
|
| * @param future
|
| */
|
| public void setFuture(Future<?> future) {
|
| this.future = future;
|
| }
|
|
|
| public List<URL> getUrls() {
|
| return urls == null && url != null ? (List<URL>) Arrays.asList(url) : urls;
|
| }
|
|
|
| public void setUrls(List<URL> urls) {
|
| this.urls = urls;
|
| }
|
|
|
| public URL getUrl() {
|
| return url;
|
| } |
|
|
| public void setUrl(URL url) {
|
| this.url = url;
|
| }
|
|
|
| /**
|
| * get method name.
|
| *
|
| * @return method name.
|
| */
|
| public String getMethodName() {
|
| return methodName;
|
| }
|
|
|
| public void setMethodName(String methodName) {
|
| this.methodName = methodName;
|
| }
|
|
|
| /**
|
| * get parameter types.
|
| *
|
| * @serial
|
| */
|
| public Class<?>[] getParameterTypes() {
|
| return parameterTypes;
|
| }
|
|
|
| public void setParameterTypes(Class<?>[] parameterTypes) {
|
| this.parameterTypes = parameterTypes;
|
| }
|
|
|
| /**
|
| * get arguments.
|
| *
|
| * @return arguments.
|
| */
|
| public Object[] getArguments() {
|
| return arguments;
|
| }
|
|
|
| public void setArguments(Object[] arguments) {
|
| this.arguments = arguments;
|
| }
|
| |
| /** |
| * set local address. |
| * |
| * @param address |
| * @return context |
| */ |
| public RpcContext setLocalAddress(InetSocketAddress address) { |
| this.localAddress = address; |
| return this; |
| } |
| |
| /** |
| * set local address. |
| * |
| * @param host |
| * @param port |
| * @return context |
| */ |
| public RpcContext setLocalAddress(String host, int port) { |
| if (port < 0) { |
| port = 0; |
| } |
| this.localAddress = InetSocketAddress.createUnresolved(host, port); |
| return this; |
| } |
| |
| /** |
| * get local address. |
| * |
| * @return local address |
| */ |
| public InetSocketAddress getLocalAddress() { |
| return localAddress; |
| } |
| |
| public String getLocalAddressString() { |
| return getLocalHost() + ":" + getLocalPort(); |
| } |
| |
| /** |
| * get local host name. |
| * |
| * @return local host name |
| */ |
| public String getLocalHostName() { |
| String host = localAddress == null ? null : localAddress.getHostName(); |
| if (host == null || host.length() == 0) { |
| return getLocalHost(); |
| } |
| return host; |
| } |
| |
| /** |
| * set remote address. |
| * |
| * @param address |
| * @return context |
| */ |
| public RpcContext setRemoteAddress(InetSocketAddress address) { |
| this.remoteAddress = address; |
| return this; |
| } |
| |
| /** |
| * set remote address. |
| * |
| * @param host |
| * @param port |
| * @return context |
| */ |
| public RpcContext setRemoteAddress(String host, int port) { |
| if (port < 0) { |
| port = 0; |
| } |
| this.remoteAddress = InetSocketAddress.createUnresolved(host, port); |
| return this; |
| } |
| |
| /** |
| * get remote address. |
| * |
| * @return remote address |
| */ |
| public InetSocketAddress getRemoteAddress() { |
| return remoteAddress; |
| } |
| |
| /** |
| * get remote address string. |
| * |
| * @return remote address string. |
| */ |
| public String getRemoteAddressString() { |
| return getRemoteHost() + ":" + getRemotePort(); |
| } |
| |
| /** |
| * get remote host name. |
| * |
| * @return remote host name |
| */ |
| public String getRemoteHostName() { |
| return remoteAddress == null ? null : remoteAddress.getHostName(); |
| } |
| |
| /** |
| * get local host. |
| * |
| * @return local host |
| */ |
| public String getLocalHost() { |
| String host = localAddress == null ? null : |
| localAddress.getAddress() == null ? localAddress.getHostName()
|
| : NetUtils.filterLocalHost(localAddress.getAddress().getHostAddress()); |
| if (host == null || host.length() == 0) { |
| return NetUtils.getLocalHost(); |
| } |
| return host; |
| } |
| |
| /** |
| * get local port. |
| * |
| * @return port |
| */ |
| public int getLocalPort() { |
| return localAddress == null ? 0 : localAddress.getPort(); |
| } |
| |
| /** |
| * get remote host. |
| * |
| * @return remote host |
| */ |
| public String getRemoteHost() { |
| return remoteAddress == null ? null : |
| remoteAddress.getAddress() == null ? remoteAddress.getHostName()
|
| : NetUtils.filterLocalHost(remoteAddress.getAddress().getHostAddress()); |
| } |
| |
| /** |
| * get remote port. |
| * |
| * @return remote port |
| */ |
| public int getRemotePort() { |
| return remoteAddress == null ? 0 : remoteAddress.getPort(); |
| } |
|
|
| /**
|
| * get attachment.
|
| *
|
| * @param key
|
| * @return attachment
|
| */
|
| public String getAttachment(String key) {
|
| return attachments.get(key);
|
| }
|
| |
| /** |
| * set attachment. |
| * |
| * @param key |
| * @param value |
| * @return context |
| */ |
| public RpcContext setAttachment(String key, String value) { |
| if (value == null) { |
| attachments.remove(key); |
| } else { |
| attachments.put(key, value); |
| } |
| return this; |
| } |
| |
| /** |
| * remove attachment. |
| * |
| * @param key |
| * @return context |
| */ |
| public RpcContext removeAttachment(String key) { |
| attachments.remove(key); |
| return this; |
| } |
|
|
| /**
|
| * get attachments.
|
| *
|
| * @return attachments
|
| */
|
| public Map<String, String> getAttachments() {
|
| return attachments;
|
| }
|
|
|
| /**
|
| * set attachments
|
| *
|
| * @param attachment
|
| * @return context
|
| */
|
| public RpcContext setAttachments(Map<String, String> attachment) {
|
| this.attachments.clear();
|
| if (attachment != null && attachment.size() > 0) {
|
| this.attachments.putAll(attachment);
|
| }
|
| return this;
|
| }
|
|
|
| public void clearAttachments() {
|
| this.attachments.clear();
|
| }
|
|
|
| /**
|
| * get values.
|
| *
|
| * @return values
|
| */
|
| public Map<String, Object> get() {
|
| return values;
|
| }
|
|
|
| /**
|
| * set value.
|
| *
|
| * @param key
|
| * @param value
|
| * @return context
|
| */
|
| public RpcContext set(String key, Object value) {
|
| if (value == null) {
|
| values.remove(key);
|
| } else {
|
| values.put(key, value);
|
| }
|
| return this;
|
| }
|
|
|
| /**
|
| * remove value.
|
| *
|
| * @param key
|
| * @return value
|
| */
|
| public RpcContext remove(String key) {
|
| values.remove(key);
|
| return this;
|
| }
|
|
|
| /**
|
| * get value.
|
| *
|
| * @param key
|
| * @return value
|
| */
|
| public Object get(String key) {
|
| return values.get(key);
|
| }
|
|
|
| public RpcContext setInvokers(List<Invoker<?>> invokers) {
|
| this.invokers = invokers;
|
| if (invokers != null && invokers.size() > 0) {
|
| List<URL> urls = new ArrayList<URL>(invokers.size());
|
| for (Invoker<?> invoker : invokers) {
|
| urls.add(invoker.getUrl());
|
| }
|
| setUrls(urls);
|
| }
|
| return this;
|
| }
|
|
|
| public RpcContext setInvoker(Invoker<?> invoker) {
|
| this.invoker = invoker;
|
| if (invoker != null) {
|
| setUrl(invoker.getUrl());
|
| }
|
| return this;
|
| }
|
|
|
| public RpcContext setInvocation(Invocation invocation) {
|
| this.invocation = invocation;
|
| if (invocation != null) {
|
| setMethodName(invocation.getMethodName());
|
| setParameterTypes(invocation.getParameterTypes());
|
| setArguments(invocation.getArguments());
|
| }
|
| return this;
|
| }
|
|
|
| /**
|
| * @deprecated Replace to isProviderSide()
|
| */
|
| @Deprecated
|
| public boolean isServerSide() {
|
| return isProviderSide();
|
| }
|
|
|
| /**
|
| * @deprecated Replace to isConsumerSide()
|
| */
|
| @Deprecated
|
| public boolean isClientSide() {
|
| return isConsumerSide();
|
| }
|
|
|
| /**
|
| * @deprecated Replace to getUrls()
|
| */
|
| @Deprecated
|
| @SuppressWarnings({ "unchecked", "rawtypes" })
|
| public List<Invoker<?>> getInvokers() {
|
| return invokers == null && invoker != null ? (List)Arrays.asList(invoker) : invokers;
|
| }
|
|
|
| /**
|
| * @deprecated Replace to getUrl()
|
| */
|
| @Deprecated
|
| public Invoker<?> getInvoker() {
|
| return invoker;
|
| }
|
|
|
| /**
|
| * @deprecated Replace to getMethodName(), getParameterTypes(), getArguments()
|
| */
|
| @Deprecated
|
| public Invocation getInvocation() {
|
| return invocation;
|
| }
|
|
|
| /**
|
| * 异步调用 ,需要返回值,即使步调用Future.get方法,也会处理调用超时问题.
|
| * @param callable
|
| * @return 通过future.get()获取返回结果.
|
| */
|
| @SuppressWarnings("unchecked")
|
| public <T> Future<T> asyncCall(Callable<T> callable) {
|
| try {
|
| try {
|
| setAttachment(Constants.Attachments.IS_ASYNC_KEY, Boolean.TRUE.toString());
|
| final T o = callable.call();
|
| //local调用会直接返回结果.
|
| if (o != null) {
|
| FutureTask<T> f = new FutureTask<T>(new Callable<T>() {
|
| public T call() throws Exception {
|
| return o;
|
| }
|
| });
|
| f.run();
|
| return f;
|
| } else {
|
|
|
| }
|
| } catch (Exception e) {
|
| throw new RpcException(e);
|
| } finally {
|
| removeAttachment(Constants.Attachments.IS_ASYNC_KEY);
|
| }
|
| } catch (final RpcException e) {
|
| return new Future<T>() {
|
| public boolean cancel(boolean mayInterruptIfRunning) {
|
| return false;
|
| }
|
| public boolean isCancelled() {
|
| return false;
|
| }
|
| public boolean isDone() {
|
| return true;
|
| }
|
| public T get() throws InterruptedException, ExecutionException {
|
| throw new ExecutionException(e.getCause());
|
| }
|
| public T get(long timeout, TimeUnit unit)
|
| throws InterruptedException, ExecutionException,
|
| TimeoutException {
|
| return get();
|
| }
|
| };
|
| }
|
| return ((Future<T>)getContext().getFuture());
|
| }
|
|
|
| /**
|
| * oneway调用,只发送请求,不接收返回结果.
|
| * @param callable
|
| */
|
| public void asyncCall(Runnable runable) {
|
| try {
|
| setAttachment(Constants.Attachments.IS_ONEWAY_KEY, Boolean.TRUE.toString());
|
| runable.run();
|
| } catch (Throwable e) {
|
| //FIXME 异常是否应该放在future中?
|
| throw new RpcException("oneway call error ." + e.getMessage(), e);
|
| } finally {
|
| removeAttachment(Constants.Attachments.IS_ONEWAY_KEY);
|
| }
|
| }
|
| } |