Core Java

Java Everywhere: Write Once Run Anywhere with DukeScript

For quite some time already, Java has been failing on its “write once, run anywhere” promise. DukeScript would like to change that by enabling a clean separation of view and logic in cross-platform applications. In this article, a simple scenario is used to introduce the basics of DukeScript.

For many years, Java Swing enabled developers to write applications that could run on any operating system. That all came to an end with the arrival of smart phones, tablets, and embedded computers. In the enterprise, the desktop dominated for many years. In the meantime, however, every IT project includes plans for a future where the application will need to be ported to mobile platforms. Building native applications for all platforms requires special skills and is expensive in terms of both maintenance and development. What is to be done?

DukeScript (DukeScript.com) gives you a Java-based solution again that enables cross-platform applications to be developed. DukeScript provides a clean separation of view and logic enabling UI designers to focus on UI design and coders to focus on writing well-tested application code.

The Best of Both Worlds

The basic idea of DukeScript is simple. Every operating system offers the possibility to run basic Java applications. On Android, that’s done natively with the Dalvik Runtime and ART, on iOS you have RoboVM, and on many other platforms you have the OpenJDK and Oracle’s Java SE Embedded. Simultaneously, there are a range of Java virtual machines available for the browser (TeaVM, Doppio, Bck2Brwsr), which all function without a browser plugin. What’s missing here, however, is a uniform view technology, while, at the same time, a modern HTML renderer component is available on almost all platforms. When you combine these disparate technologies, virtual machines, and components together, you have the basis of a comprehensive framework.

By combining all these pieces together, all their advantages can be leveraged, at the same time. For example, Java has, of all the programming languages, the best IDE support and enables maintainable code to be written, and to easily be refactored, thanks to its static typing. For these reasons, it is better suited than JavaScript as the language to use for large projects. On the UI side, for HTML and CSS, you have access to an arsenal of free and commercial frameworks and services. When UI and business logic are cleanly separated from each other, we can make use of the complete arsenal, without any exceptions and without any limitations. To demonstrate these points, we’re now going to develop and style a To Do List application.

The ViewModel

DukeScript uses the Model-View-ViewModel (MVVM) design pattern for the separation of visualization and logic. The View is defined in a markup language and binds active elements declaratively to the properties of the ViewModel. By means of this architecture, the ViewModel does not need to know about the View. Without any changes, the View can be swapped out from the ViewModel. All the View logic is defined in the ViewModel. In the MVVM pattern, the Model is the remainder of the application, while how the Model is to be visualized is undefined and, therefore, unlimited.

epple_dukescript_1a

Let’s start with the ViewModel. Listing 1 shows how the ViewModel is created. The @Model annotation ensures that a class named Task will be generated. At the same time, setters and getters for the properties title and complete will automatically be created. This saves the developer from having to write a bunch of code and the structure of the ViewModel class is compact and understandable at a single glance. The creation process happens automatically in the background, so that the class is available immediately during development in the IDE.

Listing 1

@Model(className = "Task", properties = {
@Property(name = "title", type = String.class),
@Property(name = "complete", type = boolean.class)
})
public static class TaskModel {}

For more complex tasks, we can wrap our Model. Listing 2 shows a TaskListViewModel that represents a list of Tasks, together with additional properties. The @Function annotation marks methods that can be called from the View.

Listing 2

@Model(className = "TaskListViewModel", properties = {
  @Property(name = "input", type = String.class),
  @Property(name = "tasks", type = Task.class, array = true),
  @Property(name = "editing", type = Task.class)
}, targetId = "body")
final class TaskListViewModelDefinition {
 
  @Function
  public static void editTask(TaskListViewModel list, Task data) {
    list.setEditing(data);
  }
 
  @Function
  public static void stopEditing(TaskListViewModel list) {
    list.setEditing(null);
  }
 
  @Function
  @ModelOperation
  public static void deleteTask(TaskListViewModel model, Task data) {
    model.getTasks().remove(data);
  }
 
  @Function
  @ModelOperation
  public static void addTask(TaskListViewModel model) {
    if (null == model.getInput() || model.getInput().length() == 0) {
      return;
    }
    Task task = new Task(model.getInput(), false);
    model.setInput(""); 
    model.getTasks().add(task);
  }
}

Unit Tests with DukeScript

Two methods in the code above are marked as @ModelOperation. In DukeScript, you do that with methods that also need to be called from outside the View, which in our example (Listing 3) is a unit test. The test shows how the generated ViewModel can be used. In the first test case we simulate the keying in of a new task by a user, who enters a task (setInput) and confirms the input, for example via a button or the Enter key (addTask). Even though there is no View yet, we can already test the ViewModel’s methods. This scenario shows really well the clean decoupling of the components.

Listing 3

public class TodoListTest {
  @Test
  public void testAddTask() {
    TaskListViewModel taskList = new TaskListViewModel();
    Assert.assertEquals(taskList.getTasks().size(), 0);
    taskList.setInput("Buy milk!");
    taskList.addTask();
    Assert.assertEquals(taskList.getTasks().size(), 1);
    Task task = taskList.getTasks().get(0);
    Assert.assertEquals(task.getTitle(), "Buy milk!");
  }
  @Test
  public void testDeleteTask() {
    TaskListViewModel taskList = new TaskListViewModel();
    taskList.getTasks().add(new Task("Buy milk!", false));
    Assert.assertEquals(taskList.getTasks().size(), 1);
    Task task = taskList.getTasks().get(0);
    taskList.deleteTask(task);
    Assert.assertEquals(taskList.getTasks().size(), 0);
  }
}

Serialization with JSON

When you look at the annotations that define the ViewModel classes, you should notice that they appear to be a bit like JSON messages. That’s no coincidence, since great value is placed in DukeScript in being able to easily integrate with JSON. The toString method of a ViewModel class returns a JSON string. Just as easily you can create a ViewModel object from a JSON string. Listing 4 illustrates how the ViewModel is serialized and deserialized again. When all you need is a copy of an object, use the clone method instead. The purpose of Models.parse is to deserialize messages from a server or from locally persisted data.

Listing 4

TaskListViewModel copy;
String json = original.toString();
InputStream inputStream = new ByteArrayInputStream( 
  json.getBytes(StandardCharsets.UTF_8));
try {
  copy = Models.parse(BrwsrCtx.findDefault(TaskListViewModel.class),
  TaskListViewModel.class, inputStream);
} catch (IOException ex) {
  Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}

The View

By default, DukeScript uses HTML to define the View. Thanks to the clean separation of the View from the ViewModel, other formats can be used, too. The dukescript-javafx project demonstrates how that works. With this project, DukeScript ViewModels can easily be visualized in JavaFX applications. The language used for defining the Views, in this case, is FXML. Controls.js also uses an alternative format for the definition of Views, which will be discussed later in this article.

For the To Do List application that we’re creating in this article, we’ll simply use the standard HTML format, shown in Listing 5. Elements that depend on the ViewModel make use of the data-bind attribute. In this way, they are declaratively bound to the properties and methods of the ViewModel. Also, for-each loops and conditional statements can be defined in this way.

In most cases, the data-bind attribute does everything you need. However, sometimes you’ll need to create an HTML element, though the HTML element may not be required for the View. For these cases, there are special comments. In the example in Listing 5 below, via <!– ko foreach: tasks –> we iterate over the list of Tasks, while <!– /ko –> closes the loop. More about binding syntax can be learned from the comments in Listing 5, as well as from the DukeScript site.

Listing 5

<ul>
    <!-- Iterate over the List of Tasks in the TaskListViewModel -->
    <!-- ko foreach: tasks -->
    <li>
        <!-- When the Task is not being edited... -->
        <!-- ko ifnot: $root.editing()===$data -->
        <!-- ...bind the checkbox state to the Task property named "complete" -->
        <input type="checkbox" name="" data-bind="checked: complete"/>
        <!--...bind the text of the span to the Task property named "title" -->
        <span data-bind="text: title"></span>
        <span class="btns">
            <!-- ...on click, call the 'editTask' method -->
            <button  data-bind="click: $root.editTask">Edit</button>
            <!-- ...on click, call the 'deleteTask' method -->
            <button  data-bind="click: $root.deleteTask">Delete</button>
        </span>
        <!-- /ko -->
        <!-- When the Task is being edited, show an input field... -->
        <!-- ko if: $root.editing()===$data -->
        <!-- ...on Submit (Enter) call the 'stopEditing' method -->
        <form data-bind="submit: $root.stopEditing">
            <!-- ...bind the entered text to the Task property named "title"`-->
            <input type="text" data-bind="textInput: title"/>
        </form>
        <!-- /ko -->
    </li>
    <!-- /ko -->
    <li>
        <!-- On Submit (Enter) call the 'addTask' method... -->
        <form data-bind="submit: addTask">
            <!-- ...bind the entered text to the Task property named "input" -->
            <input type="text" data-bind="textInput: input"/>
        </form>
    </li>
</ul>

The functioning prototype defined above renders as shown below. Visually it may appear a bit humble, so let’s change that in the sections that follow!

eppleton-english-4

The Designer/Developer Experiment

Before the arrival of DukeScript, several other frameworks have arisen with the promise of being able to decouple design from development. In the real world, very little tends to remain from that promise. Design tends to require proprietary tools that raise not much more than a tired laugh from professional designers. An example of this is JavaFX. With the JavaFX Scene Builder, you can’t even create a polygon, while the future of the tool is anything but clear. Moreover, the task of creating a design tends to be left to the developer, who needs to spend time getting comfortable with a whole range of different and conflicting tools to do so.

To test whether all this works better with DukeScript, I’ve set myself a small challenge. I started by finding and buying a completed design for my To Do List application, shown in the screenshot below.

eppleton-english-3

I then looked around for someone to change the PSD file to HTML (you can find hundreds of services for this task online, when you search for “PSD to HTML”). I ended up choosing Rapidxhtml because this service is cheap and, despite that, has had positive reviews.

For a “real” project, and to ensure better communication, I’d definitely prefer direct interaction with a designer. However, for this experiment it is an advantage that communication is limited to credit cards and web forms since in this way we can ensure that the designer isn’t aware of any special requirements that DukeScript might demand.

I upload the PSD file to the website and indicate my styling requirements. For example, checkboxes and scrollbars cost extra since the applicable styling is more elaborate. For this reason, I decide to not go for these more elaborate choices. In the end, the complete order isn’t all that expensive. Per page, the conversion costs, including all the selected extras (width resizing, HTML5 with CSS3, etc) around EUR 170. Payment is up front and delivery is, in principle, within 24 hours. Sounds good and I waited in suspense.

Already after 6 hours, I received an e-mail with a link to the design. Not bad. At first glance, the result looked good, though the width resizing didn’t work. Two hours later, after passing back my review comments, I had a new version with correctly functioning resizing. The screenshot below shows the result.

epple_dukescript_4

Further remarks on small imperfections were ignored. For a “real” project, a premium service or a design agency with applicable proposals is probably a better choice. Listing 6 shows the HTML I received.

Listing 6

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <title>TODO</title>
        <meta name="robots" content="index, follow">
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta name="author" content="RapidxHTML" />
        <link rel="stylesheet" href="css/normalize.css">
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body>
        <!--[if lt IE 7]>
        <p class="chromeframe">You are using an outdated browser.
        <a href="http://browsehappy.com/">Upgrade your browser today</a> 
        or <a href="http://www.google.com/chromeframe/?redirect=true">install 
        Google Chrome Frame</a> to better experience this site.</p>
        <![endif]-->
        <!-- box -->
        <div id="box">
            <div class="box-cont">
                <header class="box-header">
                    <div class="box-title">My tasks for today</div>
                    <div class="box-links">
                        <a href=""><img src="images/btn-cal.png" alt="" /></a>
                        <a href=""><img src="images/btn-settings.png" alt="" /></a>
                    </div>
                </header>
                <section class="todo">
                    <section class="todo-bg">
                        <ul class="todo-list">
                            <li class="done">
                                <input type="checkbox" name="" 
                                       class="toggle" checked="checked" />
                                Design a to-do list 
                                <span class="btns">
                                 <a href=""><img src="images/icon-edit.png" /></a>
                                 <a href=""><img src="images/icon-delete.png" /></a>
                                </span>
                            </li>
                            <li><input type="checkbox" name="" class="toggle" />
                                Design a super task<br />with 2 lines 
                                <span class="btns">
                                  <a href=""><img src="images/icon-edit.png" /></a>
                                  <a href=""><img src="images/icon-delete.png" /></a>
                                </span>
                            </li>
                            <li><input type="checkbox" name="" class="toggle" />
                                fix the dog toy 
                                <span class="btns">
                                  <a href=""><img src="images/icon-edit.png" /></a>
                                  <a href=""><img src="images/icon-delete.png" /></a>
                                </span>
                            </li>
                            <li><input type="checkbox" name="" class="toggle" />
                                buy coffee <span class="btns">
                                  <a href=""><img src="images/icon-edit.png" /></a>
                                  <a href=""><img src="images/icon-delete.png" /></a>
                                </span>
                            </li>
                            <li><input type="checkbox" name="" class="toggle" />
                                feed the dog <span class="btns">
                                  <a href=""><img src="images/icon-edit.png" /></a>
                                  <a href=""><img src="images/icon-delete.png" /></a>
                                </span>
                            </li>
                            <li><input type="checkbox" name="" class="toggle" />
                                take a walk with the dog 
                                <img src="icon_smile.gif" 
                                     alt=":)" 
                                     class="wp-smiley"> 
                                <span class="btns">
                                  <a href=""><img src="images/icon-edit.png" /></a>
                                  <a href=""><img src="images/icon-delete.png" /></a>
                                </span>
                            </li>
                        </ul>
                    </section>
                </section>
            </div>
        </div>
        <!-- / box -->
        <script type="text/javascript" src="js/jquery.js"></script>
        <script type="text/javascript" src="js/modernizr-2.6.2.min.js"></script>
    </body>
</html>

Next I had to add life to the UI. The bindings that you see below you’re already familiar with, from the prototype. Listing 7 shows the rewritten code.

Listing 7

<!DOCTYPE html>
<head>
    <title>TODO</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="css/normalize.css">
    <link rel="stylesheet" href="css/style.css">
</head>
<body id="body">
    <!-- box -->
    <div id="box">
        <div class="box-cont">
            <header class="box-header">
                <div class="box-title">My tasks for today</div>
                <div class="box-links">
                    <a href=""><img src="images/btn-cal.png" alt="" /></a>
                    <a href=""><img src="images/btn-settings.png" alt="" /></a>
                </div>
            </header>
            <section class="todo">
                <section class="todo-bg">
                    <ul class="todo-list" >
                        <!-- ko foreach: tasks -->   
                        <li>
                            <!-- ko ifnot: $root.editing()===$data -->
                            <input type="checkbox" name="" class="toggle" 
                                   data-bind="checked: complete"/>
                            <span data-bind="text: title"></span>
                            <span class="btns">
                                <img src="images/icon-edit.png" alt="" 
                                     data-bind="click: $root.editTask"  />
                                <img src="images/icon-delete.png" alt="" 
                                     data-bind="click: $root.deleteTask" />
                            </span>
                            <!-- /ko -->
                            <!-- ko if: $root.editing()===$data -->
                            <form data-bind="submit: $root.stopEditing">
                                <input type="text" data-bind="textInput: title"/>
                            </form>
                            <!-- /ko -->
                        </li>
                        <!-- /ko -->
                        <li>
                            <form data-bind="submit: addTask">
                                <input type="text" data-bind="textInput: input"/>
                            </form>
                        </li>
                    </ul>
                </section>
            </section>
        </div>
    </div>
    <!-- / box -->
</body>
</html>

In the screenshot below, you can see the result.

eppleton-english-1

The UI looks like the design example and functions on all platforms. With that, the experiment was a complete success—it was possible to delegate the design completely. Without special requirements the designer and the conversion service were able to deliver usable assets that could be integrated into the application with minimal changes.

In this way, the developer is able to focus fully on the implementation of the required functionality and concentrate on the business logic of the application. Those who have experience with desktop application development know that, on a regular basis, a lot of development time is wasted on converting the application design. With DukeScript, you can confidently delegate these concerns to design professionals, which frees up valuable time for the implementation of the functional requirements of the application.

How to Develop DukeScript Applications

Currently, DukeScript supports the various desktop platforms, as well as iOS, Android, and the browser. The available Maven archetypes create, for each supported platform, a separate subproject. For each platform, specific tasks are made available for testing and packaging the subproject. For example, the subprojects for Android and iOS offer the possibility to run them in a simulator or on a connected device, while the subproject for the browser automatically builds a static website.

Recent enhancements have enabled support for embedded platforms to enable DukeScript to be used in IoT applications. Therefore, since Oracle ended the support of JavaFX on embedded platforms, there’s now again the possibility of developing professional GUIs with Java on embedded devices. In these cases, the OpenJDK is usually sufficient as JVM, so that no costly Java SE embedded licensing is needed, even for commercial projects.

With the help of the Maven archetypes, DukeScript application development can be done via the various Java IDEs. Specifically for NetBeans IDE, there’s also a plugin with a range of supporting features to make development even more comfortable. For example, there’s code completion in the HTML Editor for the data-bind directive, while the DOM Inspector enables you to inspect the running application. Changes to HTML and CSS are automatically picked up by the running application. From version 0.8 onwards, even hot swapping has been introduced to the Maven archetypes. Changes in the code are automatically deployed into the running application and can immediately be tested, as shown in the screenshot below. Even JavaScript developers should be jealous, since—unlike with JavaScript development—the state of the application is maintained, without requiring any kind of manual reloading.

eppleton-english-2

Controls.js for Java—DukeScript without HTML

DukeScript strives to enable cross-platform development without JavaScript. Normally, the frontend of DukeScript applications is written with the help of HTML and CSS. This aspect of the development of the application can, as has been shown, be delegated, while it continues to require tests to be written and adaptations to be done for the various platforms, as well as the manual editing of HTML files.

As an alternative approach, the Controls.js for Java project lets you develop a complete UI via drag and drop. When taking this approach, you have Maven archetypes and a NetBeans plugin to support you. Controls.js makes use of its own component library. Each individual control can be visualized via skins, while a Skin Editor is provided for creating custom skins. The ViewModel remains the same, while the binding is done with the help of visual editors.

epple_dukescript_7

Conclusion

To conclude, let’s examine the the million dollar question: “Is DukeScript appropriate for my project?” The advantages are clear.

  • With a common codebase, applications can be developed for many platforms.
  • The workflow is well-structured, while rich and well established tools are available to support you.
  • Design tasks can be delegated, significantly minimizing the cost of application maintenance and development.

Despite that, DukeScript is not the best solution for each and every application. Those who value their own branding, together with a uniform cross-platform design, are better served by DukeScript than those who are interested in a native look and feel for their application on each device to which it will be deployed. I’d also not try to create a 3D modeling tool via DukeScript, nor any kind of application that needs to make use of optimized rendering pipelines.

However, DukeScript is a very good choice for business applications. For simple business applications, it pays off to use Controls.js for Java, which enables a rapid application development workflow. Also, for applications with a server-backend, DukeScript is well suited, thanks to its simple communication mechanisms. Overall, DukeScript offers Java developers a smooth entrypoint into cross-platform development, without requiring the abandonment of the world’s most widely used programming language, which is statically typed with the best IDE support, certainly better than any other programming language in the world today.

Toni Epple

Anton is a consultant worldwide for a wide variety of companies, ranging from startups to Fortune 500 companies, in many areas, including finance institutions and aerospace. His main interest is Client side development, and he has authored books and numerous articles on this topic. He is a member of the NetBeans Dream Team and a Oracle Java Champion. In 2013 he was elected as a JavaONE Rockstar, in 2014 he received a Duke’s Choice Award for his work on DukeScript.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button