[Arakhnę-Dev] [329] * Fixing the Caller API to support Sun JVM and the other JVMs (dalvik ...).

[ Thread Index | Date Index | More arakhne.org/dev Archives ]


Revision: 329
Author:   galland
Date:     2012-02-07 11:48:05 +0100 (Tue, 07 Feb 2012)
Log Message:
-----------
* Fixing the Caller API to support Sun JVM and the other JVMs (dalvik...). The Sun JVM provides the native Reflection utility class that is not provided by the other JVM.

Modified Paths:
--------------
    trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/Caller.java
    trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/Caller.java
    trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/StackTraceCaller.java
    trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/SunCaller.java

Modified: trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/Caller.java
===================================================================
--- trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/Caller.java	2012-02-06 23:22:36 UTC (rev 328)
+++ trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/Caller.java	2012-02-07 10:48:05 UTC (rev 329)
@@ -41,14 +41,19 @@
 	
 	private static org.arakhne.vmutil.caller.Caller caller = null;
 
-	private static org.arakhne.vmutil.caller.Caller getCaller() {
+	/** Replies the stack trace mamager used by this utility
+	 * class.
+	 * 
+	 * @return the stack trace mamager.
+	 */
+	public static org.arakhne.vmutil.caller.Caller getCaller() {
 		synchronized(Caller.class) {
 			if (caller==null) {
-				if (OperatingSystem.getCurrentOS()==OperatingSystem.ANDROID) {
-					caller = new StackTraceCaller();
+				if (StackTraceCaller.loadClass("sun.reflect.Reflection")!=null) { //$NON-NLS-1$
+					caller = new SunCaller();
 				}
 				else {
-					caller = new SunCaller();
+					caller = new StackTraceCaller();
 				}
 			}
 			return caller;
@@ -56,7 +61,7 @@
 	}
 	
 	/** Replies the method of the caller that invoked the function
-	 * from which <code>GetCallerClass()</code> was invoked.
+	 * from which <code>getCallerMethod()</code> was invoked.
 	 * <p>
 	 * The returned value is the name of the method instead of a
 	 * {@link Method} instance. It is due to JRE that does not
@@ -89,20 +94,20 @@
 	 * </pre>
 	 * 
 	 * @return the method of the caller that invoked the function
-	 * from which <code>GetCallerClass()</code> was invoked.
+	 * from which <code>getCallerMethod()</code> was invoked.
 	 */
 	public static String getCallerMethod() {
-    	return getCaller().getCallerMethod(1);
+    	return getCaller().getCallerMethod(2);
 	}
 
 	/** Replies the class of the caller that invoked the function
-	 * from which <code>GetCallerClass()</code> was invoked.
+	 * from which <code>getCallerClass()</code> was invoked.
 	 * 
 	 * @return the class of the caller that invoked the function
-	 * from which <code>GetCallerClass()</code> was invoked.
+	 * from which <code>getCallerClass()</code> was invoked.
 	 */
 	public static Class<?> getCallerClass() {
-    	return getCaller().getCallerClass(1);
+    	return getCaller().getCallerClass(2);
 	}
 	
 	/** Replies the class from the stack according to its level.

Modified: trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/Caller.java
===================================================================
--- trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/Caller.java	2012-02-06 23:22:36 UTC (rev 328)
+++ trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/Caller.java	2012-02-07 10:48:05 UTC (rev 329)
@@ -21,8 +21,6 @@
 
 package org.arakhne.vmutil.caller;
 
-import java.lang.reflect.Method;
-
 /**
  * This utility class provides a way to determine which class
  * call a function.
@@ -66,7 +64,7 @@
 	 * </ul>
 	 * <p>
 	 * The returned value is the name of the method instead of a
-	 * {@link Method} instance. It is due to JRE that does not
+	 * <code>Method</code> instance. It is due to JRE that does not
 	 * store in the stack trace the complete prototype of the
 	 * methods. So the following code failed: the stack contains
 	 * the method name "test2", but no function has the prototype
@@ -100,4 +98,45 @@
 	 */
 	public String getCallerMethod(int level);
 
+	/** Replies the line number of the caller from the stack according to its level.
+	 * <p>
+	 * The given <var>level</var> permits to specify which method to reply:
+	 * <ul>
+	 * <li><code>0</code>: the method where is defined the function (<code>f<sub>0</sub></code>) 
+	 * that has called <code>getCallerClass()</code></li>
+	 * <li><code>1</code>: the method where is defined the function (<code>f<sub>1</sub></code>) 
+	 * that has called <code>f<sub>0</sub></code></li>
+	 * <li><code>2</code>: the method where is defined the function (<code>f<sub>2</sub></code>) 
+	 * that has called <code>f<sub>1</sub></code></li>
+	 * <li>etc.</li>
+	 * </ul>
+	 * <p>
+	 * The returned value is the line number of the calling method.
+	 * 
+	 * @param level is the desired level of the class
+	 * @return the line number of method from the call stack
+	 * according to the given level.
+	 */
+	public long getCallerLine(int level);
+
+	/** Replies the filename of the method of the caller from the stack according to its level.
+	 * <p>
+	 * The given <var>level</var> permits to specify which method to reply:
+	 * <ul>
+	 * <li><code>0</code>: the method where is defined the function (<code>f<sub>0</sub></code>) 
+	 * that has called <code>getCallerClass()</code></li>
+	 * <li><code>1</code>: the method where is defined the function (<code>f<sub>1</sub></code>) 
+	 * that has called <code>f<sub>0</sub></code></li>
+	 * <li><code>2</code>: the method where is defined the function (<code>f<sub>2</sub></code>) 
+	 * that has called <code>f<sub>1</sub></code></li>
+	 * <li>etc.</li>
+	 * </ul>
+	 * <p>
+	 * 
+	 * @param level is the desired level of the class
+	 * @return the filename of the method from the call
+	 * stack according to the given level.
+	 */
+	public String getCallerFilename(int level);
+
 }

Modified: trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/StackTraceCaller.java
===================================================================
--- trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/StackTraceCaller.java	2012-02-06 23:22:36 UTC (rev 328)
+++ trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/StackTraceCaller.java	2012-02-07 10:48:05 UTC (rev 329)
@@ -42,66 +42,109 @@
 		//
 	}
 	
-	/** {@inheritDoc}
+	/** Load a class but avoid any exception.
+	 * 
+	 * @param name the class name.
+	 * @return the class or <code>null</code>.
 	 */
-	@Override
-	public Class<?> getCallerClass(int level) {
-    	// Parameter value of Reflection.getClassClass:
-		//
-    	// 0: Reflection.class | Reflection.getCallerClass()
-    	// 1: Caller.class     | this 
-		// 2: ???              | Caller of this function - not interesting because known
-		// 3: ???              | Caller of the caller of this function - START INTEREST HERE
-
+	public static Class<?> loadClass(String name) {
 		try {
-			int reflectionIndex = level + 3;
-
-			StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
-			StackTraceElement element = stackTrace[reflectionIndex];
-			if (element==null)
-				throw new IllegalArgumentException();
-			String classname = element.getClassName();
-			if (classname==null || classname.isEmpty())
-				throw new IllegalArgumentException();
-			return ClassLoaderFinder.findClassLoader().loadClass(classname);
+			return ClassLoaderFinder.findClassLoader().loadClass(name);
 		}
 		catch(AssertionError e) {
 			throw e;
 		}
-		catch(IllegalArgumentException e) {
-			throw e;
+		catch(Throwable e) {
+			return null;
 		}
-		catch(Throwable _) {
-			throw new IllegalArgumentException();
-		}
 	}
 
-	/** {@inheritDoc}
+	/** Replies the stack trace element for the given level.
+	 * <p>
+	 * The given <var>level</var> permits to specify which class to reply:
+	 * <ul>
+	 * <li><code>0</code>: the class where is defined the function (<code>f<sub>0</sub></code>) 
+	 * that has called one function of <code>Caller</code></li>
+	 * <li><code>1</code>: the class where is defined the function (<code>f<sub>1</sub></code>) 
+	 * that has called <code>f<sub>0</sub></code></li>
+	 * <li><code>2</code>: the class where is defined the function (<code>f<sub>2</sub></code>) 
+	 * that has called <code>f<sub>1</sub></code></li>
+	 * <li>etc.</li>
+	 * </ul>
+	 * 
+	 * @param level is the desired level.
+	 * @return the stack trace element; or <code>null</code>.
 	 */
-	@Override
-	public String getCallerMethod(int level) {
-    	// Parameter value of Reflection.getClassClass:
-		//
-    	// 0: Reflection.class | Reflection.getCallerClass()
-    	// 1: Caller.class     | this 
-		// 2: ???              | Caller of this function - not interesting because known
-		// 3: ???              | Caller of the caller of this function - START INTEREST HERE
-		if (level<0) throw new IllegalArgumentException();
-
+	protected StackTraceElement getTraceElementAt(int level) {
+		if (level<0) return null;
 		try {
-			int reflectionIndex = level + 3;
-
 			StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
-			StackTraceElement element = stackTrace[reflectionIndex];
-			if (element==null) throw new IllegalArgumentException();
-			return element.getMethodName();
+			int j = -1;
+			boolean found = false;
+			Class<?> type;
+			for(int i=0; i<stackTrace.length; ++i) {
+				if (found) {
+					if (i-j==level) return stackTrace[i];
+				}
+				else {
+					type = loadClass(stackTrace[i].getClassName());
+					if (type!=null && Caller.class.isAssignableFrom(type)) {
+						j = i+1;
+					}
+					else if (j>=0) {
+						// First ocurrence of a class in the stack, after the
+						// inner invocation of StackTraceCaller
+						found = true;
+						if (i-j==level) return stackTrace[i];
+					}
+				}
+			}
 		}
 		catch(AssertionError e) {
 			throw e;
 		}
 		catch(Throwable _) {
-			throw new IllegalArgumentException();
+			//
 		}
+		return null;
 	}
 
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Class<?> getCallerClass(int level) {
+		StackTraceElement element = getTraceElementAt(level);
+		if (element==null) throw new IllegalArgumentException();
+		Class<?> type = loadClass(element.getClassName());
+		if (type==null) throw new IllegalArgumentException();
+		return type;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public String getCallerMethod(int level) {
+		StackTraceElement element = getTraceElementAt(level);
+		if (element==null) throw new IllegalArgumentException();
+		return element.getMethodName();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public long getCallerLine(int level) {
+		StackTraceElement element = getTraceElementAt(level);
+		if (element==null) throw new IllegalArgumentException();
+		return element.getLineNumber();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public String getCallerFilename(int level) {
+		StackTraceElement element = getTraceElementAt(level);
+		if (element==null) throw new IllegalArgumentException();
+		return element.getFileName();
+	}
+
 }

Modified: trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/SunCaller.java
===================================================================
--- trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/SunCaller.java	2012-02-06 23:22:36 UTC (rev 328)
+++ trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/caller/SunCaller.java	2012-02-07 10:48:05 UTC (rev 329)
@@ -35,8 +35,8 @@
  * @mavenartifactid $ArtifactId$
  */
 @SuppressWarnings("restriction")
-public class SunCaller implements Caller {
-
+public class SunCaller extends StackTraceCaller {
+	
 	/**
 	 */
 	public SunCaller() {
@@ -54,39 +54,7 @@
 		// 2: ???              | Caller of this function - not interesting because known
 		// 3: ???              | Caller of the caller of this function - START INTEREST HERE
 		if (level<0) throw new IllegalArgumentException();
-		return Reflection.getCallerClass(level+3);
+		return Reflection.getCallerClass(level+2);
 	}
 
-	/** {@inheritDoc}
-	 */
-	@Override
-	public String getCallerMethod(int level) {
-    	// Parameter value of Reflection.getClassClass:
-		//
-    	// 0: Reflection.class | Reflection.getCallerClass()
-    	// 1: Caller.class     | this 
-		// 2: ???              | Caller of this function - not interesting because known
-		// 3: ???              | Caller of the caller of this function - START INTEREST HERE
-		if (level<0) throw new IllegalArgumentException();
-
-		try {
-			int reflectionIndex = level + 3;
-
-			StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
-			StackTraceElement element = stackTrace[reflectionIndex];
-			if (element==null) throw new IllegalArgumentException();
-			assert(Reflection.getCallerClass(reflectionIndex).getName().equals(element.getClassName()));
-			return element.getMethodName();
-		}
-		catch(AssertionError e) {
-			throw e;
-		}
-		catch(IllegalArgumentException e) {
-			throw e;
-		}
-		catch(Throwable _) {
-			throw new IllegalArgumentException();
-		}
-	}
-
 }


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/