ptolemy.kernel.util
Class Workspace

java.lang.Object
  extended by ptolemy.kernel.util.Workspace
All Implemented Interfaces:
java.io.Serializable, Nameable

public final class Workspace
extends java.lang.Object
implements Nameable, java.io.Serializable

An instance of Workspace is used for synchronization and version tracking of interdependent groups of objects. These objects are said to be in the workspace. This is not the same as the container association in Ptolemy II. A workspace is never returned by a getContainer() method.

The workspace provides a rudimentary directory service that can be used to keep track of the objects within it. It is not required to use it in order to use the workspace for synchronization. Items are added to the directory by calling add(). The names of the items in the directory are not required to be unique.

The synchronization model of the workspace is a multiple-reader, single-writer model. Any number of threads can simultaneously read the workspace. Only one thread at a time can have write access to the workspace, and while the write access is held, no other thread can get read access.

When reading the state of objects in the workspace, a thread must ensure that no other thread is simultaneously modifying the objects in the workspace. To read-synchronize on a workspace, use the following code:

 try {
 _workspace.getReadAccess();
 // ... code that reads
 } finally {
 _workspace.doneReading();
 }
 
We assume that the _workspace variable references the workspace, as for example in the NamedObj class. The getReadAccess() method suspends the current thread if another thread is currently modifying the workspace, and otherwise returns immediately. Note that multiple readers can simultaneously have read access. The finally clause is executed even if an exception occurs. This is essential because without the call to doneReading(), the workspace will never again allow any thread to modify it.

To make safe changes to the objects in a workspace, a thread must write-synchronize using the following code:

 try {
 _workspace.getWriteAccess();
 // ... code that writes
 } finally {
 _workspace.doneWriting();
 }
 
Again, the call to doneWriting() is essential, or the workspace will remain permanently locked to either reading or writing.

Note that it is not necessary to obtain a write lock just to add an item to the workspace directory. The methods for accessing the directory are all synchronized, so there is no risk of any thread reading an inconsistent state.

Since:
Ptolemy II 0.2
Version:
$Id: Workspace.java,v 1.108 2006/09/21 15:45:37 cxh Exp $
Author:
Edward A. Lee, Mudit Goel, Lukito Muliadi, Xiaojun Liu
See Also:
Serialized Form
Accepted Rating:
Green (liuxj)
Proposed Rating:
Green (liuxj)

Constructor Summary
Workspace()
          Create a workspace with an empty string as its name.
Workspace(java.lang.String name)
          Create a workspace with the specified name.
 
Method Summary
protected  java.lang.String _description(int detail, int indent, int bracket)
          Return a description of the workspace.
 void add(NamedObj item)
          Add an item to the directory.
 java.lang.String description()
          Return a full description of the workspace and everything in its directory.
 java.lang.String description(int detail)
          Return a description of the workspace.
 java.util.Enumeration directory()
          Deprecated. Use directoryList() instead.
 java.util.List directoryList()
          Return an unmodifiable list of the items in the directory, in the order in which they were added.
 void doneReading()
          Indicate that the calling thread is finished reading.
 void doneWriting()
          Indicate that the calling thread is finished writing.
 NamedObj getContainer()
          Get the container.
 java.lang.String getDisplayName()
          Return a name to present to the user, which is the same as what is returned by getName().
 java.lang.String getFullName()
          Get the full name.
 java.lang.String getName()
          Get the name.
 java.lang.String getName(NamedObj relativeTo)
          Get the name.
 void getReadAccess()
          Obtain permission to read objects in the workspace.
 long getVersion()
          Get the version number.
 void getWriteAccess()
          Obtain permission to write to objects in the workspace.
 boolean handleModelError(NamedObj context, IllegalActionException exception)
          Handle a model error by throwing the specified exception.
 void incrVersion()
          Increment the version number by one.
 void remove(NamedObj item)
          Remove the specified item from the directory.
 void removeAll()
          Remove all items from the directory.
 void setName(java.lang.String name)
          Set or change the name.
 java.lang.String toString()
          Return a concise description of the object.
 void wait(java.lang.Object obj)
          Release all the read accesses held by the current thread and suspend the thread by calling Object.wait() on the specified object.
 void wait(java.lang.Object obj, long timeout)
          This method is equivalent to the single argument version except that you can specify a timeout, which is in milliseconds.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Constructor Detail

Workspace

public Workspace()
Create a workspace with an empty string as its name.


Workspace

public Workspace(java.lang.String name)
Create a workspace with the specified name. This name will form the prefix of the full name of all contained objects. If the name argument is null, then an empty string "" is used as the name.

Parameters:
name - Name of the workspace.
Method Detail

add

public void add(NamedObj item)
         throws IllegalActionException
Add an item to the directory. The names of the objects in the directory are not required to be unique. Only items with no container can be added. Items with a container are still viewed as being within the workspace, but they are not explicitly listed in the directory. Instead, their top-level container is expected to be listed (although this is not enforced). Increment the version number.

Parameters:
item - Item to list in the directory.
Throws:
IllegalActionException - If the item has a container, is already in the directory, or is not in this workspace.

description

public java.lang.String description()
Return a full description of the workspace and everything in its directory. This is accomplished by calling the description method with an argument for full detail.

Specified by:
description in interface Nameable
Returns:
A description of the workspace.

description

public java.lang.String description(int detail)
Return a description of the workspace. The level of detail depends on the argument, which is an or-ing of the static final constants defined in the NamedObj class. This method returns an empty string (not null) if there is nothing to report. If the contents are requested, then the items in the directory are also described.

Parameters:
detail - The level of detail.
Returns:
A description of the workspace.

directory

public java.util.Enumeration directory()
Deprecated. Use directoryList() instead.

Enumerate the items in the directory, in the order in which they were added.

Returns:
An enumeration of NamedObj objects.

directoryList

public java.util.List directoryList()
Return an unmodifiable list of the items in the directory, in the order in which they were added.

Returns:
A list of instances of NamedObj.

doneReading

public final void doneReading()
Indicate that the calling thread is finished reading. If this thread is completely done reading (it has no other read access to the workspace), then notify all threads that are waiting to get read/write access to this workspace so that they may contend for access.

Throws:
InvalidStateException - If this method is called before a corresponding call to getReadAccess() by the same thread.

doneWriting

public final void doneWriting()
Indicate that the calling thread is finished writing. If this thread is completely done writing (it has no other write access to the workspace), then notify all threads that are waiting to get read/write access to this workspace so that they may contend for access. It also increments the version number of the workspace.

Throws:
InvalidStateException - If this method is called before a corresponding call to getWriteAccess() by the same thread.

getContainer

public NamedObj getContainer()
Get the container. Always return null since a workspace has no container.

Specified by:
getContainer in interface Nameable
Returns:
null.

getDisplayName

public java.lang.String getDisplayName()
Return a name to present to the user, which is the same as what is returned by getName().

Specified by:
getDisplayName in interface Nameable
Returns:
The name.
See Also:
getName()

getFullName

public java.lang.String getFullName()
Get the full name.

Specified by:
getFullName in interface Nameable
Returns:
The name of the workspace.

getName

public java.lang.String getName()
Get the name.

Specified by:
getName in interface Nameable
Returns:
The name of the workspace.
See Also:
setName(String)

getName

public java.lang.String getName(NamedObj relativeTo)
Get the name. Since this can have no container, the relative name is always the same as the name.

Specified by:
getName in interface Nameable
Parameters:
relativeTo - This argument is ignored.
Returns:
The name of the workspace.
See Also:
setName(String)

getReadAccess

public final void getReadAccess()
Obtain permission to read objects in the workspace. This method suspends the calling thread until read access has been obtained. Read access is granted unless either another thread has write access, or there are threads that have requested write access and not gotten it yet. If this thread already has read access, then access is granted irrespective of other write requests. If the calling thread is interrupted while waiting to get read access, an InternalErrorException is thrown, and the thread does not have read permission to the workspace. It is essential that a call to this method is matched by a call to doneReading(), regardless of whether this method returns normally or an exception is thrown. This is to ensure that the workspace is in a consistent state, otherwise write access may never again be granted in this workspace.

Throws:
InternalErrorException - If the calling thread is interrupted while waiting to get read access.
See Also:
doneReading()

getVersion

public final long getVersion()
Get the version number. The version number is incremented on each call to doneWriting() and also on calls to incrVersion(). It is meant to track changes to the objects in the workspace.

Returns:
A non-negative long integer.

getWriteAccess

public final void getWriteAccess()
Obtain permission to write to objects in the workspace. Write access is granted if there are no other threads that currently have read or write access. In particular, it is granted if this thread already has write access, or if it is the only thread with read access. This method suspends the calling thread until such access has been obtained. If the calling thread is interrupted while waiting to get write access, an InternalErrorException is thrown, and the thread does not have write permission to the workspace. It is essential that a call to this method is matched by a call to doneWriting(), regardless of whether this method returns normally or an exception is thrown. This is to ensure that the workspace is in a consistent state, otherwise read or write access may never again be granted in this workspace.

Throws:
InternalErrorException - If the calling thread is interrupted while waiting to get write access.
See Also:
doneWriting()

handleModelError

public boolean handleModelError(NamedObj context,
                                IllegalActionException exception)
                         throws IllegalActionException
Handle a model error by throwing the specified exception.

Parameters:
context - The object in which the error occurred.
exception - An exception that represents the error.
Returns:
Never returns.
Throws:
IllegalActionException - The exception passed as an argument is always thrown.
Since:
Ptolemy II 2.1

incrVersion

public final void incrVersion()
Increment the version number by one.


remove

public void remove(NamedObj item)
Remove the specified item from the directory. Note that that item will still refer to this workspace as its workspace (its workspace is immutable). If the object is not in the directory, do nothing. Increment the version number.

Parameters:
item - The NamedObj to be removed.

removeAll

public void removeAll()
Remove all items from the directory. Note that those items will still refer to this workspace as their workspace (their workspace is immutable). Increment the version number.


setName

public void setName(java.lang.String name)
Set or change the name. If a null argument is given the name is set to an empty string. Increment the version number.

Specified by:
setName in interface Nameable
Parameters:
name - The new name.
See Also:
getName()

toString

public java.lang.String toString()
Return a concise description of the object.

Overrides:
toString in class java.lang.Object
Returns:
The class name and name.

wait

public void wait(java.lang.Object obj)
          throws java.lang.InterruptedException
Release all the read accesses held by the current thread and suspend the thread by calling Object.wait() on the specified object. When the call returns, re-acquire all the read accesses held earlier by the thread and return. If the calling thread is interrupted while waiting to re-acquire read accesses, an InternalErrorException is thrown, and the thread no longer has read access to the workspace. This method helps prevent deadlocks caused when a thread that waits for another thread to do something prevents it from doing that something by holding read access on the workspace.

Parameters:
obj - The object that the thread wants to wait on.
Throws:
java.lang.InterruptedException - If the calling thread is interrupted while waiting on the specified object and all the read accesses held earlier by the thread are re-acquired.
InternalErrorException - If re-acquiring the read accesses held earlier by the thread fails.

wait

public void wait(java.lang.Object obj,
                 long timeout)
          throws java.lang.InterruptedException
This method is equivalent to the single argument version except that you can specify a timeout, which is in milliseconds. If value of the timeout argument is zero, then the method is exactly equivalent to the single argument version, and no timeout is implemented. If the value is larger than zero, then the method returns if either the thread is notified by another thread or the timeout expires.

Parameters:
obj - The object that the thread wants to wait on.
timeout - The maximum amount of time to wait, in milliseconds, or zero to not specify a timeout.
Throws:
java.lang.InterruptedException - If the calling thread is interrupted while waiting on the specified object and all the read accesses held earlier by the thread are re-acquired.
InternalErrorException - If re-acquiring the read accesses held earlier by the thread fails.
See Also:
wait(Object)

_description

protected java.lang.String _description(int detail,
                                        int indent,
                                        int bracket)
Return a description of the workspace. The level of detail depends on the argument, which is an or-ing of the static final constants defined in the NamedObj class. If the contents are requested, then the items in the directory are also described. Zero, one or two brackets can be specified to surround the returned description. If one is specified it is the the leading bracket. This is used by derived classes that will append to the description. Those derived classes are responsible for the closing bracket. An argument other than 0, 1, or 2 is taken to be equivalent to 0.

Parameters:
detail - The level of detail.
indent - The amount of indenting.
bracket - The number of surrounding brackets (0, 1, or 2).
Returns:
A description of the workspace.