The philosophy of CCA is to precisely define the rules for constructing
components and to specify the required behavior a component must exhibit
and the interface between components and the Framework. However,
very little is said about the way the Framework is constructed or the way
the user interacts with the Framework to connect components together.
The reason
for this is that there will be many different Framework that can be
used in very different situations. Some Frameworks will be designed
to optimize the use of components that are distributed across a wide-area
Grid. In other cases, the Framworks will be designed to optimize
the composition of components that run on a single, massively parallel
supercomputer.
The goal is to provide a stardard way that a component can be built
so that it may be reused in any number of CCA compliant Frameworks.
What makes a CCA Framework compliant is that it implements the framework
interfaces
described below.
A CCA component is an entity that is defined by two types of public
surface features: "provides" ports and "uses" ports.
Depending on the framework, one or more provides ports may be connected
to a single uses port and a provides port may be "provided" to one or more
Uses ports. In general, if a uses-port has a member function that
returns a value, the number of providers will be restricted to be one.
Furthermore, in these cases, there must be a connected provider for the
component to
operate correctly. In frameworks that support "direct connect",
for those connections that are restricted to be one-to-one, the framework
may actually supply the provides port object reference "directly"
as the connected uses port. In these cases there is only one function
call between a user and a provider.
The official specification language of CCA is the Scientific Interface
Definition Language (Sidl). The Sidl specification of PortInfo is
given by:
package CCA{
interface PortInfo{
string getType();
string getName();
void setType(in string type);
void setName(in string name);
string toString();
};
...
};
PortInfo simply binds a text string name of a port with the the
fully qualified name of the service interface it implements.
Port interfaces are specified in SIDL and then translated to the target
component implementaton language. For example, a port of type FooInterface
from the module gov.doe.llnl.foostuff and that has a single member
function foo that takes an integer and returns a float might be
defined in SIDL as
package gov.doe.llnl.foostuff{
interface FooInterface extends Port{
float foo(in integer x);
};
A SIDL compiler will translate this specification into a java interface,
a C++ abstract class or a set of c or Fortran functions.
A default implementation of PortInfo, called DefaultPortInfo is provided
by each CCA compliant framework with a constructor of the form
public class DefaultPortInfo implements PortInfo {
public DefaultPortInfo(String portName, String portType){ ... }
public String getType(){ ... }
public String getName(){ ... }
...
}
A java programmer wishing to describe a port with name "myFooPort"
and type FooInterface would create a PortInfo object by a call of the form
PortInfo p = new DefaultPortInfo("myFooPort", "gov.doe.llnl.foostuff.FooInterface");
When a component is instantiated by the Famework, it is provided
with an instance of an object that implements the components interface
to the Framework. This is called the "Services" object and it is
used by the component to tell the framework about the ports that it provides
and uses. It is also through ports that the framework is allowed access
to the standard services provided by the framework for the components use.
The Sidl interface to the Services object is given by
package CCA{
...
interface Services {
array<PortInfo,1> getProvidesPorts();
array<PortInfo,1> getUsesPorts();
Port getPort(in string name);
void registerUsesPort(in PortInfo name_and_type);
void addProvidesPort(in ProvidesPort inPort, in PortInfo name);
void releasePort(in string name);
void addConnectionListener(in ConnectionListener l); // proposed deletion [1]
ComponentID getComponentID(); // proposed addition [2]
};
Provides Ports are provided by the component. The component
may implement the provides port itself or it may allocate an object that
implements the provides port. In either case, to tell the framework
that a specific provides port is available, the component must call addProvidesPort(
) with the reference to the port instance and a PortInfo object
naming and describing its
type.
Uses ports are named and specified by the component, but manufactured by the Framework. To tell the framwork that the component plans to use a port of a particular name and type it calls registerUsesPort().
The getProvidesPorts() and getUsesPorts() return an array of PortInfo objects that describe the current port objects the component supports.
To obtain the actual reference to the uses port (or its proxy), the
component calls getPort() with the port name. If that uses
port has not been previously registered with a call to registerUsesPort()
or addProvidesPort(), the getPort() call with throw an exception.
If the uses port requires a connected provides port and the connection
has not yet been made, the getPort() operation
will suspend until the operation is complete OR it will return with
a null reference. A good component programmer will always check the returned
value of getPort.
When a uses port has been used by the component, it should call releasePort(). This allows the framework the ability to provide a runtime substitution of one provider for another.
Each time the framework makes a connection or disconnect between a uses
port and a provides port, the framework will emit two events.
One event is delivered components at the ends of the connection (user
and provider), telling the component the name of the port that was connected
and the type of port and name of the port to it was connected/disconnected.
This information is delivered as a CCAConnectionEvent which is described
by
class ConnectionEvent extends FrameworkSpecific_Event {
void setSource(in string source);
string getSource();
};The connection event delivers the connection information as an xml record in a string available through the function getSource(). If a component is interested in seeing these events it must provide an object that implements
interface ConnectionListener{
void connectionActivity(in ConnectionEvent evt);
};
and call the services function addConnectionListener(in ConnectionListener
l);
[1] It should be noted that the connetion even specification above and the addConnectionListener may be replaced by a more general event model in the near future.
[2] To simplify the design of future service additions,
it is necessary to extract a form of proxy reference to a component that
will allow other components and services know about the port names and
types the component has. The getComponentID() function
returns an object of type:
interface ComponentID{
array<PortInfo,1> getProvidesPorts();
array<PortInfo,1> getUsesPorts();
};
Note that a ComponentID object only provides accessor methods and cannot
be used to modify the component or access framework specific implementation
details. This object, when serialized, can reside in instance
registries and it is the handle that can be used by services which are
implemented as CCA components to refer to other components.
A component is allowed to access its own ComponentID which it may then
pass to services or components that implement services.
Each CCA component must implement the Component interface.
package CCA{
interface Component {
void setServices(in Services cc);
};
The component must also have a null constructor.
The setServices() function is called by the framework after the component has been instantiated. The components behavior during the setServices invocation is very prescribed. The component saves the passed reference to the services object as a private instance variable. Prior to returning from the setServices() call, the component must instantiate and add all its initial Provides ports and register all its initial uses ports using this instance variable. Components may dynamically add new ports later, but this will cause a newPortEvent to be generated by the framework. Components cannot delete ports.
The way the framwork notifies a component to shut down is to call the
setServices() with a null value. When such an invocation of setServices
completes, it is safe for the Framework to garbage collect the component.
Below we list the complete SIDL spec described above and the bindings
of this specification to C++ and Java.
package CCA {
class FrameworkSpecific_Event {};
class ConnectionEvent extends FrameworkSpecific_Event {
void setSource(in string source);
string getSource();
};
interface ConnectionListener{
void connectionActivity(in ConnectionEvent evt);
};
interface Port {
};
interface PortInfo{
string getType();
string getName();
void setType(in string type);
void setName(in string name);
string toString();
};
interface Services {
array<PortInfo,1> getProvidesPorts();
array<PortInfo,1> getUsesPorts();
Port getPort(in string name);
void registerUsesPort(in PortInfo name_and_type);
void addProvidesPort(in ProvidesPort inPort, in PortInfo name);
void releasePort(in string name);
void addConnectionListener(in ConnectionListener l); // proposed deletion
ComponentID getComponentID(); // proposed addition
};
interface Component {
void setServices(in Services cc);
};
// ComponentID proposed addition
interface ComponentID{
array<PortInfo,1> getProvidesPorts();
array<PortInfo,1> getUsesPorts();
};
}; // end package CCA
package cca;
public interface Port{}
public interface PortInfo {
public String getType();
public String getName();
public void setName(String n);
public void setType(String t);
public String toString();
}
public interface Services {
public PortInfo[] getProvidesPorts() throws Exception;
public PortInfo[] getUsesPorts() throws CCAException;
public void addProvidesPort(Port inPort, PortInfo name) throws CCAException;
public void registerUsesPort(PortInfo name);
public Port getPort(String name) throws CCAException;
public void releasePort(String name);
public void addCCAConnectionListener(CCAConnectionListener l);
public ComponentID getComponentID();
}
public interface Component {
public void setServices(Services cc);
}
public class ConnectionVetoException extends CCAException {
public ConnectionVetoException() { ... }
public ConnectionVetoException(String s) { ... }
}
public interface ConnectionListener {
public void connectionActivity(ConnectionEvent evt);
}
public class ConnectionEvent extends EventObject {
public ConnectionEvent(String source) { ... }
void setSource(String source);
String getSource();
}
public interface ComponentID{
public PortInfo[] getProvidesPorts() throws Exception;
public PortInfo[] getUsesPorts() throws CCAException;
}
namespace cca;
#define Cfree #define Cdelete
class Port{
public:
virtual ~Port(){}
};
class PortInfo{
public:
virtual ~PortInfo(){}
virtual CONST char* getType() CONST = 0;
virtual CONST char* getName() CONST = 0;
virtual void setType(CONST char* type) = 0;
virtual void setName(CONST char* name) = 0;
virtual Cfree char* toString() = 0;
};
class DefaultPortInfo : public PortInfo {
public:
DefaultPortInfo(){}
virtual ~DefaultPortInfo() {}
DefaultPortInfo(CONST char* portname_, CONST char* porttype_);
DefaultPortInfo(CONST DefaultPortInfo &p);
CONST char* getType() CONST;
CONST char* getName() CONST;
void setType(CONST char* type);
void setName(CONST char* name);
virtual Cfree char* toString();
};
class Services{
public:
virtual ~Services(){}
virtual PortInfo** getProvidesPorts(int& length) = 0;
virtual PortInfo** getUsesPorts(int& length)= 0;
virtual Port* getPort(char *name)=0;
virtual void registerUsesPort(PortInfo *name_and_type) =0;
virtual void addProvidesPort(Port *inPort, PortInfo *name)=0;
virtual void addConnectionListener(ConnectionListener *l) = 0; //proposed deletion
virtual void releasePort(char *name) = 0;
virtual ComponentID* getComponentID(); // proposed extension
};
class Component {
public:
virtual ~Component(){}
virtual void setServices(Services *cc) = 0;
};
class ConnectionListener{
public:
virtual ~ConnectionListener(){}
virtual void connectionActivity(ConnectionEvent evt) = 0;
};
class ConnectionEvent: public FrameworkSpecificEvent{
public:
ConnectionEvent(char *source){ ... }
char* getSource() { ... }
virtual ~ConnectionEvent(){ ... }
};
class ComponentID{
public:
virtual PortInfo** getProvidesPorts(int& length) = 0;
virtual PortInfo** getUsesPorts(int& length)= 0;
};
Last modified: Fri Feb 6 13:50:51 EST 2004