//
// This file is part of the prose package.
//
// The contents of this file are subject to the Mozilla Public License
// Version 1.1 (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.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// The Original Code is prose.
//
// The Initial Developers of the Original Code are Andrei Popovici and
// Angela Nicoara. Portions created by Andrei Popovici and Angela Nicoara
// are Copyright (C) 2002 Andrei Popovici and Angela Nicoara.
// All Rights Reserved.
//
// Contributor(s):
// $Id: ProseSystem.java,v 1.4 2008/11/18 11:44:47 anicoara Exp $
// =====================================================================
//
package ch.ethz.prose;
// used packages
import java.lang.reflect.Constructor;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.StringTokenizer;
import ch.ethz.jvmai.JVMAspectInterface;
import ch.ethz.inf.util.Logger;
/**
* Class ProseSystem represents the user view of the system.
* It allows to start and stop prose, and to get access
* to an code <code>AspectManager</code>Users
* program aspects and they will insert them into the system
* using the <code>insertExtension</code> and <code>withdrawExtension</code>
* methods of the extension manager.
* <p>
* This class is also used for bootstrapping the system. Before using
* the extension system, users of this class (eventually applications)
* will have to call
* <blockquote><pre>
* ProseSystem.startup();
* Another way to start this system happens over the <code>RootComponent<code/>
* module.
* </pre></blockquote>
* this will setup the system, according to special system properties too,
* like
* <ul>
* <li> <code>ch.ethz.prose.EXManager</code>
* </ul>
* <P>
* Known Properties:
* <UL>
* <LI><CODE>ch.ethz.prose.JVMAIProvider</CODE> <b>Values:class names</b> <br>
* <b>Usage:</b> controlls the creation of the JVMAI</LI>
* <LI><CODE>ch.ethz.prose.EXManager</CODE> <B>Values:class name</B> <BR>
* <B>Usage:</B> controlls the creation of the extension manager (<CODE>AspectManager</CODE>)</LI>
* <LI><CODE>ch.ethz.prose.HotSwapClassWeaver</CODE> <B>Values: class Name</B> <BR>
* <B>Usage:</B> controlls which class weaver implementation should be used
* (only for HotSwap <CODE>JVMAIProvider</CODE> and <CODE>EXManager</CODE>)</LI>
* <LI><CODE>ch.ethz.prose.JVMAIPackagePrefixes</CODE> <b>Values: package prefixes</b> <br>
* <b>Usage:</b> controlls the package prefixes eliminated or used by jvmai</LI>
* <LI><CODE>ch.ethz.prose.JVMAIOpenWorldAssumption</CODE> <b>Values:true or false</b> <br>
* <b>Usage:</b> controlls whether prose uses an open world (excludes package prefixes) or
* a closed world (includes package prefixes)</LI>
* <LI><CODE>prose.port</CODE> <B>Values: port number (integer with value from 1 to 65535)</B> <BR>
* <B>Usage:</B> enables prose clients to connect to specified port</LI>
* </UL>
*
*
* @version $Revision: 1.4 $
* @author Andrei Popovici
* @author Angela Nicoara
*/
public class ProseSystem implements Component {
static private AspectManager currentExtM = null;
static private AspectManager testExtM = null;
static private JVMAspectInterface aspectInterface = null;
static boolean systemUp = false;
static ProsePermission permission = new ProsePermission("startupExtensionSystem");
// caching Variables as input to function <JoinPointManager>.connectToJVMAI
static ch.ethz.jvmai.Provider provider = null;
static String[] packagePrefixes = null;
static boolean openWorldAssumption;
/** Start up application-specific functionality.
* This method should be called before using the extension system.
* <p><em>Note:this method is idempotent. Successive, successful calls to
* <code>startup</code> have the same effect as a single call.
* Use <code>teardown</code> in between to actually re-do the startup. NOT YET IMPLEMENTED.</em><p>
*
* Note: in case that the ProsePermission "startupExtensionSystem" is granted to the
* caller, this method is executed as privileged only restricted
* by the permissions not granted to RUNES classes
*
* @exception SystemStartupException one of the specified properties did
* not comply to the startup/teardown naming convention or one of the
* startup methods of additional systems failed.
*
*/
public synchronized static void startup() throws SystemStartupException {
if (systemUp)
return;
// ATENTION!
// Because the JVM 1.4.1 blocks, we run "RemoteProseComponent" before "ProseSystem".
if (!System.getProperty("prose.port","UNKNOWN").equals("UNKNOWN"))
ch.ethz.prose.tools.RemoteProseComponent.startup();
try { Thread.sleep(500); } catch (InterruptedException e) {}
try {
// security check
//AccessController.checkPermission(permission); // FIXME : uncomment this line.
// if no exception occurred, we can perform the startup under priv. rights
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws SystemStartupException {
doStartup();
return null;
}
});
} catch (AccessControlException e) {
// we start the system in the standard way
doStartup();
} catch (PrivilegedActionException e) {
e.printStackTrace();
throw new SystemStartupException(e.toString());
}
/* ATENTION!
* Because the JVM 1.4.1 blocks, we run "RemoteProseComponent" before "ProseSystem".
if (!System.getProperty("prose.port","UNKNOWN").equals("UNKNOWN"))
ch.ethz.prose.tools.RemoteProseComponent.startup();
*/
systemUp=true;
}
/**
* The real startup method
*/
private synchronized static void doStartup() throws SystemStartupException {
try {
// get the jvmai-provider
String providerClassName = System.getProperty("ch.ethz.prose.JVMAIProvider");
if(providerClassName==null)
providerClassName = "ch.ethz.inf.iks.jvmai.jvmdi.DebuggerProvider";
Class providerClass = Class.forName(providerClassName);
provider = (ch.ethz.jvmai.Provider)providerClass.newInstance();
packagePrefixes = new String[0];
openWorldAssumption = true;
String packageList = System.getProperty("ch.ethz.prose.JVMAIPackagePrefixes");
String openWorldParam = System.getProperty("ch.ethz.prose.JVMAIOpenWorldAssumption");
if(packageList==null && openWorldParam==null) {
packagePrefixes = new String[] {"ch.ethz.prose."};
openWorldAssumption = true;
}
else {
if(packageList==null) {
packagePrefixes = new String[0];
}
else {
StringTokenizer tokenizer = new StringTokenizer(packageList,",");
packagePrefixes = new String[tokenizer.countTokens()];
for(int p=0; p<packagePrefixes.length; p++) {
packagePrefixes[p] = tokenizer.nextToken();
}
}
if(openWorldParam==null) {
openWorldAssumption = true;
}
else {
openWorldAssumption = openWorldParam.toUpperCase().equals("TRUE");
}
}
// initialize the aspect interface and the info interface
aspectInterface = provider.getAspectInterface();
// start the aspect interface!
aspectInterface.startup(packagePrefixes,openWorldAssumption);
aspectInterface.suspendNotification(Thread.currentThread());
// set the default extension manager
String extMName = System.getProperty("ch.ethz.prose.EXManager");
if (extMName != null) {
Class[] paramTypes = new Class[] {boolean.class, JVMAspectInterface.class};
Object[] params = new Object[] {Boolean.TRUE, aspectInterface};
Class extMClass = Class.forName(extMName);
Constructor extMConstructor = extMClass.getConstructor(paramTypes);
currentExtM = (AspectManager)extMConstructor.newInstance(params);
params[0] = Boolean.FALSE;
testExtM = (AspectManager)extMConstructor.newInstance(params);
}
else {
currentExtM = new LocalAspectManager(true, aspectInterface);
testExtM = new LocalAspectManager(false, aspectInterface);
}
currentExtM.startup();
testExtM.startup();
systemUp = true;
}
catch(Throwable e) {
e.printStackTrace();
if (currentExtM != null) {
currentExtM.teardown();
currentExtM = null;
}
if (testExtM != null) {
currentExtM.teardown();
testExtM = null;
}
if (aspectInterface != null)
aspectInterface.teardown();
aspectInterface = null;
if (e instanceof SystemStartupException)
throw (SystemStartupException)e;
throw new SystemStartupException(e.toString());
}
finally {
// start doing aspects
if (aspectInterface != null)
aspectInterface.resumeNotification(Thread.currentThread());
}
Logger.message("ProseComponent.startup: succeeded! ");
}
/**
* Tear down prose functionality. Withdraw all existing aspects and remove the
* current AspectManager and JoinPointManager.
*
* <p><em>Note:this method is idempotent. Successive, successful calls to
* <code>teardown</code> have the same effect as a single call.
* </em>.
*
* @exception SystemTeardownException if the teardown fails
*/
public static void teardown() throws SystemTeardownException {
if (!systemUp)
return;
if (getAspectManager() != null) {
currentExtM.teardown();
currentExtM = null;
}
if (getTestAspectManager() != null) {
testExtM.teardown();
testExtM = null;
}
if (aspectInterface != null)
aspectInterface.teardown();
aspectInterface = null;
systemUp = false;
}
/**
* Returns <code>true</code> if the local AspectManager
* is set up and running.
*/
public static boolean isActive() {
return systemUp;
}
/**
* Return the aspect manager currently in use.
*/
public static AspectManager getAspectManager() {
try { startup(); } catch (Exception e) {}
return currentExtM;
}
/**
* Return the currently used extension manager for testing aspects. This
* extension manager is not attached to the JVMAI System.
*/
public static AspectManager getTestAspectManager() {
try { startup(); } catch (Exception e) {}
return testExtM;
}
}