Tutorial

[evn]Setup your environment

You need to setup your environment properly to follow this tutorial step by step. Please make you have the following software installed on your machine:

  1. Java, JRE or JDK 1.6+

    java-version


     Get Java

  2. Ant 1.7+

    ant-version


     Get Ant

  3. Maven 2 or Maven 3

    mvn-version


     Get Maven

  4. Rythm. Please follow the document guide to download latest Rythm distribution package
    and unzip to a local folder, e.g. C:\

    extract-rythm

[hello] Hello world!

As our first step in the journey, let's first get our feet wet and say “Hello world!” using Rythm.

  1. Create a project folder named “HelloWorld”, and create a src folder under it:

    create-project-folder

  2. Add an ant build.xml file to HelloWorld project:

    create-build-xml

    And copy the content from the github version to your build.xml file

  3. Add a build.properties file to HelloWorld project:

    create-build-properties

    Put the following lines to the build.properties file:

    src=src
    lib=lib
    classes=classes
    
    # change this line to make it point to your rythm folder
    rythm.home=c:\\rythm-engine-1.0-b9-SNAPSHOT
    rythm.lib=${rythm.home}/lib
    
  4. Create the HelloWorld.java source file in the src folder:

    create-helloworld-java

    Add the following lines to your first Rythm program:

    import org.rythmengine.Rythm;
    
    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println(Rythm.render("hello @who!", "rythm"));
        }
    }
    
  5. Now we are ready, and let's run it:

    first-run

    All good, we got the result! But wait, it's hello rythm!, not the Hello World! as we expected. Let's go back to our program and do a bit changes from

    System.out.println(Rythm.render("hello @who!", "rythm"));
    

    to

    System.out.println(Rythm.render("Hello @who!", "World"));
    

    and then run again:

    second-run

    Yes! we made it!

    Now let's change the inline template content into a template file. To make it a bit more fancy, we create it as a web page instead of a plain text file. Following standard Java project convention, we will create the file in a resources folder

    create-template-file

    and add some content into the helloworld.html file:

    @args String who
    <html>
    <head>
    <title>Hello world from Rythm</title>
    </head>
    <body>
    <h1>Hello @who</h1>
    </body>
    </html>
    

    And we have to change our program to make it render an external template file instead of an inline template content. Let change the line from

    System.out.println(Rythm.render("Hello @who!", "World"));
    

    to

    System.out.println(Rythm.render("helloworld.html", "World"));
    

    And run the program again and see what we get:

    third-run

    Oh no, this isn't what we want! What happened?

    Okay here is what's going on: Rythm take “helloworld.html” as a template content rather than an external filename because Rythm cannot find a file named helloworld.html. We need to tell Rythm where the template file is. There are 2 ways to tell Rythm where to load an external file:

    1. Set the home.template property to let Rythm know where the template files are stored. This must be done before calling Rythm to render anything
    2. Put the template file into Java's class path

    Let's try home.template approach first. Change the HelloWorld.java file as the follows:

    import java.util.*;
    import org.rythmengine.Rythm;
    
    public class HelloWorld {
        public static void main(String[] args) {
            // use Map to store the configuration
            Map<String, Object> map = new HashMap<String, Object>();
            // tell rythm where to find the template files
            map.put("home.template", "resources");
            // init Rythm with our predefined configuration
            Rythm.init(map);
            System.out.println(Rythm.render("helloworld.html", "World"));
        }
    }
    

    And run again:

    forth-run

    Now it comes out what we wanted.

    Next step let's try the class path approach. First revert the HelloWorld.java program back to what is previously by commenting out those home.template configuration lines:

    import java.util.*;
    import org.rythmengine.Rythm;
    
    public class HelloWorld {
        public static void main(String[] args) {
            // use Map to store the configuration
            //Map<String, Object> map = new HashMap<String, Object>();
            // tell rythm where to find the template files
            //map.put("home.template", "resources");
            // init Rythm with our predefined configuration
            //Rythm.init(map);
            System.out.println(Rythm.render("helloworld.html", "World"));
        }
    }
    

    And do a bit changes in our build.xml file under the HelloWorld project root folder. What we want to do is to tell ant we need to copy the helloworld.html file from the resources folder to the classes folder before running the program. Let's add the following line

    <copy file="resources/helloworld.html" todir="${classes}"/>
    

    to the init target in the build.xml file, right above the closing </target> tag. After you have finished the init target should looks like the follows:

    <target name="init">
        <tstamp/>
        <mkdir dir="${classes}"/>
        <copy file="resources/helloworld.html" todir="${classes}"/>
    </target>
    

    And then run the program again, you should get the same result as previous.

    To summarize what we have learned from HelloWorld project so far

    1. Calling to Rythm.render() will cause Rythm to process a template with a supplied parameter and return the result
    2. template is passed into Rythm.render as the first parameter, it could be either an inline template content (Hello @who!), or an external template file name (helloworld.html)
    3. the template argument is passed into Rythm.render() following the template parameter (the first parameter)

    Now let's put a little challenge to our HelloWorld project. We want the template not only say “Hello”, but also be able to say “Greeting” depend on user's input. First change the following line in our helloworld.html template file:

    @args String who
    ...
    <h1>Hello @who</h1>
    

    to

    @args String action, String who
    ...
    <h1>@action @who</h1>
    

    Meaning we don't hard code “Hello” in our template, rather, we add a template argument @action so user can change the output of the template by passing different @action to the template.

    Then go to the Java file and add one more parameter to the render line of HelloWorld.java program so it changed from:

    System.out.println(Rythm.render("helloworld.html", "World"));
    

    to

    System.out.println(Rythm.render("helloworld.html", "World", "Greeting"));
    

    Run the program we get

    fifth-run

    See there is a problem in the result, we want to say “Greeting World” and it becomes “World Greeting”, this is because the argument @action is declared before the argument @who in the template source. So just swap the “World” and “Greeting” in the HelloWorld.java will fix the problem.

    In case a template has a lot of arguments we want to use the argument name instead of position to pass the parameters. Rythm support passing template arguments by name. Here is the new HelloWorld.java:

    import java.util.*;
    import org.rythmengine.Rythm;
    
    public class HelloWorld {
        public static void main(String[] args) {
            Map<String, Object> params = new HashMap<String, Object>(2);
            params.put("who", "World");
            params.put("action", "Greeting");
            System.out.println(Rythm.render("helloworld.html", params));
        }
    }
    

    After you putting the new version to your HelloWorld.java file, run the program again. This time we got the correct output:

    sixth-run

    For people who think populating a Map data structure is boring, Rythm provides a utility class NamedParameter to make it easier:

    import java.util.*;
    import org.rythmengine.Rythm;
    import org.rythmengine.utils.*;
    
    public class HelloWorld {
        public static void main(String[] args) {
            NamedParams np = NamedParams.instance;
            System.out.println(
                Rythm.render("helloworld.html", 
                    np.from(
                        np.pair("who", "World"), 
                        np.pair("action", "Greeting"))));
        }
    }
    

    Before we wrap up our HelloWorld project, we want to touch a bit more about Rythm's special @ character. Let's suppose the user design a template where he put an email address inside. As we know all email address contains the @ character. What will happen if we update our template and add an email address like the follows:

    @args String who, String action
    <html>
    <head>
    <title>Hello world from Rythm</title>
    </head>
    <body>
    <h1>@action @who</h1>
    <p>Please contact me at green@rythmengine.com</p>
    </body>
    </html>
    

    Run the program we get this:

    seven-run

    So Rythm complaining rythmengine.com cannot be resolved to a type, obviously it treat the email host as an expression. Ths solution is to put one additional @ to @rythmengine.com, so the email address in a template changes to green@@rythmengine.com. Double @ tell rythm that this is not the special character to lead a syntax element, but rather a literal @ sign. When you finish changing the template source run the program again and it shows the good result:

    eight-run

    Alright I think it is enough for us to wrap up the HelloWorld project. We have learned a lot of things about Rythm though this tiny project:

    1. Calling to Rythm.render() will cause Rythm to process a template with a supplied parameter and return the result
    2. template is passed into Rythm.render as the first parameter, it could be either an inline template content (Hello @who!), or an external template file name (helloworld.html)
    3. the template argument is passed into Rythm.render() following the template parameter (the first parameter)
    4. Rythm.render() accept passing template parameters by position or by name. Use Map<String, Object> to pass the parameters by name
    5. If you need to show the special @ sign in the template directly, double it.

    For the next step we are going to do something serious!

[bookstore]Duke's bookstore

Duke's bookstore is coming soon. Stay tuned!