Lorsque vous téléchargez une ressource dans une application Java Webstart, une fenêtre de progression du téléchargement s'affiche généralement, indiquant la progression du téléchargement. Si cette fenêtre est la fenêtre de progression par défaut, elle possède un bouton d'annulation. J'essaye fondamentalement d'implémenter ce bouton d'annulation dans une fenêtre de progression de téléchargement faite sur commande.Annuler un téléchargement personnalisé Java Webstart
Comme il n'y a aucune méthode que vous pourriez appeler pour annuler le téléchargement, j'ai essayé de trouver comment cela a été fait dans la fenêtre de progression par défaut. En raison de la mise en œuvre avec un ServiceManager, il est un peu difficile de trouver l'implémentation réelle. Mais j'ai finalement trouvé ceci: [jdk-source on googlecode (DownloadServiceImpl)].
Lorsque vous recherchez "annuler" ou que vous descendez simplement à la méthode de progression, vous verrez que cela devrait être aussi facile que de lancer une RuntimeException. Malheureusement, cela ne fonctionne pas vraiment. Cela arrête simplement la méthode de progression d'être appelée. La ressource est toujours téléchargée en arrière-plan et la méthode loadPart ne retourne jamais.
Si vous voulez essayer cela par vous-même, j'ai préparé un petit exemple. Vous aurez besoin d'une sorte de serveur web (un serveur web local est suffisant bien sûr). J'ai essayé ceci sur Windows XP (32 bits) avec Java 1.6.0_21 (et apache tomcat 6).
Un fichier jnlp simple, ressemblerait à ceci (vous voulez probablement changer le port):
<?xml version="1.0" encoding="utf-8"?>
<jnlp
spec="1.0+"
codebase="http://127.0.0.1:8080/DownloadTest"
href="DownloadTest.jnlp"
version="1.0">
<information>
<title>DownloadTest</title>
<vendor>Download Tester</vendor>
</information>
<resources os="Windows">
<java version="1.6.0_18+" href="http://java.sun.com/products/autodl/j2se" />
<jar href="DownloadTest.jar" main="true"/>
<jar href="largeResource.jar" download="lazy" part="One"/>
</resources>
<application-desc main-class="downloadtest.Main">
</application-desc>
</jnlp>
Ensuite, vous aurez besoin d'un grand fichier en tant que ressource (le contenu n'a pas d'importance du tout). Par exemple sur de nombreuses machines Windows, vous trouverez "driver.cab" sous "Windows \ Driver Cache \ i386". Le fichier doit être ajouté à une archive jar (jar -cf largeResource.jar <input file>
).
Le programme principal ressemble à ceci (vous devrez inclure jnlp.jar comme lib, que vous pouvez trouver à <jdk_home>\sample\jnlp\servlet
):
package downloadtest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.jnlp.DownloadService;
import javax.jnlp.DownloadServiceListener;
import javax.jnlp.ServiceManager;
import javax.jnlp.UnavailableServiceException;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
public class Main {
private static DownloadService downloadService;
private static DownloadServiceListener customDownloadWindow;
static {
try {
downloadService = (DownloadService) ServiceManager.lookup("javax.jnlp.DownloadService");
} catch (UnavailableServiceException ex) {
System.err.println("DownloadService not available.");
}
customDownloadWindow = new CustomProgress();
}
public static void main(String[] args) {
JFrame frame = new JFrame("DownloadTest");
frame.setBounds(0, 0, 200, 100);
frame.setDefaultCloseOperation(JDialog.EXIT_ON_CLOSE);
frame.setLayout(null);
JButton startDownload = new JButton("download");
startDownload.setBounds(20, 20, 150, 40);
startDownload.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() {
try {
downloadService.loadPart("One", customDownloadWindow);
//downloadService.loadPart("One", downloadService.getDefaultProgressWindow());
} catch (IOException ex) {
ex.printStackTrace();
System.err.println("IOException loadPart.");
}
return null;
}
}.execute();
}
});
frame.add(startDownload);
frame.setVisible(true);
}
}
Vous pouvez essayer chaque fenêtre de progression de téléchargement en décommentant un « DownloadService. loadPart ... "ligne et commenter l'autre.
Et enfin la fenêtre de progression personnalisée lui-même:
package downloadtest;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.jnlp.DownloadServiceListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
public class CustomProgress implements DownloadServiceListener {
JFrame frame = null;
JProgressBar progressBar = null;
boolean uiCreated = false;
boolean canceled = false;
public CustomProgress() {
}
private void create() {
JPanel top = createComponents();
frame = new JFrame(); // top level custom progress indicator UI
frame.getContentPane().add(top, BorderLayout.CENTER);
frame.setBounds(300,300,400,300);
frame.pack();
updateProgressUI(0);
}
private JPanel createComponents() {
JPanel top = new JPanel();
top.setBackground(Color.WHITE);
top.setLayout(new BorderLayout(20, 20));
String lblText = "<html><font color=green size=+2>JDK Documentation</font>" +
"<br/> The one-stop shop for Java enlightenment! <br/></html>";
JLabel lbl = new JLabel(lblText);
top.add(lbl, BorderLayout.NORTH);
progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
progressBar.setStringPainted(true);
top.add(progressBar, BorderLayout.CENTER);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
CustomProgress.this.canceled = true;
}
});
top.add(cancelButton, BorderLayout.SOUTH);
return top;
}
public void progress(URL url, String version, long readSoFar,
long total, int overallPercent) {
updateProgressUI(overallPercent);
}
public void upgradingArchive(java.net.URL url,
java.lang.String version,
int patchPercent,
int overallPercent) {
updateProgressUI(overallPercent);
}
public void validating(java.net.URL url,
java.lang.String version,
long entry,
long total,
int overallPercent) {
updateProgressUI(overallPercent);
}
public void downloadFailed(URL url, String string) {
System.err.println("Download failed");
}
private void updateProgressUI(int overallPercent) {
if (overallPercent > 0 && overallPercent < 99) {
if (!uiCreated) {
uiCreated = true;
// create custom progress indicator's UI only if
// there is more work to do, meaning overallPercent > 0 and < 100
// this prevents flashing when RIA is loaded from cache
create();
}
progressBar.setValue(overallPercent);
if (canceled) {
throw new RuntimeException("canceled by user");
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
} else {
// hide frame when overallPercent is above 99
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (frame != null) {
frame.setVisible(false);
frame.dispose();
}
}
});
}
}
}
Ceci est essentiellement tiré d'un tutoriel Oracle (http://download.oracle.com/javase/tutorial/deployment/webstart/customProgressIndicatorForAppln.html) . Je viens d'ajouter un bouton d'annulation. Lorsque vous générez ce fichier jar et que vous le placez avec les fichiers largeResource.jar et DownloadTest.jnlp dans un dossier public de votre serveur Web, vous devez pouvoir démarrer l'application via votre navigateur Web. Ensuite, cliquez sur le bouton de téléchargement et avant qu'il ne soit terminé, cliquez sur le bouton Annuler dans la fenêtre de téléchargement. Après avoir essayé la fenêtre de progression personnalisée, vous devez supprimer l'application (ou simplement la ressource) de votre cache Java (car la ressource est téléchargée en arrière-plan, même si vous cliquez sur le bouton Annuler). Alors, pourquoi cela fonctionne-t-il avec la fenêtre de progression par défaut, mais pas avec la fenêtre de progression personnalisée? Y a-t-il une possibilité facile d'annuler un téléchargement avec une fenêtre de téléchargement personnalisée?
Toute aide ou conseil apprécié.
Drax
Eh bien je pourrais définir un DefaultUncaughtExceptionHandler pour tous les threads ('Thread.setDefaultUncaughtExceptionHandler (new DownloadUncaughtExceptionHandler())' 'qui est probablement similaire à votre solution (sinon la même chose) et mettre la méthode loadPart dans un thread au lieu d'un SwingWorker. De cette façon, le gestionnaire d'exceptions serait appelé, mais le problème demeure que le téléchargement de la ressource continue en arrière-plan. – Drax
Le téléchargement a-t-il lieu dans un autre thread? Pouvez-vous obtenir une poignée sur le fil? –