Page 1 of 1

Creating an updater in Java Rate Topic: ***** 2 Votes

#1 H3R3T1C  Icon User is offline

  • Android Expert
  • member icon

Reputation: 278
  • View blog
  • Posts: 757
  • Joined: 30-March 07

Posted 18 September 2010 - 04:19 PM

*
POPULAR

This tutorial is going to show you how to make an updater for you app!
Ok lets get started!
To start off lets first start off by creating a new project. I named my new project Update app but you can call yours what ever you like. If you IDE did not create a main class for go ahead and make one now. Now since this is just and example of how to implement the updater this app wont actually do anything.
Now we need to create an updater class so create a new class and name it Updater.
In the new Updater class we need to create 3 methods like so:
public class Updater {
    
    public static String getLatestVersion()
    {
        
    }
    public static String getWhatsNew()
    {
        
    }
    private static String getData(String address)
    {
        
    }

}

Ok now were going to add the code to retrieve the data from our update site. You can just copy paste this into your getData() method. All this code dose is get the web page.
private static String getData(String address)throws Exception
    {
        URL url = new URL(address);
        
        InputStream html = null;

        html = url.openStream();
        
        int c = 0;
        StringBuffer buffer = new StringBuffer("");

        while(c != -1) {
            c = html.read();
            
        buffer.append((char)c);
        }
        return buffer.toString();
    }


Now for the other two methods were going to be doing the following:
Pass the URL of our update checking site to the getData() method.
From there were going to parse the data accordingly to get the data we need.
Return the parsed data!
The following code can just be copied and pasted for right now!
private final static String versionURL = "";
    private final static String historyURL = "";
    public static String getLatestVersion() throws Exception
    {
        String data = getData(versionURL);
        return data.substring(data.indexOf("[version]")+9,data.indexOf("[/version]"));
    }
    public static String getWhatsNew() throws Exception
    {
        String data = getData(historyURL);
        return data.substring(data.indexOf("[history]")+9,data.indexOf("[/history]"));
    }



As you may of noticed there are to private String globals. These are going to hold the url's of our update pages. Right now their empty Strings but we'll fill then in later :).

This what our full class should look like:
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
 *
 * @author Thomas Otero H3R3T1C
 */
public class Updater {
    private final static String versionURL = "";
    private final static String historyURL = "";
    public static String getLatestVersion() throws Exception
    {
        String data = getData(versionURL);
        return data.substring(data.indexOf("[version]")+9,data.indexOf("[/version]"));
    }
    public static String getWhatsNew() throws Exception
    {
        String data = getData(historyURL);
        return data.substring(data.indexOf("[history]")+9,data.indexOf("[/history]"));
    }
    private static String getData(String address)throws Exception
    {
        URL url = new URL(address);
        
        InputStream html = null;

        html = url.openStream();
        
        int c = 0;
        StringBuffer buffer = new StringBuffer("");

        while(c != -1) {
            c = html.read();
            
        buffer.append((char)c);
        }
        return buffer.toString();
    }
}



Ok now before we continue coding we need to create our update site. If you have your own server where you can host the update pages then just skip the part about using bravenet to host our update files but make sure to read about the html files we will be creating to update our app!
The best free site to set up our update site is http://www.bravenet.com/. Go there and sign up for your free account. Once your account is all set up go to the websites tab. In here were going to set up our pages.
Click the Build new Website link. Now click use subdomain. Enter whatever you want for your subdomain. Im going to enter h3r3t1cupdate for my subdomain. Now just click ok. Now click on text/visual editor. In the right panel you should see index.html. Right click on it and select edit file with text editor. You should now be in the text editor. We want to create a new file so click on the new file button and name it version.html. Now refresh the page and you should now see the newly created file in the right panel. Right click and select edit with text editor. Delete all the text in this file and replace with this:
[version]1[/version]

Click save and now were done with this page!
Now lets go back to our Updater class.
In our Updater class we need to put our url for the version in the versionURL String. It should look something like this:
 private final static String versionURL = "http://<My SubDomain>.bravehost.com/version.html";


replace <My SubDomain> the subdomain you created earlier.

We should now be able to test the getLatestVersion() method!
In our main add this code:

public static void main(String[] args) {
        try {
            System.out.println(Updater.getLatestVersion());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

The output on the screen should be 1. If it is then everything is working so far but if its not you might of messed something up so go back and make sure you code is correct!
Ok now go back to the text editor on bavehost and create a new file called history.html. Open it up and replace all the text with this:
[history]This is where my history goes![/history]


Note: The history can also use HTML formatting to display update history. Put your HTML formatted history in between the [history] tags. Make sure your formatting starts with <html> or java will not recognize it as HTML formatting!

Save it and fill in the historyURL String like so:
private final static String historyURL = "<My SubDomain>.bravehost.com/history.html";


Remember to replace <My SubDomain> with your subdomain.

Next create a new class called UpdateInfo. In this class we will display to the user whats new and ask the user if they wish to update or now. I have already created the GUI so just copy paste this code into the class file!
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/**
 *
 * @author Thomas Otero H3R3T1C
 */
public class UpdateInfo extends JFrame{

    private JEditorPane infoPane;
    private JScrollPane scp;
    private JButton ok;
    private JButton cancel;
    private JPanel pan1;
    private JPanel pan2;

    public UpdateInfo(String info) {
        initComponents();
        infoPane.setText(info);
    }

    private void initComponents() {

        this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        this.setTitle("New Update Found");
        pan1 = new JPanel();
        pan1.setLayout(new BorderLayout());

        pan2 = new JPanel();
        pan2.setLayout(new FlowLayout());

        infoPane = new JEditorPane();
        infoPane.setContentType("text/html");

        scp = new JScrollPane();
        scp.setViewportView(infoPane);

        ok = new JButton("Update");
        ok.addActionListener( new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                update();
            }
        });

        cancel = new JButton("Cancel");
        cancel.addActionListener( new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                UpdateInfo.this.dispose();
            }
        });
        pan2.add(ok);
        pan2.add(cancel);
        pan1.add(pan2, BorderLayout.SOUTH);
        pan1.add(scp, BorderLayout.CENTER);
        this.add(pan1);
        pack();
        show();
        this.setSize(300, 200);
    }
    private void update()
    {
        // TODO: Add my Code!
    }

}



Now lest test again to make sure everything is working. In our main replace the code with this:
public static void main(String[] args) {
        try {
            if (Integer.parseInt(Updater.getLatestVersion()) > 0) {
                new UpdateInfo(Updater.getWhatsNew());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


This code does the following:
It gets the latest version and parses it to an int.
It checks to see if the version is higher then 0
If it is then it shows the update info frame with the whats new as the string data to be shown.

Next we need to create a new project. The purpose of this new project is to download our update and replace the old files with the new ones! The reason we need to do this in a separate project is because if the jar we are trying to update is running then we would not be able to replace it with the new updated one!

So lets create our new project and call it Update. For this part of the tutorial I will be just providing you with the code but I will be explaining what each section does!
Create a new Class called Main_Gui in our new project.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;


/**
 *
 * @author Thomas Otero (H3R3T1C)
 */
public class Main_Gui extends JFrame{

    private Thread worker;
    private final String root = "update/";

    private JTextArea outText;
    private JButton cancle;
    private JButton launch;
    private JScrollPane sp;
    private JPanel pan1;
    private JPanel pan2;

     public Main_Gui() {
        initComponents();
        outText.setText("Contacting Download Server...");
        download();
    }
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

       

        pan1 = new JPanel();
        pan1.setLayout(new BorderLayout());

        pan2 = new JPanel();
        pan2.setLayout(new FlowLayout());

        outText = new JTextArea();
        sp = new JScrollPane();
        sp.setViewportView(outText);
        
        launch = new JButton("Launch App");
        launch.setEnabled(false);
        launch.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                launch();
            }
        });
        pan2.add(launch);

        cancle = new JButton("Cancel Update");
        cancle.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        pan2.add(cancle);
        pan1.add(sp,BorderLayout.CENTER);
        pan1.add(pan2,BorderLayout.SOUTH);

        add(pan1);
        pack();
        this.setSize(500, 400);
    }

    private void download()
    {
        worker = new Thread(
        new Runnable(){
            public void run()
            {
                try {
                    downloadFile(getDownloadLinkFromHost());
                    unzip();
                    copyFiles(new File(root),new File("").getAbsolutePath());
                    cleanup();
                    launch.setEnabled(true);
                    outText.setText(outText.getText()+"\nUpdate Finished!");
                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null, "An error occured while preforming update!");
                }
            }
        });
        worker.start();
    }
    private void launch()
    {
        String[] run = {"java","-jar","update app.jar"};
        try {
            Runtime.getRuntime().exec(run);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        System.exit(0);
    }
    private void cleanup()
    {
        outText.setText(outText.getText()+"\nPreforming clean up...");
        File f = new File("update.zip");
        f.delete();
        remove(new File(root));
        new File(root).delete();
    }
    private void remove(File f)
    {
        File[]files = f.listFiles();
        for(File ff:files)
        {
            if(ff.isDirectory())
            {
                remove(ff);
                ff.delete();
            }
            else
            {
                ff.delete();
            }
        }
    }
    private void copyFiles(File f,String dir) throws IOException
    {
        File[]files = f.listFiles();
        for(File ff:files)
        {
            if(ff.isDirectory()){
                new File(dir+"/"+ff.getName()).mkdir();
                copyFiles(ff,dir+"/"+ff.getName());
            }
            else
            {
                copy(ff.getAbsolutePath(),dir+"/"+ff.getName());
            }

        }
    }
    public void copy(String srFile, String dtFile) throws FileNotFoundException, IOException{

          File f1 = new File(srFile);
          File f2 = new File(dtFile);

          InputStream in = new FileInputStream(f1);

          OutputStream out = new FileOutputStream(f2);

          byte[] buf = new byte[1024];
          int len;
          while ((len = in.read(buf)) > 0){
            out.write(buf, 0, len);
          }
          in.close();
          out.close();
      }
    private void unzip() throws IOException
    {
         int BUFFER = 2048;
         BufferedOutputStream dest = null;
         BufferedInputStream is = null;
         ZipEntry entry;
         ZipFile zipfile = new ZipFile("update.zip");
         Enumeration e = zipfile.entries();
         (new File(root)).mkdir();
         while(e.hasMoreElements()) {
            entry = (ZipEntry) e.nextElement();
            outText.setText(outText.getText()+"\nExtracting: " +entry);
            if(entry.isDirectory())
                (new File(root+entry.getName())).mkdir();
            else{
                (new File(root+entry.getName())).createNewFile();
                is = new BufferedInputStream
                  (zipfile.getInputStream(entry));
                int count;
                byte data[] = new byte[BUFFER];
                FileOutputStream fos = new
                  FileOutputStream(root+entry.getName());
                dest = new
                  BufferedOutputStream(fos, BUFFER);
                while ((count = is.read(data, 0, BUFFER))
                  != -1) {
                   dest.write(data, 0, count);
                }
                dest.flush();
                dest.close();
                is.close();
            }
         }

    }
    private void downloadFile(String link) throws MalformedURLException, IOException
    {
        URL url = new URL(link);
        URLConnection conn = url.openConnection();
        InputStream is = conn.getInputStream();
        long max = conn.getContentLength();
        outText.setText(outText.getText()+"\n"+"Downloding file...\nUpdate Size(compressed): "+max+" Bytes");
        BufferedOutputStream fOut = new BufferedOutputStream(new FileOutputStream(new File("update.zip")));
        byte[] buffer = new byte[32 * 1024];
        int bytesRead = 0;
        int in = 0;
        while ((bytesRead = is.read(buffer)) != -1) {
            in += bytesRead;
            fOut.write(buffer, 0, bytesRead);
        }
        fOut.flush();
        fOut.close();
        is.close();
        outText.setText(outText.getText()+"\nDownload Complete!");

    }
    private String getDownloadLinkFromHost() throws MalformedURLException, IOException
    {
        String path = "http://h3r3t1cupdate.bravehost.com/url.html";
        URL url = new URL(path);

        InputStream html = null;

        html = url.openStream();

        int c = 0;
        StringBuilder buffer = new StringBuilder("");

        while(c != -1) {
            c = html.read();
        buffer.append((char)c);

        }
        return buffer.substring(buffer.indexOf("[url]")+5,buffer.indexOf("[/url]"));
    }
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Main_Gui().setVisible(true);
            }
        });
    }


}


The purpose of getDownloadLinkFromHost() is to get the download link for the update package! Note that the update package needs to be zipped! For my method of getting the download link I have made another web page on bravehost called url.html. In url.html I have my url for the download page surrounded by the tags.
Next the method downloadFile() downloads the file!
Then the unzip() method unzips the the update.zip file to the temp dir called update. From there the copyFiles() method copies the files from the temp dir to the root dir of our java application. From there we call clean up to delete all the files in the temp dir. After all that is done then the Lanuch app button is enabled and when pressed it should now launch the newly updated app!

Now go back to our first project that we made and open the UpdateInfo class. In there under the update() method add this code:
String[] run = {"java","-jar","updater/update.jar"};
        try {
            Runtime.getRuntime().exec(run);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        System.exit(0);


VERY IMPORTANT: For all this to work when you are ready to package your java program to distribute make sure that you include the folder updater with the update.jar in it for this to properly work!
So the final paths should look like this:
../<my app>.jar
../updater/update.jar

Also if you ever find the need to update update.jar you can have the updater copy the new update.jar file to the app root then when your app is ran check to see if there is update.jar in the app root. If its there replace the old update.jar with the new one!

The full project can be downloaded here: Attached File  update_example.zip (39.51K)
Number of downloads: 2161

Is This A Good Question/Topic? 9
  • +

Replies To: Creating an updater in Java

#2 R3pt1l3  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 04-December 10

Posted 06 December 2010 - 06:58 PM

this is awesome
Was This Post Helpful? 0
  • +
  • -

#3 Atspulgs  Icon User is offline

  • D.I.C Regular

Reputation: 68
  • View blog
  • Posts: 380
  • Joined: 29-July 09

Posted 09 December 2010 - 07:37 PM

Very nice, may come in handy. -tabs the link-
Was This Post Helpful? 0
  • +
  • -

#4 ScottH323  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 03-February 11

Posted 26 February 2011 - 09:56 AM

thanks for the guide but i have 2 slight problems. the first being when i added this into my programme and compiled it to .jars then put them togeather how you said i would click the update button but it would not run update.jar

my path is currently this:

LibTiles.jar
updater/update.jar

i have another folder in there also called lib but i dont think that would make much differance. I also cannot open the update.jar by itself and it just gives that annoying pang noise.

Secondly when i run it through netbeans (Main_Gui) it gets to a point when it starts to extract then comes up with an error saying it cannot complete and this error in the console:
java.io.IOException: The system cannot find the path specified
        at java.io.WinNTFileSystem.createFileExclusively(Native Method)
        at java.io.File.createNewFile(File.java:883)
        at update.Main_Gui.unzip(Main_Gui.java:188)
        at update.Main_Gui.access$300(Main_Gui.java:33)
        at update.Main_Gui$3.run(Main_Gui.java:99)
        at java.lang.Thread.run(Thread.java:662)


This is what is in the download window:
Contacting Download Server...
Downloding file...
Update Size(compressed): 229227 Bytes
Download Complete!
Extracting: LibTiles/lib/
Extracting: LibTiles/lib/appframework-1.0.3.jar


Any help would be greatly appreciated.
Was This Post Helpful? 0
  • +
  • -

#5 lnc12  Icon User is offline

  • D.I.C Regular

Reputation: 1
  • View blog
  • Posts: 268
  • Joined: 21-May 08

Posted 02 October 2011 - 10:26 AM

Thank you so much
Was This Post Helpful? 0
  • +
  • -

#6 Damsch12  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 33
  • Joined: 20-December 11

Posted 20 January 2012 - 06:30 AM

I made an updater for my Java programs following this tutorial and worked perfectly, but then I tried to modify it a bit so it uses a .ini or .txt file to load the urls, but I dont know why the updater.jar file doesnt execute update.jar, everything seems ok, if I manually run update.jar the program executes.

I already opened a topic in the Java help forum.
www.dreamincode.net/forums/topic/263279-problems-executing-an-other-jar/

Is there any way to modify the updater so it works with a .ini or .txt file?
Was This Post Helpful? 0
  • +
  • -

#7 Tezlastorme  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 13-April 12

Posted 13 April 2012 - 03:14 AM

Thanks very much it works fine for me apart from one problem: It isn't deleting the update.zip after it has updated and I don't know why. I followed this almost tutorial exactly.
Was This Post Helpful? 0
  • +
  • -

#8 Ruben1123  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 19-May 12

Posted 25 June 2012 - 07:55 PM

This was great, thanks.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1