001: /*
002: * PluginList.java - Plugin list downloaded from server
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2001, 2003 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 java.io.*;
027: import java.net.URL;
028: import java.util.*;
029: import java.util.zip.GZIPInputStream;
030: import org.xml.sax.XMLReader;
031: import org.xml.sax.InputSource;
032: import org.xml.sax.helpers.XMLReaderFactory;
033: import org.gjt.sp.util.Log;
034: import org.gjt.sp.util.StandardUtilities;
035: import org.gjt.sp.util.WorkRequest;
036: import org.gjt.sp.util.IOUtilities;
037: import org.gjt.sp.jedit.*;
038:
039: //}}}
040:
041: /**
042: * Plugin list downloaded from server.
043: * @since jEdit 3.2pre2
044: * @version $Id: PluginList.java 10739 2007-09-24 20:05:11Z kpouer $
045: */
046: class PluginList {
047: /**
048: * Magic numbers used for auto-detecting GZIP files.
049: */
050: public static final int GZIP_MAGIC_1 = 0x1f;
051: public static final int GZIP_MAGIC_2 = 0x8b;
052:
053: final List<Plugin> plugins = new ArrayList<Plugin>();
054: final Map<String, Plugin> pluginHash = new HashMap<String, Plugin>();
055: final List<PluginSet> pluginSets = new ArrayList<PluginSet>();
056:
057: /**
058: * The mirror id.
059: * @since jEdit 4.3pre3
060: */
061: private final String id;
062: private String cachedURL;
063: private WorkRequest workRequest;
064: String gzipURL;
065:
066: //{{{ PluginList constructor
067: PluginList(WorkRequest workRequest) {
068: id = jEdit.getProperty("plugin-manager.mirror.id");
069: this .workRequest = workRequest;
070: readPluginList(true);
071: }
072:
073: void readPluginList(boolean allowRetry) {
074: gzipURL = jEdit.getProperty("plugin-manager.export-url");
075: if (!id.equals(MirrorList.Mirror.NONE))
076: gzipURL += "?mirror=" + id;
077: String path = null;
078: if (jEdit.getSettingsDirectory() == null) {
079: cachedURL = gzipURL;
080: } else {
081: path = jEdit.getSettingsDirectory() + File.separator
082: + "pluginMgr-Cached.xml.gz";
083: cachedURL = "file:///" + path;
084: }
085: boolean downloadIt = !id.equals(jEdit
086: .getProperty("plugin-manager.mirror.cached-id"));
087: if (path != null) {
088: try {
089:
090: File f = new File(path);
091: if (!f.canRead())
092: downloadIt = true;
093: long currentTime = System.currentTimeMillis();
094: long age = currentTime - f.lastModified();
095: /* By default only download plugin lists every 5 minutes */
096: long interval = jEdit.getIntegerProperty(
097: "plugin-manager.list-cache.minutes", 5) * 60 * 1000;
098: if (age > interval) {
099: Log
100: .log(Log.MESSAGE, this ,
101: "PluginList cached copy too old. Downloading from mirror. ");
102: downloadIt = true;
103: }
104: } catch (Exception e) {
105: Log.log(Log.MESSAGE, this ,
106: "No cached copy. Downloading from mirror. ");
107: downloadIt = true;
108: }
109: }
110: if (downloadIt && cachedURL != gzipURL) {
111: downloadPluginList();
112: }
113: InputStream in = null, inputStream = null;
114: try {
115: if (cachedURL != gzipURL)
116: Log.log(Log.MESSAGE, this , "Using cached pluginlist");
117: inputStream = new URL(cachedURL).openStream();
118: XMLReader parser = XMLReaderFactory.createXMLReader();
119: PluginListHandler handler = new PluginListHandler(this ,
120: cachedURL);
121: in = new BufferedInputStream(inputStream);
122: if (in.markSupported()) {
123: in.mark(2);
124: int b1 = in.read();
125: int b2 = in.read();
126: in.reset();
127:
128: if (b1 == GZIP_MAGIC_1 && b2 == GZIP_MAGIC_2)
129: in = new GZIPInputStream(in);
130: }
131: InputSource isrc = new InputSource(new InputStreamReader(
132: in, "UTF8"));
133: isrc.setSystemId("jedit.jar");
134: parser.setContentHandler(handler);
135: parser.setDTDHandler(handler);
136: parser.setEntityResolver(handler);
137: parser.setErrorHandler(handler);
138: parser.parse(isrc);
139:
140: } catch (Exception e) {
141: Log.log(Log.ERROR, this , "readpluginlist: error", e);
142: if (cachedURL.startsWith("file:///")) {
143: Log
144: .log(Log.DEBUG, this ,
145: "Unable to read plugin list, deleting cached file and try again");
146: new File(cachedURL.substring(8)).delete();
147: if (allowRetry) {
148: plugins.clear();
149: pluginHash.clear();
150: pluginSets.clear();
151: readPluginList(false);
152: }
153: }
154: } finally {
155: IOUtilities.closeQuietly(in);
156: IOUtilities.closeQuietly(inputStream);
157: }
158:
159: }
160:
161: /** Caches it locally */
162: void downloadPluginList() {
163: BufferedInputStream is = null;
164: BufferedOutputStream out = null;
165: try {
166:
167: workRequest.setStatus(jEdit
168: .getProperty("plugin-manager.list-download"));
169: InputStream inputStream = new URL(gzipURL).openStream();
170: String fileName = cachedURL.replaceFirst("file:///", "");
171: out = new BufferedOutputStream(new FileOutputStream(
172: fileName));
173: long start = System.currentTimeMillis();
174: is = new BufferedInputStream(inputStream);
175: IOUtilities.copyStream(4096, null, is, out, false);
176: jEdit.setProperty("plugin-manager.mirror.cached-id", id);
177: Log.log(Log.MESSAGE, this , "Updated cached pluginlist "
178: + (System.currentTimeMillis() - start));
179: } catch (Exception e) {
180: Log.log(Log.ERROR, this , "CacheRemotePluginList: error", e);
181: } finally {
182: IOUtilities.closeQuietly(out);
183: IOUtilities.closeQuietly(is);
184: }
185: }
186:
187: //{{{ addPlugin() method
188: void addPlugin(Plugin plugin) {
189: plugin.checkIfInstalled();
190: plugins.add(plugin);
191: pluginHash.put(plugin.name, plugin);
192: } //}}}
193:
194: //{{{ addPluginSet() method
195: void addPluginSet(PluginSet set) {
196: pluginSets.add(set);
197: } //}}}
198:
199: //{{{ finished() method
200: void finished() {
201: // after the entire list is loaded, fill out plugin field
202: // in dependencies
203: for (int i = 0; i < plugins.size(); i++) {
204: Plugin plugin = plugins.get(i);
205: for (int j = 0; j < plugin.branches.size(); j++) {
206: Branch branch = plugin.branches.get(j);
207: for (int k = 0; k < branch.deps.size(); k++) {
208: Dependency dep = branch.deps.get(k);
209: if (dep.what.equals("plugin"))
210: dep.plugin = pluginHash.get(dep.pluginName);
211: }
212: }
213: }
214: } //}}}
215:
216: //{{{ dump() method
217: void dump() {
218: for (int i = 0; i < plugins.size(); i++) {
219: System.err.println(plugins.get(i));
220: System.err.println();
221: }
222: } //}}}
223:
224: //{{{ getMirrorId() method
225: /**
226: * Returns the mirror ID.
227: *
228: * @return the mirror ID
229: * @since jEdit 4.3pre3
230: */
231: String getMirrorId() {
232: return id;
233: } //}}}
234:
235: //{{{ PluginSet class
236: static class PluginSet {
237: String name;
238: String description;
239: final List<String> plugins = new ArrayList<String>();
240:
241: public String toString() {
242: return plugins.toString();
243: }
244: } //}}}
245:
246: //{{{ Plugin class
247: public static class Plugin {
248: String jar;
249: String name;
250: String description;
251: String author;
252: final List<Branch> branches = new ArrayList<Branch>();
253:
254: //String installed;
255: //String installedVersion;
256:
257: void checkIfInstalled() {
258: /* // check if the plugin is already installed.
259: // this is a bit of hack
260: PluginJAR[] jars = jEdit.getPluginJARs();
261: for(int i = 0; i < jars.length; i++)
262: {
263: String path = jars[i].getPath();
264: if(!new File(path).exists())
265: continue;
266:
267: if(MiscUtilities.getFileName(path).equals(jar))
268: {
269: installed = path;
270:
271: EditPlugin plugin = jars[i].getPlugin();
272: if(plugin != null)
273: {
274: installedVersion = jEdit.getProperty(
275: "plugin." + plugin.getClassName()
276: + ".version");
277: }
278: break;
279: }
280: }
281:
282: String[] notLoaded = jEdit.getNotLoadedPluginJARs();
283: for(int i = 0; i < notLoaded.length; i++)
284: {
285: String path = notLoaded[i];
286:
287: if(MiscUtilities.getFileName(path).equals(jar))
288: {
289: installed = path;
290: break;
291: }
292: } */
293: }
294:
295: String getInstalledVersion() {
296: PluginJAR[] jars = jEdit.getPluginJARs();
297: for (int i = 0; i < jars.length; i++) {
298: String path = jars[i].getPath();
299:
300: if (MiscUtilities.getFileName(path).equals(jar)) {
301: EditPlugin plugin = jars[i].getPlugin();
302: if (plugin != null) {
303: return jEdit.getProperty("plugin."
304: + plugin.getClassName() + ".version");
305: } else
306: return null;
307: }
308: }
309:
310: return null;
311: }
312:
313: String getInstalledPath() {
314: PluginJAR[] jars = jEdit.getPluginJARs();
315: for (int i = 0; i < jars.length; i++) {
316: String path = jars[i].getPath();
317:
318: if (MiscUtilities.getFileName(path).equals(jar))
319: return path;
320: }
321:
322: return null;
323: }
324:
325: /**
326: * Find the first branch compatible with the running jEdit release.
327: */
328: Branch getCompatibleBranch() {
329: for (int i = 0; i < branches.size(); i++) {
330: Branch branch = branches.get(i);
331: if (branch.canSatisfyDependencies())
332: return branch;
333: }
334:
335: return null;
336: }
337:
338: boolean canBeInstalled() {
339: Branch branch = getCompatibleBranch();
340: return branch != null && !branch.obsolete
341: && branch.canSatisfyDependencies();
342: }
343:
344: void install(Roster roster, String installDirectory,
345: boolean downloadSource) {
346: String installed = getInstalledPath();
347:
348: Branch branch = getCompatibleBranch();
349: if (branch.obsolete) {
350: if (installed != null)
351: roster.addRemove(installed);
352: return;
353: }
354:
355: //branch.satisfyDependencies(roster,installDirectory,
356: // downloadSource);
357:
358: if (installed != null) {
359: installDirectory = MiscUtilities
360: .getParentOfPath(installed);
361: }
362:
363: roster.addInstall(installed,
364: downloadSource ? branch.downloadSource
365: : branch.download, installDirectory,
366: downloadSource ? branch.downloadSourceSize
367: : branch.downloadSize);
368:
369: }
370:
371: public String toString() {
372: return name;
373: }
374: } //}}}
375:
376: //{{{ Branch class
377: static class Branch {
378: String version;
379: String date;
380: int downloadSize;
381: String download;
382: int downloadSourceSize;
383: String downloadSource;
384: boolean obsolete;
385: final List<Dependency> deps = new ArrayList<Dependency>();
386:
387: boolean canSatisfyDependencies() {
388: for (int i = 0; i < deps.size(); i++) {
389: Dependency dep = deps.get(i);
390: if (!dep.canSatisfy())
391: return false;
392: }
393:
394: return true;
395: }
396:
397: void satisfyDependencies(Roster roster,
398: String installDirectory, boolean downloadSource) {
399: for (int i = 0; i < deps.size(); i++) {
400: Dependency dep = deps.get(i);
401: dep.satisfy(roster, installDirectory, downloadSource);
402: }
403: }
404:
405: public String toString() {
406: return "[version=" + version + ",download=" + download
407: + ",obsolete=" + obsolete + ",deps=" + deps + ']';
408: }
409: } //}}}
410:
411: //{{{ Dependency class
412: static class Dependency {
413: final String what;
414: final String from;
415: final String to;
416: // only used if what is "plugin"
417: final String pluginName;
418: Plugin plugin;
419:
420: Dependency(String what, String from, String to,
421: String pluginName) {
422: this .what = what;
423: this .from = from;
424: this .to = to;
425: this .pluginName = pluginName;
426: }
427:
428: boolean isSatisfied() {
429: if (what.equals("plugin")) {
430: for (int i = 0; i < plugin.branches.size(); i++) {
431: String installedVersion = plugin
432: .getInstalledVersion();
433: if (installedVersion != null
434: && (from == null || StandardUtilities
435: .compareStrings(installedVersion,
436: from, false) >= 0)
437: && (to == null || StandardUtilities
438: .compareStrings(installedVersion,
439: to, false) <= 0)) {
440: return true;
441: }
442: }
443:
444: return false;
445: } else if (what.equals("jdk")) {
446: String javaVersion = System.getProperty("java.version")
447: .substring(0, 3);
448:
449: if ((from == null || StandardUtilities.compareStrings(
450: javaVersion, from, false) >= 0)
451: && (to == null || StandardUtilities
452: .compareStrings(javaVersion, to, false) <= 0))
453: return true;
454: else
455: return false;
456: } else if (what.equals("jedit")) {
457: String build = jEdit.getBuild();
458:
459: if ((from == null || StandardUtilities.compareStrings(
460: build, from, false) >= 0)
461: && (to == null || StandardUtilities
462: .compareStrings(build, to, false) <= 0))
463: return true;
464: else
465: return false;
466: } else {
467: Log.log(Log.ERROR, this , "Invalid dependency: " + what);
468: return false;
469: }
470: }
471:
472: boolean canSatisfy() {
473: if (isSatisfied())
474: return true;
475: if (what.equals("plugin"))
476: return plugin.canBeInstalled();
477: return false;
478: }
479:
480: void satisfy(Roster roster, String installDirectory,
481: boolean downloadSource) {
482: if (what.equals("plugin")) {
483: String installedVersion = plugin.getInstalledVersion();
484: for (int i = 0; i < plugin.branches.size(); i++) {
485: Branch branch = plugin.branches.get(i);
486: if ((installedVersion == null || StandardUtilities
487: .compareStrings(installedVersion,
488: branch.version, false) < 0)
489: && (from == null || StandardUtilities
490: .compareStrings(branch.version,
491: from, false) >= 0)
492: && (to == null || StandardUtilities
493: .compareStrings(branch.version, to,
494: false) <= 0)) {
495: plugin.install(roster, installDirectory,
496: downloadSource);
497: return;
498: }
499: }
500: }
501: }
502:
503: public String toString() {
504: return "[what=" + what + ",from=" + from + ",to=" + to
505: + ",plugin=" + plugin + ']';
506: }
507: } //}}}
508: }
|