001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.plugins; 003 004 import java.io.File; 005 import java.io.FileNotFoundException; 006 import java.io.FileOutputStream; 007 import java.io.IOException; 008 import java.io.InputStream; 009 import java.net.URL; 010 import java.net.URLClassLoader; 011 import java.util.List; 012 013 import org.openstreetmap.josm.Main; 014 import org.openstreetmap.josm.gui.MapFrame; 015 import org.openstreetmap.josm.gui.download.DownloadSelection; 016 import org.openstreetmap.josm.gui.preferences.PreferenceSetting; 017 018 /** 019 * For all purposes of loading dynamic resources, the Plugin's class loader should be used 020 * (or else, the plugin jar will not be within the class path). 021 * 022 * A plugin may subclass this abstract base class (but it is optional). 023 * 024 * The actual implementation of this class is optional, as all functions will be called 025 * via reflection. This is to be able to change this interface without the need of 026 * recompiling or even breaking the plugins. If your class does not provide a 027 * function here (or does provide a function with a mismatching signature), it will not 028 * be called. That simple. 029 * 030 * Or in other words: See this base class as an documentation of what automatic callbacks 031 * are provided (you can register yourself to more callbacks in your plugin class 032 * constructor). 033 * 034 * Subclassing Plugin and overriding some functions makes it easy for you to keep sync 035 * with the correct actual plugin architecture of JOSM. 036 * 037 * @author Immanuel.Scholz 038 */ 039 public abstract class Plugin { 040 041 /** 042 * This is the info available for this plugin. You can access this from your 043 * constructor. 044 * 045 * (The actual implementation to request the info from a static variable 046 * is a bit hacky, but it works). 047 */ 048 private PluginInformation info = null; 049 050 /** 051 * Creates the plugin 052 * 053 * @param info the plugin information describing the plugin. 054 */ 055 public Plugin(PluginInformation info) { 056 this.info = info; 057 } 058 059 /** 060 * Replies the plugin information object for this plugin 061 * 062 * @return the plugin information object 063 */ 064 public PluginInformation getPluginInformation() { 065 return info; 066 } 067 068 /** 069 * Sets the plugin information object for this plugin 070 * 071 * @parma info the plugin information object 072 */ 073 public void setPluginInformation(PluginInformation info) { 074 this.info = info; 075 } 076 077 /** 078 * @return The directory for the plugin to store all kind of stuff. 079 */ 080 public String getPluginDir() { 081 return new File(Main.pref.getPluginsDirectory(), info.name).getPath(); 082 } 083 084 /** 085 * Called after Main.mapFrame is initalized. (After the first data is loaded). 086 * You can use this callback to tweak the newFrame to your needs, as example install 087 * an alternative Painter. 088 */ 089 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {} 090 091 /** 092 * Called in the preferences dialog to create a preferences page for the plugin, 093 * if any available. 094 */ 095 public PreferenceSetting getPreferenceSetting() { return null; } 096 097 /** 098 * Called in the download dialog to give the plugin a chance to modify the list 099 * of bounding box selectors. 100 */ 101 public void addDownloadSelection(List<DownloadSelection> list) {} 102 103 /** 104 * Copies the resource 'from' to the file in the plugin directory named 'to'. 105 */ 106 public void copy(String from, String to) throws FileNotFoundException, IOException { 107 String pluginDirName = getPluginDir(); 108 File pluginDir = new File(pluginDirName); 109 if (!pluginDir.exists()) { 110 pluginDir.mkdirs(); 111 } 112 FileOutputStream out = new FileOutputStream(new File(pluginDirName, to)); 113 InputStream in = getClass().getResourceAsStream(from); 114 byte[] buffer = new byte[8192]; 115 for(int len = in.read(buffer); len > 0; len = in.read(buffer)) { 116 out.write(buffer, 0, len); 117 } 118 in.close(); 119 out.close(); 120 } 121 122 /** 123 * Get a class loader for loading resources from the plugin jar. 124 * 125 * This can be used to avoid getting a file from another plugin that 126 * happens to have a file with the same file name and path. 127 * 128 * Usage: Instead of 129 * getClass().getResource("/resources/pluginProperties.properties"); 130 * write 131 * getPluginResourceClassLoader().getResource("resources/pluginProperties.properties"); 132 * 133 * (Note the missing leading "/".) 134 */ 135 public ClassLoader getPluginResourceClassLoader() { 136 File pluginDir = Main.pref.getPluginsDirectory(); 137 File pluginJar = new File(pluginDir, info.name + ".jar"); 138 URL pluginJarUrl = PluginInformation.fileToURL(pluginJar); 139 URLClassLoader pluginClassLoader = new URLClassLoader(new URL[] { pluginJarUrl } , Main.class.getClassLoader()); 140 return pluginClassLoader; 141 } 142 }