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

com.alibaba.dubbo.common.bytecode.Proxy Maven / Gradle / Ivy

/*
 * 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.common.bytecode;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicLong;

import com.alibaba.dubbo.common.utils.ClassHelper;
import com.alibaba.dubbo.common.utils.ReflectUtils;

/**
 * Proxy.
 * 
 * @author qian.lei
 */

public abstract class Proxy
{
	private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);

	private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();

	public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler(){
		public Object invoke(Object proxy, Method method, Object[] args){ return null; }
	};

	public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler(){
		public Object invoke(Object proxy, Method method, Object[] args){ throw new UnsupportedOperationException("Method [" + ReflectUtils.getName(method) + "] unimplemented."); }
	};

	private static final Map> ProxyCacheMap = new WeakHashMap>();

	private static final Object PendingGenerationMarker = new Object();

	/**
	 * Get proxy.
	 * 
	 * @param ics interface class array.
	 * @return Proxy instance.
	 */
	public static Proxy getProxy(Class... ics)
	{
		return getProxy(ClassHelper.getCallerClassLoader(Proxy.class), ics);
	}

	/**
	 * Get proxy.
	 * @param cl class loader.
	 * @param ics interface class array.
	 * 
	 * @return Proxy instance.
	 */
	public static Proxy getProxy(ClassLoader cl, Class... ics)
	{
		if( ics.length > 65535 )
			throw new IllegalArgumentException("interface limit exceeded");
		
		StringBuilder sb = new StringBuilder();
		for(int i=0;i tmp = null;
			try
			{
				tmp = Class.forName(itf, false, cl);
			}
			catch(ClassNotFoundException e)
			{}

			if( tmp != ics[i] )
				throw new IllegalArgumentException(ics[i] + " is not visible from class loader");

		    sb.append(itf).append(';');
		}

		// use interface class name list as key.
		String key = sb.toString();

		// get cache by class loader.
		Map cache;
		synchronized( ProxyCacheMap )
		{
			cache = ProxyCacheMap.get(cl);
			if( cache == null )
		    {
				cache = new HashMap();
				ProxyCacheMap.put(cl, cache);
		    }
		}

		Proxy proxy = null;
		synchronized( cache )
		{
			do
			{
				Object value = cache.get(key);
				if( value instanceof Reference )
				{
					proxy = (Proxy)((Reference)value).get();
					if( proxy != null )
						return proxy;
				}

				if( value == PendingGenerationMarker )
				{
					try{ cache.wait(); }catch(InterruptedException e){}
				}
				else
				{
					cache.put(key, PendingGenerationMarker);
					break;
				}
			}
			while( true );
		}

		long id = PROXY_CLASS_COUNTER.getAndIncrement();
		String pkg = null;
		ClassGenerator ccp = null, ccm = null;
		try
		{
			ccp = ClassGenerator.newInstance(cl);

			Set worked = new HashSet();
			List methods = new ArrayList();

			for(int i=0;i rt = method.getReturnType();
					Class[] pts = method.getParameterTypes();

					StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
					for(int j=0;j[]{ InvocationHandler.class }, new Class[0], "handler=$1;");
            ccp.addDefaultConstructor();
			Class clazz = ccp.toClass();
			clazz.getField("methods").set(null, methods.toArray(new Method[0]));

			// create Proxy class.
			String fcn = Proxy.class.getName() + id;
			ccm = ClassGenerator.newInstance(cl);
			ccm.setClassName(fcn);
			ccm.addDefaultConstructor();
			ccm.setSuperClass(Proxy.class);
			ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
			Class pc = ccm.toClass();
			proxy = (Proxy)pc.newInstance();
		}
		catch(RuntimeException e)
		{
			throw e;
		}
		catch(Exception e)
		{
			throw new RuntimeException(e.getMessage(), e);
		}
		finally
		{
			// release ClassGenerator
			if( ccp != null )
				ccp.release();
			if( ccm != null )
				ccm.release();
			synchronized( cache )
			{
				if( proxy == null )
					cache.remove(key);
				else
					cache.put(key, new WeakReference(proxy));
				cache.notifyAll();
			}
		}
		return proxy;
	}

	/**
	 * get instance with default handler.
	 * 
	 * @return instance.
	 */
	public Object newInstance()
	{
		return newInstance(THROW_UNSUPPORTED_INVOKER);
	}

	/**
	 * get instance with special handler.
	 * 
	 * @return instance.
	 */
	abstract public Object newInstance(InvocationHandler handler);

	protected Proxy(){}

	private static String asArgument(Class cl, String name)
	{
		if( cl.isPrimitive() )
		{
			if( Boolean.TYPE == cl )
				return name + "==null?false:((Boolean)" + name + ").booleanValue()";
			if( Byte.TYPE == cl )
				return name + "==null?(byte)0:((Byte)" + name + ").byteValue()";
			if( Character.TYPE == cl )
				return name + "==null?(char)0:((Character)" + name + ").charValue()";
			if( Double.TYPE == cl )
				return name + "==null?(double)0:((Double)" + name + ").doubleValue()";
			if( Float.TYPE == cl )
				return name + "==null?(float)0:((Float)" + name + ").floatValue()";
			if( Integer.TYPE == cl )
				return name + "==null?(int)0:((Integer)" + name + ").intValue()";
			if( Long.TYPE == cl )
				return name + "==null?(long)0:((Long)" + name + ").longValue()";
			if( Short.TYPE == cl )
				return name + "==null?(short)0:((Short)" + name + ").shortValue()";
			throw new RuntimeException(name+" is unknown primitive type."); 
		}
		return "(" + ReflectUtils.getName(cl) + ")"+name;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy