Getdown Java – The funky application updater

Getdown Java – The funky application updater

Reading Time: ~ 10 minutes

Ok, let’s take this right out of the way and Getdown to the point: Other than the name recalling the famous song from Kool & the Gang (which incidentally you feel like your computer broke when watching the video clip) this post doesn’t have any relation to the funk movement. UNLESS of course you get, as I do, your kicks from some cool and hip coding sessions, in which case you are in for a treat!

Getdown with the Problem

What problem is Getdown trying to solve?

The problem of updating your application on a client’s machine!

There are a couple of ways how to do this:

  • You can never update your application. (don’t do this)
  • You can program the perfect application on the first go. (alright I can’t say that with a straight face)
  • You can tell the client to download and install a new version. (a lot of hassle if you ask me)
  • You can quietly update it without the client even realizing (= happy client).

Of course the last one is a much more desirable alternative. You can also prompt the user for the update instead of doing it quietly.

Why create a new way?

Some of you may be wondering why create a new method of doing this if Java Web Start already did it? On their Rationale Page, the guys from Getdown explain why they thought Java Web Start (JWS from now on) was lacking behind and how they sought to improve it. I will sum up the problems and their goals with getdown here:

Problems

  • JWS fails irrecoverably. And frequently the only way around it is uninstalling and reinstalling the application
  • Due to caching proxies, proxies that change headers or even mess with the request URI, JWS also fails often
  • The scalability lacks since JWS uses a not-so-simple protocol that requires a running servlet engine to service it.
  • JWS also has a big choice of functionalities which end up bloating the mechanism and, most of the time, is not useful for anyone other than Sun itself.
  • The choice of where to place the data by JWS is a questionable one. It places on several different folders and the location is not know to the application without it trying to do some guess work.
  • The passing of arguments to the JVM is restricted to a pre-defined set.

Design Goals

To address these problems outlined above, Getdown made some design goals:

  • Every file will be check-summed and any failure on this will result in a re-download of the corrupt file. The user will have zero effort on this. The application can also, periodically, re-validate the files to prevent corruption.
  • To avoid problems with using the internet, Getdown will use files that never change.
  • Files will be simple plain files that can be served using the simplest and most scalable HTTP server.
  • Getdown will do nothing other than what is necessary to download, update and invoke a single application.
  • All the application files will be stored in a single directory (and subdirectories), which can reside anywhere in the system. The application will be told where this folder is located.
  • Arguments will be allowed to be passed to the underlying JVM.

 

These problems and design goals were written here in a condensed form. For more information visit their Rationale page (linked above).

How does it work?

Now the way it works it actually quite simple. There is an step-by-step explanation on their website, however, I prefer things visually depicted so I made a workflow of the process:

Getdown process workflow
Click on the image to enlarge it

On the most perfect run, it will go to 3 of the 5 areas: Blue, yellow and green. But if needed it will perform an upgrade (pink) and even try a last resort (purple) if there is a problem.

Speaking about problems, getdown also has a quite robust recovery system for some scenarios like:

  • A file is partially downloaded due to network failure.
  • The digest.txt file (will be discussed shortly) becomes corrupt
  • The getdown.txt file (will be discussed shortly) becomes corrupt
  • The version.txt file (will be discussed shortly) becomes corrupt
  • User’s drive is full or their network connection is down

For all these cases there is a recovery scenario which can be seen here.

Example Project

Now, us being programmers, we want to see some code.

Let’s create a simple application to serve to our “clients” and let’s create the necessary files and project to use getdown to get that application to the masses.

If you don’t know how to create a Maven project than, my friend, I can only point you to the post on how to do it. (It is a very short post… it’s worth it)

First in order to have something to show, we are creating a basic (and I really mean basic here) JavaFx8 application. There is absolutely nothing to it: a mock button in the middle of a box.

Here is the code for it (the project outline is shown after the classes are all in its place):

The Main Class

This class will only kick-start everything. It loads the view file (the fxml), sets a title and defines the window size.

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

 

The Controller Class

This one is just a Stub, hence there appears to be no sense in having it. However if you want to add some functionalities to that button later, or something else, here is the place.

public class Controller {
}

 

The View

The fxml file can be substituted by simple programatically set-up of the view, however for the sake of simplicity we make use of this faster/easier solution:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>


<GridPane alignment="center" hgap="10" prefHeight="100.0" prefWidth="100.0" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:controller="org.fdiez.Controller">
   <columnConstraints>
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
   </rowConstraints>
   <children>
      <Button mnemonicParsing="false" text="BTrululu" />
   </children>
</GridPane>

 

The POM

Since this is a Maven project we also have a pom.xml file, thus let’s check it out. This file already contains the necessary stuff to run the Getdown project successfully which will be explained ahead.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.fdiez</groupId>
    <artifactId>getdown</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <finalName>getdownEx</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.bitbucket.joxley</groupId>
                <artifactId>getdown-maven-plugin</artifactId>
                <version>0.0.1</version>
                <configuration>
                    <appdir>target</appdir>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>digest</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.5</version>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/resources/</directory>
                                    <filtering>true</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

The structure

If you followed along, and placed stuff around the project, you’ve hopefully ended up with something similar to this:

Structure of a Maven Project for Getdown

Starting the getdown fun

You can already run your “application” if you run the Main class. Now it is time to ship these to your customers.

So first you have to prepare the files. You need the file you’ll send to your customer and some files you’ll put behind an easy Webserver that support the http serving of files (check how do this locally).

Getdown Version

For this post we are using the most current version of Getdown available Version 1.6.2.

In the newer versions of getdown we now generate 2  digest files instead of 1. So in some cases it will fail if you try to generate the code yourself.

Configuring the Project

Alright, with that being said, we need to create the getdown.txt file which will give our downloader/updater some information on what it needs to download and check.

For that let’s add a new file under resources which will call getdown.txt and add the following content:

# The URL from which the client is downloaded
appbase = http://localhost:1234

# UI Configuration
ui.name = fdiez.org Getdown Example Application

# Application jar files
code = getdownEx.jar

# The main entry point for the application
class = org.fdiez.Main

version=1

There are several other options available, including more to configure the UI of the downloader. For example, you can put a background image in the downloader (which you should of course provide), among other goodies.

These, however are the most important ones:

  • appbase: this is the url where you’ve uploaded your application jar, the digest and the getdown.txt
  • version: used to match against the version online (called “appbase”)
  • code: the application jar file(s) names. (The name we will set on the POM in the next step… stay tuned)

Best Shot at pipelining the process

Now this is great, and we would have to start preparing all by hand (and we still have to do a bit of work), however there is a maven plugin which can help us a bit in the process!

You could use John Oxley’s Maven Plugin, however the version underneath the hood is still the 1.3 version of Getdown, which means that the second digest does not get generated. If you care for a bit more work (once!) than just:

  • Grab a copy of the up-to-date code out of my repository by: git clone https://github.com/Flavsditz/getdown-maven.git
  • navigate to the folder where it is located and run: mvn clean install in order to install it to your local repo.
  • now add it to the pom

By using this, and because we stored the getdown.txt in the resources folder, we also need another plugin which will take care of copying the file to the correct location when compiling the project.

So without further ado, here is what to add to the POM:

<build>
        <finalName>getdownEx</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.bitbucket.joxley</groupId>
                <artifactId>getdown-maven-plugin</artifactId>
                <version>1.0.2</version>
                <configuration>
                    <appdir>target</appdir>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>digest</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.5</version>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/resources/</directory>
                                    <filtering>true</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

If you’ve followed the maven project how to you already should have the maven-compiler-plugin in place. So you will have:

  • finalName – is the name of the JAR, which should be the name that is in the getdown.txt file you wrote before.
  • getdown-maven-plugin – the plugin which will try to streamline the process and generate the digest for you.
  • maven-resources-plugin – this will tell maven the correct place to look for the files, in our case, the place where the getdown-maven plugin should look for the getdown.txt

 

Running everything

So with that configured, if you run mvn clean install you should end up with something like this one on your target folder:

generated files by the getdown-maven

As you can see the digest files got generated for us.

Deploying

Put the digest.txt, digest2.txt, getdown.txt and getdownEx.jar files in your Webserver where they can be reached by the URL you’ve described inside the getdown.txt file.

 

The customer comes in

Finally your customer can start his application.

You need to provide just 2 files inside a folder:

  • The Getdown file (version 1.6.2)
  • A stub getdown.txt file. That means a TEXT File with just one line: the appbase with the URL from before

So you’ll end up with something like:

├── gtdwn
│   ├── getdown-1.6.2.jar
│   └── getdown.txt

That is it! All he/she has to do is run the getdown file on the folder where these files are contained. So:

java -jar getdown-1.6.2.jar gtdwn

 

Which will start a small screen, which you can configure with images, font and “whatelse” as mentioned before. When completely configured it can look something like this:

Fully Configured UI from Getdown

 

If you want to do something similar, make sure you check the docs on it!

Once everything is loaded you application will start and show that awesome button from before 😉

 

Play around

If you now go back to the project and for example change the text on the button or even (crazy!) add another button, you just have to recompile everything and put the files you generated on your webserver (this could be automatic!).

Now if you re-start your application you should see the changes, i.e. Getdown took control of the situation and updated your program!

Awesome… I know…

 

Wrapping Up

You saw a complete explanation and a simple example of what you can do with getdown. There are tons of more information if you head to their website and look around. You can deploy the whole as applets, and sign/encrypt files.

Check the possibilities out and see what you can use for your next project!

Until the next time!

Leave your opinion, start a discussion, share an experience or just a compliment...

%d bloggers like this: