diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractAnalysisComponentDecorator.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractAnalysisComponentDecorator.java index d59a0ccd4293aba8dfdbe681023262815301f2f2..61c69394bee1995554de7f40e16970dea07d086d 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractAnalysisComponentDecorator.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractAnalysisComponentDecorator.java @@ -45,6 +45,9 @@ import org.eclipse.emf.ecore.resource.Resource; */ public abstract class AbstractAnalysisComponentDecorator<T extends MIAnalysisComponent> implements MIAnalysisComponent { + /** The singleton factory to create components. */ + protected static final MIAnalysisMetaModelFactory FACTORY = MIAnalysisMetaModelFactory.eINSTANCE; + /** The component wrapped by this decorator. */ protected final T analysisComponent; @@ -103,15 +106,12 @@ public abstract class AbstractAnalysisComponentDecorator<T extends MIAnalysisCom /** * Delivers a new copy of the wrapped component. * - * @param factory - * The factory which is used to create the component. - * * @return A (deep) copy of the wrapped component. */ - public final T newCopy(final MIAnalysisMetaModelFactory factory) { - final T componentCopy = this.createComponent(factory); + public final T newCopy() { + final T componentCopy = this.createComponent(); - this.refineComponentCopy(factory, componentCopy); + this.refineComponentCopy(componentCopy); return componentCopy; } @@ -119,26 +119,21 @@ public abstract class AbstractAnalysisComponentDecorator<T extends MIAnalysisCom /** * Inheriting classes should implement this method to deliver the actual copy (without further properties) of the wrapped component. * - * @param factory - * The factory which should be used to create the component. - * * @return A (non-deep) copy of the wrapped component. */ - protected abstract T createComponent(final MIAnalysisMetaModelFactory factory); + protected abstract T createComponent(); /** * Inheriting classes should overwrite this method in order to refine the copy of the wrapped component. The new method should call * {@code super.refineComponentCopy(factory, componentCopy)} though, in order to make sure that the other properties will be copied as well. * - * @param factory - * The factory which should be used to create the new sub components. * @param componentCopy * The copy of the wrapped component, which can be refined by inheriting classes. */ - protected void refineComponentCopy(final MIAnalysisMetaModelFactory factory, final T componentCopy) { + protected void refineComponentCopy(final T componentCopy) { // Copy the properties for (final MIProperty property : this.analysisComponent.getProperties()) { - final MIProperty propertyCopy = factory.createProperty(); + final MIProperty propertyCopy = FACTORY.createProperty(); propertyCopy.setName(property.getName()); propertyCopy.setValue(property.getValue()); componentCopy.getProperties().add(propertyCopy); diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractPluginDecorator.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractPluginDecorator.java index af72fb9f8c5039b0713eee255ec3c001afb1aaec..c8ef7ed6da316b3814d4da0aa9986e04824c6a1d 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractPluginDecorator.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/AbstractPluginDecorator.java @@ -18,7 +18,6 @@ package kieker.webgui.domain.pluginDecorators; import java.util.Map; -import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; import kieker.analysis.model.analysisMetaModel.MIDisplay; import kieker.analysis.model.analysisMetaModel.MIOutputPort; import kieker.analysis.model.analysisMetaModel.MIPlugin; @@ -75,12 +74,12 @@ public abstract class AbstractPluginDecorator<T extends MIPlugin> extends Abstra } @Override - protected void refineComponentCopy(final MIAnalysisMetaModelFactory factory, final T componentCopy) { - super.refineComponentCopy(factory, componentCopy); + protected void refineComponentCopy(final T componentCopy) { + super.refineComponentCopy(componentCopy); // Copy the output ports of the plugin instance for (final MIOutputPort outputPort : super.analysisComponent.getOutputPorts()) { - final MIOutputPort outputPortCopy = factory.createOutputPort(); + final MIOutputPort outputPortCopy = FACTORY.createOutputPort(); outputPortCopy.setName(outputPort.getName()); outputPortCopy.setParent(componentCopy); componentCopy.getOutputPorts().add(outputPortCopy); @@ -88,14 +87,14 @@ public abstract class AbstractPluginDecorator<T extends MIPlugin> extends Abstra // Copy the repository "ports" for (final MIRepositoryConnector repositoryConnector : super.analysisComponent.getRepositories()) { - final MIRepositoryConnector repositoryConnectorCopy = factory.createRepositoryConnector(); + final MIRepositoryConnector repositoryConnectorCopy = FACTORY.createRepositoryConnector(); repositoryConnectorCopy.setName(repositoryConnector.getName()); componentCopy.getRepositories().add(repositoryConnectorCopy); } // Copy the displays for (final MIDisplay display : super.analysisComponent.getDisplays()) { - final MIDisplay displayCopy = factory.createDisplay(); + final MIDisplay displayCopy = FACTORY.createDisplay(); displayCopy.setName(display.getName()); displayCopy.setParent(componentCopy); componentCopy.getDisplays().add(displayCopy); diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/FilterDecorator.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/FilterDecorator.java index 0a0042849fe0339883361d5b7dd63406996f839f..8e22e903c71e5434aff2e8587beb5665e444badd 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/FilterDecorator.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/FilterDecorator.java @@ -18,7 +18,6 @@ package kieker.webgui.domain.pluginDecorators; import java.util.Map; -import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; import kieker.analysis.model.analysisMetaModel.MIFilter; import kieker.analysis.model.analysisMetaModel.MIInputPort; @@ -54,17 +53,17 @@ public class FilterDecorator extends AbstractPluginDecorator<MIFilter> implement } @Override - protected final MIFilter createComponent(final MIAnalysisMetaModelFactory factory) { - return factory.createFilter(); + protected final MIFilter createComponent() { + return FACTORY.createFilter(); } @Override - protected final void refineComponentCopy(final MIAnalysisMetaModelFactory factory, final MIFilter componentCopy) { - super.refineComponentCopy(factory, componentCopy); + protected final void refineComponentCopy(final MIFilter componentCopy) { + super.refineComponentCopy(componentCopy); // Copy the input ports of the plugin instance for (final MIInputPort inputPort : super.analysisComponent.getInputPorts()) { - final MIInputPort inputPortCopy = factory.createInputPort(); + final MIInputPort inputPortCopy = FACTORY.createInputPort(); inputPortCopy.setName(inputPort.getName()); inputPortCopy.setParent(componentCopy); componentCopy.getInputPorts().add(inputPortCopy); diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/ReaderDecorator.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/ReaderDecorator.java index 529c93c1e476b9d72bda96f969451ee22f12d587..45e9287191e01f92e5a0e47e882367f33a6f00a1 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/ReaderDecorator.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/ReaderDecorator.java @@ -18,7 +18,6 @@ package kieker.webgui.domain.pluginDecorators; import java.util.Map; -import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; import kieker.analysis.model.analysisMetaModel.MIReader; /** @@ -51,8 +50,8 @@ public class ReaderDecorator extends AbstractPluginDecorator<MIReader> implement } @Override - protected final MIReader createComponent(final MIAnalysisMetaModelFactory factory) { - return factory.createReader(); + protected final MIReader createComponent() { + return FACTORY.createReader(); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/RepositoryDecorator.java b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/RepositoryDecorator.java index ab70fcff300b861d5aa865b36b268dbf137c48f4..b34aa8981a89546a2178d131a3911e048eb273cd 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/RepositoryDecorator.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/domain/pluginDecorators/RepositoryDecorator.java @@ -18,7 +18,6 @@ package kieker.webgui.domain.pluginDecorators; import java.util.Map; -import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; import kieker.analysis.model.analysisMetaModel.MIRepository; /** @@ -49,8 +48,8 @@ public class RepositoryDecorator extends AbstractAnalysisComponentDecorator<MIRe } @Override - protected final MIRepository createComponent(final MIAnalysisMetaModelFactory factory) { - return factory.createRepository(); + protected final MIRepository createComponent() { + return FACTORY.createRepository(); } } 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 5cd525e1ba180e7feaab2dd00a99e77c9646294c..3663716f9d68e8650600e367c09c7e83393e8064 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 @@ -46,12 +46,8 @@ import com.google.common.collect.Collections2; import com.google.common.io.Files; import kieker.analysis.AnalysisController; -import kieker.analysis.analysisComponent.AbstractAnalysisComponent; import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.analysis.plugin.filter.AbstractFilterPlugin; -import kieker.analysis.plugin.reader.AbstractReaderPlugin; -import kieker.analysis.repository.AbstractRepository; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; import kieker.webgui.common.ClassAndMethodContainer; @@ -67,7 +63,6 @@ import kieker.webgui.persistence.IProjectDAO; import kieker.webgui.persistence.impl.util.Class2ModelInstanceConverter; import kieker.webgui.persistence.impl.util.CloseableURLClassLoader; import kieker.webgui.persistence.impl.util.PluginFinder; -import kieker.webgui.persistence.impl.util.SimpleCastFunction; import org.primefaces.model.UploadedFile; @@ -133,79 +128,29 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { this.initializeAvailableComponentsListContainersForAllProjects(); } - private void initializeAvailableComponentsListContainersForAllProjects() throws IOException { - for (final String project : this.listAllProjects()) { - this.initializeAvailableComponentsListContainers(project); - } + @Override + public File getProjectFile(final String projectName) { + return FSProjectDAOImpl.assembleKaxFile(projectName); } - private void initializeAvailableComponentsListContainers(final String project) throws IOException { - try { - final Object dummyObject = new Object(); - // Deliver a dummy object as a requester to make sure that the classloader can be disposed. Once the program exits this scope, it can be released. - final CloseableURLClassLoader classLoader = (CloseableURLClassLoader) this.getClassLoader(project, dummyObject); // NOPMD (No ordinary classloader) - final ClassAndMethodContainer classAndMethodContainer = new ClassAndMethodContainer(classLoader); - - final List<ReaderDecorator> readers = new ArrayList<ReaderDecorator>(); - final List<FilterDecorator> filters = new ArrayList<FilterDecorator>(); - final List<RepositoryDecorator> repositories = new ArrayList<RepositoryDecorator>(); - - // Update the components using all available dependencies - final Collection<String> libs = this.listAllLibraries(project); - for (final String lib : libs) { - this.initializeAvailableComponentsLists(readers, filters, repositories, this.getURL(lib, project), classLoader, classAndMethodContainer); - } - // Update the components using the Kieker library. - this.initializeAvailableComponentsLists(readers, filters, repositories, this.getKiekerURL(), classLoader, classAndMethodContainer); - - // Assemble the final object containing the available components - but make sure that the lists cannot be modified. - final ComponentListContainer componentList = new ComponentListContainer(Collections.unmodifiableList(readers), Collections.unmodifiableList(filters), - Collections.unmodifiableList(repositories)); - this.availableComponents.put(project, componentList); - - classLoader.close(); - } catch (final ReflectionException ex) { - FSProjectDAOImpl.LOG.warn("An error occured while initializing the project '" + project + "'.", ex); - } catch (final ProjectNotExistingException ex) { - // Technically this should not happen. Log but ignore this exception. - FSProjectDAOImpl.LOG.warn("An error occured while initializing the project '" + project + "'.", ex); - } + @Override + public String getAnalysisLayout(final String projectName) { + return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_ANALYSIS_LAYOUT, null); } - private void initializeAvailableComponentsLists(final List<ReaderDecorator> readers, final List<FilterDecorator> filters, - final List<RepositoryDecorator> repositories, final URL lib, final ClassLoader classLoader, final ClassAndMethodContainer classAndMethodContainer) - throws IOException { - // FInd the available classes within the library - final Collection<Class<AbstractRepository>> repositoryClasses = this.pluginFinder.getAllRepositoriesWithinJar(lib, classLoader, classAndMethodContainer); - final Collection<Class<AbstractFilterPlugin>> filterClasses = this.pluginFinder.getAllFiltersWithinJar(lib, classLoader, classAndMethodContainer); - final Collection<Class<AbstractReaderPlugin>> readerClasses = this.pluginFinder.getAllReadersWithinJar(lib, classLoader, classAndMethodContainer); - - // Rule those out which are for programmatic purposes only and transform the remaining with the converter service into model instances. - final Collection<RepositoryDecorator> repositoryModelInstances = Collections2.transform(Collections2.transform( - Collections2.filter(repositoryClasses, new IsNotProgrammaticOnly(classAndMethodContainer)), - new SimpleCastFunction<Class<? extends AbstractAnalysisComponent>, Class<AbstractRepository>>()), new ConvertRepositoryClass2ModelInstanceFunction( - classAndMethodContainer)); - final Collection<FilterDecorator> filterModelInstances = Collections2.transform(Collections2.transform( - Collections2.filter(filterClasses, new IsNotProgrammaticOnly(classAndMethodContainer)), - new SimpleCastFunction<Class<? extends AbstractAnalysisComponent>, Class<AbstractFilterPlugin>>()), new ConvertFilterClass2ModelInstanceFunction( - classAndMethodContainer)); - final Collection<ReaderDecorator> readerModelInstances = Collections2.transform(Collections2.transform( - Collections2.filter(readerClasses, new IsNotProgrammaticOnly(classAndMethodContainer)), - new SimpleCastFunction<Class<? extends AbstractAnalysisComponent>, Class<AbstractReaderPlugin>>()), new ConvertReaderClass2ModelInstanceFunction( - classAndMethodContainer)); + @Override + public String getCockpitLayout(final String projectName) { + return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_COCKPIT_LAYOUT, null); + } - // Add the model instances to our lists. - repositories.addAll(repositoryModelInstances); - readers.addAll(readerModelInstances); - filters.addAll(filterModelInstances); + @Override + public String getOwner(final String projectName) { + return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_OWNER, "N/A"); } - private static void createDirectoryIfNecessary(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 + "'."); - } + @Override + public String getLastUser(final String projectName) { + return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_LAST_USER, "N/A"); } @Override @@ -230,7 +175,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { final File libDir = this.assembleLibDir(projectName); // We need an "empty" project in order to save it. - final MIProject emptyProject = FSProjectDAOImpl.FACTORY.createProject(); + final MIProject emptyProject = FACTORY.createProject(); // Make sure that the project doesn't exist already if (projectDir.exists()) { @@ -391,36 +336,6 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { FSProjectDAOImpl.savePropertiesFile(properties, projectName); } - private static final Properties loadPropertiesFile(final String projectName) throws IOException { - final File metaFile = FSProjectDAOImpl.assembleMetaFile(projectName); - final Properties properties = new Properties(); - - FileInputStream in = null; - try { - in = new FileInputStream(metaFile); - properties.load(in); - } finally { - if (in != null) { - in.close(); - } - } - - return properties; - } - - private static final void savePropertiesFile(final Properties properties, final String projectName) throws IOException { - final File metaFile = FSProjectDAOImpl.assembleMetaFile(projectName); - FileOutputStream out = null; - try { - out = new FileOutputStream(metaFile); - properties.store(out, ""); - } finally { - if (out != null) { - out.close(); - } - } - } - @Override public long getCurrTimeStamp(final String projectName) throws ProjectNotExistingException { // Check whether the project exists @@ -452,11 +367,6 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { this.initializeAvailableComponentsListContainers(projectName); } - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#getClassLoader(java.lang.String) - */ @Override public ClassLoader getClassLoader(final String projectName, final Object requester) throws ProjectNotExistingException, IOException { // Check whether the project exists @@ -501,20 +411,6 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return classLoader; } - /** - * This method tries to create a new temporary directory within our temp directory. - * - * @return A file object pointing to the new temporary directory. - */ - private File createTemporaryDirectory() { - return Files.createTempDir(); - } - - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#listAllLibraries(java.lang.String) - */ @Override public List<String> listAllLibraries(final String projectName) throws ProjectNotExistingException { // Check whether the project exists @@ -537,11 +433,6 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return result; } - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#listAllProjects() - */ @Override public Collection<String> listAllProjects() { final List<String> result = new ArrayList<String>(); @@ -557,16 +448,175 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return result; } - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#getAvailableComponents(java.lang.String) - */ @Override public ComponentListContainer getAvailableComponents(final String project) { return this.availableComponents.get(project); } + @Override + public boolean deleteLibrary(final String projectName, final String libName) throws IOException { + final File libDir = this.assembleLibDir(projectName); + final File libFile = new File(libDir, libName); + final boolean result = libFile.delete(); + // Reload the available components + this.initializeAvailableComponentsListContainers(projectName); + + return result; + } + + @Override + public void released() { + synchronized (this.classLoaders) { + int open = 0; + + 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) { + toBeClosed.add(entry.getKey()); + } else { + open++; + } + } + 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); + FSProjectDAOImpl.LOG.info("Closed classloader (" + classLoader + ")"); + } catch (final IOException ex) { + 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."); + } + } + + private void initializeAvailableComponentsListContainersForAllProjects() throws IOException { + for (final String project : this.listAllProjects()) { + this.initializeAvailableComponentsListContainers(project); + } + } + + private void initializeAvailableComponentsListContainers(final String project) throws IOException { + try { + final Object dummyObject = new Object(); + // Deliver a dummy object as a requester to make sure that the classloader can be disposed. Once the program exits this scope, it can be released. + final CloseableURLClassLoader classLoader = (CloseableURLClassLoader) this.getClassLoader(project, dummyObject); // NOPMD (No ordinary classloader) + final ClassAndMethodContainer classAndMethodContainer = new ClassAndMethodContainer(classLoader); + + final List<ReaderDecorator> readers = new ArrayList<ReaderDecorator>(); + final List<FilterDecorator> filters = new ArrayList<FilterDecorator>(); + final List<RepositoryDecorator> repositories = new ArrayList<RepositoryDecorator>(); + + // Update the components using all available dependencies + final Collection<String> libs = this.listAllLibraries(project); + for (final String lib : libs) { + this.initializeAvailableComponentsLists(readers, filters, repositories, this.getURL(lib, project), classLoader, classAndMethodContainer); + } + // Update the components using the Kieker library. + this.initializeAvailableComponentsLists(readers, filters, repositories, this.getKiekerURL(), classLoader, classAndMethodContainer); + + // Assemble the final object containing the available components - but make sure that the lists cannot be modified. + final ComponentListContainer componentList = new ComponentListContainer(Collections.unmodifiableList(readers), Collections.unmodifiableList(filters), + Collections.unmodifiableList(repositories)); + this.availableComponents.put(project, componentList); + + classLoader.close(); + } catch (final ReflectionException ex) { + FSProjectDAOImpl.LOG.warn("An error occured while initializing the project '" + project + "'.", ex); + } catch (final ProjectNotExistingException ex) { + // Technically this should not happen. Log but ignore this exception. + FSProjectDAOImpl.LOG.warn("An error occured while initializing the project '" + project + "'.", ex); + } + } + + private void initializeAvailableComponentsLists(final List<ReaderDecorator> readers, final List<FilterDecorator> filters, + final List<RepositoryDecorator> repositories, final URL lib, final ClassLoader classLoader, final ClassAndMethodContainer classAndMethodContainer) + throws IOException { + // FInd the available classes within the library + final Collection<Class<?>> repositoryClasses = this.pluginFinder.getAllRepositoriesWithinJar(lib, classLoader, classAndMethodContainer); + final Collection<Class<?>> filterClasses = this.pluginFinder.getAllFiltersWithinJar(lib, classLoader, classAndMethodContainer); + final Collection<Class<?>> readerClasses = this.pluginFinder.getAllReadersWithinJar(lib, classLoader, classAndMethodContainer); + + // Rule those out which are for programmatic purposes only and transform the remaining with the converter service into model instances. + final Collection<RepositoryDecorator> repositoryModelInstances = Collections2.transform( + Collections2.filter(repositoryClasses, new IsNotProgrammaticOnly(classAndMethodContainer)), new ConvertRepositoryClass2ModelInstanceFunction( + classAndMethodContainer)); + final Collection<FilterDecorator> filterModelInstances = Collections2.transform(Collections2.filter(filterClasses, new IsNotProgrammaticOnly( + classAndMethodContainer)), new ConvertFilterClass2ModelInstanceFunction(classAndMethodContainer)); + final Collection<ReaderDecorator> readerModelInstances = Collections2.transform(Collections2.filter(readerClasses, new IsNotProgrammaticOnly( + classAndMethodContainer)), new ConvertReaderClass2ModelInstanceFunction(classAndMethodContainer)); + + // Add the model instances to our lists. + repositories.addAll(repositoryModelInstances); + readers.addAll(readerModelInstances); + filters.addAll(filterModelInstances); + } + + private static void createDirectoryIfNecessary(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 + "'."); + } + } + + private static final Properties loadPropertiesFile(final String projectName) throws IOException { + final File metaFile = FSProjectDAOImpl.assembleMetaFile(projectName); + final Properties properties = new Properties(); + + FileInputStream in = null; + try { + in = new FileInputStream(metaFile); + properties.load(in); + } finally { + if (in != null) { + in.close(); + } + } + + return properties; + } + + private static final void savePropertiesFile(final Properties properties, final String projectName) throws IOException { + final File metaFile = FSProjectDAOImpl.assembleMetaFile(projectName); + FileOutputStream out = null; + try { + out = new FileOutputStream(metaFile); + properties.store(out, ""); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * This method tries to create a new temporary directory within our temp directory. + * + * @return A file object pointing to the new temporary directory. + */ + private File createTemporaryDirectory() { + return Files.createTempDir(); + } + /** * Checks whether a project with the name exists on the file system. * @@ -647,22 +697,6 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return new File(FSProjectDAOImpl.ROOT_DIRECTORY + File.separator + projectName + File.separator + FSProjectDAOImpl.LIB_DIRECTORY); } - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#deleteLibrary(java.lang.String, java.lang.String) - */ - @Override - public boolean deleteLibrary(final String projectName, final String libName) throws IOException { - final File libDir = this.assembleLibDir(projectName); - final File libFile = new File(libDir, libName); - final boolean result = libFile.delete(); - // Reload the available components - this.initializeAvailableComponentsListContainers(projectName); - - return result; - } - /** * Delivers an URL pointing to the kieker library within this application. * @@ -672,56 +706,6 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return Thread.currentThread().getContextClassLoader().getResource(FSProjectDAOImpl.KIEKER_LIB); } - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#getProjectFile(java.lang.String) - */ - @Override - public File getProjectFile(final String projectName) { - return FSProjectDAOImpl.assembleKaxFile(projectName); - } - - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#getAnalysisLayout(java.lang.String) - */ - @Override - public String getAnalysisLayout(final String projectName) { - return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_ANALYSIS_LAYOUT, null); - } - - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#getCockpitLayout(java.lang.String) - */ - @Override - public String getCockpitLayout(final String projectName) { - return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_COCKPIT_LAYOUT, null); - } - - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#getOwner(java.lang.String) - */ - @Override - public String getOwner(final String projectName) { - return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_OWNER, "N/A"); - } - - /* - * (non-Javadoc) - * - * @see kieker.webgui.persistence.IProjectDAO#getLastUser(java.lang.String) - */ - @Override - public String getLastUser(final String projectName) { - return FSProjectDAOImpl.getProperty(projectName, FSProjectDAOImpl.PROPERTY_KEY_LAST_USER, "N/A"); - } - private static String getProperty(final String projectName, final String propertyKey, final String defaultValue) { try { final Properties properties = FSProjectDAOImpl.loadPropertiesFile(projectName); @@ -737,55 +721,6 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return defaultValue; } - /* - * (non-Javadoc) - * - * @see org.springframework.util.WeakReferenceMonitor.ReleaseListener#released() - */ - @Override - public void released() { - synchronized (this.classLoaders) { - int open = 0; - - 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) { - toBeClosed.add(entry.getKey()); - } else { - open++; - } - } - 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); - FSProjectDAOImpl.LOG.info("Closed classloader (" + classLoader + ")"); - } catch (final IOException ex) { - 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."); - } - } - /** * This helper class is responsible for creating a classloader as a privileged action. This is recommended due to the java security manager. * @@ -824,7 +759,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { * * @author Nils Christian Ehmke */ - private class IsNotProgrammaticOnly implements Predicate<Class<? extends AbstractAnalysisComponent>> { + private class IsNotProgrammaticOnly implements Predicate<Class<?>> { private final ClassAndMethodContainer classAndMethodContainer; @@ -833,7 +768,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { } @Override - public boolean apply(@Nullable final Class<? extends AbstractAnalysisComponent> elem) { + public boolean apply(@Nullable final Class<?> elem) { return (elem != null) && !FSProjectDAOImpl.this.class2ModelInstanceConverter.isProgrammaticOnly(elem, this.classAndMethodContainer); } @@ -844,7 +779,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { * * @author Nils Christian Ehmke */ - private class ConvertRepositoryClass2ModelInstanceFunction implements Function<Class<AbstractRepository>, RepositoryDecorator> { + private class ConvertRepositoryClass2ModelInstanceFunction implements Function<Class<?>, RepositoryDecorator> { private final ClassAndMethodContainer classAndMethodContainer; @@ -854,7 +789,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { @Override @Nullable - public RepositoryDecorator apply(@Nullable final Class<AbstractRepository> repository) { + public RepositoryDecorator apply(@Nullable final Class<?> repository) { if (repository == null) { return null; } @@ -868,7 +803,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { * * @author Nils Christian Ehmke */ - private class ConvertReaderClass2ModelInstanceFunction implements Function<Class<AbstractReaderPlugin>, ReaderDecorator> { + private class ConvertReaderClass2ModelInstanceFunction implements Function<Class<?>, ReaderDecorator> { private final ClassAndMethodContainer classAndMethodContainer; @@ -878,7 +813,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { @Override @Nullable - public ReaderDecorator apply(@Nullable final Class<AbstractReaderPlugin> reader) { + public ReaderDecorator apply(@Nullable final Class<?> reader) { if (reader == null) { return null; } @@ -892,7 +827,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { * * @author Nils Christian Ehmke */ - private class ConvertFilterClass2ModelInstanceFunction implements Function<Class<AbstractFilterPlugin>, FilterDecorator> { + private class ConvertFilterClass2ModelInstanceFunction implements Function<Class<?>, FilterDecorator> { private final ClassAndMethodContainer classAndMethodContainer; @@ -902,7 +837,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { @Override @Nullable - public FilterDecorator apply(@Nullable final Class<AbstractFilterPlugin> filter) { + public FilterDecorator apply(@Nullable final Class<?> filter) { if (filter == null) { return null; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/Class2ModelInstanceConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/Class2ModelInstanceConverter.java index c2753c05e45c9aa987b2dd099e51c4b690262b65..c08811df411cc1892fe49d1b6a630b023d987ffe 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/Class2ModelInstanceConverter.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/Class2ModelInstanceConverter.java @@ -23,7 +23,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import kieker.analysis.analysisComponent.AbstractAnalysisComponent; import kieker.analysis.model.analysisMetaModel.MIAnalysisComponent; import kieker.analysis.model.analysisMetaModel.MIAnalysisMetaModelFactory; import kieker.analysis.model.analysisMetaModel.MIDisplay; @@ -35,10 +34,6 @@ import kieker.analysis.model.analysisMetaModel.MIProperty; import kieker.analysis.model.analysisMetaModel.MIReader; import kieker.analysis.model.analysisMetaModel.MIRepository; import kieker.analysis.model.analysisMetaModel.MIRepositoryConnector; -import kieker.analysis.plugin.AbstractPlugin; -import kieker.analysis.plugin.filter.AbstractFilterPlugin; -import kieker.analysis.plugin.reader.AbstractReaderPlugin; -import kieker.analysis.repository.AbstractRepository; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; import kieker.webgui.common.ClassAndMethodContainer; @@ -72,7 +67,7 @@ public class Class2ModelInstanceConverter { } /** - * Converts the given {@link AbstractReaderPlugin} instance into a model instance using the given parameters. + * Converts the given {@link kieker.analysis.plugin.reader.AbstractReaderPlugin} class instance into a model instance using the given parameters. * * @param clazz * The class to convert. @@ -81,12 +76,12 @@ public class Class2ModelInstanceConverter { * * @return A model instance representing the given class as a meta model component. */ - public ReaderDecorator convertReaderClass2ModelInstance(final Class<AbstractReaderPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer) { + public ReaderDecorator convertReaderClass2ModelInstance(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { return (ReaderDecorator) this.convertComponentClass2ModelInstance(clazz, classAndMethodContainer, Type.Reader); } /** - * Converts the given {@link AbstractFilterPlugin} instance into a model instance using the given parameters. + * Converts the given {@link kieker.analysis.plugin.filter.AbstractFilterPlugin} instance into a model instance using the given parameters. * * @param clazz * The class to convert. @@ -95,12 +90,12 @@ public class Class2ModelInstanceConverter { * * @return A model instance representing the given class as a meta model component. */ - public FilterDecorator convertFilterClass2ModelInstance(final Class<AbstractFilterPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer) { + public FilterDecorator convertFilterClass2ModelInstance(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { return (FilterDecorator) this.convertComponentClass2ModelInstance(clazz, classAndMethodContainer, Type.Filter); } /** - * Converts the given {@link AbstractRepository} instance into a model instance using the given parameters. + * Converts the given {@link kieker.analysis.repository.AbstractRepository} instance into a model instance using the given parameters. * * @param clazz * The class to convert. @@ -109,14 +104,12 @@ public class Class2ModelInstanceConverter { * * @return A model instance representing the given class as a meta model component. */ - public RepositoryDecorator convertRepositoryClass2ModelInstance(final Class<AbstractRepository> clazz, final ClassAndMethodContainer classAndMethodContainer) { + public RepositoryDecorator convertRepositoryClass2ModelInstance(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { return (RepositoryDecorator) this.convertComponentClass2ModelInstance(clazz, classAndMethodContainer, Type.Repository); } - @SuppressWarnings("unchecked") - private AbstractAnalysisComponentDecorator<? extends MIAnalysisComponent> convertComponentClass2ModelInstance( - final Class<? extends AbstractAnalysisComponent> clazz, - final ClassAndMethodContainer classAndMethodContainer, final Type type) { + private AbstractAnalysisComponentDecorator<?> convertComponentClass2ModelInstance(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer, + final Type type) { final MIAnalysisComponent plugin = this.createSuitableModelInstance(clazz, classAndMethodContainer); final Collection<MIProperty> properties = new ArrayList<MIProperty>(); @@ -126,6 +119,7 @@ public class Class2ModelInstanceConverter { final Collection<MIRepositoryConnector> repositories = new ArrayList<MIRepositoryConnector>(); final Map<String, String> propertyDescriptions = new HashMap<String, String>(); final Map<String, String> displayDescriptions = new HashMap<String, String>(); + String description = ""; String dependency = ""; boolean fullyInitialized = true; @@ -136,19 +130,19 @@ public class Class2ModelInstanceConverter { this.fillProperties(clazz, classAndMethodContainer, properties, propertyDescriptions); plugin.getProperties().addAll(properties); if ((type == Type.Filter) || (type == Type.Reader)) { - this.fillOutputPorts((Class<AbstractPlugin>) clazz, classAndMethodContainer, outputPorts, (MIPlugin) plugin); - this.fillDisplays((Class<AbstractPlugin>) clazz, classAndMethodContainer, displays, displayDescriptions); - this.fillRepositories((Class<AbstractPlugin>) clazz, classAndMethodContainer, repositories); + this.fillOutputPorts(clazz, classAndMethodContainer, outputPorts, (MIPlugin) plugin); + this.fillDisplays(clazz, classAndMethodContainer, displays, displayDescriptions); + this.fillRepositories(clazz, classAndMethodContainer, repositories); ((MIPlugin) plugin).getOutputPorts().addAll(outputPorts); ((MIPlugin) plugin).getDisplays().addAll(displays); ((MIPlugin) plugin).getRepositories().addAll(repositories); if (type == Type.Filter) { - this.fillInputPorts((Class<AbstractFilterPlugin>) clazz, classAndMethodContainer, inputPorts, (MIFilter) plugin); + this.fillInputPorts(clazz, classAndMethodContainer, inputPorts, (MIFilter) plugin); ((MIFilter) plugin).getInputPorts().addAll(inputPorts); } } } catch (final Throwable ex) { // NOCS NOPMD (Throwable) - Class2ModelInstanceConverter.LOG.info("A component with the classname '" + clazz.getCanonicalName() + "' could not be initialized.", ex); + Class2ModelInstanceConverter.LOG.warn("A component with the classname '" + clazz.getCanonicalName() + "' could not be initialized.", ex); plugin.getProperties().clear(); if ((type == Type.Filter) || (type == Type.Reader)) { @@ -186,8 +180,7 @@ public class Class2ModelInstanceConverter { return result; } - private void fillInputPorts(final Class<AbstractFilterPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer, - final Collection<MIInputPort> inputPorts, + private void fillInputPorts(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer, final Collection<MIInputPort> inputPorts, final MIFilter parent) { final Collection<Method> methods = this.getInputPortMethods(clazz, classAndMethodContainer); for (final Method method : methods) { @@ -199,8 +192,7 @@ public class Class2ModelInstanceConverter { } } - private void fillDisplays(final Class<? extends AbstractPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer, - final Collection<MIDisplay> displays, + private void fillDisplays(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer, final Collection<MIDisplay> displays, final Map<String, String> displayDescriptions) { final Collection<Method> methods = this.getDisplayMethods(clazz, classAndMethodContainer); for (final Method method : methods) { @@ -212,7 +204,7 @@ public class Class2ModelInstanceConverter { } } - private Collection<Method> getAnnotatedMethods(final Class<? extends AbstractPlugin> clazz, final Class<? extends Annotation> annotation) { + private Collection<Method> getAnnotatedMethods(final Class<?> clazz, final Class<? extends Annotation> annotation) { final Collection<Method> result = new ArrayList<Method>(); final Method[] methods = clazz.getMethods(); @@ -225,18 +217,19 @@ public class Class2ModelInstanceConverter { return result; } - private Collection<Method> getInputPortMethods(final Class<AbstractFilterPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer) { + private Collection<Method> getInputPortMethods(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { return this.getAnnotatedMethods(clazz, classAndMethodContainer.getInputPortAnnotationClass()); } - private Collection<Method> getDisplayMethods(final Class<? extends AbstractPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer) { + private Collection<Method> getDisplayMethods(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { return this.getAnnotatedMethods(clazz, classAndMethodContainer.getDisplayAnnotationClass()); } - private void fillOutputPorts(final Class<? extends AbstractPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer, - final Collection<MIOutputPort> outputPorts, final MIPlugin parent) { + private void fillOutputPorts(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer, final Collection<MIOutputPort> outputPorts, + final MIPlugin parent) { final Annotation annotation = this.getSuitableAnnotation(clazz, classAndMethodContainer); final Annotation[] outputPortAnnotations = (Annotation[]) new Mirror().on(annotation).invoke().method("outputPorts").withoutArgs(); + for (final Annotation outputPortAnnotation : outputPortAnnotations) { final MIOutputPort newPort = Class2ModelInstanceConverter.FACTORY.createOutputPort(); newPort.setName((String) new Mirror().on(outputPortAnnotation).invoke().method("name").withoutArgs()); @@ -245,10 +238,11 @@ public class Class2ModelInstanceConverter { } } - private void fillProperties(final Class<? extends AbstractAnalysisComponent> clazz, final ClassAndMethodContainer classAndMethodContainer, - final Collection<MIProperty> properties, final Map<String, String> propertyDescriptions) { + private void fillProperties(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer, final Collection<MIProperty> properties, + final Map<String, String> propertyDescriptions) { final Annotation annotation = this.getSuitableAnnotation(clazz, classAndMethodContainer); final Annotation[] propertyAnnotations = (Annotation[]) new Mirror().on(annotation).invoke().method("configuration").withoutArgs(); + for (final Annotation propertyAnnotation : propertyAnnotations) { final MIProperty newProperty = Class2ModelInstanceConverter.FACTORY.createProperty(); newProperty.setName((String) new Mirror().on(propertyAnnotation).invoke().method("name").withoutArgs()); @@ -258,7 +252,7 @@ public class Class2ModelInstanceConverter { } } - private void fillRepositories(final Class<? extends AbstractPlugin> clazz, final ClassAndMethodContainer classAndMethodContainer, + private void fillRepositories(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer, final Collection<MIRepositoryConnector> repositories) { final Annotation annotation = this.getSuitableAnnotation(clazz, classAndMethodContainer); final Annotation[] repositoryPortAnnotations = (Annotation[]) new Mirror().on(annotation).invoke().method("repositoryPorts").withoutArgs(); @@ -271,17 +265,17 @@ public class Class2ModelInstanceConverter { } } - private String fillDependency(final Class<? extends AbstractAnalysisComponent> clazz, final ClassAndMethodContainer classAndMethodContainer) { + private String fillDependency(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { final Annotation annotation = this.getSuitableAnnotation(clazz, classAndMethodContainer); return (String) new Mirror().on(annotation).invoke().method("dependencies").withoutArgs(); } - private String fillDescription(final Class<? extends AbstractAnalysisComponent> clazz, final ClassAndMethodContainer classAndMethodContainer) { + private String fillDescription(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { final Annotation annotation = this.getSuitableAnnotation(clazz, classAndMethodContainer); return (String) new Mirror().on(annotation).invoke().method("description").withoutArgs(); } - private Annotation getSuitableAnnotation(final Class<? extends AbstractAnalysisComponent> clazz, final ClassAndMethodContainer classAndMethodContainer) { + private Annotation getSuitableAnnotation(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { // Get the two potential annotations final Annotation annotationPlugin = clazz.getAnnotation(classAndMethodContainer.getPluginAnnotationClass()); final Annotation annotationRepository = clazz.getAnnotation(classAndMethodContainer.getRepositoryAnnotationClass()); @@ -294,8 +288,7 @@ public class Class2ModelInstanceConverter { } } - private MIAnalysisComponent createSuitableModelInstance(final Class<? extends AbstractAnalysisComponent> clazz, - final ClassAndMethodContainer classAndMethodContainer) { + private MIAnalysisComponent createSuitableModelInstance(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { if (classAndMethodContainer.getAbstractReaderPluginClass().isAssignableFrom(clazz)) { return Class2ModelInstanceConverter.FACTORY.createReader(); } else if (classAndMethodContainer.getAbstractFilterPluginClass().isAssignableFrom(clazz)) { @@ -315,7 +308,7 @@ public class Class2ModelInstanceConverter { * * @return The state of the programmaticOnly flag of the plugin or repository. */ - public boolean isProgrammaticOnly(final Class<? extends AbstractAnalysisComponent> clazz, final ClassAndMethodContainer classAndMethodContainer) { + public boolean isProgrammaticOnly(final Class<?> clazz, final ClassAndMethodContainer classAndMethodContainer) { final Annotation annotation = this.getSuitableAnnotation(clazz, classAndMethodContainer); return (Boolean) new Mirror().on(annotation).invoke().method("programmaticOnly").withoutArgs(); } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/CloseableURLClassLoader.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/CloseableURLClassLoader.java index f2084d59baf70b9adcbcc7b0260922f9d18d76da..4844d0257b456a2e0f9ffed5f7db482b6d5858a5 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/CloseableURLClassLoader.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/CloseableURLClassLoader.java @@ -17,9 +17,11 @@ package kieker.webgui.persistence.impl.util; import java.io.Closeable; import java.io.IOException; +import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; import java.util.Collection; +import java.util.jar.JarFile; /** * A class loader which extends the {@link URLClassLoader} with a close-method using a hack. This will probably only work for a Sun VM. The class itself will @@ -52,21 +54,22 @@ public class CloseableURLClassLoader extends URLClassLoader implements Closeable try { final Class<URLClassLoader> clazz = URLClassLoader.class; - final java.lang.reflect.Field ucp = clazz.getDeclaredField("ucp"); + final Field ucp = clazz.getDeclaredField("ucp"); ucp.setAccessible(true); final Object sunMiscURLClassPath = ucp.get(this); - final java.lang.reflect.Field loaders = sunMiscURLClassPath.getClass().getDeclaredField("loaders"); + final Field loaders = sunMiscURLClassPath.getClass().getDeclaredField("loaders"); loaders.setAccessible(true); // Run through all available loaders and try to close them final Object javaUtilCollection = loaders.get(sunMiscURLClassPath); for (final Object sunMiscURLClassPathJarLoader : ((Collection<?>) javaUtilCollection).toArray()) { try { - final java.lang.reflect.Field loader = sunMiscURLClassPathJarLoader.getClass().getDeclaredField("jar"); + final Field loader = sunMiscURLClassPathJarLoader.getClass().getDeclaredField("jar"); loader.setAccessible(true); + final Object javaUtilIarJarFile = loader.get(sunMiscURLClassPathJarLoader); - ((java.util.jar.JarFile) javaUtilIarJarFile).close(); + ((JarFile) javaUtilIarJarFile).close(); } catch (final Throwable t) { // NOCS, NOPMD (Catch of Throwable) // if we got this far, this is probably not a JAR loader so skip it } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/PluginFinder.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/PluginFinder.java index ad6db336daf100ad17940cddee231c3a2aea8371..92ac8ef3284fc58c368444faac0fb7364fee4abb 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/PluginFinder.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/PluginFinder.java @@ -29,21 +29,22 @@ import javax.annotation.Nullable; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; -import kieker.analysis.plugin.filter.AbstractFilterPlugin; -import kieker.analysis.plugin.reader.AbstractReaderPlugin; -import kieker.analysis.repository.AbstractRepository; +import kieker.common.logging.Log; +import kieker.common.logging.LogFactory; import kieker.webgui.common.ClassAndMethodContainer; import org.springframework.stereotype.Service; /** - * This tool class can be used to find all plugins and repositories within a given jar file - assuming that the given class loader knows these jars. + * This tool class can be used to find all plugins and repositories within a given jar file - assume that the given class loader knows these jars. * * @author Nils Christian Ehmke */ @Service public class PluginFinder { + private static final Log LOG = LogFactory.getLog(PluginFinder.class); + /** * Default constructor. <b>Do not use this constructor. This bean is Spring managed.</b> */ @@ -52,7 +53,8 @@ public class PluginFinder { } /** - * This method delivers all classes which are available in the given jar and are compatible with <code>AbstractRepository</code>. None of them is abstract. + * This method delivers all classes which are available in the given jar and are compatible with {@link kieker.analysis.repository.AbstractRepository}. None of + * them is abstract. * * @param url * The URL for the jar. @@ -66,15 +68,16 @@ public class PluginFinder { * @throws IOException * If something went wrong during the opening of the jar file. */ - public Collection<Class<AbstractRepository>> getAllRepositoriesWithinJar(final URL url, final ClassLoader classLoader, - final ClassAndMethodContainer classAndMethodContainer) throws IOException { - return Collections2.transform(Collections2.filter(Collections2.filter(this.getAllClassesWithinJar(url, classLoader), - new IsRepositoryPredicate(classAndMethodContainer)), new IsNotAbstractPredicate()), new SimpleCastFunction<Class<?>, Class<AbstractRepository>>()); + public Collection<Class<?>> getAllRepositoriesWithinJar(final URL url, final ClassLoader classLoader, final ClassAndMethodContainer classAndMethodContainer) + throws IOException { + // Get all classes within the Jar. Filter the classes which are not repositories. Filter the abstract classes. + return Collections2.filter(Collections2.filter(this.getAllClassesWithinJar(url, classLoader), new IsRepositoryPredicate(classAndMethodContainer)), + new IsNotAbstractPredicate()); } /** * This method delivers all classes which are available in the given jar and have the Plugin-Annotation from the Kieker framework (And are correctly compatible - * with <code>AbstractReaderPlugin</code>). None of them is abstract. + * with {@link kieker.analysis.plugin.reader.AbstractReaderPlugin}). None of them is abstract. * * @param url * The URL for the jar. @@ -88,15 +91,16 @@ public class PluginFinder { * @throws IOException * If something went wrong during the opening of the jar file. */ - public Collection<Class<AbstractReaderPlugin>> getAllReadersWithinJar(final URL url, final ClassLoader classLoader, - final ClassAndMethodContainer classAndMethodContainer) throws IOException { - return Collections2.transform(Collections2.filter(Collections2.filter(this.getAllClassesWithinJar(url, classLoader), - new IsReaderPredicate(classAndMethodContainer)), new IsNotAbstractPredicate()), new SimpleCastFunction<Class<?>, Class<AbstractReaderPlugin>>()); + public Collection<Class<?>> getAllReadersWithinJar(final URL url, final ClassLoader classLoader, final ClassAndMethodContainer classAndMethodContainer) + throws IOException { + // Get all classes within the Jar. Filter the classes which are not readers. Filter the abstract classes. + return Collections2.filter(Collections2.filter(this.getAllClassesWithinJar(url, classLoader), new IsReaderPredicate(classAndMethodContainer)), + new IsNotAbstractPredicate()); } /** * This method delivers all classes which are available in the given jar and have the Plugin-Annotation from the Kieker framework (And are correctly compatible - * with <code>AbstractFilterPlugin</code>). None of them is abstract. + * with {@link kieker.analysis.plugin.filter.AbstractFilterPlugin}). None of them is abstract. * * @param url * The URL for the jar. @@ -110,10 +114,11 @@ public class PluginFinder { * @throws IOException * If something went wrong during the opening of the jar file. */ - public Collection<Class<AbstractFilterPlugin>> getAllFiltersWithinJar(final URL url, final ClassLoader classLoader, - final ClassAndMethodContainer classAndMethodContainer) throws IOException { - return Collections2.transform(Collections2.filter(Collections2.filter(this.getAllClassesWithinJar(url, classLoader), - new IsFilterPredicate(classAndMethodContainer)), new IsNotAbstractPredicate()), new SimpleCastFunction<Class<?>, Class<AbstractFilterPlugin>>()); + public Collection<Class<?>> getAllFiltersWithinJar(final URL url, final ClassLoader classLoader, final ClassAndMethodContainer classAndMethodContainer) + throws IOException { + // Get all classes within the Jar. Filter the classes which are not filters. Filter the abstract classes. + return Collections2.filter(Collections2.filter(this.getAllClassesWithinJar(url, classLoader), new IsFilterPredicate(classAndMethodContainer)), + new IsNotAbstractPredicate()); } /** @@ -140,11 +145,10 @@ public class PluginFinder { while ((jarEntry = stream.getNextJarEntry()) != null) { try { // Assemble the correct name - String name = jarEntry.toString(); - name = name.replace('/', '.'); - name = name.replace(".class", ""); + final String className = jarEntry.toString().replace('/', '.').replace(".class", ""); + // Try to find a class with the same name and put it into our list - final Class<?> c = classLoader.loadClass(name); + final Class<?> c = classLoader.loadClass(className); result.add(c); } catch (final Throwable ex) { // NOPMD (Generic throwable and empty catch block) NOCS (IllegalCatchCheck) // Ignore error. @@ -158,8 +162,8 @@ public class PluginFinder { try { stream.close(); } catch (final IOException ex1) { - // Ignore this - ex1.printStackTrace(); + // Log but ignore this fail. + LOG.warn("Could not close stream.", ex1); } } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/SimpleCastFunction.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/SimpleCastFunction.java deleted file mode 100644 index 8d74af1b269457e2ec262f010e7a6f5019bde2e7..0000000000000000000000000000000000000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/impl/util/SimpleCastFunction.java +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************** - * Copyright 2013 Kieker Project (http://kieker-monitoring.net) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ***************************************************************************/ - -package kieker.webgui.persistence.impl.util; - -import javax.annotation.Nullable; - -import com.google.common.base.Function; - -/** - * A function which simply casts from the source type to the target type. - * - * @author Nils Christian Ehmke - * - * @param <S> - * The source type. - * @param <T> - * The target type. - */ -public class SimpleCastFunction<S, T> implements Function<S, T> { - - /** - * Default constructor. - */ - public SimpleCastFunction() { - // No code necessary - } - - @SuppressWarnings("unchecked") - @Override - @Nullable - public T apply(@Nullable final S elem) { - return (T) elem; - } - -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java index f1127958151fbcb7ef81087cf7085b52af5a7bfd..991801f340e7b66e68e689d455ffa38fd760e3f7 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/view/CurrentAnalysisEditorBean.java @@ -336,7 +336,7 @@ public class CurrentAnalysisEditorBean { */ public void addRepository(final RepositoryDecorator container) { // Create a new instance for the model - final MIRepository repository = container.newCopy(CurrentAnalysisEditorBean.MODEL_FACTORY); + final MIRepository repository = container.newCopy(); // Add it to the project - and to the graph this.project.getRepositories().add(repository); @@ -353,7 +353,7 @@ public class CurrentAnalysisEditorBean { */ public void addReader(final ReaderDecorator container) { // Create a new instance for the model - final MIPlugin plugin = container.newCopy(CurrentAnalysisEditorBean.MODEL_FACTORY); + final MIPlugin plugin = container.newCopy(); // Add it to the project - and to the graph this.project.getPlugins().add(plugin); @@ -370,7 +370,7 @@ public class CurrentAnalysisEditorBean { */ public void addFilter(final FilterDecorator container) { // Create a new instance for the model - final MIPlugin plugin = container.newCopy(CurrentAnalysisEditorBean.MODEL_FACTORY); + final MIPlugin plugin = container.newCopy(); // Add it to the project - and to the graph this.project.getPlugins().add(plugin); diff --git a/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/util/PluginFinderTest.java b/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/util/PluginFinderTest.java index a1aac2145afe25938097a515fdf8575e4c152096..f7d506e0071f93fd5bc785c84ad6b960da646aa1 100644 --- a/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/util/PluginFinderTest.java +++ b/Kieker.WebGUI/src/test/java/kieker/webgui/persistence/impl/util/PluginFinderTest.java @@ -23,9 +23,6 @@ import java.util.Collection; import org.junit.Assert; import org.junit.Test; -import kieker.analysis.plugin.filter.AbstractFilterPlugin; -import kieker.analysis.plugin.reader.AbstractReaderPlugin; -import kieker.analysis.repository.AbstractRepository; import kieker.webgui.common.ClassAndMethodContainer; import kieker.webgui.common.exception.ReflectionException; @@ -59,9 +56,9 @@ public class PluginFinderTest { final ClassAndMethodContainer classAndMethodContainer = new ClassAndMethodContainer(classLoader); try { - final Collection<Class<AbstractFilterPlugin>> filters = pluginFinder.getAllFiltersWithinJar(kiekerURL, classLoader, classAndMethodContainer); - final Collection<Class<AbstractReaderPlugin>> readers = pluginFinder.getAllReadersWithinJar(kiekerURL, classLoader, classAndMethodContainer); - final Collection<Class<AbstractRepository>> repositories = pluginFinder.getAllRepositoriesWithinJar(kiekerURL, classLoader, classAndMethodContainer); + final Collection<Class<?>> filters = pluginFinder.getAllFiltersWithinJar(kiekerURL, classLoader, classAndMethodContainer); + final Collection<Class<?>> readers = pluginFinder.getAllReadersWithinJar(kiekerURL, classLoader, classAndMethodContainer); + final Collection<Class<?>> repositories = pluginFinder.getAllRepositoriesWithinJar(kiekerURL, classLoader, classAndMethodContainer); // There should be at least one element of both types Assert.assertFalse("No filters found.", filters.isEmpty());