All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.dubbo.rpc.support.MockInvoker Maven / Gradle / Ivy

The newest version!
/*
 * 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.support;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.json.JSON;
import com.alibaba.dubbo.common.utils.ConfigUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.alibaba.dubbo.rpc.RpcResult;
import com.frameworkx.common.extension.utils.ExtensionExtendUtil;

import net.jahhan.com.alibaba.dubbo.common.utils.PojoUtils;
import net.jahhan.com.alibaba.dubbo.common.utils.ReflectUtils;
import net.jahhan.common.extension.constant.JahhanErrorCode;
import net.jahhan.common.extension.utils.StringUtils;
import net.jahhan.exception.JahhanException;
import net.jahhan.spi.ProxyFactory;

/**
 * @author chao.liuc
 * @author william.liangf
 * 
 */
final public class MockInvoker implements Invoker {
	private final static ProxyFactory proxyFactory = ExtensionExtendUtil.getAdaptiveExtension(ProxyFactory.class);
	private final static Map> mocks = new ConcurrentHashMap>();
	private final static Map throwables = new ConcurrentHashMap();

	private final URL url;

	public MockInvoker(URL url) {
		this.url = url;
	}

	public Result invoke(Invocation invocation) throws JahhanException {
		String mock = getUrl().getParameter(invocation.getMethodName() + "." + Constants.MOCK_KEY);
		if (invocation instanceof RpcInvocation) {
			((RpcInvocation) invocation).setInvoker(this);
		}
		if (StringUtils.isBlank(mock)) {
			mock = getUrl().getParameter(Constants.MOCK_KEY);
		}

		if (StringUtils.isBlank(mock)) {
			throw new JahhanException(new IllegalAccessException("mock can not be null. url :" + url));
		}
		mock = normallizeMock(URL.decode(mock));
		if (Constants.RETURN_PREFIX.trim().equalsIgnoreCase(mock.trim())) {
			RpcResult result = new RpcResult();
			result.setValue(null);
			return result;
		} else if (mock.startsWith(Constants.RETURN_PREFIX)) {
			mock = mock.substring(Constants.RETURN_PREFIX.length()).trim();
			mock = mock.replace('`', '"');
			try {
				Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
				Object value = parseMockValue(mock, returnTypes);
				return new RpcResult(value);
			} catch (Exception ew) {
				throw new JahhanException("mock return invoke error. method :" + invocation.getMethodName()
						+ ", mock:" + mock + ", url: " + url, ew);
			}
		} else if (mock.startsWith(Constants.THROW_PREFIX)) {
			mock = mock.substring(Constants.THROW_PREFIX.length()).trim();
			mock = mock.replace('`', '"');
			if (StringUtils.isBlank(mock)) {
				throw new JahhanException(" mocked exception for Service degradation. ");
			} else { // 用户自定义类
				Throwable t = getThrowable(mock);
				throw new JahhanException(JahhanErrorCode.BIZ_EXCEPTION, t);
			}
		} else { // impl mock
			try {
				Invoker invoker = getInvoker(mock);
				return invoker.invoke(invocation);
			} catch (Throwable t) {
				throw new JahhanException("Failed to create mock implemention class " + mock, t);
			}
		}
	}

	private Throwable getThrowable(String throwstr) {
		Throwable throwable = (Throwable) throwables.get(throwstr);
		if (throwable != null) {
			return throwable;
		} else {
			Throwable t = null;
			try {
				Class bizException = ReflectUtils.forName(throwstr);
				Constructor constructor;
				constructor = ReflectUtils.findConstructor(bizException, String.class);
				t = (Throwable) constructor.newInstance(new Object[] { " mocked exception for Service degradation. " });
				if (throwables.size() < 1000) {
					throwables.put(throwstr, t);
				}
			} catch (Exception e) {
				throw new JahhanException("mock throw error :" + throwstr + " argument error.", e);
			}
			return t;
		}
	}

	@SuppressWarnings("unchecked")
	private Invoker getInvoker(String mockService) {
		Invoker invoker = (Invoker) mocks.get(mockService);
		if (invoker != null) {
			return invoker;
		} else {
			Class serviceType = (Class) ReflectUtils.forName(url.getServiceInterface());
			if (ConfigUtils.isDefault(mockService)) {
				mockService = serviceType.getName() + "Mock";
			}

			Class mockClass = ReflectUtils.forName(mockService);
			if (!serviceType.isAssignableFrom(mockClass)) {
				throw new IllegalArgumentException("The mock implemention class " + mockClass.getName()
						+ " not implement interface " + serviceType.getName());
			}

			if (!serviceType.isAssignableFrom(mockClass)) {
				throw new IllegalArgumentException("The mock implemention class " + mockClass.getName()
						+ " not implement interface " + serviceType.getName());
			}
			try {
				T mockObject = (T) mockClass.newInstance();
				invoker = proxyFactory.getInvoker(mockObject, (Class) serviceType, url);
				if (mocks.size() < 10000) {
					mocks.put(mockService, invoker);
				}
				return invoker;
			} catch (InstantiationException e) {
				throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName()
						+ "()\" in mock implemention class " + mockClass.getName(), e);
			} catch (IllegalAccessException e) {
				throw new IllegalStateException(e);
			}
		}
	}

	// mock=fail:throw
	// mock=fail:return
	// mock=xx.Service
	private String normallizeMock(String mock) {
		if (mock == null || mock.trim().length() == 0) {
			return mock;
		} else if (ConfigUtils.isDefault(mock) || "fail".equalsIgnoreCase(mock.trim())
				|| "force".equalsIgnoreCase(mock.trim())) {
			mock = url.getServiceInterface() + "Mock";
		}
		if (mock.startsWith(Constants.FAIL_PREFIX)) {
			mock = mock.substring(Constants.FAIL_PREFIX.length()).trim();
		} else if (mock.startsWith(Constants.FORCE_PREFIX)) {
			mock = mock.substring(Constants.FORCE_PREFIX.length()).trim();
		}
		return mock;
	}

	public static Object parseMockValue(String mock) throws Exception {
		return parseMockValue(mock, null);
	}

	public static Object parseMockValue(String mock, Type[] returnTypes) throws Exception {
		Object value = null;
		if ("empty".equals(mock)) {
			value = ReflectUtils
					.getEmptyObject(returnTypes != null && returnTypes.length > 0 ? (Class) returnTypes[0] : null);
		} else if ("null".equals(mock)) {
			value = null;
		} else if ("true".equals(mock)) {
			value = true;
		} else if ("false".equals(mock)) {
			value = false;
		} else if (mock.length() >= 2
				&& (mock.startsWith("\"") && mock.endsWith("\"") || mock.startsWith("\'") && mock.endsWith("\'"))) {
			value = mock.subSequence(1, mock.length() - 1);
		} else if (returnTypes != null && returnTypes.length > 0 && returnTypes[0] == String.class) {
			value = mock;
		} else if (StringUtils.isNumeric(mock)) {
			value = JSON.parse(mock);
		} else if (mock.startsWith("{")) {
			value = JSON.parse(mock, Map.class);
		} else if (mock.startsWith("[")) {
			value = JSON.parse(mock, List.class);
		} else {
			value = mock;
		}
		if (returnTypes != null && returnTypes.length > 0) {
			value = PojoUtils.realize(value, (Class) returnTypes[0], returnTypes.length > 1 ? returnTypes[1] : null);
		}
		return value;
	}

	public URL getUrl() {
		return this.url;
	}

	public boolean isAvailable() {
		return true;
	}

	public void destroy() {
		// do nothing
	}

	public Class getInterface() {
		// FIXME
		return null;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy