📄 pluginmanager.java
字号:
* @param plugin the plugin.
* @param xpath the xpath expression.
* @return the value of the element selected by the xpath expression.
*/
private String getElementValue(Plugin plugin, String xpath) {
File pluginDir = pluginDirs.get(plugin);
if (pluginDir == null) {
return null;
}
try {
File pluginConfig = new File(pluginDir, "plugin.xml");
if (pluginConfig.exists()) {
SAXReader saxReader = new SAXReader();
saxReader.setEncoding("UTF-8");
Document pluginXML = saxReader.read(pluginConfig);
Element element = (Element)pluginXML.selectSingleNode(xpath);
if (element != null) {
return element.getTextTrim();
}
}
}
catch (Exception e) {
Log.error(e);
}
return null;
}
/**
* An enumberation for plugin license agreement types.
*/
public enum License {
/**
* The plugin is distributed using a commercial license.
*/
commercial,
/**
* The plugin is distributed using the GNU Public License (GPL).
*/
gpl,
/**
* The plugin is distributed using the Apache license.
*/
apache,
/**
* The plugin is for internal use at an organization only and is not re-distributed.
*/
internal,
/**
* The plugin is distributed under another license agreement not covered by
* one of the other choices. The license agreement should be detailed in the
* plugin Readme.
*/
other
}
/**
* A service that monitors the plugin directory for plugins. It periodically
* checks for new plugin JAR files and extracts them if they haven't already
* been extracted. Then, any new plugin directories are loaded.
*/
private class PluginMonitor implements Runnable {
/**
* Tracks if the monitor is currently running.
*/
private boolean running = false;
public void run() {
// If the task is already running, return.
synchronized (this) {
if (running) {
return;
}
running = true;
}
try {
running = true;
// Look for extra plugin directories specified as a system property.
String pluginDirs = System.getProperty("pluginDirs");
if (pluginDirs != null) {
StringTokenizer st = new StringTokenizer(pluginDirs, ", ");
while (st.hasMoreTokens()) {
String dir = st.nextToken();
if (!devPlugins.contains(dir)) {
loadPlugin(new File(dir));
devPlugins.add(dir);
}
}
}
File[] jars = pluginDirectory.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String fileName = pathname.getName().toLowerCase();
return (fileName.endsWith(".jar") || fileName.endsWith(".war"));
}
});
if (jars == null) {
return;
}
for (File jarFile : jars) {
String pluginName = jarFile.getName().substring(0,
jarFile.getName().length() - 4).toLowerCase();
// See if the JAR has already been exploded.
File dir = new File(pluginDirectory, pluginName);
// If the JAR hasn't been exploded, do so.
if (!dir.exists()) {
unzipPlugin(pluginName, jarFile, dir);
}
// See if the JAR is newer than the directory. If so, the plugin
// needs to be unloaded and then reloaded.
else if (jarFile.lastModified() > dir.lastModified()) {
unloadPlugin(pluginName);
// Give the plugin 2 seconds to unload.
Thread.sleep(2000);
// Ask the system to clean up references.
System.gc();
int count = 0;
while (!deleteDir(dir) && count < 5) {
Log.warn("Error unloading plugin " + pluginName + ". " +
"Will attempt again momentarily.");
Thread.sleep(8000);
count++;
// Ask the system to clean up references.
System.gc();
}
// If the delete operation was a success, unzip the plugin.
if (count != 5) {
unzipPlugin(pluginName, jarFile, dir);
}
}
}
File[] dirs = pluginDirectory.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
// Sort the list of directories so that the "admin" plugin is always
// first in the list.
Arrays.sort(dirs, new Comparator<File>() {
public int compare(File file1, File file2) {
if (file1.getName().equals("admin")) {
return -1;
}
else if (file2.getName().equals("admin")) {
return 1;
}
else {
return file1.compareTo(file2);
}
}
});
// Turn the list of JAR/WAR files into a set so that we can do lookups.
Set<String> jarSet = new HashSet<String>();
for (File file : jars) {
jarSet.add(file.getName().toLowerCase());
}
// See if any currently running plugins need to be unloaded
// due to the JAR file being deleted (ignore admin plugin).
// Build a list of plugins to delete first so that the plugins
// keyset isn't modified as we're iterating through it.
List<String> toDelete = new ArrayList<String>();
for (File pluginDir : dirs) {
String pluginName = pluginDir.getName();
if (pluginName.equals("admin")) {
continue;
}
if (!jarSet.contains(pluginName + ".jar")) {
if (!jarSet.contains(pluginName + ".war")) {
toDelete.add(pluginName);
}
}
}
for (String pluginName : toDelete) {
unloadPlugin(pluginName);
System.gc();
int count = 0;
File dir = new File(pluginDirectory, pluginName);
while (!deleteDir(dir) && count < 5) {
Log.error("Error unloading plugin " + pluginName + ". " +
"Will attempt again momentarily.");
Thread.sleep(10000);
count++;
}
}
// Load all plugins that need to be loaded.
for (File dirFile : dirs) {
// If the plugin hasn't already been started, start it.
if (dirFile.exists() && !plugins.containsKey(dirFile.getName())) {
loadPlugin(dirFile);
}
}
}
catch (Throwable e) {
Log.error(e);
}
// Finished running task.
synchronized (this) {
running = false;
}
}
/**
* Unzips a plugin from a JAR file into a directory. If the JAR file
* isn't a plugin, this method will do nothing.
*
* @param pluginName the name of the plugin.
* @param file the JAR file
* @param dir the directory to extract the plugin to.
*/
private void unzipPlugin(String pluginName, File file, File dir) {
try {
ZipFile zipFile = new JarFile(file);
// Ensure that this JAR is a plugin.
if (zipFile.getEntry("plugin.xml") == null) {
return;
}
dir.mkdir();
// Set the date of the JAR file to the newly created folder
dir.setLastModified(file.lastModified());
Log.debug("Extracting plugin: " + pluginName);
for (Enumeration e = zipFile.entries(); e.hasMoreElements();) {
JarEntry entry = (JarEntry)e.nextElement();
File entryFile = new File(dir, entry.getName());
// Ignore any manifest.mf entries.
if (entry.getName().toLowerCase().endsWith("manifest.mf")) {
continue;
}
if (!entry.isDirectory()) {
entryFile.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(entryFile);
InputStream zin = zipFile.getInputStream(entry);
byte[] b = new byte[512];
int len;
while ((len = zin.read(b)) != -1) {
out.write(b, 0, len);
}
out.flush();
out.close();
zin.close();
}
}
zipFile.close();
// The lib directory of the plugin may contain Pack200 versions of the JAR
// file. If so, unpack them.
unpackArchives(new File(dir, "lib"));
}
catch (Exception e) {
Log.error(e);
}
}
/**
* Converts any pack files in a directory into standard JAR files. Each
* pack file will be deleted after being converted to a JAR. If no
* pack files are found, this method does nothing.
*
* @param libDir the directory containing pack files.
*/
private void unpackArchives(File libDir) {
// Get a list of all packed files in the lib directory.
File [] packedFiles = libDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".pack");
}
});
if (packedFiles == null) {
// Do nothing since no .pack files were found
return;
}
// Unpack each.
for (File packedFile : packedFiles) {
try {
String jarName = packedFile.getName().substring(0,
packedFile.getName().length() - ".pack".length());
// Delete JAR file with same name if it exists (could be due to upgrade
// from old Wildfire release).
File jarFile = new File(libDir, jarName);
if (jarFile.exists()) {
jarFile.delete();
}
InputStream in = new BufferedInputStream(new FileInputStream(packedFile));
JarOutputStream out = new JarOutputStream(new BufferedOutputStream(
new FileOutputStream(new File(libDir, jarName))));
Pack200.Unpacker unpacker = Pack200.newUnpacker();
// Call the unpacker
unpacker.unpack(in, out);
in.close();
out.close();
packedFile.delete();
}
catch (Exception e) {
Log.error(e);
}
}
}
/**
* Deletes a directory.
*
* @param dir the directory to delete.
* @return true if the directory was deleted.
*/
private boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] childDirs = dir.list();
// Always try to delete JAR files first since that's what will
// be under contention. We do this by always sorting the lib directory
// first.
List<String> children = new ArrayList<String>(Arrays.asList(childDirs));
Collections.sort(children, new Comparator<String>() {
public int compare(String o1, String o2) {
if (o1.equals("lib")) {
return -1;
}
if (o2.equals("lib")) {
return 1;
}
else {
return o1.compareTo(o2);
}
}
});
for (String file : children) {
boolean success = deleteDir(new File(dir, file));
if (!success) {
Log.debug("Plugin removal: could not delete: " + new File(dir, file));
return false;
}
}
}
return dir.delete();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -