From 75365e5aa48b9388f8c5c5c8980cb106e1fd4a87 Mon Sep 17 00:00:00 2001 From: Nils Christian Ehmke <nie@informatik.uni-kiel.de> Date: Mon, 3 Dec 2012 14:51:57 +0100 Subject: [PATCH] Added a simple meta file to the projects; Added some parameters to the shell scripts (#642); Some code modifications for quality reasons --- .../.settings/org.eclipse.jdt.ui.prefs | 2 +- Kieker.WebGUI/bin/Kieker.WebGUI.bat | 5 +- Kieker.WebGUI/bin/Kieker.WebGUI.sh | 2 +- .../bin/data/Advanced Example/meta.dat | 3 + .../bin/data/Bookstore-Example/meta.dat | 3 + .../common/layout/GraphFlowLayouter.java | 41 +++---- .../webgui/persistence/IProjectDAO.java | 16 ++- .../persistence/impl/FSProjectDAOImpl.java | 111 +++++++++++++++--- .../impl/util/CloseableURLClassLoader.java | 49 ++++---- .../webgui/service/IProjectService.java | 15 ++- .../service/impl/ProjectServiceImpl.java | 13 +- .../web/beans/application/ProjectsBean.java | 23 +++- .../dialogs/ProjectOverviewPageDialogs.xhtml | 2 +- .../webapp/pages/ProjectOverviewPage.xhtml | 2 +- 14 files changed, 216 insertions(+), 71 deletions(-) create mode 100644 Kieker.WebGUI/bin/data/Advanced Example/meta.dat create mode 100644 Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat diff --git a/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs b/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs index 9961c8b4..85c1f324 100644 --- a/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs +++ b/Kieker.WebGUI/.settings/org.eclipse.jdt.ui.prefs @@ -58,7 +58,7 @@ formatter_settings_version=12 org.eclipse.jdt.ui.exception.name=ex org.eclipse.jdt.ui.gettersetter.use.is=true org.eclipse.jdt.ui.ignorelowercasenames=true -org.eclipse.jdt.ui.importorder=java;javax;junit;org;com;kieker;org.primefaces;org.eclipse; +org.eclipse.jdt.ui.importorder=java;javax;junit;org;com;kieker;org.primefaces;org.eclipse;de.cau.cs.kieler; org.eclipse.jdt.ui.keywordthis=false org.eclipse.jdt.ui.ondemandthreshold=99 org.eclipse.jdt.ui.overrideannotation=true diff --git a/Kieker.WebGUI/bin/Kieker.WebGUI.bat b/Kieker.WebGUI/bin/Kieker.WebGUI.bat index a8a11623..62e25701 100644 --- a/Kieker.WebGUI/bin/Kieker.WebGUI.bat +++ b/Kieker.WebGUI/bin/Kieker.WebGUI.bat @@ -1,6 +1,7 @@ @echo off REM @author Nils Christian Ehmke -java -XX:PermSize=256M -XX:MaxPermSize=512M -Xms128M -Xmx256M -jar ..\lib\jetty-runner-*.jar --path /Kieker.WebGUI ..\target\Kieker.WebGUI-*.war +java -XX:PermSize=256M -XX:MaxPermSize=512M -Xms128M -Xmx256M -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -jar ..\lib\jetty-runner-*.jar --path /Kieker.WebGUI ..\target\Kieker.WebGUI-*.war + +@echo on -@echo on \ No newline at end of file diff --git a/Kieker.WebGUI/bin/Kieker.WebGUI.sh b/Kieker.WebGUI/bin/Kieker.WebGUI.sh index 511e8516..fc2ebe5e 100644 --- a/Kieker.WebGUI/bin/Kieker.WebGUI.sh +++ b/Kieker.WebGUI/bin/Kieker.WebGUI.sh @@ -2,4 +2,4 @@ # @author Nils Christian Ehmke -java -XX:PermSize=256M -XX:MaxPermSize=512M -Xms128M -Xmx256M -jar ../lib/jetty-runner-*.jar --path /Kieker.WebGUI ../target/Kieker.WebGUI-*.war \ No newline at end of file +java -XX:PermSize=256M -XX:MaxPermSize=512M -Xms128M -Xmx256M -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -jar ../lib/jetty-runner-*.jar --path /Kieker.WebGUI ../target/Kieker.WebGUI-*.war \ No newline at end of file diff --git a/Kieker.WebGUI/bin/data/Advanced Example/meta.dat b/Kieker.WebGUI/bin/data/Advanced Example/meta.dat new file mode 100644 index 00000000..ea9e2b79 --- /dev/null +++ b/Kieker.WebGUI/bin/data/Advanced Example/meta.dat @@ -0,0 +1,3 @@ +# +#Mon Dec 03 14:49:14 CET 2012 +owner=Kieker-Administrator diff --git a/Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat b/Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat new file mode 100644 index 00000000..ea9e2b79 --- /dev/null +++ b/Kieker.WebGUI/bin/data/Bookstore-Example/meta.dat @@ -0,0 +1,3 @@ +# +#Mon Dec 03 14:49:14 CET 2012 +owner=Kieker-Administrator diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java index 44edc884..c233fd10 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/layout/GraphFlowLayouter.java @@ -19,9 +19,15 @@ package kieker.webgui.common.layout; import java.util.ArrayList; import java.util.List; +import kieker.webgui.common.exception.InvalidInputSizeException; +import kieker.webgui.common.exception.UninitializedGraphException; + +import org.eclipse.emf.common.util.EList; + import de.cau.cs.kieler.core.alg.BasicProgressMonitor; import de.cau.cs.kieler.core.alg.IKielerProgressMonitor; import de.cau.cs.kieler.core.kgraph.KEdge; +import de.cau.cs.kieler.core.kgraph.KLabeledGraphElement; import de.cau.cs.kieler.core.kgraph.KNode; import de.cau.cs.kieler.core.kgraph.KPort; import de.cau.cs.kieler.kiml.AbstractLayoutProvider; @@ -34,11 +40,6 @@ import de.cau.cs.kieler.kiml.options.PortConstraints; import de.cau.cs.kieler.kiml.util.KimlUtil; import de.cau.cs.kieler.klay.layered.LayeredLayoutProvider; -import kieker.webgui.common.exception.InvalidInputSizeException; -import kieker.webgui.common.exception.UninitializedGraphException; - -import org.eclipse.emf.common.util.EList; - /** * This class provides a single method, that is used for GraphFlow layouting. The JavaScript GraphFlow throws an "autoLayout"-Event upon using the function * autoLayout(). This event provides two Strings which may be used by this class' layoutGraph(nodes, edges) method. The return value can then be used as an argument @@ -69,7 +70,7 @@ public final class GraphFlowLayouter { layoutInformation.getGraph().getData(KShapeLayout.class).setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL); // prepare array of lists - List<Object> child; + List<KLabeledGraphElement> child; final int dimHalf = Integer.parseInt(positions[0]); final int dim = dimHalf * 2; @@ -101,8 +102,8 @@ public final class GraphFlowLayouter { node = KimlUtil.createInitializedNode(); node.setParent(layoutInformation.getGraph()); - child = new ArrayList<Object>(); - layoutInformation.getChildren()[i] = child; + child = new ArrayList<KLabeledGraphElement>(); + layoutInformation.getChildren().add(i, child); child.add(node); // set node dimensions @@ -190,13 +191,13 @@ public final class GraphFlowLayouter { // read from String sourceID = Integer.parseInt(edgeInfo[e++]); targetID = Integer.parseInt(edgeInfo[e++]); - sourcePort = (KPort) layoutInformation.getChildren()[sourceID].get(1 + Integer.parseInt(edgeInfo[e++])); - targetPort = (KPort) layoutInformation.getChildren()[targetID].get(1 + Integer.parseInt(edgeInfo[e++])); + sourcePort = (KPort) layoutInformation.getChildren().get(sourceID).get(1 + Integer.parseInt(edgeInfo[e++])); + targetPort = (KPort) layoutInformation.getChildren().get(targetID).get(1 + Integer.parseInt(edgeInfo[e++])); // add edge to graph edge = KimlUtil.createInitializedEdge(); - edge.setSource((KNode) layoutInformation.getChildren()[sourceID].get(0)); - edge.setTarget((KNode) layoutInformation.getChildren()[targetID].get(0)); + edge.setSource((KNode) layoutInformation.getChildren().get(sourceID).get(0)); + edge.setTarget((KNode) layoutInformation.getChildren().get(targetID).get(0)); // set ports of edge edge.setSourcePort(sourcePort); @@ -204,7 +205,7 @@ public final class GraphFlowLayouter { edge.setTargetPort(targetPort); targetPort.getEdges().add(edge); - layoutInformation.getEdges()[ea++] = edge; + layoutInformation.getEdges().add(ea++, edge); } } @@ -221,8 +222,8 @@ public final class GraphFlowLayouter { private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) { final String[] edgeInfo = edgesStr.split(" "); final String[] positions = nodesStr.split(" "); - final List<Object>[] children = new ArrayList[positions.length / 2]; - final KEdge[] edges = new KEdge[edgeInfo.length / 4]; + final List<List<KLabeledGraphElement>> children = new ArrayList<List<KLabeledGraphElement>>(positions.length / 2); + final List<KEdge> edges = new ArrayList<KEdge>(edgeInfo.length / 4); final LayoutInformation layoutInformation = new LayoutInformation(KimlUtil.createInitializedNode(), children, edges); GraphFlowLayouter.addNodes(positions, layoutInformation); @@ -328,11 +329,11 @@ public final class GraphFlowLayouter { /** * An array containing the child node and the ports from left to right. */ - private final List<Object>[] children; + private final List<List<KLabeledGraphElement>> children; /** * An array containing edges. This way we can return edge information in the same order. */ - private final KEdge[] edges; + private final List<KEdge> edges; /** * Creates a new instance of this class. @@ -344,7 +345,7 @@ public final class GraphFlowLayouter { * @param edges * The edges of the graph. */ - public LayoutInformation(final KNode graph, final List<Object>[] children, final KEdge[] edges) { + public LayoutInformation(final KNode graph, final List<List<KLabeledGraphElement>> children, final List<KEdge> edges) { this.graph = graph; this.children = children; this.edges = edges; @@ -364,7 +365,7 @@ public final class GraphFlowLayouter { * * @return The current value of the property. */ - public List<Object>[] getChildren() { + public List<List<KLabeledGraphElement>> getChildren() { return this.children; } @@ -373,7 +374,7 @@ public final class GraphFlowLayouter { * * @return The current value of the property. */ - public KEdge[] getEdges() { + public List<KEdge> getEdges() { return this.edges; } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java index cb2f9839..b0612cbc 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/persistence/IProjectDAO.java @@ -45,13 +45,15 @@ public interface IProjectDAO { * * @param projectName * The name of the new project. + * @param username + * The name of the user who created the project. * @throws ProjectAlreadyExistingException * If a project with the same name exists already. * @throws IOException * If something went wrong during the creation of the project. */ @PreAuthorize("hasAnyRole('User', 'Administrator')") - public abstract void addProject(String projectName) throws ProjectAlreadyExistingException, IOException; + public abstract void addProject(String projectName, final String username) throws ProjectAlreadyExistingException, IOException; /** * This method makes a copy of a project and saves it under another name. If the method fails due to an {@link IOException}, it will make sure that the @@ -223,6 +225,16 @@ public interface IProjectDAO { * @return An object containing the available components as model instances. */ @PreAuthorize("isAuthenticated()") - public abstract ComponentListContainer getAvailableComponents(String project); + public abstract ComponentListContainer getAvailableComponents(final String project); + + /** + * Delivers the owner of the given project or a substituion if the meta data are corrupt or missing. + * + * @param projectName + * The name of the project whose owner should be delivered. + * @return The owner (creator) of the project. + */ + @PreAuthorize("isAuthenticated()") + public abstract String getOwner(final String projectName); } 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 d577e054..88afa664 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 @@ -19,9 +19,11 @@ package kieker.webgui.persistence.impl; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; @@ -39,6 +41,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.PostConstruct; @@ -97,6 +100,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { private static final MIAnalysisMetaModelFactory FACTORY = MIAnalysisMetaModelFactory.eINSTANCE; private static final String KIEKER_LIB = "kieker-1.6_emf.jar"; + private static final String META_FILE = "meta.dat"; private static final String KAX_EXTENSION = "kax"; private static final String LIB_EXTENSION = "jar"; private static final String LIB_DIRECTORY = "lib"; @@ -156,7 +160,9 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { */ private void initializeAvailableComponents(final String project) throws IOException { try { - final CloseableURLClassLoader classLoader = (CloseableURLClassLoader) this.getClassLoader(project, this); + 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); final ClassAndMethodContainer classAndMethodContainer = new ClassAndMethodContainer(classLoader); final List<PluginContainer> readers = new ArrayList<PluginContainer>(); @@ -781,10 +787,11 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { */ @Override @PreAuthorize("hasAnyRole('User', 'Administrator')") - public void addProject(final String projectName) throws ProjectAlreadyExistingException, IOException { + public void addProject(final String projectName, final String username) throws ProjectAlreadyExistingException, IOException { // Assemble all necessary paths and files for the given project - final File projectDir = this.assembleProjectDir(projectName); - final File projectFile = this.assembleKaxFile(projectName); + final File projectDir = FSProjectDAOImpl.assembleProjectDir(projectName); + final File projectFile = FSProjectDAOImpl.assembleKaxFile(projectName); + final File metaFile = FSProjectDAOImpl.assembleMetaFile(projectName); final File libDir = this.assembleLibDir(projectName); // We need an "empty" project in order to save it. @@ -796,11 +803,25 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { } try { - // Try to create the directories - if (projectDir.mkdir() && libDir.mkdir()) { + // Try to create the directories and files + if (projectDir.mkdir() && libDir.mkdir() && metaFile.createNewFile()) { // Try to save the file AnalysisController.saveToFile(projectFile, emptyProject); this.initializeAvailableComponents(projectName); + + // Store the initial meta data + final Properties properties = new Properties(); + properties.put("owner", username); + + FileOutputStream out = null; + try { + out = new FileOutputStream(metaFile); + properties.store(out, ""); + } finally { + if (out != null) { + out.close(); + } + } } else { // The directories could not be created throw new IOException("Project-Directories could not be created."); @@ -831,7 +852,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { public void copyProject(final String originalProjectName, final String newProjectName) throws ProjectNotExistingException, ProjectAlreadyExistingException, IOException { // Get the necessary paths - final File dstProjDir = this.assembleProjectDir(newProjectName); + final File dstProjDir = FSProjectDAOImpl.assembleProjectDir(newProjectName); final File srcLibDir = this.assembleLibDir(originalProjectName); final File dstLibDir = this.assembleLibDir(newProjectName); @@ -840,8 +861,8 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { throw new ProjectAlreadyExistingException("A project with the name '" + newProjectName + "' exists already."); } - final File srcKaxFile = this.assembleKaxFile(originalProjectName); - final File dstKaxFile = this.assembleKaxFile(newProjectName); + final File srcKaxFile = FSProjectDAOImpl.assembleKaxFile(originalProjectName); + final File dstKaxFile = FSProjectDAOImpl.assembleKaxFile(newProjectName); try { if (dstProjDir.mkdir() && dstLibDir.mkdir()) { @@ -886,7 +907,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { try { // Load the project - return AnalysisController.loadFromFile(this.assembleKaxFile(projectName).getAbsoluteFile()); + return AnalysisController.loadFromFile(FSProjectDAOImpl.assembleKaxFile(projectName).getAbsoluteFile()); } catch (final FileNotFoundException ex) { throw new ProjectNotExistingException("A project with the name '" + projectName + "' does not exist.", ex); } @@ -906,7 +927,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { // Load the project final Object project = ClassAndMethodContainer.invokeClassMethod(classAndMethodContainer.getAnalysisControllerLoadFromFile(), null, - this.assembleKaxFile(projectName)); + FSProjectDAOImpl.assembleKaxFile(projectName)); if (project == null) { throw new IOException("Project could not be loaded."); @@ -936,7 +957,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { } // Try to save it. - AnalysisController.saveToFile(this.assembleKaxFile(projectName), project); + AnalysisController.saveToFile(FSProjectDAOImpl.assembleKaxFile(projectName), project); } /* @@ -951,7 +972,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { if (!this.projectExists(projectName)) { throw new ProjectNotExistingException("A project with the name '" + projectName + "' does not exist."); } - return this.assembleKaxFile(projectName).lastModified(); + return FSProjectDAOImpl.assembleKaxFile(projectName).lastModified(); } /* @@ -1090,6 +1111,11 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { return result; } + /* + * (non-Javadoc) + * + * @see kieker.webgui.persistence.IProjectDAO#getAvailableComponents(java.lang.String) + */ @Override @PreAuthorize("isAuthenticated()") public ComponentListContainer getAvailableComponents(final String project) { @@ -1104,9 +1130,20 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { * @return true if and only if a directory with the name of the project exists in the root dir. */ private boolean projectExists(final String projectName) { - return this.assembleKaxFile(projectName).exists(); + return FSProjectDAOImpl.assembleKaxFile(projectName).exists(); } + /** + * Delivers the url of the given library to the given project. + * + * @param lib + * The library of the project. + * @param project + * The project itself. + * @return An URL pointing to the URL. + * @throws MalformedURLException + * If something went wrong. + */ private URL getURL(final String lib, final String project) throws MalformedURLException { final File file = new File(FSProjectDAOImpl.ROOT_DIRECTORY + File.separator + project + File.separator + FSProjectDAOImpl.LIB_DIRECTORY + File.separator + lib); @@ -1120,7 +1157,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { * The name of the project. * @return The directory of the project. */ - private File assembleProjectDir(final String projectName) { + private static File assembleProjectDir(final String projectName) { return new File(FSProjectDAOImpl.ROOT_DIRECTORY + File.separator + projectName); } @@ -1131,10 +1168,21 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { * The name of the project. * @return The kax-file of the project. */ - private File assembleKaxFile(final String projectName) { + private static File assembleKaxFile(final String projectName) { return new File(FSProjectDAOImpl.ROOT_DIRECTORY + File.separator + projectName + File.separator + projectName + "." + FSProjectDAOImpl.KAX_EXTENSION); } + /** + * Assembles the {@link File}-element pointing to the meta file of the given project. + * + * @param projectName + * The name of the project. + * @return The meta file of the project. + */ + private static File assembleMetaFile(final String projectName) { + return new File(FSProjectDAOImpl.ROOT_DIRECTORY + File.separator + projectName + File.separator + FSProjectDAOImpl.META_FILE); + } + /** * Assembles the {@link File}-element pointing to the library directory of the given project. * @@ -1180,7 +1228,7 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { @Override @PreAuthorize("isAuthenticated()") public File getProjectFile(final String projectName) { - return this.assembleKaxFile(projectName); + return FSProjectDAOImpl.assembleKaxFile(projectName); } /* @@ -1232,6 +1280,35 @@ public class FSProjectDAOImpl implements IProjectDAO, ReleaseListener { } } + /* + * (non-Javadoc) + * + * @see kieker.webgui.persistence.IProjectDAO#getOwner(java.lang.String) + */ + @Override + public String getOwner(final String projectName) { + final File metaFile = FSProjectDAOImpl.assembleMetaFile(projectName); + final Properties properties = new Properties(); + InputStream inputStream = null; + try { + inputStream = new FileInputStream(metaFile); + properties.load(inputStream); + return properties.getProperty("owner"); + } catch (final IOException ex) { + FSProjectDAOImpl.LOG.warn("Could not open meta file.", ex); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (final IOException ex) { + FSProjectDAOImpl.LOG.warn("Could not open meta file.", ex); + } + } + + return "N/A"; + } + /** * This helper class is responsible for creating a classloader as a privileged action. This is recommended due to the java security manager. * 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 e20604da..91086e00 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 @@ -30,6 +30,8 @@ import java.util.Collection; */ public class CloseableURLClassLoader extends URLClassLoader implements Closeable { + private boolean closed = false; + /** * Creates a new instance of this class using the given parameters. * @@ -48,31 +50,36 @@ public class CloseableURLClassLoader extends URLClassLoader implements Closeable * @see java.io.Closeable#close() */ @Override - public void close() throws IOException { - try { - final Class<URLClassLoader> clazz = URLClassLoader.class; - final java.lang.reflect.Field ucp = clazz.getDeclaredField("ucp"); - ucp.setAccessible(true); + public synchronized void close() throws IOException { + // Make sure that the classloader can only be closed once. + if (!this.closed) { + this.closed = true; + + try { + final Class<URLClassLoader> clazz = URLClassLoader.class; + final java.lang.reflect.Field ucp = clazz.getDeclaredField("ucp"); + ucp.setAccessible(true); - final Object sunMiscURLClassPath = ucp.get(this); - final java.lang.reflect.Field loaders = sunMiscURLClassPath.getClass().getDeclaredField("loaders"); - loaders.setAccessible(true); + final Object sunMiscURLClassPath = ucp.get(this); + final java.lang.reflect.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"); - loader.setAccessible(true); - final Object javaUtilIarJarFile = loader.get(sunMiscURLClassPathJarLoader); - ((java.util.jar.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 + // 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"); + loader.setAccessible(true); + final Object javaUtilIarJarFile = loader.get(sunMiscURLClassPathJarLoader); + ((java.util.jar.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 + } } + } catch (final Throwable ex) { // NOCS, NOPMD (Catch of Throwable) + // probably not a SUN VM + throw new IOException("Not a Sun VM.", ex); } - } catch (final Throwable ex) { // NOCS, NOPMD (Catch of Throwable) - // probably not a SUN VM - throw new IOException("Not a Sun VM.", ex); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java index 5b441bd9..7e4d7f9e 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/IProjectService.java @@ -48,12 +48,14 @@ public interface IProjectService { * * @param projectName * The name of the new project. + * @param username + * The name of the user who created the project. * @throws ProjectAlreadyExistingException * If a project with the same name exists already. * @throws IOException * If something went wrong during the creation of the project. */ - public void addProject(final String projectName) throws ProjectAlreadyExistingException, IOException; + public void addProject(final String projectName, final String username) throws ProjectAlreadyExistingException, IOException; /** * This method makes a copy of a project and saves it under another name. If the method fails due to an {@link IOException}, it will make sure that the @@ -137,6 +139,17 @@ public interface IProjectService { */ public long getCurrTimeStamp(final String projectName) throws ProjectNotExistingException; + /** + * Delivers the owner of the given project or a substituion if the meta data are corrupt or missing. + * + * @param projectName + * The name of the project whose owner should be delivered. + * @return The owner (creator) of the project. + * @throws ProjectNotExistingException + * If a project with the given name does not exist. + */ + public String getOwner(final String projectName) throws ProjectNotExistingException; + /** * This method tries to upload a dependency to the given project. An existing version of the library will be overwritten. * diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java index 3ef50786..568abefd 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/ProjectServiceImpl.java @@ -63,11 +63,11 @@ public final class ProjectServiceImpl implements IProjectService { } @Override - public void addProject(final String projectName) throws ProjectAlreadyExistingException, IOException { + public void addProject(final String projectName, final String username) throws ProjectAlreadyExistingException, IOException { final Object projectLock = this.getLock(projectName, this.fileSystemLocks); synchronized (projectLock) { - this.projectDAO.addProject(projectName); + this.projectDAO.addProject(projectName, username); } } @@ -283,4 +283,13 @@ public final class ProjectServiceImpl implements IProjectService { return this.projectDAO.deleteLibrary(projectName, libName); } } + + @Override + public String getOwner(final String projectName) throws ProjectNotExistingException { + final Object projectLock = this.getLock(projectName, this.fileSystemLocks); + + synchronized (projectLock) { + return this.projectDAO.getOwner(projectName); + } + } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ProjectsBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ProjectsBean.java index 88b7f9e1..6afa88c1 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ProjectsBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/web/beans/application/ProjectsBean.java @@ -37,6 +37,7 @@ import kieker.webgui.common.exception.ProjectAlreadyExistingException; import kieker.webgui.common.exception.ProjectLoadException; import kieker.webgui.common.exception.ProjectNotExistingException; import kieker.webgui.service.IProjectService; +import kieker.webgui.web.beans.session.UserBean; import kieker.webgui.web.beans.view.CurrentProjectOverviewBean; /** @@ -88,11 +89,13 @@ public final class ProjectsBean { * The name for the new project which should be added to the application. * @param currentProjectOverviewBean * The current instance of {@link CurrentProjectOverviewBean} which will be used to update the list of projects. + * @param userBean + * The current instance of {@link UserBean} which will be used to get the name of the user. */ - public void addProject(final String project, final CurrentProjectOverviewBean currentProjectOverviewBean) { + public void addProject(final String project, final CurrentProjectOverviewBean currentProjectOverviewBean, final UserBean userBean) { try { // Try and use the FS-Manager to create the project atomically. - this.projectService.addProject(project); + this.projectService.addProject(project, userBean.getUsername()); // If there were no exception, everything went well. We can add the project to our list. this.projects.add(project); // Inform the user @@ -186,7 +189,23 @@ public final class ProjectsBean { // We can assume that something went wrong return ProjectsBean.DEFAULT_TIMESTAMP; } + } + /** + * Delivers the owner of the given project or a substituion if the meta data are corrupt or missing. + * + * @param project + * The name of the project whose owner should be delivered. + * @return The owner (creator) of the project. + */ + public String getOwner(final String project) { + try { + return this.projectService.getOwner(project); + } catch (final ProjectNotExistingException ex) { + ProjectsBean.LOG.info("A project with the given name does not exist.", ex); + // We can assume that something went wrong + return "N/A"; + } } /** diff --git a/Kieker.WebGUI/src/main/webapp/dialogs/ProjectOverviewPageDialogs.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/ProjectOverviewPageDialogs.xhtml index 25ae3ba6..efe32748 100644 --- a/Kieker.WebGUI/src/main/webapp/dialogs/ProjectOverviewPageDialogs.xhtml +++ b/Kieker.WebGUI/src/main/webapp/dialogs/ProjectOverviewPageDialogs.xhtml @@ -18,7 +18,7 @@ <hr/> <div style="text-align: right"> - <p:commandButton value="#{localizedMessages.ok}" action="#{projectsBean.addProject(stringBean.string, currentProjectOverviewBean)}" update=":projectsListForm :messages" oncomplete="newProjectDialog.hide()" /> + <p:commandButton value="#{localizedMessages.ok}" action="#{projectsBean.addProject(stringBean.string, currentProjectOverviewBean, userBean)}" update=":projectsListForm :messages" oncomplete="newProjectDialog.hide()" /> </div> </h:form> </p:dialog> diff --git a/Kieker.WebGUI/src/main/webapp/pages/ProjectOverviewPage.xhtml b/Kieker.WebGUI/src/main/webapp/pages/ProjectOverviewPage.xhtml index 4c60dc7a..65259561 100644 --- a/Kieker.WebGUI/src/main/webapp/pages/ProjectOverviewPage.xhtml +++ b/Kieker.WebGUI/src/main/webapp/pages/ProjectOverviewPage.xhtml @@ -79,7 +79,7 @@ </p:column> <p:column headerText="#{localizedProjectOverviewMessages.owner}" style="text-align: center"> - <h:outputText value="N/A" /> + <h:outputText value="#{projectsBean.getOwner(project)}" /> </p:column> <p:column headerText="#{localizedProjectOverviewMessages.lastModification}" sortBy="#{projectsBean.getCurrTimeStamp(project)}" style="text-align: center"> -- GitLab