Welcome to the first lesson of the Spiderwiz Tutorial. In this lesson you will learn how to build a basic functional Spiderwiz Application. We will start with a simple command-line Java project. It will not do much, but it will have all the building blocks needed for much more complex applications. In fact you will discover that writing much more complex Spiderwiz applications is not that much harder than writing this simple one.
The application contains one data object – HelloWorld
, which prints, guess what, “Hello World”.
So we start by creating a new empty Java application project. We use Maven along this tutorial, but you can use any project management tool as you may find convenient. The Spiderwiz dependency is described in the Download page and we will copy it here for convenience:
<dependency> <groupId>org.spiderwiz</groupId> <artifactId>spiderwiz-core</artifactId> <version>4.0</version> </dependency>
Our application comprises two source files – HelloWorldMain.java
, which is the entry (and exit) point of the application, and HelloWorld.java
, which codes the HelloWorld
object. Let’s see the first and then explain it:
package org.spiderwiz.tutorial.lesson1; import java.util.List; import org.spiderwiz.core.DataObject; import org.spiderwiz.core.Main; /** * Provides the entry point of the application. Initializes and executes the Spiderwiz framework. */ public class HelloWorldMain extends Main{ private static final String ROOT_DIRECTORY = ""; private static final String CONF_FILENAME = "hello-world.conf"; private static final String APP_NAME = "Hello World"; private static final String APP_VERSION = "Z1.01"; // Version Z1.01: Initial version /** * Class constructor with constant parameters. */ public HelloWorldMain() { super(ROOT_DIRECTORY, CONF_FILENAME, APP_NAME, APP_VERSION); } /** * Application entry point. Instantiate the class, initialize the instance, then call a command-line hook that would shut down * the application when "exit" is typed. * * @param args the command line arguments. Not used in this application. */ public static void main(String[] args) { HelloWorldMain main = new HelloWorldMain(); if (main.init()) main.commandLineHook(); } /** * @return the list of produced objects, in this case HelloWorld is the only one. */ @Override protected String[] getProducedObjects() { return new String[]{HelloWorld.ObjectCode}; } /** * @return the list of consumed objects, in this case HelloWorld is the only one. */ @Override protected String[] getConsumedObjects() { return new String[]{HelloWorld.ObjectCode}; } /** * Add HelloWorld class to the object factory list of this application. * @param factoryList */ @Override protected void populateObjectFactory(List<Class<? extends DataObject>> factoryList) { super.populateObjectFactory(factoryList); factoryList.add(HelloWorld.class); } /** * Create a HelloWorld object, set its field and commit it. */ @Override protected void postStart() { try { HelloWorld helloWorld = createTopLevelObject(HelloWorld.class, null); helloWorld.setSayHello("Hello World"); helloWorld.commit(); return; } catch (NoSuchFieldException | IllegalAccessException ex) { ex.printStackTrace(); } } }
Every Spiderwiz application must extend org.spiderwiz.core.Main class and call its init() method in order to set the framework mechanism in motion. We do it with HelloWorldMain
. The Main
constructor requires four parameters – the root file folder of the application, the name of the configuration file (that must reside in the root folder), application name and version. In our case we hard code all these. We provide an empty string as the root folder as we want it to be the current working directory.
Next we implement a static main()
method (line 29) that serves as the application’s entry point. Inside the method we create an instance of HelloWorldMain
and call its init() method. If successful, we set up a cleanup and exit point by calling Main.commandLineHook(). This is a shortcut for adding a shutdown hook that calls Main.cleanup() upon application termination and reading lines from the standard input stream until the command “exit” is encountered, then terminating the application.
We implement the abstract methods Main.getProducedObjects() (line 39) and Main.getConsumedObjects() (line 47). The only data object that we both produce and consume is HelloWorldMain
, so in both methods we return a list containing a single element – HelloWorld.ObjectCode
. We will come back to it in a moment when we discuss HelloWorld.java
.
We also override Main.populateObjectFactory() (line 56). This is where we register the class that implements HelloWorld
. Note that before adding this class to the factory list, we must call super.populateObjectFactory(factoryList)
in order to preserve pre-registered classes.
Last is to override Main.postStart() (line 65) that is called after framework initialization. We create a HelloWorld
object (using createTopLevelObject()), set its sayHello
property and commit it.
The second file, HelloWorld.java
, is where we define the HelloWorld
object and implement its task. Here it goes:
package org.spiderwiz.tutorial.lesson1; import org.spiderwiz.annotation.WizField; import org.spiderwiz.core.DataObject; /** * Implements HelloWorld data object. */ public class HelloWorld extends DataObject{ /** * Mandatory public static field for all data objects. */ public final static String ObjectCode = "HLWRLD"; @WizField private String sayHello; public String getSayHello() { return sayHello; } public void setSayHello(String sayHello) { this.sayHello = sayHello; } /** * @return null as this is a root object. */ @Override protected String getParentCode() { return null; } /** * @return true as this object is disposable. */ @Override protected boolean isDisposable() { return true; } /** * Do the consumer work. * @return true to indicate that the event has been handled. */ @Override protected boolean onEvent() { System.out.println(getSayHello()); return true; } }
Classes that implement Spiderwiz Data Objects extend org.spiderwiz.core.DataObject. In order to participate in the game, classes that extend this class must define a public static String
field named ObjectCode
that uniquely identifies the data object type across the service mesh. Its value may contain any character except a comma. We define this field with the value “HLWRLD”. Our class also contains one String property – sayHello
.
Next we need to implement two abstract methods – getParentCode() and isDisposable(). The first returns null
because the class defines a root object (that has no parent). The second returns true
because the object is disposable – it can be discarded after its event is handled.
We achieve our task by overriding onEvent(). This method is fired when the producer of the object commits it. Our implementation gets the value of sayHello
property and outputs it to the console. We return true
to indicate that we have completely handled the event. (You will see later why this is important).
So, are we ready to greet the world? Well, hold on. If you try to run what we have done so far, you will get the following message on your console:
Could not open setting file hello-world.conf
hello-world.conf
is the configuration file name as we defined in HelloWorldMain
. Every Spiderwiz application requires a configuration file. In our case there is not much to put there and we can even leave it empty to use defaults, but a file must exist in what we defined as a root folder (the working directory where we launched the application in our case).
Since we prefer to have a fixed place for our application’s log folder, we will include one line in hello-world.conf
:
[log folder]/tests/HelloWorld/Logs
Now we are ready to run. Shoot it, and you will see the following on your console:
Hello World ver. Z1.01 (core version Z2.30) has been initiated successfully Include spiderwiz-admin.jar in your project in order to use www.spiderwiz.org/SpiderAdmin Hello World
The first message is displayed by the framework when every Spiderwiz application is initialized. Application name and version are taken from the call to Main
class constructor as shown above. “Core version” is the version of the Spiderwiz framework used.
Ignore the second message for now, we will come back to it later.
The third message, “Hello World”, is what our HelloWord object prints.
At this point, the application is still active and waiting for user input. Type exit
(case insensitive), the application will terminate and you will see the following:
exit Hello World undeployed
Before concluding this lesson, we should mention two more effects of running this (and every Spiderwiz) application. The first is the logs that are created by the framework under the log folder defined in the configuration file. After running the application you will see that a sub-folder was created with a name representing the running date (e.g. 20-06-02
), under which you will find a file with a name representing the hour of the day (e.g. am10.txt
). Inside that file you will see log messages that are, in this case, similar to what is displayed on the console:
10:54:31:125 Hello World ver. Z1.01 (core version Z2.30) has been initiated successfully 10:54:31:200 Include spiderwiz-admin.jar in your project in order to use www.spiderwiz.org/SpiderAdmin 10:54:33:413 Hello World undeployed
You don’t see the “Hello World” message because this was not logged but just printed to stdout
by our sample application.
For detailed information about the logging system see Spiderwiz Logging System in the project’s Javadoc.
Lastly, you may notice that the configuration file, hello-world.conf
, was automatically changed after the first run of the application. Now it shows something like:
[application uuid]4088df1e-7a23-4688-8d05-80a15b2622be [log folder]/tests/HelloWorld/Logs
The property application uuid
was added by the framework, and it should normally stay there along the life of the application instance. This is an essential part of Spiderwiz routing mechanism and you shall not touch it unless you have a good reason. If you need to move the application to another location on the cloud, move it together with its configuration file with that line inside.
So far so good. If you think that this is a long way around to say “Hello World” you are right, of course. But, hey, when did you last see a shorter “Hello World” application? But don’t worry. Stay with us, and you will soon discover that developing even the most convoluted service mesh is not that much harder than writing this one.
In the next lesson we will start to learn about weaving a service mesh. We will see what are Producers and Consumers, and how easy it is to link them with Spiderwiz.