|
What this is
Other links
The source code
/*
* 06/13/2003
*
* PluginDownload.java - The manager for plugins update.
* Copyright (C) 2003 Paolo Giarrusso
* blaisorblade_work@yahoo.it
* www.jext.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.jext.misc;
import java.net.*;
import java.io.*;
import java.util.zip.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Window;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.JOptionPane;
import org.jext.Jext;
import org.jext.Utilities;
import org.jext.JARClassLoader;
import org.jext.misc.DownloaderThread;
/**
* This is the master class of all the plugin update process; see the code of main() for
* a sample of use.
* @author Blaisorblade
* @since Jext3.2pre4
*/
public class PluginDownload {
private PluginDownload() {}//"static" class
//URL's to refer to(they are initialized below, in the static constructor)
private static URL autoUpdateVersionUrl, autoUpdateListUrl;
private final static String jarName = "autoUpdate.jar";
private static URL autoUpdateJarUrl;
//Where we save the new version of autoUpdate.jar
private final static File downloadedJarPath = new File(Jext.SETTINGS_DIRECTORY + jarName);
private final static File downloadedListPath = new File(Jext.SETTINGS_DIRECTORY + "plugList.xml");
private static String defaultJarPath;
//classloaders for the update.
private static ClassLoader loader = null, newVerLoader = null, defLoader = null;
//references to data model and UI elements.
private static AbstractPlugReader plugReader;
private static JDialog updateWindow;
private static JFrame parentFrame = null;
//flags
/**
* Remember if we have already done the boot process(currently downloading the
* latest version of autoUpdate.jar).
*/
private static boolean hasBooted;
public static boolean debug = false;
//Property keys
//private static final String versionKey = "plugDownload.core.version";
//private static final String baseUrlKey = ;
private static final String waitLabelKey = "plugDownload.core.waitWindow.label";
private static final String waitTitleKey = "plugDownload.core.waitWindow.title";
static {
if (Jext.getProperties() == null) //this is needed during testing, when all starts from our main().
Jext.initProperties();
String baseURL = Jext.getProperty("plugDownload.core.baseAddress", "http://www.jext.org/");
//baseURL = "http://localhost/jext/"; //Uncomment this for local testing.
//FIXME: Also add proxing ability!! See system properties set by jEdit
//inside jEdit.java
try {
autoUpdateVersionUrl = new URL(baseURL + "plugReader.version");
autoUpdateJarUrl = new URL(baseURL + jarName);
autoUpdateListUrl = new URL(baseURL + "plugins.xml.php");
} catch (MalformedURLException mue) {
mue.printStackTrace();
}
}
private static String getDefaultJarPath() {
if (defaultJarPath == null)
defaultJarPath = Jext.JEXT_HOME + File.separator + ".." + File.separator +
"bin" + File.separator + jarName;
return defaultJarPath;
}
private static void downloadJar() {
//try {
HandlingRunnable handler = new HandlingRunnable() {
public void run(Object dial, Throwable excep) {
if (dial != null)
((JDialog) dial).dispose();
}
};
DownloaderThread t = new DownloaderThread(autoUpdateJarUrl, handler, downloadedJarPath.getPath()) {
public Object work() {
JDialog dial = null;
//now if we didn't do this yet, check for new core version.
if (debug || !hasBooted) {
try {
byte buf[] = new byte[10];
InputStream releaseInp = autoUpdateVersionUrl.openStream();
releaseInp.read(buf);
releaseInp.close();
int currVersion = Integer.parseInt(Jext.getProperty("plugDownload.core.version"));
int newVersion = Integer.parseInt(new String(buf).trim());
//If there is a new version, download it.
if (currVersion < newVersion) {
dial = new WaitDialog();
dial.setVisible(true);
try {
super.work(); //does the download work.
} catch (Throwable t) {
JOptionPane.showMessageDialog(dial,
Jext.getProperty("plugDownload.core.coreDownError.text"),
Jext.getProperty("plugDownload.core.downError.title"),
JOptionPane.ERROR_MESSAGE);
throw (IOException)t;
}
if (!debug) { //during testing this is commented out.
Jext.setProperty("plugDownload.core.version", String.valueOf(newVersion));
}
}
//anyway, the jar is up-to-date, and we remember this.
hasBooted = true;
} catch (IOException ioe) {
//In this case, we can't update the autoUpdate.jar file; but then we use the current one.
System.err.println("Caught exception while trying to update autoUpdate.jar");
ioe.printStackTrace();
}
} //if needed, we've tried to do the update. Now let's get the list.
downloadList();
return dial;
}
};
t.start(true);
/*} catch (Throwable t) { //will never happen, because the above construct doesn't return any exception.
t.printStackTrace();
}*/
}
/** This method downloads the core Jar if needed and shows the dialog.*/
/*FIXME: needs to be rewritten. As of now, it starts a thread which downloads the jar core, which run a callback in the
* event-handling thread, which checks if things went ok and downloads the plugin list in a new thread, which then shows
* the dialog in a callback.
*/
/*private static void downloadJar() {
if (debug || !hasBooted) {
try {
InputStream releaseInp = autoUpdateVersionUrl.openStream();
byte buf[] = new byte[10];
releaseInp.read(buf);
int currVersion = Integer.parseInt(Jext.getProperty("plugDownload.core.version"));
final int newVersion = Integer.parseInt(new String(buf).trim());
if (currVersion < newVersion) {
final JDialog dial = new WaitDialog(parentFrame);
dial.setVisible(true);
Utilities.copy(true, new DownloaderThread(autoUpdateJarUrl, null, downloadedJarPath.getPath()) {
public Object construct() {
Throwable ret = (Throwable) super.construct();
dial.dispose();
if (ret != null) {
ret.printStackTrace();
JOptionPane.showMessageDialog(dial,
Jext.getProperty("plugDownload.core.coreDownError.text"),
Jext.getProperty("plugDownload.core.downError.title"),
JOptionPane.ERROR_MESSAGE);
return ret;
}
if (!debug) {
//during testing this is commented out.
Jext.setProperty("plugDownload.core.version", String.valueOf(newVersion));
}
hasBooted = true;
downloadList();
return null;
}
});
return;
/*Utilities.downloadFile(autoUpdateJarUrl, downloadedJarPath.getPath(), true, new HandlingRunnable() {
public void run() {
//let's close the window and let things go on.
dial.dispose();
if (excep != null) {
excep.printStackTrace();
JOptionPane.showMessageDialog(dial,
Jext.getProperty("plugDownload.core.coreDownError.text"),
Jext.getProperty("plugDownload.core.downError.title"),
JOptionPane.ERROR_MESSAGE);
return;
}
if (!debug) {
//during testing this is commented out.
Jext.setProperty("plugDownload.core.version", String.valueOf(newVersion));
}
hasBooted = true;
downloadList();
}
});
//the file must be ready for the call to buildChainingClassLoader, below, so if threaded there
//is need for special caution: fixed. The buildChainingClassLoader is done by the back-notify Runnable.
//actually, when doing things the right way, the lib download will start together with a progress monitor.
} else { //otherwise, the jar is up-to-date.
hasBooted = true;
}
} catch (IOException ioe) {
//In this case, we can't update the autoUpdate.jar file; but then we use the current one.
System.err.println("Caught exception while trying to update autoUpdate.jar");
ioe.printStackTrace();
}
}
//If for any reason the jar wasn't updated(either for problems or because it was up-to-date) we show
//here the dialog.
downloadList();
}*/
/**
* This method downloads the list of plugins and loads it into the
* AbstractPlugReader(there is an instance which * can be got through
* getUpdater(). It's called by the downloader thread, while its internal
* runnable is called in the AWT thread.
*/
private static void downloadList() {
/*try {
Utilities.downloadFile(autoUpdateListUrl, downloadedListPath.getPath(), false, null);
} catch (IOException ioe) {
JOptionPane.showMessageDialog(null,
Jext.getProperty("plugDownload.core.downError.text"),
Jext.getProperty("plugDownload.core.downError.title"),
JOptionPane.ERROR_MESSAGE);
System.err.println("Failed loading of XML!");
ioe.printStackTrace();
return;
}*/
Utilities.downloadFile(autoUpdateListUrl, downloadedListPath.getPath(), false,
new HandlingRunnable() {
public void run(Object o, Throwable excep) {
if (excep != null) {
JOptionPane.showMessageDialog(null,
Jext.getProperty("plugDownload.core.downError.text"),
Jext.getProperty("plugDownload.core.downError.title"),
JOptionPane.ERROR_MESSAGE);
System.err.println("Failed loading of XML!");
excep.printStackTrace();
} else
showUpdateWindow();
}
});
}
/**
* This method loads the list of plugins into the AbstractPlugReader instance which
* can be got through getUpdater().
*/
public static boolean loadList() {
Reader reader = null;
if (! downloadedListPath.exists())
return false;
try {
reader = new BufferedReader(new FileReader(downloadedListPath.getPath()));
return getUpdater().loadXml(reader);
} catch (IOException ioe) {
//HERE we must give some user visible output.(I.e. in the GUI). In fact, it happens in the caller method.
System.err.println("Caught exception while trying to download plugin list");
ioe.printStackTrace();
return false;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ioe) {}
}
}
}
private static boolean buildChainingClassLoader() {
//Now, if autoUpdate.jar has been updated, it is in the right place in the user's home;
//otherwise we need to use the default one, in jext/lib dir. Or maybe somewhere else, such as bin,
//since it mustn't be loaded at startup.
//And we build the chaining class loader that will be used to load all resources.
//We build first a ClassLoader which loads the supplied autoUpdate.jar, then
//another one which looks in the downloaded one BUT uses as fallback one
//the first one. The fallback is provided trasparently by the JDK by using
//the fallback classloader as parent of the new one. But this only works for
//resources, since for classes we must fallback not only in the case of ClassNotFoundEx.
try {
defLoader = new JARClassLoader(getDefaultJarPath(), false, null);
loader = defLoader;
System.out.println("DefLoader");
} catch (IOException ioe) {
System.err.println("You haven't installed correctly Jext! The autoUpdate.jar file is missing." +
"It should be in this position: " + getDefaultJarPath());
}
if (downloadedJarPath.exists())
try {
newVerLoader = new JARClassLoader(downloadedJarPath.getPath(), false, defLoader);
loader = newVerLoader;
System.out.println("NewVerLoader");
//here defLoader becomes the father of newVerLoader
} catch (IOException ioe) {
ioe.printStackTrace();
//The file is there, but there could be problems anyway.
}
if (loader == null)
return false;
return true;
}
private static Object getInstanceFromLoader(String className) {
if (loader != null)
try {
return loader.loadClass(className).newInstance();
} catch (InstantiationException ie) {
} catch (IllegalAccessException ie) {
} catch (ClassNotFoundException ie) {
return null;//the class is missing in both chained classLoaders.
}
//if the class was found in newVerLoader, we've tried with it, but it didn't work.
//So we only need trying with defLoader, and only if != loader.
if (defLoader != null && defLoader != loader)
try {
return defLoader.loadClass(className).newInstance();
} catch (InstantiationException ie) {
} catch (IllegalAccessException ie) {
} catch (ClassNotFoundException ie) {
}
return null;
}
private static AbstractPlugReader newUpdater() {
return (AbstractPlugReader) getInstanceFromLoader("PlugReader");
}
public static JPanel newUpdatePanel() {
return (JPanel) getInstanceFromLoader("ChoiceForm");
}
public static AbstractPlugReader getUpdater() {
if (plugReader == null)
plugReader = newUpdater();
return plugReader;
}
public static Reader getDtd() {
return new BufferedReader(new InputStreamReader(loader.getResourceAsStream("pluglist.dtd")));
}
public static JDialog getUpdateWindow() {
return updateWindow;
}
/**
* This method starts the update: downloads the new autoUpdate.jar if needed, and when this is
* done shows the window.
*/
public static void startUpdate() {
PluginDesc.initDirectories();
downloadJar();
}
public static void showUpdateWindow() {
if (!buildChainingClassLoader()) {
JOptionPane.showMessageDialog(null,
Jext.getProperty("plugDownload.core.instError.text", new Object[] {getDefaultJarPath()}),
Jext.getProperty("plugDownload.core.instError.title"),
JOptionPane.ERROR_MESSAGE);
return;
}
if (loadList()) {
updateWindow = new JDialog(parentFrame, Jext.getProperty("plugDownload.core.mainWindow.title", "Download plugins"));
JPanel updatePanel = newUpdatePanel();
updateWindow.setContentPane(updatePanel);
if (debug)
updateWindow.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
updateWindow.pack();
updateWindow.setVisible(true);
} else {
JOptionPane.showMessageDialog(null,
Jext.getProperty("plugDownload.core.downError.text"),
Jext.getProperty("plugDownload.core.downError.title"),
JOptionPane.ERROR_MESSAGE);
System.err.println("Failed loading of XML!");
}
}
public static void main(String[] args) {// for testing
debug = true;
startUpdate();
}
private static class WaitDialog extends JDialog {
WaitDialog() {
super(parentFrame, Jext.getProperty(waitTitleKey, "Wait please!"));
getContentPane().add(new JLabel(Jext.getProperty(waitLabelKey, "Please wait while updating PluginGet...")));
pack();
}
}
}
|
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.