001: /*
002: * Roster.java - A list of things to do, used in various places
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2001, 2004 Slava Pestov
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: */
022:
023: package org.gjt.sp.jedit.pluginmgr;
024:
025: //{{{ Imports
026: import javax.swing.SwingUtilities;
027: import java.awt.Component;
028: import java.io.*;
029: import java.net.*;
030: import java.util.zip.*;
031: import java.util.*;
032: import org.gjt.sp.jedit.*;
033: import org.gjt.sp.util.Log;
034: import org.gjt.sp.util.IOUtilities;
035:
036: import static org.gjt.sp.jedit.io.FileVFS.recursiveDelete;
037:
038: //}}}
039:
040: /**
041: * @author $Id: Roster.java 10793 2007-10-03 21:06:53Z kpouer $
042: */
043: class Roster {
044: //{{{ Roster constructor
045: Roster() {
046: operations = new ArrayList<Operation>();
047: toLoad = new ArrayList<String>();
048: } //}}}
049:
050: //{{{ addRemove() method
051: /**
052: * Add a remove operation for the given jar
053: * @param jar the jar name
054: */
055: void addRemove(String jar) {
056: addOperation(new Remove(jar));
057: } //}}}
058:
059: //{{{ addInstall() method
060: void addInstall(String installed, String url,
061: String installDirectory, int size) {
062: addOperation(new Install(installed, url, installDirectory, size));
063: } //}}}
064:
065: //{{{ getOperation() method
066: public Operation getOperation(int i) {
067: return operations.get(i);
068: } //}}}
069:
070: //{{{ getOperationCount() method
071: int getOperationCount() {
072: return operations.size();
073: } //}}}
074:
075: //{{{ isEmpty() method
076: boolean isEmpty() {
077: return operations.isEmpty();
078: } //}}}
079:
080: //{{{ performOperationsInWorkThread() method
081: void performOperationsInWorkThread(PluginManagerProgress progress) {
082: for (int i = 0; i < operations.size(); i++) {
083: Operation op = operations.get(i);
084: op.runInWorkThread(progress);
085: progress.done();
086:
087: if (Thread.interrupted())
088: return;
089: }
090: } //}}}
091:
092: //{{{ performOperationsInAWTThread() method
093: void performOperationsInAWTThread(Component comp) {
094: for (int i = 0; i < operations.size(); i++) {
095: Operation op = operations.get(i);
096: op.runInAWTThread(comp);
097: }
098:
099: // add the JARs before checking deps since dep check might
100: // require all JARs to be present
101: for (int i = 0; i < toLoad.size(); i++) {
102: String pluginName = toLoad.get(i);
103: if (jEdit.getPluginJAR(pluginName) != null) {
104: Log.log(Log.WARNING, this , "Already loaded: "
105: + pluginName);
106: } else
107: jEdit.addPluginJAR(pluginName);
108: }
109:
110: for (int i = 0; i < toLoad.size(); i++) {
111: String pluginName = toLoad.get(i);
112: PluginJAR plugin = jEdit.getPluginJAR(pluginName);
113: if (plugin != null)
114: plugin.checkDependencies();
115: }
116:
117: // now activate the plugins
118: for (int i = 0; i < toLoad.size(); i++) {
119: String pluginName = toLoad.get(i);
120: PluginJAR plugin = jEdit.getPluginJAR(pluginName);
121: if (plugin != null)
122: plugin.activatePluginIfNecessary();
123: }
124: } //}}}
125:
126: //{{{ Private members
127: private static File downloadDir;
128:
129: private List<Operation> operations;
130: private List<String> toLoad;
131:
132: //{{{ addOperation() method
133: private void addOperation(Operation op) {
134: for (int i = 0; i < operations.size(); i++) {
135: if (operations.get(i).equals(op))
136: return;
137: }
138:
139: operations.add(op);
140: } //}}}
141:
142: //{{{ getDownloadDir() method
143: private static String getDownloadDir() {
144: if (downloadDir == null) {
145: String settings = jEdit.getSettingsDirectory();
146: if (settings == null)
147: settings = System.getProperty("user.home");
148: downloadDir = new File(MiscUtilities.constructPath(
149: settings, "PluginManager.download"));
150: downloadDir.mkdirs();
151: }
152:
153: return downloadDir.getPath();
154: } //}}}
155:
156: //}}}
157:
158: //{{{ Operation interface
159: abstract static class Operation {
160: public void runInWorkThread(PluginManagerProgress progress) {
161: }
162:
163: public void runInAWTThread(Component comp) {
164: }
165:
166: public int getMaximum() {
167: return 0;
168: }
169: } //}}}
170:
171: //{{{ Remove class
172: class Remove extends Operation {
173: //{{{ Remove constructor
174: Remove(String jar) {
175: this .jar = jar;
176: } //}}}
177:
178: //{{{ runInAWTThread() method
179: public void runInAWTThread(Component comp) {
180: // close JAR file and all JARs that depend on this
181: PluginJAR jar = jEdit.getPluginJAR(this .jar);
182: if (jar != null) {
183: unloadPluginJAR(jar);
184: }
185:
186: toLoad.remove(this .jar);
187:
188: // remove cache file
189:
190: // move JAR first
191: File jarFile = new File(this .jar);
192: File srcFile = new File(this .jar.substring(0, this .jar
193: .length() - 4));
194:
195: Log.log(Log.NOTICE, this , "Deleting " + jarFile);
196:
197: boolean ok = jarFile.delete();
198:
199: if (srcFile.exists()) {
200: ok &= recursiveDelete(srcFile);
201: }
202:
203: if (!ok) {
204: String[] args = { this .jar };
205: GUIUtilities.error(comp,
206: "plugin-manager.remove-failed", args);
207: }
208: } //}}}
209:
210: //{{{ unloadPluginJAR() method
211: /**
212: * This should go into a public method somewhere.
213: * @param jar the jar of the plugin
214: */
215: private void unloadPluginJAR(PluginJAR jar) {
216: String[] dependents = jar.getDependentPlugins();
217: for (String path : dependents) {
218: PluginJAR _jar = jEdit.getPluginJAR(path);
219: if (_jar != null) {
220: toLoad.add(path);
221: unloadPluginJAR(_jar);
222: // clear cache file
223: String cachePath = jar.getCachePath();
224: if (cachePath != null)
225: new File(cachePath).delete();
226:
227: }
228: }
229: jEdit.removePluginJAR(jar, false);
230:
231: } //}}}
232:
233: //{{{ equals() method
234: public boolean equals(Object o) {
235: return o instanceof Remove && ((Remove) o).jar.equals(jar);
236: } //}}}
237:
238: //{{{ Private members
239: private final String jar;
240: //}}}
241: } //}}}
242:
243: //{{{ Install class
244: class Install extends Operation {
245: int size;
246:
247: //{{{ Install constructor
248: Install(String installed, String url, String installDirectory,
249: int size) {
250: // catch those hooligans passing null urls
251: if (url == null)
252: throw new NullPointerException();
253:
254: this .installed = installed;
255: this .url = url;
256: this .installDirectory = installDirectory;
257: this .size = size;
258: } //}}}
259:
260: //{{{ getMaximum() method
261: public int getMaximum() {
262: return size;
263: } //}}}
264:
265: //{{{ runInWorkThread() method
266: public void runInWorkThread(PluginManagerProgress progress) {
267: String fileName = MiscUtilities.getFileName(url);
268:
269: path = download(progress, fileName, url);
270: } //}}}
271:
272: //{{{ runInAWTThread() method
273: public void runInAWTThread(Component comp) {
274: // check if download failed
275: if (path == null)
276: return;
277:
278: // if download OK, remove existing version
279: if (installed != null)
280: new Remove(installed).runInAWTThread(comp);
281:
282: ZipFile zipFile = null;
283:
284: try {
285: zipFile = new ZipFile(path);
286:
287: Enumeration<? extends ZipEntry> e = zipFile.entries();
288: while (e.hasMoreElements()) {
289: ZipEntry entry = e.nextElement();
290: String name = entry.getName().replace('/',
291: File.separatorChar);
292: File file = new File(installDirectory, name);
293: if (entry.isDirectory())
294: file.mkdirs();
295: else {
296: new File(file.getParent()).mkdirs();
297: InputStream in = null;
298: FileOutputStream out = null;
299: try {
300: in = zipFile.getInputStream(entry);
301: out = new FileOutputStream(file);
302: IOUtilities.copyStream(4096, null, in, out,
303: false);
304: } finally {
305: IOUtilities.closeQuietly(in);
306: IOUtilities.closeQuietly(out);
307: }
308: if (file.getName().toLowerCase().endsWith(
309: ".jar"))
310: toLoad.add(file.getPath());
311: }
312: }
313: } catch (InterruptedIOException iio) {
314: } catch (ZipException e) {
315: Log.log(Log.ERROR, this , e);
316: GUIUtilities.error(null, "plugin-error-download",
317: new Object[] { "" });
318: } catch (IOException io) {
319: Log.log(Log.ERROR, this , io);
320:
321: String[] args = { io.getMessage() };
322: GUIUtilities.error(null, "ioerror", args);
323: } catch (Exception e) {
324: Log.log(Log.ERROR, this , e);
325: } finally {
326: try {
327: if (zipFile != null)
328: zipFile.close();
329: } catch (IOException io) {
330: Log.log(Log.ERROR, this , io);
331: }
332:
333: if (jEdit
334: .getBooleanProperty("plugin-manager.deleteDownloads")) {
335: new File(path).delete();
336: }
337: }
338: } //}}}
339:
340: //{{{ equals() method
341: public boolean equals(Object o) {
342: return o instanceof Install
343: && ((Install) o).url.equals(url);
344: } //}}}
345:
346: //{{{ Private members
347: private String installed;
348: private final String url;
349: private String installDirectory;
350: private String path;
351:
352: //{{{ download() method
353: private String download(PluginManagerProgress progress,
354: String fileName, String url) {
355: try {
356: String host = jEdit
357: .getProperty("plugin-manager.mirror.id");
358: if (host == null || host.equals(MirrorList.Mirror.NONE))
359: host = "default";
360:
361: String path = MiscUtilities.constructPath(
362: getDownloadDir(), fileName);
363: URLConnection conn = new URL(url).openConnection();
364: progress.setStatus(jEdit.getProperty(
365: "plugin-manager.progress", new String[] {
366: fileName, host }));
367: InputStream in = null;
368: FileOutputStream out = null;
369: try {
370: in = conn.getInputStream();
371: out = new FileOutputStream(path);
372: if (!IOUtilities
373: .copyStream(progress, in, out, true))
374: return null;
375: } finally {
376: IOUtilities.closeQuietly(in);
377: IOUtilities.closeQuietly(out);
378: }
379:
380: return path;
381: } catch (InterruptedIOException iio) {
382: // do nothing, user clicked 'Stop'
383: return null;
384: } catch (FileNotFoundException e) {
385: Log.log(Log.ERROR, this , e);
386:
387: SwingUtilities.invokeLater(new Runnable() {
388: public void run() {
389: GUIUtilities.error(null,
390: "plugin-error-download",
391: new Object[] { "" });
392: }
393: });
394:
395: return null;
396: } catch (final IOException io) {
397: Log.log(Log.ERROR, this , io);
398:
399: SwingUtilities.invokeLater(new Runnable() {
400: public void run() {
401: String[] args = { io.getMessage() };
402: GUIUtilities.error(null,
403: "plugin-error-download", args);
404: }
405: });
406:
407: return null;
408: } catch (Exception e) {
409: Log.log(Log.ERROR, this , e);
410:
411: return null;
412: }
413: } //}}}
414:
415: //}}}
416: } //}}}
417: }
|