KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > snow > updater > Updater


1 package snow.updater;
2
3 import java.util.jar.*;
4 import java.io.*;
5 import java.util.zip.GZIPInputStream JavaDoc;
6 import javax.swing.JFrame JavaDoc;
7 import javax.swing.JOptionPane JavaDoc;
8 import java.util.*;
9 import snow.utils.ProcessUtils;
10 import java.util.zip.ZipEntry JavaDoc;
11 import java.util.zip.ZipFile JavaDoc;
12 import snow.utils.SysUtils;
13 import java.io.InputStream JavaDoc;
14 import java.io.FileOutputStream JavaDoc;
15 import snow.utils.gui.ProgressModalDialog;
16 import snow.utils.storage.FileUtils;
17 import java.net.*;
18 //import javax.jnlp.BasicService;
19
//import javax.jnlp.ServiceManager;
20
import java.io.File JavaDoc;
21
22 /** General purpose to update a running app (jar based), not JNLP.
23 * downloads the jar, eventually as pack200 and replace the jar (after
24 * app shutdown) from a separate process.
25 */

26 public final class Updater
27 {
28    /** Constructor. */
29    public Updater()
30    {
31    }
32
33    /** simplified try... just look if a jarName is found on classpath. If no, assume we're in WebStartMode
34    */

35    public static boolean isWebStartMode(String JavaDoc jarName)
36    {
37       try{
38         // BasicService bs = (BasicService) ServiceManager.lookup("javax.jnlp.BasicService");
39
// if(bs!=null) return true;
40
File JavaDoc tf = getJarCurrentlyRunning(jarName);
41         if(tf==null) return true;
42       }
43       catch(Exception JavaDoc e) {
44       }
45
46       return false;
47    }
48
49    public static boolean isNewVersionAvailable(String JavaDoc jarName, String JavaDoc url) throws Exception JavaDoc
50    {
51       if(shutdownHook!=null)
52       {
53          throw new Exception JavaDoc("An update is already pending, please close the application.");
54       }
55
56       File JavaDoc tf = getJarCurrentlyRunning(jarName);
57       if(tf==null) return false; // WebStart mode
58

59       long[] dl = getDateAndSizeOnServer(new URL(url));
60       if(dl[0]-tf.lastModified() > 1000*3600)
61       {
62          return true;
63       }
64
65       return false;
66    }
67
68    private static Thread JavaDoc shutdownHook = null;
69
70
71    public static void updateAndLaunchReplacerTask(String JavaDoc jarName, String JavaDoc url) throws Exception JavaDoc
72    {
73       if(shutdownHook!=null)
74       {
75          throw new Exception JavaDoc("An update is already pending, please close the application.");
76       }
77       final File JavaDoc tf = getJarCurrentlyRunning(jarName);
78       if(tf==null) throw new Exception JavaDoc("Cannot update: there is no "+jarName+" in the classpath");
79
80       ProgressModalDialog pmd = new ProgressModalDialog((JFrame JavaDoc) null, "Downloading the new jar", true, false);
81       //JTextArea ta = pmd.addSomeShortDescriptionLines("");
82
final File JavaDoc tempDest = new File JavaDoc(tf.getAbsolutePath()+".new");
83       if(url.toLowerCase().endsWith(".pack.gz"))
84       {
85          final File JavaDoc tempDestGZ = new File JavaDoc(tf.getAbsolutePath()+".new.pack.gz");
86          tempDestGZ.deleteOnExit();
87          downloadFromServer(new URL(url), tempDestGZ, pmd);
88
89          pmd.setProgressComment("Unpack200 to "+tempDest.getName());
90          replaceJarWithPack200Decompressed(tempDest, tempDestGZ);
91       }
92       else
93       {
94          downloadFromServer(new URL(url), tempDest, pmd);
95       }
96       pmd.closeDialog();
97
98
99       extractReplacer(tf);
100
101       // tricky: the replacement must be delayed at shutdown, because
102
// we are now running jarName !
103
Runtime.getRuntime().addShutdownHook(shutdownHook = new Thread JavaDoc()
104       {
105          @Override JavaDoc public void run()
106          {
107             File JavaDoc javaExe = new File JavaDoc(System.getProperty("java.home")+"/bin/java"+(SysUtils.is_Windows_OS()?".exe":""));
108
109             ProcessBuilder JavaDoc pb = new ProcessBuilder JavaDoc(javaExe.getAbsolutePath(),
110               "JarNewVersionReplacer",
111               tf.getAbsolutePath(), // old
112
tempDest.getAbsolutePath() // new
113
);
114             try{
115                pb.start();
116             }catch(Exception JavaDoc e){ e.printStackTrace(); }
117          }
118       });
119
120       JOptionPane.showMessageDialog(null,
121           "The new version has been succesfully downloaded."
122          +"\nAnother JVM has been started that will replace"
123          +"\n "+tf
124          +"\nwith the new version when you close this application.",
125           "Download successful", JOptionPane.INFORMATION_MESSAGE);
126
127                 // SysUtils.openFileExplorer( UpdaterUtils.getJarCurrentlyRunning().getParent() );
128

129
130    }
131
132    private static void extractReplacer(File JavaDoc f) throws Exception JavaDoc
133    {
134       ZipFile JavaDoc zf = new ZipFile JavaDoc(f);
135       try{
136          ZipEntry JavaDoc ze = zf.getEntry("JarNewVersionReplacer.class");
137          if(ze==null) throw new Exception JavaDoc("JarNewVersionReplacer entry not found in jar file "+f);
138          File JavaDoc dest = new File JavaDoc(f.getParentFile(), "JarNewVersionReplacer.class");
139          FileUtils.writeToFile( zf.getInputStream(ze), dest);
140       }
141       catch(Exception JavaDoc e) {
142         throw e;
143       }
144       finally{
145          FileUtils.closeIgnoringExceptions(zf);
146       }
147    }
148
149
150
151    /** @return full path of the jar, null if webstart mode, i.e. if no name jar is found on the classpath.
152    * @param name for example tide.jar, the name of the file to replace.
153    *
154    */

155    public static File JavaDoc getJarCurrentlyRunning(String JavaDoc name) //throws Exception
156
{
157       String JavaDoc cps = System.getProperty("java.class.path","");
158       //System.out.println(""+cps);
159
String JavaDoc[] cp = cps.split(";");
160       for(String JavaDoc cpi : cp)
161       {
162          cpi = cpi.trim();
163
164          if(cpi.toLowerCase().endsWith(name))
165          {
166            if(cpi.equalsIgnoreCase(name))
167            {
168              // special case !
169
File JavaDoc fi = new File JavaDoc(System.getProperty("user.dir", ""), cpi);
170              if(fi.exists()) return fi;
171            }
172            File JavaDoc fi = new File JavaDoc(cpi);
173            if(fi.exists()) return fi;
174          }
175       }
176       // => assume is WebStart mode
177
return null;
178    }
179
180    public static long[] getDateAndSizeOnServer(URL url) throws Exception JavaDoc
181    {
182       HttpURLConnection con = (HttpURLConnection) url.openConnection();
183       long date = con.getLastModified();
184       long size = con.getContentLength();
185       con.disconnect();
186       if(date<1 || size<1) throw new Exception JavaDoc("No connection to "+url);
187       return new long[]{ date, size };
188    }
189
190    private static void downloadFromServer(URL url, File JavaDoc dest, ProgressModalDialog pmd) throws Exception JavaDoc
191    {
192       HttpURLConnection con = (HttpURLConnection) url.openConnection();
193       con.setDoOutput(false);
194       long date = con.getLastModified();
195       long size = con.getContentLength();
196       long start = System.currentTimeMillis();
197       pmd.setProgressComment("Downloading "+url+", "+FileUtils.formatSize(size)+"");
198       pmd.start();
199       writeToFile(con.getInputStream(), dest,pmd,size);
200       if(date>0)
201       {
202          dest.setLastModified(date);
203       }
204       double speed = 8.0*size /(System.currentTimeMillis()-start); // kBit/s
205
System.out.println("Downloaded "+url+" at "+speed+" kBit/s");
206       con.disconnect();
207    }
208
209 /** @param is is closed in all situations.
210 */

211  public static void writeToFile(InputStream JavaDoc is, File JavaDoc file, ProgressModalDialog pmd, long totSize) throws Exception JavaDoc
212  {
213     if(totSize==0) totSize=500000; //500kB
214

215     File JavaDoc parent = file.getParentFile();
216     if(parent!=null && !parent.exists())
217     {
218        parent.mkdirs();
219     }
220
221     FileOutputStream JavaDoc fos = null;
222     try
223     {
224       fos = new FileOutputStream JavaDoc(file);
225       byte[] buf = new byte[256];
226       long totRead = 0;
227       int read = -1;
228       while((read=is.read(buf))!=-1)
229       {
230         if(pmd.wasCancelled()) throw new Exception JavaDoc("Download cancelled");
231
232         fos.write( buf,0,read);
233         totRead+=read;
234
235         pmd.setProgressValue((int)(totRead*90.0/totSize),"");
236
237       }
238     }
239     catch(Exception JavaDoc e)
240     {
241       throw e;
242     }
243     finally
244     {
245       FileUtils.closeIgnoringExceptions( fos );
246       FileUtils.closeIgnoringExceptions( is );
247     }
248   }
249
250 @SuppressWarnings JavaDoc("unchecked")
251   private static void replaceJarWithPack200Decompressed(File JavaDoc jarFile, File JavaDoc pack200GzFile) throws Exception JavaDoc
252   {
253      File JavaDoc tmpDest = File.createTempFile("jar_"+jarFile.getName(), null);
254      tmpDest.deleteOnExit();
255      FileOutputStream JavaDoc fostream = null;
256      JarOutputStream jostream = null;
257      FileInputStream fis = null;
258
259      try
260      {
261         fostream = new FileOutputStream JavaDoc(tmpDest);
262         jostream = new JarOutputStream(fostream);
263
264         Pack200.Unpacker unpacker = Pack200.newUnpacker();
265         Map p = unpacker.properties();
266         p.put(Pack200.Unpacker.DEFLATE_HINT, Pack200.Unpacker.TRUE);
267
268         fis = new FileInputStream(pack200GzFile);
269         GZIPInputStream JavaDoc gis = new GZIPInputStream JavaDoc(fis);
270
271         unpacker.unpack(gis, jostream);
272
273         // Must explicitly close the output.
274
jostream.close();
275         fis.close();
276
277         // ok, it worked => replace the files
278
if(jarFile.exists())
279         {
280            if(!jarFile.delete())
281            {
282               throw new Exception JavaDoc("Cannot delete "+jarFile);
283            }
284         }
285
286
287
288      }
289      catch(Exception JavaDoc e)
290      {
291         throw e;
292      }
293      finally
294      {
295         FileUtils.closeIgnoringExceptions( fis );
296         FileUtils.closeIgnoringExceptions( fostream );
297      }
298
299      long lm = tmpDest.lastModified();
300      tmpDest.renameTo(jarFile);
301      // overtake the date. this is necessary because this function is also used by the updater.
302
jarFile.setLastModified(lm);
303
304
305   }
306
307   public static void main(String JavaDoc[] arguments)
308   {
309      new File JavaDoc("C:/proj/tide/published/snowmail.sn.funpic.de/tide/tide.jar").
310           setLastModified(1000200030000l);
311   }
312
313
314 } // Updater
Popular Tags