Permalink
Browse files

[MARKET-35] Fixed issue with uninstalling plugins on Windows

  • Loading branch information...
1 parent 9b670e9 commit e76c54020377988e756b1f61917bf681b7bdabec @wgorman wgorman committed Sep 16, 2012
Showing with 130 additions and 6 deletions.
  1. +1 −1 ivy.xml
  2. +13 −5 src/org/pentaho/marketplace/MarketplaceService.java
  3. +116 −0 src/org/pentaho/marketplace/Util.java
View
2 ivy.xml
@@ -24,7 +24,7 @@
<dependency org="net.sf.flexjson" name="flexjson" rev="2.1" transitive="false" conf="default->default"/>
<dependency org="org.springframework.security" name="spring-security-core" rev="2.0.5.RELEASE" transitive="false"/>
<dependency org="javax.servlet" name="servlet-api" rev="2.4" />
-
+ <dependency org="org.hibernate" name="hibernate" rev="3.2.6.ga" transitive="false"/>
<!-- Pentaho dependencies -->
<dependency org="pentaho" name="pentaho-bi-platform-api" rev="${dependency.bi-platform.revision}" changing="true" transitive="false"/>
View
18 src/org/pentaho/marketplace/MarketplaceService.java
@@ -22,6 +22,7 @@
import java.io.File;
import java.io.FileReader;
import java.io.StringReader;
+import java.net.URLClassLoader;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -141,12 +142,16 @@ public MarketplaceService() {
}
- return plugins;
-
-
-
+ return plugins;
+ }
+
+ private void closeClassLoader(String pluginId) {
+ IPluginManager pluginManager = PentahoSystem.get(IPluginManager.class, PentahoSessionHolder.getSession());
+ ClassLoader cl = pluginManager.getClassLoader(pluginId);
+ if (cl != null && cl instanceof URLClassLoader) {
+ Util.closeURLClassLoader((URLClassLoader)cl);
+ }
}
-
public StatusMessage uninstallPlugin(String id) throws MarketplaceSecurityException {
Plugin plugins[] = getPlugins();
@@ -161,6 +166,9 @@ public StatusMessage uninstallPlugin(String id) throws MarketplaceSecurityExcept
return new StatusMessage("NO_PLUGIN", "Plugin Not Found");
}
+ // before deletion, close class loader
+ closeClassLoader(toUninstall.getId());
+
String versionBranch = toUninstall.getInstalledBranch();
// get plugin path
View
116 src/org/pentaho/marketplace/Util.java
@@ -0,0 +1,116 @@
+package org.pentaho.marketplace;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+import java.util.jar.JarFile;
+
+import org.hibernate.util.ReflectHelper;
+
+/**
+ * General utility class for the marketplace.
+ *
+ * @author Will Gorman (wgorman@pentaho.com)
+ *
+ */
+@SuppressWarnings("rawtypes")
+public class Util {
+
+ private static Object getFieldObject( Class clazz, String name, Object obj) throws Exception {
+ Field field = clazz.getDeclaredField(name);
+ field.setAccessible(true);
+ return field.get(obj);
+ }
+
+ /**
+ * This method is designed to clear out classloader file locks in windows.
+ *
+ * @param clazzLdr class loader to clean up
+ */
+ public static void closeURLClassLoader(URLClassLoader clazzLdr) {
+ HashSet<String> closedFiles = new HashSet<String>();
+ try {
+ Object obj = getFieldObject(URLClassLoader.class, "ucp", clazzLdr);
+ ArrayList loaders = (ArrayList) getFieldObject(obj.getClass(), "loaders", obj);
+ for (Object ldr : loaders) {
+ try {
+ JarFile file = (JarFile) getFieldObject(ldr.getClass(), "jar", ldr);
+ closedFiles.add(file.getName());
+ file.close();
+ } catch (Exception e) {
+ // skip
+ }
+ }
+ } catch (Exception e) {
+ // skip
+ }
+
+ try {
+ Vector nativeLibArr = (Vector) getFieldObject(ClassLoader.class, "nativeLibraries", clazzLdr);
+ for (Object lib : nativeLibArr) {
+ try {
+ Method fMethod = lib.getClass().getDeclaredMethod("finalize", new Class[0]);
+ fMethod.setAccessible(true);
+ fMethod.invoke(lib, new Object[0]);
+ } catch (Exception e) {
+ // skip
+ }
+ }
+ } catch (Exception e) {
+ // skip
+ }
+
+ HashMap uCache = null;
+ HashMap fCache = null;
+
+ try {
+ Class factory = getFieldObject(ReflectHelper.classForName("sun.net.www.protocol.jar.JarURLConnection"), "factory", null).getClass();
+ try {
+ fCache = (HashMap) getFieldObject(factory, "fileCache", null);
+ } catch (Exception e) {
+ // skip
+ }
+ try {
+ uCache = (HashMap) getFieldObject(factory, "urlCache", null);
+ } catch (Exception e) {
+ // skip
+ }
+ if (uCache != null) {
+ for (Object file : ((HashMap)uCache.clone()).keySet()) {
+ if (file instanceof JarFile) {
+ JarFile jar = (JarFile) file;
+ if (!closedFiles.contains(jar.getName())) continue;
+ try {
+ jar.close();
+ } catch (IOException e) {
+ // skip
+ }
+ if (fCache != null) fCache.remove(uCache.get(jar));
+ uCache.remove(jar);
+ }
+ }
+ } else if (fCache != null) {
+ for (Object key : ((HashMap) fCache.clone()).keySet()) {
+ Object file = fCache.get(key);
+ if (file instanceof JarFile) {
+ JarFile jar = (JarFile) file;
+ if (!closedFiles.contains(jar.getName())) continue;
+ try {
+ jar.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ fCache.remove(key);
+ }
+ }
+ }
+ } catch (Exception e) {
+ // skip
+ }
+ }
+}

0 comments on commit e76c540

Please sign in to comment.