{"id":388,"date":"2020-05-25T09:38:30","date_gmt":"2020-05-25T09:38:30","guid":{"rendered":"http:\/\/spiderwiz.org\/project\/?page_id=388"},"modified":"2025-04-09T06:15:57","modified_gmt":"2025-04-09T06:15:57","slug":"lesson-1","status":"publish","type":"page","link":"https:\/\/spiderwiz.org\/project\/tutorial\/lesson-1\/","title":{"rendered":"Lesson 1: Hello World"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Welcome to the first lesson of the&nbsp;<strong>Spiderwiz Tutorial<\/strong>. In this lesson you will learn how to build a basic functional&nbsp;<strong>Spiderwiz Application<\/strong>. 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 <em>Spiderwiz<\/em> applications is not that much harder than writing this simple one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The application contains one data object \u2013 <code>HelloWorld<\/code>, which prints, guess what, \u201cHello World\u201d.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So we start by creating a new empty Java application project. We use <a href=\"https:\/\/maven.apache.org\/\">Maven<\/a> along this tutorial, but you can use any project management tool as you may find convenient. The <em>Spiderwiz<\/em> dependency is described in the <a href=\"http:\/\/spiderwiz.org\/project\/download\/\">Download<\/a> page and we will copy it here for convenience:<br><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>&lt;dependency&gt;\n    &lt;groupId&gt;org.spiderwiz&lt;\/groupId&gt;\n    &lt;artifactId&gt;spiderwiz-core&lt;\/artifactId&gt;\n    &lt;version&gt;4.0&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"> Our application comprises two source files \u2013 <code>HelloWorldMain.java<\/code>, which is the entry (and exit) point of the application, and <code>HelloWorld.java<\/code>, which codes the <code>HelloWorld<\/code> object. Let\u2019s see the first and then explain it: <\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>package org.spiderwiz.tutorial.lesson1;\n\nimport java.util.List;\nimport org.spiderwiz.core.DataObject;\nimport org.spiderwiz.core.Main;\n\n\/**\n * Provides the entry point of the application. Initializes and executes the Spiderwiz framework.\n *\/\npublic class HelloWorldMain extends Main{\n    private static final String ROOT_DIRECTORY = &quot;&quot;;\n    private static final String CONF_FILENAME = &quot;hello-world.conf&quot;;\n    private static final String APP_NAME = &quot;Hello World&quot;;\n    private static final String APP_VERSION = &quot;Z1.01&quot;;  \/\/ Version Z1.01: Initial version\n\n    \/**\n     * Class constructor with constant parameters.\n     *\/\n    public HelloWorldMain() {\n        super(ROOT_DIRECTORY, CONF_FILENAME, APP_NAME, APP_VERSION);\n    }\n\n    \/**\n     * Application entry point. Instantiate the class, initialize the instance, then call a command-line hook that would shut down\n     * the application when &quot;exit&quot; is typed.\n     * \n     * @param args the command line arguments. Not used in this application.\n     *\/\n    public static void main(String[] args) {\n        HelloWorldMain main = new HelloWorldMain();\n        if (main.init())\n            main.commandLineHook();\n    }\n    \n    \/**\n     * @return the list of produced objects, in this case HelloWorld is the only one.\n     *\/\n    @Override\n    protected String[] getProducedObjects() {\n        return new String[]{HelloWorld.ObjectCode};\n    }\n\n    \/**\n     * @return the list of consumed objects, in this case HelloWorld is the only one.\n     *\/\n    @Override\n    protected String[] getConsumedObjects() {\n        return new String[]{HelloWorld.ObjectCode};\n    }\n\n    \/**\n     * Add HelloWorld class to the object factory list of this application.\n     * @param factoryList\n     *\/\n    @Override\n    protected void populateObjectFactory(List&lt;Class&lt;? extends DataObject&gt;&gt; factoryList) {\n        super.populateObjectFactory(factoryList);\n        factoryList.add(HelloWorld.class);\n    }\n\n    \/**\n     * Create a HelloWorld object, set its field and commit it.\n     *\/\n    @Override\n    protected void postStart() {\n        try {\n            HelloWorld helloWorld = createTopLevelObject(HelloWorld.class, null);\n            helloWorld.setSayHello(&quot;Hello World&quot;);\n            helloWorld.commit();\n            return;\n        } catch (NoSuchFieldException | IllegalAccessException ex) {\n            ex.printStackTrace();\n        }\n    }\n}<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Every Spiderwiz application must extend <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html\">org.spiderwiz.core.Main<\/a> class and call its <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#init()\">init()<\/a> method in order to set the framework mechanism in motion. We do it with <code>HelloWorldMain<\/code>. The <code>Main<\/code> constructor requires four parameters \u2013 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next we implement a static <code>main()<\/code> method (line 29) that serves as the application\u2019s entry point. Inside the method we create an instance of <code>HelloWorldMain<\/code> and call its <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#init()\">init()<\/a> method. If successful, we set up a cleanup and exit point by calling <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#commandLineHook()\">Main.commandLineHook()<\/a>. This is a shortcut for adding a shutdown hook that calls <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#cleanup()\">Main.cleanup()<\/a> upon application termination and reading lines from the standard input stream until the command &#8220;exit&#8221; is encountered, then terminating the application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We implement the abstract methods <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#getProducedObjects()\">Main.getProducedObjects()<\/a> (line 39) and <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#getConsumedObjects()\">Main.getConsumedObjects()<\/a> (line 47). The only data object that we both produce and consume is <code>HelloWorldMain<\/code>, so in both methods we return a list containing a single element &#8211; <code>HelloWorld.ObjectCode<\/code>. We will come back to it in a moment when we discuss <code>HelloWorld.java<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We also override <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#populateObjectFactory(java.util.List)\">Main.populateObjectFactory()<\/a> (line 56). This is where we register the class that implements <code>HelloWorld<\/code>. Note that before adding this class to the factory list, we must call <code>super.populateObjectFactory(factoryList)<\/code> in order to preserve pre-registered classes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Last is to override <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#postStart()\">Main.postStart()<\/a> (line 65) that is called after framework initialization. We create a <code>HelloWorld<\/code> object (using <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/Main.html#createTopLevelObject(java.lang.Class,java.lang.String)\">createTopLevelObject()<\/a>), set its <code>sayHello<\/code> property and <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/DataObject.html#commit()\">commit<\/a> it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The second file, <code>HelloWorld.java<\/code>, is where we define the <code>HelloWorld<\/code> object and implement its task. Here it goes:  <\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>package org.spiderwiz.tutorial.lesson1;\n\nimport org.spiderwiz.annotation.WizField;\nimport org.spiderwiz.core.DataObject;\n\n\/**\n * Implements HelloWorld data object.\n *\/\npublic class HelloWorld extends DataObject{\n\n    \/**\n     * Mandatory public static field for all data objects.\n     *\/\n    public final static String ObjectCode = &quot;HLWRLD&quot;;\n    \n    @WizField private String sayHello;\n\n    public String getSayHello() {\n        return sayHello;\n    }\n\n    public void setSayHello(String sayHello) {\n        this.sayHello = sayHello;\n    }\n\n    \/**\n     * @return null as this is a root object.\n     *\/\n    @Override\n    protected String getParentCode() {\n        return null;\n    }\n\n    \/**\n     * @return true as this object is disposable.\n     *\/\n    @Override\n    protected boolean isDisposable() {\n        return true;\n    }\n\n    \/**\n     * Do the consumer work.\n     * @return true to indicate that the event has been handled.\n     *\/\n    @Override\n    protected boolean onEvent() {\n        System.out.println(getSayHello());\n        return true;\n    }\n}<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Classes that implement <em>Spiderwiz Data Objects<\/em> extend <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/DataObject.html\">org.spiderwiz.core.DataObject<\/a>. In order to participate in the game, classes that extend this class must define a <code>public static String<\/code> field named <code>ObjectCode<\/code> 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 &#8220;HLWRLD&#8221;. Our class also contains one String property \u2013 <code>sayHello<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next we need to implement two abstract methods &#8211; <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/DataObject.html#getParentCode()\">getParentCode()<\/a> and <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/DataObject.html#isDisposable()\">isDisposable()<\/a>. The first returns <code>null<\/code> because the class defines a <em>root object<\/em> (that has no parent). The second returns <code>true<\/code> because the object is <em>disposable<\/em> \u2013 it can be discarded after its event is handled.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We achieve our task by overriding <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/DataObject.html#onEvent()\">onEvent()<\/a>. This method is fired when the producer of the object <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/DataObject.html#commit()\">commits<\/a> it. Our implementation gets the value of <code>sayHello<\/code> property and outputs it to the console. We return <code>true<\/code> to indicate that we have completely handled the event. (You will see later why this is important).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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:<br><\/p>\n\n\n\n<pre>Could not open setting file hello-world.conf<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>hello-world.conf<\/code> is the configuration file name as we defined in <code>HelloWorldMain<\/code>. Every Spiderwiz application requires a <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/doc-files\/config.html\">configuration file<\/a>. 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).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since we prefer to have a fixed place for our <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/doc-files\/logging.html\">application\u2019s log folder<\/a>, we will include one line in <code>hello-world.conf<\/code>:<br><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>[log folder]\/tests\/HelloWorld\/Logs<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Now we are ready to run. Shoot it, and you will see the following on your console:<br><\/p>\n\n\n\n<pre>Hello World ver. Z1.01 (core version Z2.30) has been initiated successfully\nInclude spiderwiz-admin.jar in your project in order to use www.spiderwiz.org\/SpiderAdmin\nHello World\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first message is displayed by the framework when every Spiderwiz application is initialized. Application name and version are taken from the call to <code>Main<\/code> class constructor as shown above. \u201cCore version\u201d is the version of the Spiderwiz framework used.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ignore the second message for now, we will come back to it later.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The third message, \u201cHello World\u201d, is what our HelloWord object prints.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At this point, the application is still active and waiting for user input. Type <code>exit<\/code> (case insensitive), the application will terminate and you will see the following:<br><\/p>\n\n\n\n<pre>exit\nHello World undeployed\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">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. <code>20-06-02<\/code>), under which you will find a file with a name representing the hour of the day (e.g. <code>am10.txt<\/code>). Inside that file you will see log messages that are, in this case, similar to what is displayed on the console:<br><\/p>\n\n\n\n<pre>10:54:31:125 Hello World ver. Z1.01 (core version Z2.30) has been initiated successfully\n10:54:31:200 Include spiderwiz-admin.jar in your project in order to use www.spiderwiz.org\/SpiderAdmin\n10:54:33:413 Hello World undeployed\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You don\u2019t see the \u201cHello World\u201d message because this was not logged but just printed to <code>stdout<\/code> by our sample application.<br><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For detailed information about the logging system see <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/doc-files\/logging.html\">Spiderwiz Logging System<\/a> in the project\u2019s Javadoc.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lastly, you may notice that the configuration file, <code>hello-world.conf<\/code>, was automatically changed after the first run of the application. Now it shows something like:<br><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>[application uuid]4088df1e-7a23-4688-8d05-80a15b2622be\n[log folder]\/tests\/HelloWorld\/Logs<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The property <code>application uuid<\/code> 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So far so good. If you think that this is a long way around to say \u201cHello World\u201d you are right, of course. But, hey, when did you last see a shorter \u201cHello World\u201d application? But don\u2019t 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the <a href=\"http:\/\/spiderwiz.org\/project\/tutorial\/lesson-2\/\">next lesson<\/a> we will start to learn about weaving a service mesh. We will see what are <em>Producers<\/em> and <em>Consumers<\/em>, and how easy it is to link them with Spiderwiz.<br><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to build a basic functional Spiderwiz Application. The application will contain one data object &#8211; HelloWorld, which will print, guess what, &#8220;Hello World&#8221;.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":145,"menu_order":1,"comment_status":"closed","ping_status":"closed","template":"tutorial-child.php","meta":{"footnotes":""},"class_list":["post-388","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/388","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/comments?post=388"}],"version-history":[{"count":59,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/388\/revisions"}],"predecessor-version":[{"id":1420,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/388\/revisions\/1420"}],"up":[{"embeddable":true,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/145"}],"wp:attachment":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/media?parent=388"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}