To introduce fabric application development we will create a simple "Hello World" application.
You may create your own fabric application and client application, or you may use the files and projects provided in tutorial_samples.zip and tutorial_samples.tgz archives. These files and projects are not included in the Fabric Software Development Kit (SDK) installation, but will be available for later versions. The fabric APIs are not dependent on a particular build tool or development environment (IDE), so you may use your preferred build tools. For your convenience, we have included project files for several platforms. These can be seen in the table to the right.
In this Kick Start tutorial we will
create a Hello World fabric task
create fabric application, process flow, and task XML files
package and deploy the Hello World fabric application
create a simple Hello World client
submit Hello World requests to the fabric
What our Hello World application will do
client submits a request to the fabric to execute our Hello World fabric application's process flow
the process flow calls the our Hello World task
the Hello World task returns "Hello World!" in the fabric request to the process flow
the process flow returns the request to the client
the client receives "Hello World!" in the completed request, and prints the message to the console
Projects Provided For Tutorial Samples
Language
Platform
Project Type
Java 1.5
All
Eclipse
Java 1.5
All
Ant scripts
.NET 2.0
Windows
Visual Studio 2005
'C'
Windows
Visual Studio 2005
'C'
Linux
Make scripts
Click the language of your choice for this page:
To create your own fabric application and client, you will need to have done the following:
Read through all the pages in Appistry EAF Essentials to become familiar with the fabric application components and services.
Install the Fabric SDK on your development workstation. Please refer to the Installation procedure.
Download either the tutorial_samples.zip or tutorial_samples.tgz archive from here, and copy the archive into the top level SDK directory ("/usr/local/appistry_eaf_sdk" on unix or "C:\Program Files\Fabric" on Windows) that was created during the SDK install in step #2.
Extract the .zip or .tgz tutorial samples archive into the top level SDK directory. A "tutorial_samples" subdirectory should be created with a path of "/usr/local/appistry_eaf_sdk/tutorial_samples" on unix or "C:\Program Files\Fabric\tutorial_samples" on Windows. Make sure when you extract your archive, particularly using the .zip file, that you do not end up with two tutorial_samples directories like this: "C:\Program Files\Fabric\tutorial_samples\tutorial_samples\...."
Have your build environment setup for Java, .NET, and/or 'C'. We presume in this tutorial that you know how to use the build environment of your choice. We have provided projects for several, as mentioned, for your convenience.
Install at least one fabric worker on a computer. This may be on your development workstation or one or more separate boxes. If the worker is not on your local workstation, then the worker or workers must be accessible over the network from your development workstation. Please refer to the Installing the Fabric procedure.
Java and .NET developers implement fabric tasks as simple object-oriented classes that are marked up using fabric annotations in Java, or fabric attributes in .NET, and 'C' developers implement tasks as 'C' libraries using fabric task interfaces. Examples in each language are shown below.
What is a fabric request object? When a fabric client submits an execution request into a fabric, the request and it's user data is passed in a fabric request object. The fabric request object exists for the duration of the request, and is passed to each task executed to fulfill the request. When the fabric has fulfilled the client's request, the fabric request object is returned to the client. A fabric developer can get values from, and set values to the fabric request object using the fabric client API and fabric task API. The Java and .NET task API in particular support several methods for manipulating values in the fabric request object. This Kick Start tutorial demonstrates just one way to return a value to the client from the task via the fabric request object.
In each Hello World task, the value "Hello World!" is mapped from the method call into the fabric request object. In the cases of Java and .NET, the mapping is accomplished using a Java annotation or a .NET attribute. In the 'C' example, the value "Hello World!" is set into the fabric request object directly and not returned by the function. Please note that the Java Task API 3.5 version of the sample task also required this direct approach, whereas the Java Task API 3.7 version does not, and can be completely accomplished using annotations if the developer so chooses.
Read more about tasks under the Task APIs for .NET, 'C' (CentOS, RHEL, SUSE and Windows), and Java.
HelloWorld.java (in tutorial_samples/java/hello_world/com/appistry/samples/hello_world/)
01.
02. package com.appistry.samples.hello_world;
03.
04. import com.appistry.task.Annotations.TaskReturnValue;
05.
06. public class HelloWorld {
07.
08. // map method return value into "hello"09. // key in current fabric request object
10. @TaskReturnValue(name="hello")
11. publicString greet() {
12. return"Hello World!";
13. }
14. }
HelloWorld.cs (in tutorial_samples/dotnet/hello_world/hello_world_app/)
01. using System;
02. using Appistry.Task;
03.
04. namespace Appistry.Samples.HelloWorld
05. {
06. public class HelloWorld
07. {
08. // map method return value into "hello"09. // key in current fabric request object
10. [return: TaskReturnValue("hello")]
11. public string Greet()
12. {
13. return"Hello World!";
14. }
15. }
16. }
hello_world.cpp (in tutorial_samples/cpp/hello_world/hello_world_app/)
01. #include "fabric_client.h"
02. #include <string>
03. using namespace std;
04.
05. #ifdef _WIN32
06. #include <windows.h>
07. #endif
08.
09. extern "C" void greet(fab_req* request)
10. {
11. // set value to return to client into
12. // current fabric request object
13. fab_req_set_string(request, "hello", "Hello World!");
14. }
15.
hello_world.def (Windows only) (in tutorial_samples/cpp/hello_world/hello_world_app/)
1. EXPORTS
2. greet
Hello World Task XML Definition
Now that we have created our Hello World fabric task, we must present it to the fabric in a task XML definition file. This definition file declaratively defines the task to the fabric, and includes 2 elements
Module element
Task element
Module element
The module element has 3 attributes: file, implementation, and classname.
Attribute
Description
file
The file attribute specifies the file containing the task and is case sensitive. For Java, this is a .class or .jar file. For .NET this is a .NET assembly. For compiled languages, this is the name of the DLL or library. The file attribute is case sensitive.
implementation
The implementation attribute specifies the task's run time environment: .NET, DLL, or Java. DLL is used for any language including 'C' that creates a DLL or library.
className
In Java and .NET, the className identifies the class containing the task implementation. In .NET, the className value is the fully-qualified name of the class including package for Java, and namespace for .NET. If the class is not part of a Java package or a .NET namespace, the className value is simply the class name. The className attribute is case sensitive. The className attribute is required if the implementation is .NET or Java. This attribute is ignored if the implementation is DLL.
Task element
The task element has one attribute: name, and can contain a method sub-element.
Attribute
Description
name
The name attribute identifies the name of the task. The name can be the same as the name of the task function, or it can be an alias for that function. Our example here uses an alias. The name attribute is used to reference the task function from process flow XML definitions. The name attribute is case sensitive.
Method sub-element
The method element identifies the actual function name for the task. For Java and .NET, this is the actual name of the method in the class to be executed. For 'C' this is the actual name of the function to be executed.
Next we must define a fabric process flow to execute our Hello World task. Tasks execute in the fabric in the context of a process flow. Process flows declaratively describe a state machine of activities to be carried out to fulfill a client request in the fabric. The process flow XML is the same for each of our three language samples.
The process flow definition file defines the transition after a task completes. The basic unit of a process definition file is a state. A state is defined as an action to be performed and the transition rules to be followed based on the results of that action. An action is a task or a sub-process flow. The transitions are the rules ordering the execution of the tasks.
The process flow definition file contains the following elements.
Process element
State element
Task element
Arc element
Process element
The process element has two attributes: default-retries and default-timeout. These attributes apply to all tasks within the process flow definition file.
Attribute
Description
name
The name of the process flow. This element is required.
default-retries
Default-retries specifies the number of times the task my be re-attempted before returning an error.
default-timeout
Default-timeout specifies the amount of time, in seconds, a task may take to complete before returning an error.
State element
The state element represents the task in the process flow. The first state in every process flow definition is "start". The state element must contain one task sub-element and one or more arc sub-elements. The state element has one attribute that we use in the Kick Start sample: name.
Attribute
Description
name
The name attribute uniquely identifies this "state" in the process flow. The name attribute is case sensitive.
Task element
The task element specifies the task to be run upon entering this state in the process flow. The task element has one attribute that we use in the Kick Start sample: name.
Attribute
Description
name
The name specifies the task to be run upon entering this state in the process flow. The value for name is the exact name listed in the task XML definition for the given task. In our example, the name "helloWorld" in the process flow XML definition below references the name "helloWorld" in task XML definition above. The name attribute is case sensitive.
Arc element
An arc element defines the transition from one state in the process flow to the next state. In a one-step process flow, which only executes one task, the transition is to the finish state. The arc element has two attributes that we use in the Kick Start sample: task-status and next-state.
Attribute
Description
task-status
The task-status attribute identifies the status of the task or sub-process. This attribute has three possible values: complete, not-attempted, and task-not-completed. These values are set by the fabric during task execution.
next-state
The next-state attribute identifies the process flow state to be executed next if this arc is followed.
The values for task-status are defined below.
task-status value
Description
complete
The task or sub-process completed successfully.
not-attempted
The application fabric did not attempt to complete the task or sub-process.
not-completed
The task took too long to complete or the task or sub-process status could not be determined.
Our last step is to define the fabric application XML definition.
A fabric application definition file groups the task and process flow files together into a single fabric application. The fabric uses this file to identify the components of a fabric application. The basic elements of a fabric application definition file are tasks and process flows.
The application definition file contains the following elements.
App element
Tasks element
Process-flows element
App element
The app element sets the name of the fabric application, and specifies the version number of the application for deployment in the fabric. The app element has two attributes: name and version. The app element has two sub-elements that we use in the Kick Start sample: tasks and process-flows.
Attribute
Description
name
The name attribute sets the name of the fabric application. The name of the fabric application is also the name of the application definition XML file.
version
The version attribute indicates the application version. The fabric uses the version value to ensure the most current application is running. All version numbers are right justified and zero filled. So, 1.2 is considered 1.02. Therefore, when comparing version 1.2 with 1.19, the application fabric actually compares 1.02 with 1.19. Version 1.19 is considered newer than version 1.2. Also, when comparing version 1.0.0 with 1.0 and 1, 1.0.0 is considered newer than version 1.0 and 1.0 is considered newer than version 1.
When do I change the version number?
Any change to an application that requires redepolying the application to the fabric requires you to increment this value. If the application is already installed, the fabric does not allow you to deploy a lesser or equal version of the same application.
Tasks element
The tasks element identifies the list of task definition files in the application. The file sub-element the name of the task file.
Process-flow element
The process-flows element identifies the list of process flow definition files in the application. The file sub-element specifies the name of a process flow definition file and must be identical to the process name. The process-flows element must follow the tasks element.
File element
The file element specifies the name of a file that is part of this fabric application. The file element is used by both the tasks and process-flows elements. The file element has one attribute: name.
Attribute
Description
name
The name attribute's value is the name of a file that is part of the fabric application.
Now that we have developed and deployed our fabric application to the fabric, we need a client to submit requests to the fabric for our application. Any application that can use the fabric client API in Java, .NET or 'C' can be a fabric client. These API libraries are found in the files listed in the table below.
Language
Dependency
Java
fabric.jar
NET
Appistry.NET.dll
'C'
fabric.dll (windows) or libfabric.so (unix)
Fabric Client Overview
When a client application makes a request to the fabric through the fabric client API, at a minimum it is required to specify what fabric application and process flow is to be executed to fulfill the request. Additionally, the request must provide any user data that is required by the tasks which the process flow will execute. The fabric request holds these data values in a map of name/value pairs. Upon execution in the fabric, these name/value pairs are marshalled between the request and the executed task.
Client Implementation
We will build our Hello World client implementation using the blocking calls in the fabric client API. The term "blocking" here refers to the fact that the execution call to the fabric will not return until the request has been completed in the fabric.
In each of the code samples below for Java, .NET and 'C', we implement an executable main which makes a fabric call on a process flow. The fabric API client needs information listed in the table below to allow it to communicate with the fabric.
Parameter
Description
fabric MCAST address
The fabric MCAST address must match the fabric-address entry in the addr.cfg file deployed on to your fabric workers. The default is "239.255.0.1".
fabric request port
The fabric MCAST port must match the request-port entry in the addr.cfg file deployed on to your fabric workers. The default is 31000.
MCAST time-to-live (TTL)
The MCAST TTL defaults to zero (0) indicating that MCAST traffic will stay on the local computer. If your fabric client workstation and your fabric worker(s) are on separate boxes on the same local network, you need to specify a setting of one (1) for the MCAST TTL. If network routers are between the client and the worker(s), then you may need to specify a higher number. The MCAST TTL gets decremented by each network router until reaching zero (0), at that time a router will discard the packet. If the MCAST TTL is set too low the client on one computer may not be able to communicate with worker(s) running on remote computers.
encryption type
The encryption type parameters specifies which encryption to use between the client and the fabric. The default is NONE.
The expected output from our client's call to the fabric application is shown below.
Hello World!
HelloWorldClient.java (in tutorial_samples/java/hello_world/)
001. package com.appistry.samples.hello_world;
002.
003. import com.appistry.fabric.Encryption;
004. import com.appistry.fabric.Fabric;
005. import com.appistry.fabric.FabricRequest;
006.
007. public class HelloWorldClient {
008.
009. publicstatic void main(String[] args) {
010. // construct a fabric API object instance specifying fabric
011. // address values from fabric.cfg, Mcast TTL and encryption type
012. // Mcast TTL must be 1 or greater if the fabric client is running
013. // on a box separate from the fabric workers.
014. Fabric fabric = new Fabric("239.255.0.1", 31000, 1, Encryption.NONE);
015.
016. // construct a fabric request object instance specifying
017. // the fabric application and process flow to run
018. FabricRequest request = new FabricRequest("hello_world_java_app", "hello_world_flow");
019.
020. // submit the request to the fabric
021. fabric.execute(request);
022.
023. // print out the value returned from our fabric task
024. System.out.println(request.get("hello"));
025. }
026. }
HelloWorldClient.cs (in tutorial_samples/dotnet/hello_world/hello_world_client/)
0001. using System;
0002. using Appistry.FabricAPI;
0003.
0004. namespace Appistry.Samples.HelloWorld
0005. {
0006. public class HelloWorldClient
0007. {
0008. static void Main(string[] args)
0009. {
0010. try
0011. {
0012. // construct a fabric API object instance specifying fabric
0013. // address values from fabric.cfg, Mcast TTL and encryption type
0014. // Mcast TTL must be 1 or greater if the fabric client is running
0015. // on a box separate from the fabric workers.
0016. Fabric fabric = new Fabric("239.255.0.1", 31000, 1, Encryption.NONE);
0017.
0018. // construct a fabric request object instance specifying
0019. // the fabric application and process flow to run
0020. FabricRequest request = new FabricRequest("hello_world_dotnet_app", "hello_world_flow");
0021.
0022. // submit the request to the fabric
0023. fabric.Execute(request);
0024.
0025. // print out the value returned from our fabric task
0026. Console.WriteLine(request["hello"]);
0027. }
0028. catch (Exception e)
0029. {
0030. Console.WriteLine(e.ToString());
0031. }
0032. }
0033. }
0034. }
hello_world_client.cpp (in tutorial_samples/cpp/hello_world/hello_world_client/)
0001. #include "fabric_client.h"
0002.
0003. #include <iostream>
0004. using namespace std;
0005.
0006. int main(int argc, char* argv[])
0007. {
0008. // construct a fabric properties object to specify our Mcast TTL.
0009. // Mcast TTL must be 1 or greater if the fabric client is running
0010. // on a box separate from the fabric workers.
0011. fab_properties* properties = fab_properties_new();
0012. fab_properties_set_mcast_ttl(properties, 1);
0013.
0014. // construct a fabric API object instance specifying fabric
0015. // address values from fabric.cfg.
0016. fabric* fabric = fab_new("239.255.0.1", 31000, properties);
0017.
0018. // construct a fabric request object instance specifying
0019. // the fabric application and process flow to run
0020. fab_req* request = fab_req_new("hello_world_cpp_app", "hello_world_flow");
0021.
0022. // submit the request to the fabric
0023. int rc = fab_execute(fabric, request);
0024.
0025. if ( rc == FAB_SUCCESS )
0026. // print out the value returned from our fabric task
0027. cout << fab_req_get_string(request, "hello") << endl;
0028. else
0029. cout << "Fabric Error Code: " << rc << " Message: " << fab_req_error_message(request) << endl;
0030.
0031. // free up our request and fabric API resources
0032. fab_req_free(request);
0033. fab_free(fabric);
0034.
0035. return rc;
0036. }
0037.
What is a fab_properties object?
The 'C' sample does not specify the MCAST TTL or Encryption type, but rather is taking a NULL as its third parameter. The third parameter is a fab_properties object. The fab_properties object takes and holds values such as MCAST TTL and Encryption type. When NULL is passed for the fab_properties object, defaults are used.
Running the Hello World Fabric Client and Application
Before running the Hello World client, do the following.
Verify the fabric is running. If the fabric is not running, refer to Installing the Fabric for instructions.
Start a Log Monitor in a separate window or terminal, if you haven't already. To start the Log Monitor run the following command. The MCAST address must match the fabric-address set in the addr.cfg file.
log_monitor 239.255.0.1:4000
Run the client
Run the Hello World client. The following output appears:
Mixing it up
It is entirely possible to call the one language version of the Hello World fabric application using a different language version of the client. For example, you can use the Java client to call the 'C' version of the fabric application. Just change the Java client to use the "hello_world_cpp_app" fabric application instead of the "hello_world_java_app" version.
This is made possible by the fact that our application only uses primitive data types. If you have a fabric client and application that passes objects (for example Java client passing Java objects to/from a Java-based fabric application), then this would, of course, not work.
When using Java and Ant You can issue the command "ant run" to execute the client.