/* *******************************************************************
* Copyright (c) 1999-2001 Xerox Corporation,
* 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Xerox/PARC initial implementation
* ******************************************************************/
package org.aspectj.runtime.internal;
import java.util.Stack;
import org.aspectj.lang.NoAspectBoundException;
import org.aspectj.runtime.CFlow;
import org.aspectj.runtime.internal.cflowstack.ThreadStack;
import org.aspectj.runtime.internal.cflowstack.ThreadStackFactory;
import org.aspectj.runtime.internal.cflowstack.ThreadStackFactoryImpl;
import org.aspectj.runtime.internal.cflowstack.ThreadStackFactoryImpl11;
/*
* How we benefit from ThreadLocal when it is available at runtime:
*
* When the CFlowStack class is loaded, we run its static initializer. This checks the JVM
* version number and loads an appropriate implementation of the ThreadStackFactory.
* There are two possible implementations depending on whether this is a 1.1 or 1.2+ JVM.
* Rather than doing a Class.forName for ThreadLocal and catching a ClassNotFoundEx in order
* to determine the JVM version, we look at the java class version which I believe can help
* us identify the Java level.
*
* In the 1.1 JVM case we use a factory implementation that does not use ThreadLocal storage.
* In the 1.2+ JVM case we use a factory implementation that does use ThreadLocal storage.
*
* Once we have the factory set, whenever someone builds a CFlowStack object, we ask the
* factory for a new stack proxy - this is an object that can return us the right stack
* that we should use on a particular thread. The reason we create the proxy in the ctor and
* not lazily in the getThreadStack() method is because it means the getThreadStack() method in
* this class does not have to be synchronized.
*
* When any of the methods in CFlowStack need to operate on the stack (peek/pop/etc), they
* all delegate to getThreadStack() which asks the proxy for the right stack. Depending on the
* factory loaded to build the proxy, the call to proxy.getThreadStack() will return a threadlocal
* based stack or it will call the original implementation of getThreadStack() which manages
* a Hashtable of threads->stacks.
*
*/
public class CFlowStack {
private static ThreadStackFactory tsFactory;
private ThreadStack stackProxy;
static {
selectFactoryForVMVersion();
}
public CFlowStack() {
stackProxy = tsFactory.getNewThreadStack();
}
private Stack getThreadStack() {
return stackProxy.getThreadStack();
}
//XXX dangerous, try to remove
public void push(Object obj) {
getThreadStack().push(obj);
}
public void pushInstance(Object obj) {
getThreadStack().push(new CFlow(obj));
}
public void push(Object[] obj) {
getThreadStack().push(new CFlowPlusState(obj));
}
public void pop() {
Stack s = getThreadStack();
s.pop();
if (s.isEmpty()) {
stackProxy.removeThreadStack();
}
}
public Object peek() {
Stack stack = getThreadStack();
if (stack.isEmpty()) throw new org.aspectj.lang.NoAspectBoundException();
return (Object)stack.peek();
}
public Object get(int index) {
CFlow cf = peekCFlow();
return (null == cf ? null : cf.get(index));
}
public Object peekInstance() {
CFlow cf = peekCFlow();
if (cf != null ) return cf.getAspect();
else throw new NoAspectBoundException();
}
public CFlow peekCFlow() {
Stack stack = getThreadStack();
if (stack.isEmpty()) return null;
return (CFlow)stack.peek();
}
public CFlow peekTopCFlow() {
Stack stack = getThreadStack();
if (stack.isEmpty()) return null;
return (CFlow)stack.elementAt(0);
}
public boolean isValid() {
return !getThreadStack().isEmpty();
}
private static ThreadStackFactory getThreadLocalStackFactory() { return new ThreadStackFactoryImpl(); }
private static ThreadStackFactory getThreadLocalStackFactoryFor11() { return new ThreadStackFactoryImpl11(); }
private static void selectFactoryForVMVersion() {
String override = getSystemPropertyWithoutSecurityException("aspectj.runtime.cflowstack.usethreadlocal","unspecified");
boolean useThreadLocalImplementation = false;
if (override.equals("unspecified")) {
String v = System.getProperty("java.class.version","0.0");
// Java 1.2 is version 46.0 and above
useThreadLocalImplementation = (v.compareTo("46.0") >= 0);
} else {
useThreadLocalImplementation = override.equals("yes") || override.equals("true");
}
// System.err.println("Trying to use thread local implementation? "+useThreadLocalImplementation);
if (useThreadLocalImplementation) {
tsFactory = getThreadLocalStackFactory();
} else {
tsFactory = getThreadLocalStackFactoryFor11();
}
}
private static String getSystemPropertyWithoutSecurityException (String aPropertyName, String aDefaultValue) {
try {
return System.getProperty(aPropertyName, aDefaultValue);
}
catch (SecurityException ex) {
return aDefaultValue;
}
}
// For debug ...
public static String getThreadStackFactoryClassName() {
return tsFactory.getClass().getName();
}
}