I got the code done last week but I'm only just now finishing up the
build.xml file. So, as promised, here's what I did (a bit of a long
post but
I think I got it all)
Firstly to get more familiar with the workspace I followed Sebastien's
instructions from the Domain/Contribution repository thread [1] and
ran up
the workspace to have a play.
"You can use the latest tutorial modules to see the end to end
integration,
with the following steps:
1. Start tutorial/domain/.../LaunchTutorialAdmin.
2. Open http://localhost:9990/ui/composite in your Web browser. You
should
see all the tutorial contributions and deployables that I've added to
that
domain.
3. Click the feeds in the "composite install image" to see the resolved
composites.
4. Start all the launch programs in tutorial/nodes, you can start them in
any order you want.
5. Open tutorial/assets/tutorial.html in your Web browser, follow the
links
to the various store implementations."
The workspace is allowing you to organize the relationships between
contributions/composites, the domain composite that describes the whole
application and the nodes that will run the composites. It processes
all of
the contributions that have been provided, the composites they
contain, the
association of composite with the domain and with nodes and produces
fully
resolved composites in terms of the contributions that are require to run
them and the service and reference URIs that they will use.
This resolved composite information is available from the workspace
through
composite specific feeds. From this feed you can get URLs to the required
contributions and the composite. In fact what happens each time you do
a GET
on the composite URL is that all of the composites assigned to the domain
are read and the domain composite is "built" in full using the composite
builder. The individual composite that was requested is then extracted
and
returned. In this way policy matching, cross domain wiring, autowiring
etc
is manged at the domain level using the same code used by the nodes to
build
individual composites.
This is very similar in layout with what is happening with our current
domain/node implementation where you add contributions to the domain and
nodes run the resulting composites. However there is a big difference
here
in that there is now an implication that the domain is fully configured
before you start the nodes as the workspace is responsible for
configuring
service / reference URIs based on prior knowledge of node configurations.
Previously you could start nodes and have them register with the domain
without having to provide this knowledge manually to the domain. I guess
automatic node registration could be rolled into this if we want.
In making the calculator-distributed sample work I wanted to be able
to test
the sample in our maven build so having a set of HTTP forms (which the
workspace does provide) to fill in is interesting but not that useful. So
immediately I went looking for the files that the workspace writes to
see if
I could create those and install them pre-configured ready for the
test to
run. I used the tutorial files as templates and made the following to
match
the calculator-distributed scenario.
Firstly there is a file (workspace.xml) [2] that describes all each
contribution's location and URI
<workspace xmlns="http://tuscany.apache.org/xmlns/sca/1.0" xmlns:ns1="
http://tuscany.apache.org/xmlns/sca/1.0">
<contribution location="file:./target/classes/nodeA" uri="nodeA"/>
<contribution location="file:./target/classes/nodeB" uri="nodeB"/>
<contribution location="file:./target/classes/nodeC" uri="nodeC"/>
<contribution location="file:./target/classes/cloud" uri="
http://tuscany.apache.org/xmlns/sca/1.0/cloud"/>
</workspace>
Then there is a file (domain.composite) [3] that is a serialized
version of
the domain composite, i.e. what you would get from the specs
getDomainLevelComposite() method. This shows which composites are
deployed
at the domain level.
<composite name="domain.composite"
targetNamespace="http://tuscany.apache.org/xmlns/sca/1.0"
xmlns="http://www.osoa.org/xmlns/sca/1.0" xmlns:ns1="
http://www.osoa.org/xmlns/sca/1.0">
<include name="ns2:CalculatorA" uri="nodeA" xmlns:ns2="http://sample"/>
<include name="ns2:CalculatorB" uri="nodeB" xmlns:ns2="http://sample"/>
<include name="ns2:CalculatorC" uri="nodeC" xmlns:ns2="http://sample"/>
</composite>
Lastly there is a file (cloud.composite) [4] that is another SCA
composite
that describes the nodes that are going to run composites.
<composite name="cloud.composite"
targetNamespace="http://tuscany.apache.org/xmlns/sca/1.0"
xmlns="http://www.osoa.org/xmlns/sca/1.0" xmlns:ns1="
http://www.osoa.org/xmlns/sca/1.0">
<include name="ns2:NodeA" uri="
http://tuscany.apache.org/xmlns/sca/1.0/cloud" xmlns:ns2="
http://sample/cloud"/>
<include name="ns2:NodeB" uri="
http://tuscany.apache.org/xmlns/sca/1.0/cloud" xmlns:ns2="
http://sample/cloud"/>
<include name="ns2:NodeC" uri="
http://tuscany.apache.org/xmlns/sca/1.0/cloud" xmlns:ns2="
http://sample/cloud"/>
</composite>
Each included node composite looks something like
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:t="http://tuscany.apache.org/xmlns/sca/1.0"
targetNamespace="http://sample/cloud"
xmlns:s="http://sample"
name="NodeA">
<component name="NodeA">
<t:implementation.node uri="nodeA" composite="s:CalculatorA"/>
<service name="Node">
<binding.sca uri="http://localhost:8100"/>
</service>
</component>
</composite>
You will note that the node holds default binding URI information.
With these files the workspace can produce the fully configured
composites
that will run on each node.
Having done this I rewrote the code in the "node" package to create a
set of
launchers for the various parts of the sample.
node.LaunchDomain [5] was the first and simply calls the
DomainAdminLauncher
from the workspace-admin package. This starts an SCA application,
reads all
these files, makes some web pages available and more importantly make the
resolved composite information available at URLs starting
http://host:9990/.
..
node.LaunchCalculatorNodeA, B, C [6] allows each node to be started. You
will note that in each of these a node gets started with a line something
like
node =
nodeFactory.createSCANode("http://localhost:9990/node-image/NodeA");
This is a slightly different take on the node creation process we had
before
(this new node code is in the node2-* packages). It lets you create a
node
given a composite information. This is derived from the helper method
Simon
Nash put on the factory and in this case is the URI of an Atom feed that
provides a link to a composite and the contributions required to run that
composite. The node runs, pulls down this information. Based on this
information it pulls down each of the contributions and the composite and
starts up the composite.
As all the composites are fully configured the nodes simply build,
activate
and start them. They don't need to go looking for service endpoints.
The actual distributed calculator application is the same as it was
before.
I hope this makes some kind of sense. Please ask if you want more
details.
Regards
Simon
[1] http://www.mail-archive.com/tuscany-dev@ws.apache.org/msg28711.html
[2]
http://svn.apache.org/repos/asf/incubator/tuscany/java/sca/samples/calculator-distributed/workspace.xml
[3]
http://svn.apache.org/repos/asf/incubator/tuscany/java/sca/samples/calculator-distributed/domain.composite
[4]
http://svn.apache.org/repos/asf/incubator/tuscany/java/sca/samples/calculator-distributed/cloud.composite
[5]
http://svn.apache.org/repos/asf/incubator/tuscany/java/sca/samples/calculator-distributed/src/main/java/node/LaunchDomain.java
[6]
http://svn.apache.org/repos/asf/incubator/tuscany/java/sca/samples/calculator-distributed/src/main/java/node/LaunchCalculatorNodeA.java