blob: c6c5f3309c461fb823f5deb693405be526a1d25c [file] [log] [blame]
/**********************************************************************
* This file is part of the "Object Teams Runtime Environment"
*
* Copyright 2002-2007 Berlin Institute of Technology, Germany.
*
* 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
* $Id: Team.java 23408 2010-02-03 18:07:35Z stephan $
*
* Please visit http://www.objectteams.org for updates and contact.
*
* Contributors:
* Berlin Institute of Technology - Initial API and implementation
**********************************************************************/
package org.objectteams;
import java.awt.EventQueue;
import java.util.HashSet;
import java.util.Iterator;
import java.util.WeakHashMap;
/**
* This is the root class of all team definitions.
* Any class with the <tt>team</tt> modifier implicitly
* inherits from this class.
*
*/
public /* team */ class Team implements ITeam {
// Technical note: comments starting with //$Debug are intended
// for a standalone tool that generates an interface
// which the debugger needs in order to know about line numbers in this class.
/*
* Synchronization: This class supports two levels of synchronization:
* <ul>
* <li>Fields of <code>Team</code> are synchronized
* using <code>this</code> as the monitor.
* <li>Those calls that (un)register a team at its base classes are synchronized
* via <code>registrationLock</code>
* </ul>
* This allows releasing the lock on <code>this</code> before calling to the base class.
* Note, that the synchronized portion of each initial-wrapper is also synchronized
* (against <code>_OT$addTeam/_OT$removeTeam</code>) and that it calls back to
* the registered teams (method <code>isActive()</code>).
* Without <code>registrationLock</code> this situation could easily deadlock:
* Thread1: <pre>t.activate() -> Base._OT$addTeam()</pre>: owns t, waits for Base.
* Thread2: <pre>b.bm() (initial wrapper) -> t.isActive()</pre>: owns Base, waits for t.
*/
/**
* Internal field used by the runtime to install a lifting participant if one is configured.
*/
public static ILiftingParticipant _OT$liftingParticipant = null;
/**
* Default constructor for debugging purpose.
*/
public Team() {} //$Debug(TeamConstructor)
/*
* manual copy-inheritance of a role interface from ITeam.
*/
public interface ILowerable extends ITeam.ILowerable {}
/*
* manual copy-inheritance of a role interface from ITeam.
*/
public interface IConfined extends ITeam.IConfined {}
/**
* Special role type that<ul>
* <li> does not extend java.lang.Object
* <li> may not leak references outside the team.
* </ul>
*/
protected interface Confined {
/* internal method needed for cast and instanceof
* (this method will be generated for role classes) */
ITeam _OT$getTeam();
}
/**
* This class would have been generated by the OT-compiler.
* Don't explicitly use it in client code!
*/
protected class __OT__Confined implements Confined {
// internal method needed for cast and instanceof
public ITeam _OT$getTeam() {
return Team.this; //$Debug(ConfinedGetTeam)
}
}
/**
* Internal function for identifying a Team.
* Should not be called by client code.
*/
public int _OT$getID () {return -1;}
/**
* The constant <code>ALL_THREADS</code> is used for global team (de-)activation.
*/
public static final Thread ALL_THREADS = new Thread();
private static final int _OT$UNREGISTERED = 0;
private static final int _OT$REGISTERED = 1;
private int _OT$registrationState = _OT$UNREGISTERED;
private boolean _OT$globalActive = false;
private ThreadLocal<Integer> _OT$implicitActivationsPerThread = new ThreadLocal<Integer>() {
protected synchronized Integer initialValue() {
return Integer.valueOf(0);
}
};
private boolean _OT$lazyGlobalActiveFlag = false;
/**
* <code>_OT$activatedThreads</code> contains all threads for which this team instance is active.
* key = activated thread
* value = Boolean(true) for explicit activation | Boolean(false) for implicit activation.
*/
private WeakHashMap<Thread, Boolean> _OT$activatedThreads = new WeakHashMap<Thread, Boolean>();
/** This lock is used to protect activate/deactivate methods <strong>including</strong>
* the calls to doRegistration/doUnregistration.
*/
private Object _OT$registrationLock= new Object();
/**
* {@inheritDoc}
*/
public void activate() {
activate(Thread.currentThread());
}
/**
* {@inheritDoc}
*/
public void deactivate() {
deactivate(Thread.currentThread());
}
/**
* {@inheritDoc}
*/
public void activate(Thread thread) {
// acquire both locks to avoid incomplete execution:
synchronized (this._OT$registrationLock) {
synchronized (this) {
if (thread.equals(ALL_THREADS)) {
_OT$globalActive = true;
_OT$lazyGlobalActiveFlag = true;
TeamThreadManager.addGlobalActiveTeam(this);
} else { // activation only for 'thread':
// register 'thread' as active:
_OT$activatedThreads.put(thread, Boolean.TRUE);
}
} // release this before calling synchronized base class methods
doRegistration(); //$Debug(ActivateMethod)
}
}
/**
* {@inheritDoc}
*/
public void deactivate(Thread thread) {
// acquire both locks to avoid incomplete execution:
synchronized (this._OT$registrationLock) {
boolean shouldUnregister= false;
synchronized(this) {
if (_OT$globalActive && EventQueue.isDispatchThread()) {
System.err.println("Warning: Deactivation for the AWT-Event-Thread is not effective right now!");
}
if (thread.equals(ALL_THREADS)) {
_OT$globalActive = false;
TeamThreadManager.removeGlobalActiveTeam(this);
// unregister all threads:
_OT$activatedThreads.clear();
shouldUnregister= true;
} else { // deactivation only for 'thread':
if (_OT$lazyGlobalActiveFlag) {
// be eager now: activate for all (other) threads:
_OT$activateForAllThreads();
}
// deactivate for 'thread', no longer active:
_OT$activatedThreads.remove(thread);
if (!_OT$lazyGlobalActiveFlag && _OT$activatedThreads.isEmpty()) {
shouldUnregister= true;
}
}
_OT$lazyGlobalActiveFlag = false;
} // release this before calling synchronized base class methods
if (shouldUnregister) //$Debug(DeactivateMethod)
doUnregistration();
}
}
public void deactivateForEndedThread(Thread thread) {
synchronized (_OT$registrationLock) {
boolean shouldUnregister= false;
synchronized (this) {
_OT$activatedThreads.remove(thread);
if (!_OT$lazyGlobalActiveFlag && _OT$activatedThreads.isEmpty())
shouldUnregister= true;
}
if (shouldUnregister)
doUnregistration();
}
}
private void _OT$activateForAllThreads() {
HashSet threads = TeamThreadManager.getExistingThreads();
Iterator it = threads.iterator();
while (it.hasNext()) {
Thread a_thread = (Thread) it.next();
activate(a_thread); // use smaller activate version (no ALL_THREADS, no registerAtBases,...
}
}
/**
* This method is used for implicit activation in team-level methods.
* Implicit activation only applies to the current thread.
* Don't call it from client code.
*/
public void _OT$implicitlyActivate() {
synchronized (this._OT$registrationLock) {
boolean shouldRegister= false;
synchronized (this) {
// this method is used for debugging purpose (team monitor)
Thread currentThread = Thread.currentThread();
if (!_OT$activatedThreads.containsKey(currentThread)) {
// register 'thread' as active:
_OT$activatedThreads.put(currentThread, Boolean.FALSE);
shouldRegister= true;
}
// increment thread local implicit activaion counter:
int implActCount = (_OT$implicitActivationsPerThread.get()).intValue();
_OT$implicitActivationsPerThread.set(Integer.valueOf(implActCount + 1 ));
}
if (shouldRegister) //$Debug(ImplicitActivateMethod)
doRegistration();
}
}
/**
* This method is used for implicitly deactivation in team-level methods.
* It respects explicit activation changes and nested calls to team-level methods.
* Implicit deactivation only applies to the current thread.
* Don't call it from client code.
*/
public void _OT$implicitlyDeactivate() {
synchronized (this._OT$registrationLock) {
boolean shouldUnregister= false;
synchronized(this) {
// this method is used for debugging purpose (team monitor)
Thread currentThread = Thread.currentThread();
boolean explicitlyActivated = false;
if (_OT$activatedThreads.containsKey(currentThread)) {
explicitlyActivated = ((Boolean) _OT$activatedThreads.get(currentThread)).booleanValue();
}
if (!explicitlyActivated
&& !_OT$lazyGlobalActiveFlag // no explicit activation overriding the implicit one
&& ((_OT$implicitActivationsPerThread.get()).intValue() == 1)) // this is the last implicit activation
{
_OT$activatedThreads.remove(currentThread);
if (_OT$activatedThreads.isEmpty()) // there are not other threads for which this theam is active
{
shouldUnregister= true;
}
}
// decrement thread local implicit activaion counter:
int implActCount = (_OT$implicitActivationsPerThread.get()).intValue();
_OT$implicitActivationsPerThread.set(Integer.valueOf(implActCount - 1));
}
if (shouldUnregister) //$Debug(ImplicitDeactivateMethod)
doUnregistration();
}
}
/**
* Define whether per-thread activation of this team should be inheritable
* such that the team will be activated automatically for any new threads
* that are spawned from a thread for which the team is already active at that time.
*
* @param inheritable whether or not activation should be inheritable to new threads
*/
public void setInheritableActivation(boolean inheritable) {
if (inheritable)
TeamThreadManager.registerTeamForActivationInheritance(this);
else
TeamThreadManager.unRegisterTeamForActivationInheritance(this);
}
// not API (for use by the TeamThreadManager)
public boolean internalIsActiveSpecificallyFor(Thread t) {
return this._OT$activatedThreads.containsKey(t);
}
/**
* {@inheritDoc}
*/
public boolean isActive() {
return isActive(Thread.currentThread());
}
/**
* {@inheritDoc}
*/
public boolean isActive(Thread thread) {
if (_OT$globalActive && EventQueue.isDispatchThread())
return true;
if (thread.equals(ALL_THREADS)) {
return _OT$globalActive;
}
if (_OT$lazyGlobalActiveFlag) {
return true;
} else {
//if (!TeamThreadManager.getExistingThreads().contains(thread)) { // this thread is already finished!
if (!thread.isAlive()) { // this thread is already finished!
throw new IllegalThreadStateException("Called 'isActive(...)' for a thread which is no longer running!");
}
return _OT$activatedThreads.containsKey(thread);
}
}
// ***** for restoring the activation state after a within block: ---->*****
private static final int _OT$INACTIVE = 0;
private static final int _OT$IMPLICIT_ACTIVE = 1;
private static final int _OT$EXPLICIT_ACTIVE = 2;
/**
* {@inheritDoc}
*/
public synchronized int _OT$saveActivationState() {
int old_state = _OT$INACTIVE;
if (_OT$lazyGlobalActiveFlag) {
old_state = _OT$EXPLICIT_ACTIVE;
} else {
Thread current_thread = Thread.currentThread();
if (_OT$activatedThreads.containsKey(current_thread)) {
old_state = _OT$IMPLICIT_ACTIVE;
if (((Boolean)_OT$activatedThreads.get(current_thread)).booleanValue()) {
old_state = _OT$EXPLICIT_ACTIVE;
}
}
}
return old_state;
}
/**
* {@inheritDoc}
*/
public void _OT$restoreActivationState(int old_state) {
synchronized (_OT$registrationLock) {
if (old_state == _OT$INACTIVE) // team was inactive before:
deactivate();
else { // team was active before: has to be reactivated:
boolean explicit = (old_state == _OT$EXPLICIT_ACTIVE);
synchronized (this) {
_OT$activatedThreads.put(Thread.currentThread(), Boolean.valueOf(explicit));
}
doRegistration();
}
}
}
// ***** <----for restoring the activation state after a within block. *****
private void doRegistration() {
if (_OT$registrationState == _OT$UNREGISTERED) {
_OT$registerAtBases();
_OT$registrationState = _OT$REGISTERED;
}
}
private void doUnregistration() {
if (_OT$registrationState == _OT$REGISTERED) {
_OT$unregisterFromBases();
_OT$registrationState = _OT$UNREGISTERED;
}
}
/**
* This method will be implemented by generated code in subteams.
* It registers the team at every base playing one of its roles.
* Don't call it from client code.
*/
public void _OT$registerAtBases() {}
/**
* This method will be implemented by generated code in subteams.
* It unregisters the team from every base playing one of its roles.
* Don't call it from client code.
*/
public void _OT$unregisterFromBases() {}
//public int _OT$activationState = -1; // TODO: remove usage of this from generated code
/**
* {@inheritDoc}
*/
public boolean hasRole(Object aBase) {
// overriding method to be generated by the compiler for each team with bound roles.
return false;
}
/**
* {@inheritDoc}
*/
public boolean hasRole(Object aBase, Class<?> roleType) {
// overriding method to be generated by the compiler for each team with bound roles.
throw new IllegalArgumentException("No such bound role type in this team: "+roleType.getName());
}
/**
* {@inheritDoc}
*/
public Object getRole(Object aBase) {
// overriding method to be generated by the compiler for each team with bound roles.
return null;
}
/**
* {@inheritDoc}
*/
public <T> T getRole(Object aBase, Class<T> roleType) {
// overriding method to be generated by the compiler for each team with bound roles.
return null;
}
/**
* {@inheritDoc}
*/
public Object[] getAllRoles() {
// overriding method to be generated by the compiler for each team with bound roles.
return new Object[0];
}
/**
* {@inheritDoc}
*/
public <T> T[] getAllRoles(Class<T> roleType) {
// overriding method to be generated by the compiler for each team with bound roles.
throw new IllegalArgumentException("Class org.objectteams.Team has no bound roles.");
}
/** Internal variable to be set from generated code. */
private boolean _OT$isExecutingCallin = false;
/**
* Method only for internal use by generated code.
*/
public boolean _OT$setExecutingCallin(boolean newFlag) {
boolean oldVal = _OT$isExecutingCallin;
_OT$isExecutingCallin = newFlag;
return oldVal;
}
/**
* {@inheritDoc}
*/
public boolean isExecutingCallin() {
return _OT$isExecutingCallin;
}
/**
* {@inheritDoc}
*/
public void unregisterRole(Object aRole) {
// overriding method to be generated by the compiler for each team with bound roles.
}
/**
* {@inheritDoc}
*/
public void unregisterRole(Object aRole, Class<?> roleType) {
// overriding method to be generated by the compiler for each team with bound roles.
}
@Override
protected void finalize() throws Throwable {
// nop, hook for the debugger
@SuppressWarnings("unused")
int i= 2+3; // Note: body must not be empty for debuggger to be able to stop.
} // $Debug(FinalizeMethod)
}