Quick start

In this section, we will instanciate an SCA composite: helloworld inside the FraSCAti FScript interactive console to discover navigation elements (nodes, axis) with a concrete example.

Launching the interactive console

In order to issue FPath queries and see their results, we will use the interactive console application provided in the FraSCAti FScript module. The console is actually just a normal client application which uses the Java APIs provided by FScript, the same way your applications can. (If your goal is to use FPath and/or FScript from your Java programs, first read FScript tutorials).

To start the console application, go to the FraSCAti FScript module directory, and issue the following command:

% mvn -P console
FScript console.

Useful commands:
- type ':help' for a list of available commands
- type ':help <cmd>' for detailed help on a specific command
- type ':quit' to exit FScript>

You should be greeted by the FraSCAti FScript console's prompt. As you can see from the welcome message, the console understands a few commands like :help and :quit. These are not part of the FPath language, but special commands to control the console application itself. We'll explain a few of these in this tutorial, but you can enter :help at the prompt to get a complete list.

Creating the example application

In this tutorial, we will use the helloworld rmi application. The helloworld-rmi-standolone composite is composed of 2 composites : the client and the server. The server provides a service allowing to display "Hello World" with a prefix defined by an SCA property.

Before we can create an instance of HelloWorld to play with, we need to add the JAR to the console's classpath. You can add a new entry to the console's classpath using the :classpath_add console command:

FScript> :classpath_add file:///full/path/to/helloworld-rmi-server.jar
Classpath updated.
FScript> :classpath_add file:///full/path/to/helloworld-rmi-client.jar
Classpath updated.
FScript> :classpath_add file:///full/path/to/frascati-debug.jar
Classpath updated.

Note

You can find helloworld-rmi*.jar in the examples/helloworld-rmi folder and the frascati-debug.jar file in the lib (or intents/debug) folder.

The argument passed to the command can be any URL which Java understands. For local files, use a file:// URL. Now that all the required code and composite definitions are available, we can create an instance of the HelloWorld composite:

FScript> c = sca-new('path/to/helloworld-rmi-standalone');
=> #<scacomponent: helloworld-rmi-standalone>
Success (took 524 ms).

This command invokes the sca-new() primitive operation with the name of the SCA composite definition to instantiate, and stores the result in a variable named c.

Note that this line is actually not an FPath expression, but an FScript statement. The difference is that FPath expressions can not have any side-effect: they can't modify the target architecture (only introspect them), and they can't even bind new variables. Once it has executed the statement above, creating a new instance of HelloWorld, the console tells us how much time it took, and prints the value of the statement. In this case, the value is #<scacomponent: helloworld-rmi-standalone>, which denotes a single SCA component node named helloworld-rmi-standalone. FPath uses a generic notion of node to represent all the elements in a software architecture. Different architectural models may define different kinds of nodes, depending on the concepts they use. For example in the case of SCA, there are following kinds of nodes: scacomponent nodes (representing the SCA components/composites themselves), scaservice and scareference nodes (their interfaces), scaproperty nodes (representing the configuration properties defined by the component), scaintent nodes (policies defined on services/references), scabinding nodes (components representing either the stub or the skeleton used to import/export interfaces).

Nodes

SCA Component node

We now have everything set up correctly to actually issue FPath queries to introspect HelloWorld. The first thing we can try is to look a the variable we have just defined above. To get the value of a variable, simply prefix its name with a dollar sign ($):

FScript> $c
=> #<scacomponent: helloworld-rmi-standalone>

This is a node which represents the top-level component of the HelloWorld application, the helloworld-rmi-standalone composite. Each kind of node in FPath defined a set of named properties, which have primitive values: strings, numbers, booleans, etc. In the case of SCA, the component nodes have two properties: a name, and a state. We can get the values of these properties by using the function of the same name:

FScript> name($c)
=> "helloworld-rmi-standalone"
FScript> state($c)
=> "STOPPED"

SCA service node

In addition of the interface node defined in the fractal model, an scaservice node is defined to follow the SCA semantic.

FScript> $c/scaservice::*
=> a node-set with 2 element(s):
#<scaservice: helloworld-rmi-standalone.r>   #<scaservice: helloworld-rmi-standalone.rbis>

Here we see that the result is still a set of nodes, but this time the nodes represents the component's services. As before, we can select a specific service, for example the rbis service, by its name. We'll store it in a new variable so we can reference it later:

FScript> rbis = $c/scaservice::rbis;
=> a node-set with 1 element(s):
#<scaservice: helloworld-rmi-standalone.rbis>
Success (took 1 ms).

FScript> s = $c/scachild::server/scaservice::*;
=> a node-set with 1 element(s):
#<scaservice: server.s>
Success (took 1 ms).

SCA Reference node

In the same way, we define the counter part: the reference node. The helloworld-rmi-standalone does not contain any reference, so we will introspect one of these children (the client component) by using the scachild axis defined in the next part of this tutorial.

FScript> print = $c/scachild::client/scareference::*;
=> a node-set with 1 element(s):
#<scareference: client.printService>
Success (took 4 ms).

We can also select a specific reference by using its name instead of the wildcard character.

SCA Intent node

The intent node is used to represent intents defined on SCA components, services, references. It extends the SCA component node as it the intent is itself an SCA component. So, an SCA intent can be manipulated/introspected in the same way as SCA components.

FScript> i = $s/scaintent::*;
=> a node-set with 1 element(s):
#<scaintent: frascati-debug on s>
Success (took 1 ms).

FScript> state($i)
=> "STARTED"

SCA Binding node

We also introduced a binding node in order to be able to interact with SCA bindings. This node inherits from the Component node kind as SCA bindings are implemented as a couple of Fractal components: one for the stub (for SCA references), the other one for the skeleton (for SCA services). Here is an example:

FScript> printServiceBinding = $c/scachild::client/scareference::printService/scabinding::*;
=> a node-set with 1 element(s):
#<scabinding: rmi-stub-primitive>
Success (took 3 ms).

FScript> $c/scachild::server/scaservice::s/scabinding::*;
=> a node-set with 1 element(s):
#<scabinding: org.objectweb.fractal.bf.connectors.rmi.RmiSkeletonContent>
Success (took 3 ms).

The Sca Binding node can be used to discover binding properties with the help of the attribute axis.

Using the previously defined printServiceBinding variable, we can use the fractal attribute axis to discover binding attributes. Then, we can easily get an attribute value:

FScript> $printServiceBinding/attribute::*;
=> a node-set with 1 element(s):
#<attribute: rmi-stub-primitive.serviceName>
Success (took 2 ms).

FScript> value( $printServiceBinding/attribute::serviceName);
=> "rmiservice"
Success (took 3 ms).

SCA Property node

An SCA property node represents configuration properties, as defined by the component in the SCA composite file. Let's select one and see properties it has:

FScript>p = $c/scaproperty::*;
=> a node-set with 1 element(s):
#<scaproperty: helloworld-rmi-standalone.composite-property>
Success (took 1 ms).

You can get the value of any SCA property with the value() instruction as following:

FScript> value($p)
=> "-->"

SCA axes

In the previous section, we've seen that FPath models software architectures using nodes to represent the elements of interest (components, services/references, properties, bindings, intents in the case of SCA). By themselves, nodes can only model individual elements, and do not give us any information on the actual structure of the system. To represent the structure, FPath connects the nodes using directed arcs. The result is that, from FPath's point of view, a software architecture is a directed graph. The vertices of this graph are the nodes we've already seen, and the edges are labelled arcs between these nodes, which represent their relationships.

The different kinds of relationships which can exist between nodes are called axes, and are the basic mechanism for navigation in FPath. We've actually already met various axes in the previous section such as scachild, scaservice, scaproperty, etc:

  • scachild labels arcs which connect composite nodes to the nodes representing their direct SCA sub-component

  • scaparent labels arcs which connect component nodes to the nodes representing their direct parents (if any)

  • scaservice labels arcs which connect component nodes to the nodes representing its SCA services

  • scareference labels arcs which connect component nodes to the nodes representing its SCA references

  • scaproperty labels arcs which connect component nodes to the nodes representing its configuration properties

  • scabinding labels arcs which connect SCA interfaces (service or reference) nodes to the nodes representing its SCA bindings

  • scaintent labels arcs which connect component (or SCA interfaces) nodes to the nodes representing its SCA intents.

With this information, we can now understand in more details what the queries from the previous section do. When we write $c/scachild::*, it actually means: “From the node(s) in variable $c, traverse all the arcs in the graph labelled scachild, and return the nodes at the other end.” Each step in a path “walks” along the corresponding axis in the graph, returning the destination nodes at the other end of the arcs.

FraSCAti Script provides several other axes to navigate in SCA architectures.

Child

FScript> $c/scachild::*
=> a node-set with 2 element(s):
#<scacomponent: client>   #<scacomponent: server>

FScript> client = $c/scachild::client;
=> a node-set with 1 element(s):
#<scacomponent: client>
Success (took 1 ms).

The expression $c/scachild::* is our first example of an actual path expression. It selects all the (direct) children of component $c, and returns them in a node-set. In this case, the result is a set of two components (more precisely two nodes representing the components) named client and server. These correspond to the client and server components, which are indeed the two direct sub-components of the HelloWorld top-level (see Figure 1, “The architecture of the HelloWorld example.”).

Parent

FScript> $client/scaparent::*
=> a node-set with 2 element(s):
#<scacomponent: helloworld-rmi-standalone>

The expression $c/scaparent::* selects all the (direct) parents (if any) of component $client, and returns them in a node-set. In this case, the result is a set of one component named helloworld-rmi-standalone.

Service

If instead of selecting the sub-components of $c we want to see its provided services, we can use the following query:

FScript> $c/scaservice::*
=> a node-set with 2 element(s):
#<scaservice: helloworld-rmi-standalone.r>      #<scaservice: helloworld-rmi-standalone.rbis>

Here, we can see that the whole composite provides 2 services named 'r' and 'rbis'.

Reference

In the same way, the following query allows us to discover SCA component references (i.e. required services):

FScript> $c/scachild::client/scareference::*
=> a node-set with 1 element(s):
#<scareference: client.printService>

We wanted to know what are SCA references needed by the client composite (i.e. what are used/required services). The result shows us that there is one dependency to a printService.

In order to know a bit more about service/reference, we can use the scabinding axis described below.

Wire

The scawire axis allows you to navigate between components. It connects client interfaces to the server interface(s) they are bound to. The connect and disconnect operations on this axis are used to create and destroy (fractal) bindings. It is an alias of the (fractal) binding axis available for Fractal components.

Binding

The scabinding axis connects a node representing an SCA reference to the node representing the SCA service it is bound to, if any. Note that the binding keyword refers to the SCA binding notion, i.e. a way to expose/import remote services (more simply, a communication protocol like WS, RMI, etc.).

It is almost always used in the form scabinding::*. For example:

FScript> psbinding = $c/scachild::client/scareference::printService/scabinding::*;
=> a node-set with 1 element(s):
#<scabinding: rmi-stub-primitive>
Success (took 2 ms).

This tells us that the interface named printService of the client (sub-)component is actually exported as a RMI service.

The scabinding node kind inherits from the (fractal) ComponentNode kind, so we can use classical (i.e. fractal) axis on it. Especially, we can use the attribute axis to discover SCA binding attributes. In this way, we are able to discover registry name, ws end-point and so on.

FScript> $psbinding/attribute::*
=> a node-set with 1 element(s):
#<attribute: rmi-stub-primitive.serviceName>

FScript> value( $psbinding/attribute::serviceName );
=> "rmiservice"
Success (took 10 ms).

Property

SCA components may define SCA properties which are configuration elements. FraSCAti allows a bit more because you are able to dynamically reconfigure SCA properties on running components. To discover configuration capabilities of a component, simply use the following pattern:

FScript> header = $c/scachild::server/scaproperty::*;
=> a node-set with 1 element(s):                     
#<scaproperty: server.header>                        
Success (took 2 ms).

FScript> value( $header )
=> "-->"

Intent

Last but not least, SCA let you define intents (policies) on services, references or components (then apply on all services and references of the component). So, there is an scaintent axis that can be used on SCA services, references or components nodes. This axis returns SCA Component node(s) as intents are themselve implemented as SCA composites with FraSCAti. So, all SCA-related axes defined here can be applied to scaintent axis results.

FScript> $c/scachild::server/scaintent::*
=> a node-set with 1 element(s):
#<scaintent: frascati-debug on s>

In this example, we are discovering an intent named frascati-debug defined on the s interface (service) of the server component.

Additional axes

In addition to previous axes, there are other derivated axes:

  • Transitive axes: select nodes recursively by applying the axis on results

    • scadescendant

    • scaancestor

  • Composed axis: combination of two axes

    • scasibling

  • Reflexive axes: add the source component to selected node

    • scachild-or-self

    • scaparent-or-self

    • scadescendant-or-self

    • scaancestor-or-self

    • scasibling-or-self