From 18c0eefc795e35eceb276e4807a38130c4d7c3d3 Mon Sep 17 00:00:00 2001 From: Nils Christian Ehmke <nie@informatik.uni-kiel.de> Date: Sat, 3 Nov 2012 11:20:29 +0100 Subject: [PATCH] Classloader issue --- .../persistence/impl/FSProjectDAOImpl.java | 76 +++++++++++++++---- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java index e13bd892..d15bcc71 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/FSProjectDAOImpl.java @@ -38,9 +38,12 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.FileSystemUtils; import org.springframework.util.WeakReferenceMonitor; import org.springframework.util.WeakReferenceMonitor.ReleaseListener; @@ -75,6 +78,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { private static final String LIB_EXTENSION = "jar"; private static final String LIB_DIRECTORY = "lib"; private static final String ROOT_DIRECTORY = "data"; + private static final String TEMP_DIRECTORY = "temp"; /** * The library for kieker which is contained in the war-file as a resource. */ @@ -86,6 +90,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { private final MIAnalysisMetaModelFactory factory = new MAnalysisMetaModelFactory(); private final Map<CloseableURLClassLoader, WeakReference<Object>> classLoaders = new ConcurrentHashMap<CloseableURLClassLoader, WeakReference<Object>>(); + private final Map<File, WeakReference<Object>> tempDirs = new ConcurrentHashMap<File, WeakReference<Object>>(); /** * Default constructor. <b>Do not use this constructor. This bean is Spring managed.</b> @@ -102,13 +107,22 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { */ @PostConstruct public void initialize() throws IOException { - // Check for our root-directory and create it if necessary - final File rootDir = new File(FSProjectDAOImpl.ROOT_DIRECTORY); - if (!rootDir.exists()) { - final boolean result = rootDir.mkdir(); - if (!result) { - throw new IOException("Could not create root directory."); - } + // Check for the necessary directories and create them if necessary + this.checkDir(FSProjectDAOImpl.ROOT_DIRECTORY); + this.checkDir(FSProjectDAOImpl.TEMP_DIRECTORY); + } + + @PreDestroy + public void destroy() throws IOException { + // Try to clear the temporary directory + FileSystemUtils.deleteRecursively(new File(FSProjectDAOImpl.TEMP_DIRECTORY)); + } + + private void checkDir(final String dirName) throws IOException { + final File dir = new File(dirName); + if (!dir.exists() && !dir.mkdir()) { + // Try to create the directory + throw new IOException("Could not create directory '" + dirName + "'."); } } @@ -366,18 +380,20 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { throw new ProjectNotExistingException("A project with the name '" + projectName + "' does not exist."); } + // Create a new temporary directory + final File tempDir = this.createTemporaryDirectory(); final List<URL> libs = new ArrayList<URL>(); - // Collect all libraries of the project - - // Run through the libs and put them into our list. + // Copy and collect all libraries of the project final File libDir = new File(FSProjectDAOImpl.ROOT_DIRECTORY + File.separator + projectName + File.separator + FSProjectDAOImpl.LIB_DIRECTORY); final File[] files = libDir.listFiles(); if (files != null) { for (final File file : files) { if (file.getName().endsWith("." + FSProjectDAOImpl.LIB_EXTENSION)) { + final File newLibFile = new File(tempDir, file.getName()); + FileCopyUtils.copy(file, newLibFile); try { - libs.add(file.toURI().toURL()); + libs.add(newLibFile.toURI().toURL()); } catch (final MalformedURLException ex) { ex.printStackTrace(); } @@ -393,12 +409,25 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { final CloseableURLClassLoader classLoader = AccessController.doPrivileged(action); // Remember the requester - this.classLoaders.put(classLoader, new WeakReference<Object>(requester)); + final WeakReference<Object> ref = new WeakReference<Object>(requester); + this.classLoaders.put(classLoader, ref); + this.tempDirs.put(tempDir, ref); WeakReferenceMonitor.monitor(requester, this); return classLoader; } + private File createTemporaryDirectory() { + int counter = 0; + File tempDir; + do { + tempDir = new File(FSProjectDAOImpl.TEMP_DIRECTORY, "temp" + counter); + counter++; + } while (!tempDir.mkdir()); + + return tempDir; + } + /* * (non-Javadoc) * @@ -614,16 +643,24 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { synchronized (this.classLoaders) { int open = 0; - final List<CloseableURLClassLoader> toBeRemoved = new ArrayList<CloseableURLClassLoader>(); + final List<CloseableURLClassLoader> toBeClosed = new ArrayList<CloseableURLClassLoader>(); + final List<File> toBeRemoved = new ArrayList<File>(); + // Run through the class loaders and check which of them can be closed for (final Entry<CloseableURLClassLoader, WeakReference<Object>> entry : this.classLoaders.entrySet()) { if (entry.getValue().get() == null) { - toBeRemoved.add(entry.getKey()); + toBeClosed.add(entry.getKey()); } else { open++; } } - for (final CloseableURLClassLoader classLoader : toBeRemoved) { + for (final Entry<File, WeakReference<Object>> entry : this.tempDirs.entrySet()) { + if (entry.getValue().get() == null) { + toBeRemoved.add(entry.getKey()); + } + } + + for (final CloseableURLClassLoader classLoader : toBeClosed) { try { classLoader.close(); this.classLoaders.remove(classLoader); @@ -632,6 +669,15 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { FSProjectDAOImpl.LOG.error("Could not close classloader (" + classLoader + ")"); } } + for (final File tempDir : toBeRemoved) { + final boolean result = FileSystemUtils.deleteRecursively(tempDir); + if (result) { + this.tempDirs.remove(tempDir); + FSProjectDAOImpl.LOG.info("Removed temporary directory (" + tempDir + ")"); + } else { + FSProjectDAOImpl.LOG.error("Could not remove temporary directory (" + tempDir + ")"); + } + } FSProjectDAOImpl.LOG.info(open + " classloaders still open."); } } -- GitLab