Coverage report

  %line %branch
tsukuba_bunko.util.GenericListener
0% 
0% 

 1  
 /*
 2  
  * Common Library for TBAS Softwares
 3  
  * Language: Java
 4  
  *
 5  
  * All Rights Reserved.
 6  
  * (c) Copyright 2002 by Tsukuba Bunko.
 7  
  *
 8  
  * $Id: GenericListener.java,v 1.1 2005/07/11 12:49:19 ppoi Exp $
 9  
  */
 10  
 package tsukuba_bunko.util;
 11  
 
 12  
 import	java.lang.reflect.Method;
 13  
 import	java.lang.reflect.InvocationHandler;
 14  
 import	java.lang.reflect.InvocationTargetException;
 15  
 import	java.lang.reflect.Proxy;
 16  
 
 17  
 
 18  
 /**
 19  
  * イベントソースとイベントハンドラを接続するための枠組みを提供します. この枠組みを利用するためには,
 20  
  * Dynamic Proxy Class API を VM がサポートしている必要があります.
 21  
  * @author	$Author: ppoi $
 22  
  */
 23  
 public class GenericListener	{
 24  
 
 25  
 	/**
 26  
 	 * <code>GenericListener</code> はインスタンスを生成できません。
 27  
 	 */
 28  0
 	private GenericListener(){;}
 29  
 
 30  
 
 31  
 	/**
 32  
 	 * イベントソースとイベントハンドラを接続します。このメソッドで登録した場合、イベントハンドラはイベントソースと同じスレッドで実行されます。
 33  
 	 * @param	eventSource		イベントソース
 34  
 	 * @param	eventTarget		イベントハンドラ
 35  
 	 * @param	listenerClass	イベントソースに本来接続されるリスナクラス
 36  
 	 * @param	sourceMethod	イベントソースで呼び出されるメソッド名
 37  
 	 * @param	targetMethod	イベントハンドラで実際にイベントを処理するメソッド名
 38  
 	 * @return	イベントソースとイベントハンドラが接続された場合 <code>true</code>
 39  
 	 */
 40  
 	public static boolean connect( Object eventSource, Object eventTarget, Class listenerClass, String sourceMethod, String targetMethod )
 41  
 	{
 42  0
 		return connect( eventSource, eventTarget, listenerClass, sourceMethod, targetMethod, false );
 43  
 	}
 44  
 
 45  
 	/**
 46  
 	 * イベントソースとイベントハンドラを接続します。
 47  
 	 * 新しいスレッドを起動してイベントハンドラを実行する場合、戻り値を返すことは出来ません。また、例外の発生は通知されません。
 48  
 	 * @param	eventSource		イベントソース
 49  
 	 * @param	eventTarget		イベントハンドラ
 50  
 	 * @param	listenerClass	イベントソースに本来接続されるリスナクラス
 51  
 	 * @param	sourceMethod	イベントソースで呼び出されるメソッド名
 52  
 	 * @param	targetMethod	イベントハンドラで実際にイベントを処理するメソッド名
 53  
 	 * @param	newThread	新しいスレッドを起動してイベントハンドラを実行する場合 <code>true</code>、それ以外の場合 <code>false</code>
 54  
 	 * @return	イベントソースとイベントハンドラが接続された場合 <code>true</code>
 55  
 	 */
 56  
 	public static boolean connect( Object eventSource, Object eventTarget, Class listenerClass, String sourceMethod, String targetMethod, class="keyword">boolean newThread )
 57  
 	{
 58  
 		try	{
 59  
 		//	"add" メソッドの取得.
 60  0
 		Method	addMethod = eventSource.getClass().getMethod( ("add" + identifierOf(listenerClass)), new Class[]{listenerClass} );
 61  0
 		if( addMethod == null )	{
 62  
 			//	エラー
 63  0
 			return false;
 64  
 		}
 65  
 
 66  
 		//	リスナのインスタンスの取得.
 67  0
 		Method	sourceMethodObject = getListenerMethod( listenerClass, sourceMethod );
 68  0
 		Method	targetMethodObject = getTargetMethod( eventTarget.getClass(), targetMethod, sourceMethodObject.getParameterTypes() );
 69  0
 		Object	listenerImple = Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), new Class[]{listenerClass}, class="keyword">new InvocHandler(eventTarget, targetMethodObject, sourceMethodObject, class="keyword">newThread) );
 70  
 
 71  0
 		addMethod.invoke( eventSource, new Object[]{listenerImple} );
 72  
 		}
 73  0
 		catch( Exception e )
 74  
 		{
 75  0
 			e.printStackTrace();
 76  0
 			return false;
 77  0
 		}
 78  
 
 79  0
 		return true;
 80  
 	}
 81  
 
 82  
 	/**
 83  
 	 * 指定されたクラスの Identifier を取得します. ここでの Identidier はクラス宣言の際に
 84  
 	 *用いられるクラス名のことを指します.
 85  
 	 * @param	c	Identifier を取得するクラス
 86  
 	 * @return	Identifier
 87  
 	 */
 88  
 	private static String identifierOf( Class c )
 89  
 	{
 90  0
 		String	className = c.getName();
 91  0
 		return className.substring( className.lastIndexOf('.') + 1, className.length() );
 92  
 	}
 93  
 
 94  
 	/**
 95  
 	 * イベントソースで呼び出されるメソッドを取得します.
 96  
 	 * @param	listenerClass	リスナクラス
 97  
 	 * @param	methodName		メソッド名
 98  
 	 */
 99  
 	private static Method getListenerMethod( Class listenerClass, String methodName )
 100  
 		throws NoSuchMethodException
 101  
 	{
 102  0
 		Method	methods[] = listenerClass.getMethods();
 103  0
 		for( int i = methods.length - 1; i >= 0; --i )	{
 104  0
 			if( methodName.equals(methods[i].getName()) )	{
 105  0
 				return methods[i];
 106  
 			}
 107  
 		}
 108  0
 		throw new NoSuchMethodException( "No such method \"" + methodName + "\" in \"" + listenerClass.getName() + "\"." );
 109  
 	}
 110  
 
 111  
 	/**
 112  
 	 * 指定されたクラスにおいて指定された名前で定義されたメソッドを取得します.
 113  
 	 * @param	c	メソッドが定義されているクラス
 114  
 	 * @param	methodName	メソッド名
 115  
 	 * @param	parameterTypes	仮引数の型リスト
 116  
 	 */
 117  
 	private static Method getTargetMethod( Class c, String methodName, Class[] parameterTypes )
 118  
 		throws NoSuchMethodException
 119  
 	{
 120  0
 		Method	method = null;
 121  
 		try	{
 122  0
 			method = c.getDeclaredMethod( methodName, parameterTypes );
 123  
 		}
 124  0
 		catch( NoSuchMethodException nsme )	{
 125  0
 			method = c.getDeclaredMethod( methodName, null );
 126  0
 		}
 127  
 
 128  
 		try	{
 129  0
 			method.setAccessible( true );
 130  
 		}
 131  0
 		catch( SecurityException se )	{
 132  
 			//	ignore.
 133  0
 		}
 134  0
 		return method;
 135  
 	}
 136  
 }
 137  
 
 138  
 
 139  
 /**
 140  
  * <code>InvocationHandler</code> の実装です.
 141  
  */
 142  
 class InvocHandler	implements InvocationHandler	{
 143  
 
 144  
 	/**
 145  
 	 * 処理を実際に行うクラス
 146  
 	 */
 147  
 	private Object	_target =null;
 148  
 
 149  
 	/**
 150  
 	 * 処理を実際に行うメソッド
 151  
 	 */
 152  
 	private Method	_targetMethod = null;
 153  
 
 154  
 	/**
 155  
 	 * イベントソースによって呼び出されるメソッド
 156  
 	 */
 157  
 	private Method	_sourceMethod = null;
 158  
 
 159  
 	/**
 160  
 	 * 別スレッドを起動するかどうか
 161  
 	 */
 162  
 	private boolean	_newThread = false;
 163  
 
 164  
 
 165  
 	/**
 166  
 	 * <code>InvocHandler</code> のインスタンスを生成します.
 167  
 	 * @param	target	実際のイベントハンドラ
 168  
 	 * @param	targetMethod	実際に処理を行うメソッド
 169  
 	 * @param	sourceMethod	イベントソースによって呼び出されるメソッド
 170  
 	 */
 171  
 	InvocHandler( Object target, Method targetMethod, Method sourceMethod, boolean newThread )
 172  
 	{
 173  
 		_target = target;
 174  
 		_targetMethod = targetMethod;
 175  
 		_sourceMethod = sourceMethod;
 176  
 		_newThread = newThread;
 177  
 	}
 178  
 
 179  
 
 180  
 //
 181  
 //	InvocationHandler の実装
 182  
 //
 183  
 	/**
 184  
 	 * Processes a method invocation on a proxy instance and returns the result. This method
 185  
 	 * will be invoked on an invocation handler when a method is invoked on a proxy instance
 186  
 	 * that it is associated with.
 187  
 	 * @param	proxy	the proxy instance that the method was invoked on
 188  
 	 * @param	meth	the Method instance corresponding to the interface method invoked on
 189  
 	 * the proxy instance. The declaring class of the Method object will be the interface that
 190  
 	 * the method was declared in, which may be a superinterface of the proxy interface that
 191  
 	 * the proxy class inherits the method through.
 192  
 	 * @param	args	an array of objects containing the values of the arguments passed in
 193  
 	 * the method invocation on the proxy instance, or null if interface method takes no arguments.
 194  
 	 * Arguments of primitive types are wrapped in instances of the appropriate primitive wrapper
 195  
 	 * class, such as <code>java.lang.Integer</code> or <code>java.lang.Boolean</code>.
 196  
 	 * @return	the value to return from the method invocation on the proxy instance. If the
 197  
 	 * declared return type of the interface method is a primitive type, then the value returned
 198  
 	 * by this method must be an instance of the corresponding primitive wrapper class; otherwise,
 199  
 	 * it must be a type assignable to the declared return type. If the value returned by this
 200  
 	 * method is <code>null</code> and the interface method's return type is primitive, then a
 201  
 	 * <code>NullPointerException<code> will be thrown by the method invocation on the proxy
 202  
 	 * instance. If the value returned by this method is otherwise not compatible with the
 203  
 	 * interface method's declared return type as described above, a <code>ClassCastException</code>
 204  
 	 * will be thrown by the method invocation on the proxy instance
 205  
 	 */
 206  
 	public Object invoke( Object proxy, Method meth, Object[] args )
 207  
 		throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
 208  
 	{
 209  
 		if( !_sourceMethod.equals(meth) )	{
 210  
 			return null;
 211  
 		}
 212  
 
 213  
 		if( _targetMethod.getParameterTypes().length == 0 )	{
 214  
 			args = null;
 215  
 		}
 216  
 
 217  
 		if( _newThread )	{
 218  
 			new Thread( class="keyword">new InvokerRunner(_target, _targetMethod, args) ).start();
 219  
 			return null;
 220  
 		}
 221  
 		else	{
 222  
 			return _targetMethod.invoke( _target, args );
 223  
 		}
 224  
 	}
 225  
 }
 226  
 
 227  
 class InvokerRunner implements Runnable	{
 228  
 
 229  
 	protected Object	_target = null;
 230  
 
 231  
 	protected Method	_method = null;
 232  
 
 233  
 	protected Object[]	_args = null;
 234  
 
 235  
 
 236  
 	InvokerRunner( Object target, Method method, Object[] args )
 237  
 	{
 238  
 		super();
 239  
 		_target = target;
 240  
 		_method = method;
 241  
 		_args = args;
 242  
 	}
 243  
 
 244  
 
 245  
 	public void run()
 246  
 	{
 247  
 		try	{
 248  
 			_method.invoke( _target, _args );
 249  
 		}
 250  
 		catch( Exception e )	{
 251  
 			//ignore.
 252  
 		}
 253  
 	}
 254  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.