From e6258e8b0ad4996d32212010bdcbf00b8ec7c661 Mon Sep 17 00:00:00 2001 From: Nils Christian Ehmke <nie@informatik.uni-kiel.de> Date: Sat, 8 Sep 2012 11:00:10 +0200 Subject: [PATCH] Continued with the usage of the correct project-classloaders. --- .../Bookstore-Example/Bookstore-Example.kax | 5 + .../webgui/beans/view/CurrentCockpitBean.java | 37 +- .../beans/view/CurrentControllerBean.java | 34 +- .../java/kieker/webgui/common/ACManager.java | 405 +++--------------- .../java/kieker/webgui/common/Analysis.java | 261 +++++++++++ .../common/ClassAndMethodContainer.java | 351 ++++++++++++++- .../java/kieker/webgui/common/Triple.java | 130 ------ .../AnalysisAlreadyInstantiatedException.java | 51 +++ .../AnalysisAlreadyStartedException.java | 55 +++ .../AnalysisInstantiationException.java | 56 +++ ....java => AnalysisNotStartedException.java} | 6 +- 11 files changed, 870 insertions(+), 521 deletions(-) create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java delete mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyInstantiatedException.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyStartedException.java create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInstantiationException.java rename Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/{AnalysisNotRunningException.java => AnalysisNotStartedException.java} (89%) diff --git a/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax b/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax index cf369d16..27ecb97a 100644 --- a/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax +++ b/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax @@ -39,4 +39,9 @@ </plugins> <dependencies filePath="BookstoreApplication.jar"/> <dependencies filePath="commons-cli-1.2.jar"/> + <views name="My View" description="Some amazing view."> + <displayConnectors name="Valid Counter Display" display="//@plugins.5/@displays.0"/> + <displayConnectors name="Global Counter Display" display="//@plugins.4/@displays.0"/> + <displayConnectors name="Invalid Counter Display" display="//@plugins.3/@displays.0"/> + </views> </Project> diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitBean.java index 868468ba..f9039d87 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitBean.java @@ -20,20 +20,23 @@ package kieker.webgui.beans.view; +import java.lang.reflect.InvocationTargetException; + import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.ViewScoped; import javax.faces.context.FacesContext; -import kieker.analysis.display.AbstractDisplay; import kieker.analysis.display.HtmlText; import kieker.analysis.display.Image; -import kieker.analysis.display.PlainText; import kieker.analysis.model.analysisMetaModel.MIProject; import kieker.analysis.model.analysisMetaModel.MIView; import kieker.webgui.beans.application.ProjectsBean; import kieker.webgui.common.ACManager; +import kieker.webgui.common.ClassAndMethodContainer; +import kieker.webgui.common.FSManager; import kieker.webgui.common.Global; +import kieker.webgui.common.exception.ProjectLoadException; /** * The {@link CurrentCockpitBean} contains the necessary data behind an instance of the cockpit. It provides methods to read the state of the currently @@ -64,6 +67,8 @@ public class CurrentCockpitBean { @ManagedProperty(value = "#{projectsBean}") private ProjectsBean projectsBean; + private ClassAndMethodContainer classAndMethodContainer; + /** * Creates a new instance of this class. */ @@ -121,13 +126,19 @@ public class CurrentCockpitBean { /** * This method initializes the bean by using the current project name to load the project. <b>Do not call this method manually. It will only be accessed by * JSF.</b> + * + * @throws ProjectLoadException */ - public void initalize() { + public void initalize() throws ProjectLoadException { synchronized (this) { // Make sure that the initialization will only be done for the init request. if (!FacesContext.getCurrentInstance().isPostback() && (this.projectsBean != null)) { // Remember the given parameters this.project = this.projectsBean.openProject(this.projectName); + + if (this.project != null) { + this.classAndMethodContainer = new ClassAndMethodContainer(FSManager.getInstance().getClassLoader(this.projectName)); + } } } } @@ -152,18 +163,26 @@ public class CurrentCockpitBean { * does exist, but the return content is not plain text, null will be returned. */ public String updatePlainTextDisplay(final String displayName) { - final String result; + String result; synchronized (this) { if ((this.activeView != null) && (this.projectName != null)) { - final AbstractDisplay displayObj = ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName); + final Object displayObj = ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName); if (displayObj == null) { // The display does not exist result = "N/A"; } else { - if (displayObj instanceof PlainText) { + if (this.classAndMethodContainer.getPlainTextClass().isAssignableFrom(displayObj.getClass())) { // The display exists and is valid - result = ((PlainText) displayObj).getText(); + try { + result = (String) (this.classAndMethodContainer.getPlainTextgetTextMethod().invoke(displayObj, new Object[0])); + } catch (final IllegalAccessException e) { + result = "Error"; + } catch (final IllegalArgumentException e) { + result = "Error"; + } catch (final InvocationTargetException e) { + result = "Error"; + } } else { // The display exists, but is not valid result = null; @@ -191,7 +210,7 @@ public class CurrentCockpitBean { synchronized (this) { if ((this.activeView != null) && (this.projectName != null)) { - final AbstractDisplay displayObj = ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName); + final Object displayObj = ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName); if (displayObj == null) { // The display does not exist result = "N/A"; @@ -226,7 +245,7 @@ public class CurrentCockpitBean { synchronized (this) { if ((this.activeView != null) && (this.projectName != null)) { - final AbstractDisplay displayObj = ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName); + final Object displayObj = ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName); if (displayObj == null) { // The display does not exist result = "N/A"; diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentControllerBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentControllerBean.java index 860c94af..a0ca7527 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentControllerBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentControllerBean.java @@ -20,8 +20,6 @@ package kieker.webgui.beans.view; -import java.io.IOException; - import javax.faces.application.FacesMessage; import javax.faces.application.FacesMessage.Severity; import javax.faces.bean.ManagedBean; @@ -30,17 +28,17 @@ import javax.faces.bean.ViewScoped; import javax.faces.context.FacesContext; import kieker.analysis.AnalysisController; -import kieker.analysis.exception.AnalysisConfigurationException; import kieker.analysis.model.analysisMetaModel.MIProject; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; import kieker.webgui.beans.application.ProjectsBean; import kieker.webgui.common.ACManager; import kieker.webgui.common.Global; +import kieker.webgui.common.exception.AnalysisAlreadyInstantiatedException; +import kieker.webgui.common.exception.AnalysisAlreadyStartedException; +import kieker.webgui.common.exception.AnalysisInstantiationException; import kieker.webgui.common.exception.AnalysisNotInstantiatedException; -import kieker.webgui.common.exception.AnalysisNotRunningException; -import kieker.webgui.common.exception.ProjectAlreadyStartedException; -import kieker.webgui.common.exception.ProjectStillRunningException; +import kieker.webgui.common.exception.AnalysisNotStartedException; /** * /** @@ -166,9 +164,9 @@ public class CurrentControllerBean { synchronized (this) { ACManager.getInstance().startAnalysisController(this.projectName); } - } catch (final ProjectAlreadyStartedException ex) { - CurrentControllerBean.LOG.info("The analysis is already running.", ex); - CurrentControllerBean.showMessage(FacesMessage.SEVERITY_WARN, "The analysis is already running."); + } catch (final AnalysisAlreadyStartedException ex) { + CurrentControllerBean.LOG.info("The analysis has already been started.", ex); + CurrentControllerBean.showMessage(FacesMessage.SEVERITY_WARN, "The analysis has already been started."); } catch (final AnalysisNotInstantiatedException ex) { CurrentControllerBean.LOG.info("The analysis has not been instantiated yet.", ex); CurrentControllerBean.showMessage(FacesMessage.SEVERITY_WARN, "The analysis has not been instantiated yet."); @@ -183,11 +181,9 @@ public class CurrentControllerBean { synchronized (this) { ACManager.getInstance().stopAnalysisController(this.projectName); } - } catch (final AnalysisNotRunningException ex) { + } catch (final AnalysisNotStartedException ex) { CurrentControllerBean.LOG.info("The analysis has not been started yet.", ex); CurrentControllerBean.showMessage(FacesMessage.SEVERITY_WARN, "The analysis has not been started yet."); - } catch (final InterruptedException ex) { - CurrentControllerBean.LOG.error("Unknown interrupted exception.", ex); } } @@ -199,18 +195,12 @@ public class CurrentControllerBean { synchronized (this) { ACManager.getInstance().instantiateAnalysisController(this.projectName); } - } catch (final NullPointerException ex) { // NOPMD (Exception is explicitly thrown) - CurrentControllerBean.LOG.error("An error occurred while instantiating the analysis.", ex); - CurrentControllerBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occurred while instantiating the analysis."); - } catch (final AnalysisConfigurationException ex) { - CurrentControllerBean.LOG.error("An error occurred while instantiating the analysis.", ex); - CurrentControllerBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occurred while instantiating the analysis."); - } catch (final IOException ex) { + } catch (final AnalysisAlreadyInstantiatedException ex) { + CurrentControllerBean.LOG.error("The analysis has already been instantiated.", ex); + CurrentControllerBean.showMessage(FacesMessage.SEVERITY_ERROR, "The analysis has already been instantiated."); + } catch (final AnalysisInstantiationException ex) { CurrentControllerBean.LOG.error("An error occurred while instantiating the analysis.", ex); CurrentControllerBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occurred while instantiating the analysis."); - } catch (final ProjectStillRunningException ex) { - CurrentControllerBean.LOG.info("The analysis is still running.", ex); - CurrentControllerBean.showMessage(FacesMessage.SEVERITY_ERROR, "The analysis is still running."); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java index 973d3956..7ca07997 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java @@ -21,34 +21,18 @@ package kieker.webgui.common; import java.io.IOException; -import java.lang.Thread.State; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import kieker.analysis.AnalysisController; -import kieker.analysis.AnalysisController.AnalysisControllerWithMapping; -import kieker.analysis.AnalysisController.STATE; -import kieker.analysis.display.AbstractDisplay; -import kieker.analysis.display.HtmlText; -import kieker.analysis.display.Image; -import kieker.analysis.display.PlainText; -import kieker.analysis.display.annotation.Display; -import kieker.analysis.exception.AnalysisConfigurationException; -import kieker.analysis.model.analysisMetaModel.MIDisplayConnector; -import kieker.analysis.model.analysisMetaModel.MIPlugin; import kieker.analysis.model.analysisMetaModel.MIProject; -import kieker.analysis.model.analysisMetaModel.MIView; -import kieker.analysis.plugin.AbstractPlugin; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; +import kieker.webgui.common.exception.AnalysisAlreadyInstantiatedException; +import kieker.webgui.common.exception.AnalysisAlreadyStartedException; +import kieker.webgui.common.exception.AnalysisInstantiationException; import kieker.webgui.common.exception.AnalysisNotInstantiatedException; -import kieker.webgui.common.exception.AnalysisNotRunningException; +import kieker.webgui.common.exception.AnalysisNotStartedException; import kieker.webgui.common.exception.ProjectAlreadyStartedException; -import kieker.webgui.common.exception.ProjectStillRunningException; /** * This manager is responsible for the currently used and running instances of {@code AnalysisController}. It supplies methods to check the states of analysis, @@ -57,16 +41,12 @@ import kieker.webgui.common.exception.ProjectStillRunningException; * @author Nils Christian Ehmke * @version 1.0 */ -// TODO How to differ between views and displays with same names? -public final class ACManager { // NOCS (Class Data Abstraction Coupling) +// TODO Make this class threadsafe!! +public final class ACManager { /** * This is the log for errors, exceptions etc. */ private static final Log LOG = LogFactory.getLog(ACManager.class); - /** - * This is the maximal time the application will wait for an analysis thread to be terminated. - */ - private static final long MAX_THREAD_WAIT_TIME_MS = 1000; /** * This is the singleton instance of this class. */ @@ -75,8 +55,7 @@ public final class ACManager { // NOCS (Class Data Abstraction Coupling) * This list contains the current analysis controllers and their corresponding threads. Not every project does have a controller, but every project can have * maximal one. */ - private final ConcurrentHashMap<String, Triple<AnalysisController, Thread, UpdateDisplaysThread>> analysisController = new ConcurrentHashMap<String, - Triple<AnalysisController, Thread, UpdateDisplaysThread>>(); + private final ConcurrentHashMap<String, Analysis> analyses = new ConcurrentHashMap<String, Analysis>(); /** * Creates a new instance of this class. @@ -99,24 +78,18 @@ public final class ACManager { // NOCS (Class Data Abstraction Coupling) * * @param project * The project to be stopped. - * @throws AnalysisNotRunningException + * @throws AnalysisNotStartedException * If the analysis is not running or has not yet been initialized. * @throws InterruptedException * If the current thread has somehow been interrupted while waiting for the existing analysis thread. */ - public void stopAnalysisController(final String project) throws AnalysisNotRunningException, InterruptedException { - final Triple<AnalysisController, Thread, UpdateDisplaysThread> currController = this.analysisController.get(project); - try { - synchronized (currController) { - // Try to stop the analysis - currController.getFst().terminate(); - currController.getThd().terminate(); - currController.getSnd().join(ACManager.MAX_THREAD_WAIT_TIME_MS); - currController.getThd().join(ACManager.MAX_THREAD_WAIT_TIME_MS); - } - } catch (final NullPointerException ex) { // NOPMD - ACManager.LOG.info("Analysis is not running.", ex); - throw new AnalysisNotRunningException(); // NOPMD + public void stopAnalysisController(final String project) throws AnalysisNotStartedException { + final Analysis analysis = this.analyses.get(project); + + if (analysis != null) { + analysis.stop(); + } else { + throw new AnalysisNotStartedException("The analysis has not been started yet."); } } @@ -130,22 +103,13 @@ public final class ACManager { // NOCS (Class Data Abstraction Coupling) * @throws AnalysisNotInstantiatedException * If the analysis has not yet been initialized. */ - public void startAnalysisController(final String project) throws ProjectAlreadyStartedException, AnalysisNotInstantiatedException { - final Triple<AnalysisController, Thread, UpdateDisplaysThread> currController = this.analysisController.get(project); - // Is there an analysis after all? - try { - synchronized (currController) { - // Check whether this analysis has already been started - or is already dead. - if (currController.getSnd().getState() != State.NEW) { - throw new ProjectAlreadyStartedException(); - } - // Otherwise start the analysis - currController.getSnd().start(); - currController.getThd().start(); - } - } catch (final NullPointerException ex) { // NOPMD (Generic exception) - ACManager.LOG.info("Analysis is not instantiated.", ex); - throw new AnalysisNotInstantiatedException(); // NOPMD + public void startAnalysisController(final String project) throws AnalysisAlreadyStartedException, AnalysisNotInstantiatedException { + final Analysis analysis = this.analyses.get(project); + + if (analysis != null) { + analysis.start(); + } else { + throw new AnalysisNotInstantiatedException("The analysis has not been initialized yet."); } } @@ -157,21 +121,12 @@ public final class ACManager { // NOCS (Class Data Abstraction Coupling) * The name of the project to be cleaned. */ public void cleanAnalysisController(final String project) { - final Triple<AnalysisController, Thread, UpdateDisplaysThread> currController = this.analysisController.get(project); - // Is there an analysis after all? - try { - synchronized (currController) { - this.stopAnalysisController(project); - this.analysisController.remove(project); - } - } catch (final NullPointerException ex) { // NOPMD - ACManager.LOG.info("Analysis is not instantiated.", ex); - } catch (final AnalysisNotRunningException ex) { - ACManager.LOG.info("Analysis is not running.", ex); - } catch (final InterruptedException ex) { - ACManager.LOG.info("Unexpected interrupted exception.", ex); - } + final Analysis analysis = this.analyses.get(project); + if (analysis != null) { + analysis.stop(); + this.analyses.remove(project); + } } /** @@ -179,38 +134,20 @@ public final class ACManager { // NOCS (Class Data Abstraction Coupling) * * @param project * The project whose analysis controller should be instantiated. - * @throws NullPointerException - * If an error occurred while loading the project. - * @throws AnalysisConfigurationException - * If the given configuration is somehow invalid. - * @throws IOException - * If an error occurred while loading the project. - * @throws ProjectStillRunningException - * If there exists already an analysis controller and is still running. + * @throws AnalysisInstantiationException */ - public void instantiateAnalysisController(final String project) throws NullPointerException, AnalysisConfigurationException, IOException, - ProjectStillRunningException { - final Triple<AnalysisController, Thread, UpdateDisplaysThread> newController = new Triple<AnalysisController, Thread, UpdateDisplaysThread>(); - synchronized (newController) { - // Add the potential new project atomically - final Triple<AnalysisController, Thread, UpdateDisplaysThread> currController = this.analysisController.putIfAbsent(project, newController); - // We can just add a new controller if there wasn't an old one. - if (currController != null) { - throw new ProjectStillRunningException("The project with the name '" + project + "' is still running."); - } - final MIProject modelProject = FSManager.getInstance().openProject(project); - final ClassLoader classLoader = FSManager.getInstance().getClassLoader(project); - final AnalysisControllerWithMapping controller = AnalysisController.createAnalysisController(modelProject, classLoader); - - // Create the necessary threads for the analysis - final Thread runningThread = new ControllerRunningThread(controller); - // runningThread.start(); + public void instantiateAnalysisController(final String project) throws AnalysisAlreadyInstantiatedException, AnalysisInstantiationException { + try { + if (!this.analyses.containsKey(project)) { + final MIProject modelProject = FSManager.getInstance().openProject(project); + final ClassLoader classLoader = FSManager.getInstance().getClassLoader(project); - final UpdateDisplaysThread displayThread = new UpdateDisplaysThread(controller.getPluginMap(), modelProject); - // Put everything into our container - newController.setFst(controller.getController()); - newController.setSnd(runningThread); - newController.setThd(displayThread); + this.analyses.put(project, new Analysis(classLoader, modelProject)); + } else { + throw new AnalysisAlreadyInstantiatedException("The analysis has already been initialized."); + } + } catch (final IOException ex) { + throw new AnalysisInstantiationException("An IO-error occured while instantiating the analysis.", ex); } } @@ -222,34 +159,11 @@ public final class ACManager { // NOCS (Class Data Abstraction Coupling) * @return The current state of the corresponding {@link AnalysisController} if it exists, '' otherwise. */ public String getAnalysisControllerStateString(final String project) { - final STATE controllerState = this.getAnalysisControllerState(project); - final String controllerStateString; + final Enum<?> state = this.getAnalysisControllerState(project); - if (controllerState == null) { - controllerStateString = ""; + if (state != null) { + return state.toString(); } else { - controllerStateString = controllerState.toString(); - } - - return controllerStateString; - } - - /** - * Delivers the display object for the given display in the given view in the given project. - * - * @param project - * The name of the project. - * @param viewName - * The name of the view. - * @param displayName - * The name of the display. - * @return The display object if it exists, null otherwise. - */ - public AbstractDisplay getDisplay(final String project, final String viewName, final String displayName) { - try { - return this.analysisController.get(project).getThd().getDisplay(viewName, displayName); - } catch (final NullPointerException ex) { // NOPMD - ACManager.LOG.info("Invalid project, view or display.", ex); return null; } } @@ -261,232 +175,33 @@ public final class ACManager { // NOCS (Class Data Abstraction Coupling) * The project whose state should be delivered. * @return The current state of the corresponding {@link AnalysisController} if it exists, null otherwise. */ - public STATE getAnalysisControllerState(final String project) { - // If the given project is null, we return a null-state. - if (project == null) { - return null; - } - final Triple<AnalysisController, Thread, UpdateDisplaysThread> controller = this.analysisController.get(project); + public Enum<?> getAnalysisControllerState(final String project) { + final Analysis analysis = this.analyses.get(project); - final STATE controllerState; - if (controller == null) { - controllerState = null; + if (analysis != null) { + return analysis.getCurrentState(); } else { - synchronized (controller) { - if (controller.getFst() == null) { - controllerState = null; - } else { - controllerState = controller.getFst().getState(); - } - } - } - - return controllerState; - } - - /** - * This method delivers the current displays of the given project. They can be used to show the stored information but should <b>not</b> be modified. - * - * @param projectName - * The name of the project whose displays should be delivered. - * @return A list of pairs containing the displays and the name of them. - */ - public List<Pair<String, AbstractDisplay>> getCurrentDisplays(final String projectName) { - final List<Pair<String, AbstractDisplay>> result = new ArrayList<Pair<String, AbstractDisplay>>(); - - return result; - } - - /** - * This helper thread is responsible for running an instance of {@link AnalysisControllerWithMapping}. - * - * @author Nils Christian Ehmke - * @version 1.0 - */ - private static class ControllerRunningThread extends Thread { - /** - * The controller managed by this thread. - */ - private final AnalysisControllerWithMapping controller; - - /** - * Default constructor. - * - * @param controller - * The controller to be managed by this thread. - */ - public ControllerRunningThread(final AnalysisControllerWithMapping controller) { - this.controller = controller; - } - - @Override - public void run() { - try { - this.controller.getController().run(); - } catch (final IllegalStateException ex) { - ACManager.LOG.error("An error occured while starting the analysis.", ex); - ex.printStackTrace(); - } catch (final AnalysisConfigurationException ex) { - ACManager.LOG.error("An error occured while starting the analysis.", ex); - ex.printStackTrace(); - } + return null; } } /** - * This helper thread is used to update the available displays of the given analysis at regular intervals. <b>Important:</b> If the interrupt-method of the - * thread is being called, it will be terminated. + * Delivers the display object for the given display in the given view in the given project. * - * @author Nils Christian Ehmke - * @version 1.0 + * @param project + * The name of the project. + * @param viewName + * The name of the view. + * @param displayName + * The name of the display. + * @return The display object if it exists, null otherwise. */ - private static class UpdateDisplaysThread extends Thread { - - /** - * This is the time the thread waits between the updates. - */ - private static final long SLEEP_TIME_MS = 2 * 1000; - /** - * The map between the instances of {@link MIPlugin} and {@link AbstractPlugin} within the running analysis instance. - */ - private final Map<MIPlugin, AbstractPlugin> myPluginMap; - /** - * The model instance. - */ - private final MIProject myProject; - /** - * The map containing all available display objects. - */ - private final Map<String, Map<String, AbstractDisplay>> displayObjects = new ConcurrentHashMap<String, Map<String, AbstractDisplay>>(); // NOPMD - /** - * This map contains the mapping to get the methods to be called. - */ - private final Map<AbstractDisplay, Method> methodMap = new ConcurrentHashMap<AbstractDisplay, Method>(); // NOPMD (Use of concurrent hash map) - /** - * The field determining whether the thread has been terminated or not. // (USeConcurrentHashMap) - */ - private volatile boolean terminated = false; - - /** - * Creates a new instance of this class using the given parameters. - * - * @param pluginMap - * The map between the instances of {@link MIPlugin} and {@link AbstractPlugin} within the running analysis instance. - * @param modelProject - * The model instance. - */ - public UpdateDisplaysThread(final Map<MIPlugin, AbstractPlugin> pluginMap, final MIProject modelProject) { - this.myPluginMap = pluginMap; - this.myProject = modelProject; - - // Initialize the hashmaps and the necessary objects - for (final MIView view : this.myProject.getViews()) { - final Map<String, AbstractDisplay> viewMap = new ConcurrentHashMap<String, AbstractDisplay>(); // NOPMD (Use of concurrent hash map) - this.displayObjects.put(view.getName(), viewMap); - for (final MIDisplayConnector displayConnector : view.getDisplayConnectors()) { - final Method displayMethod = UpdateDisplaysThread.getDisplayMethod(this.myPluginMap.get(displayConnector.getDisplay().getParent()).getClass(), - displayConnector.getDisplay().getName()); - - // Make sure that the method really exists and that is has the correct parameters - if ((displayMethod != null) && (displayMethod.getParameterTypes().length == 1)) { - final Class<?> parameterType = displayMethod.getParameterTypes()[0]; - final AbstractDisplay displayObject; - // Get the correct type - if (Image.class.isAssignableFrom(parameterType)) { - displayObject = new Image(); - } else { - if (PlainText.class.isAssignableFrom(parameterType)) { - displayObject = new PlainText(); - } else { - if (HtmlText.class.isAssignableFrom(parameterType)) { - displayObject = new HtmlText(); - } else { - displayObject = null; - } - } - } - if (displayObject != null) { - viewMap.put(displayConnector.getName(), displayObject); - this.methodMap.put(displayObject, displayMethod); - } - } - } - } - } - - /** - * Delivers the correct method to be invoked for an update of the display. - * - * @param clazz - * The class of the plugin. - * @param displayName - * The name within the display-annotation. - * @return The method instance. - */ - private static Method getDisplayMethod(final Class<? extends AbstractPlugin> clazz, final String displayName) { - final Method[] methods = clazz.getMethods(); - for (final Method method : methods) { - final Display displayAnnot = method.getAnnotation(Display.class); - if ((displayAnnot != null) && displayAnnot.name().equals(displayName)) { - // We found the correct method - return method; - } - } + public Object getDisplay(final String project, final String viewName, final String displayName) { + final Analysis analysis = this.analyses.get(project); + if (analysis != null) { + return analysis.getDisplay(viewName, displayName); + } else { return null; } - - /** - * Terminates this thread. - */ - public void terminate() { - this.terminated = true; - } - - /** - * Delivers the display object for the given view and the given display. - * - * @param viewName - * The name of the view. - * @param displayName - * The name of the display in the view. - * @return The object for the given display if it exists, null otherwise. - */ - public AbstractDisplay getDisplay(final String viewName, final String displayName) { - return this.displayObjects.get(viewName).get(displayName); - } - - @Override - public void run() { - // Run until we have been interrupted - while (!this.terminated) { - for (final MIView view : this.myProject.getViews()) { - final Map<String, AbstractDisplay> viewMap = this.displayObjects.get(view.getName()); // NOPMD (Use of concurrent hash map) - for (final MIDisplayConnector displayConnector : view.getDisplayConnectors()) { - final AbstractDisplay displayObject = viewMap.get(displayConnector.getName()); - final AbstractPlugin pluginObject = this.myPluginMap.get(displayConnector.getDisplay().getParent()); - // Update the display object - try { - this.methodMap.get(displayObject).invoke(pluginObject, displayObject); - } catch (final IllegalAccessException ex) { - ACManager.LOG.error("An error occured while updating the display.", ex); - } catch (final IllegalArgumentException ex) { - ACManager.LOG.error("An error occured while updating the display.", ex); - } catch (final InvocationTargetException ex) { - ACManager.LOG.error("An error occured while updating the display.", ex); - } catch (final NullPointerException ex) { // NOPMD - ACManager.LOG.error("An error occured while updating the display.", ex); - } - } - } - - // Wait a little bit. - try { - Thread.sleep(UpdateDisplaysThread.SLEEP_TIME_MS); - } catch (final InterruptedException ex) { - // We have been interrupted. Exit the thread - return; - } - } - } } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java new file mode 100644 index 00000000..614566c3 --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java @@ -0,0 +1,261 @@ +package kieker.webgui.common; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.annotation.PostConstruct; + +import kieker.analysis.model.analysisMetaModel.MIDisplayConnector; +import kieker.analysis.model.analysisMetaModel.MIProject; +import kieker.analysis.model.analysisMetaModel.MIView; +import kieker.analysis.plugin.AbstractPlugin; +import kieker.common.logging.Log; +import kieker.common.logging.LogFactory; +import kieker.webgui.common.exception.AnalysisAlreadyStartedException; +import kieker.webgui.common.exception.AnalysisInstantiationException; +import kieker.webgui.common.exception.ProjectLoadException; + +// TODO AnalysisController, Thread etc. have to be initialized via the class loader as well +public class Analysis { + /** + * This is the log for errors, exceptions etc. + */ + private static final Log LOG = LogFactory.getLog(Analysis.class); + private static final long MAX_THREAD_WAIT_TIME_MS = 1000; + private final ClassAndMethodContainer classAndMethodContainer; + private final MIProject modelProject; + private final Object analysisController; + private final Object analysisControllerThread; + private final UpdateDisplaysThread updateDisplaysThread; + + public Analysis(final ClassLoader classLoader, final MIProject modelProject) throws AnalysisInstantiationException { + try { + this.modelProject = modelProject; + this.classAndMethodContainer = new ClassAndMethodContainer(classLoader); + + final Method createMethod = this.classAndMethodContainer.getAnalysisControllerCreateAnalysisController(); + final Object controllerAndMapping = ClassAndMethodContainer.invokeClassMethod(createMethod, null, this.modelProject, classLoader); + this.analysisController = ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getAnalysisControllerWithMappingGetController(), + controllerAndMapping, null); + this.analysisControllerThread = ClassAndMethodContainer.invokeConstructor(this.classAndMethodContainer.getAnalysisControllerThreadConstructor(), + this.analysisController); + this.updateDisplaysThread = new UpdateDisplaysThread(ClassAndMethodContainer.invokeMethod( + this.classAndMethodContainer.getAnalysisControllerWithMappingGetMapping(), controllerAndMapping, null)); + if ((this.analysisController == null) || (this.analysisControllerThread == null)) { + throw new AnalysisInstantiationException("An error occured while instantiating the analysis."); + } + } catch (final ProjectLoadException ex) { + throw new AnalysisInstantiationException("An error occured while instantiating the analysis.", ex); + } catch (final NullPointerException ex) { + throw new AnalysisInstantiationException("An error occured while instantiating the analysis.", ex); + } + } + + public void start() throws AnalysisAlreadyStartedException { + synchronized (this) { + try { + this.classAndMethodContainer.getAnalysisControllerThreadStart().invoke(this.analysisControllerThread, new Object[0]); + this.updateDisplaysThread.start(); + } catch (final IllegalThreadStateException ex) { + throw new AnalysisAlreadyStartedException("The analysis has already been started once. It has to be reinitialized to be runnable again.", ex); + } catch (final IllegalAccessException ex) { + Analysis.LOG.error("An error occured during a reflection method call.", ex); + } catch (final IllegalArgumentException ex) { + Analysis.LOG.error("An error occured during a reflection method call.", ex); + } catch (final InvocationTargetException ex) { + throw new AnalysisAlreadyStartedException("The analysis has already been started once. It has to be reinitialized to be runnable again.", ex); + } + } + + } + + public void stop() { + synchronized (this) { + try { + this.classAndMethodContainer.getAnalysisControllerThreadTerminate().invoke(this.analysisControllerThread, new Object[0]); + this.updateDisplaysThread.terminate(); + + this.classAndMethodContainer.getAnalysisControllerThreadJoin().invoke(this.analysisControllerThread, Analysis.MAX_THREAD_WAIT_TIME_MS); + this.updateDisplaysThread.join(Analysis.MAX_THREAD_WAIT_TIME_MS); + } catch (final InterruptedException ex) { + // Log the exception, but don't handle it further + Analysis.LOG.info("An interrupted exception occured.", ex); + } catch (final IllegalAccessException ex) { + Analysis.LOG.error("An error occured during a reflection method call.", ex); + } catch (final IllegalArgumentException ex) { + Analysis.LOG.error("An error occured during a reflection method call.", ex); + } catch (final InvocationTargetException ex) { + Analysis.LOG.error("An error occured during a reflection method call.", ex); + } + } + } + + public Enum<?> getCurrentState() { + synchronized (this) { + return (Enum<?>) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getAnalysisControllerGetState(), this.analysisController, null); + } + } + + public Object getDisplay(final String viewName, final String displayName) { + return this.updateDisplaysThread.getDisplay(viewName, displayName); + } + + /** + * This manager is responsible for the currently used and running instances of {@code AnalysisController}. It supplies methods to check the states of analysis, + * instantiate, start and to stop them. + * + * @author Nils Christian Ehmke + * @version 1.0 + */ + private class UpdateDisplaysThread extends Thread { + + /** + * This is the time the thread waits between the updates. + */ + private static final long SLEEP_TIME_MS = 2 * 1000; + private final Object pluginMap; + /** + * The map containing all available display objects. + */ + private final Map<String, Map<String, Object>> displayObjects = new ConcurrentHashMap<String, Map<String, Object>>(); // NOPMD + /** + * This map contains the mapping to get the methods to be called. + */ + private final Map<Object, Method> methodMap = new ConcurrentHashMap<Object, Method>(); // NOPMD (Use of concurrent hash map) + /** + * The field determining whether the thread has been terminated or not. // (USeConcurrentHashMap) + */ + private volatile boolean terminated = false; + + public UpdateDisplaysThread(final Object object) { + this.pluginMap = object; + } + + @PostConstruct + private void initialize() { + // Initialize the hashmaps and the necessary objects + for (final MIView view : Analysis.this.modelProject.getViews()) { + final Map<String, Object> viewMap = new ConcurrentHashMap<String, Object>(); // NOPMD (Use of concurrent hash map) + this.displayObjects.put(view.getName(), viewMap); + for (final MIDisplayConnector displayConnector : view.getDisplayConnectors()) { + // final Method displayMethod = this.getDisplayMethod(this.pluginMap.get(displayConnector.getDisplay().getParent()).getClass(), + // displayConnector.getDisplay().getName()); + + // Make sure that the method really exists and that is has the correct parameters + /* + * if ((displayMethod != null) && (displayMethod.getParameterTypes().length == 1)) { + * final Class<?> parameterType = displayMethod.getParameterTypes()[0]; + * final Object displayObject; + * // Get the correct type + * if (Analysis.this.classAndMethodContainer.getImageClass().isAssignableFrom(parameterType)) { + * displayObject = new Image(); + * } else { + * if (Analysis.this.classAndMethodContainer.getPlainTextClass().isAssignableFrom(parameterType)) { + * displayObject = new PlainText(); + * } else { + * if (Analysis.this.classAndMethodContainer.getHtmlTextClass().isAssignableFrom(parameterType)) { + * displayObject = new HtmlText(); + * } else { + * displayObject = null; + * } + * } + * } + * if (displayObject != null) { + * viewMap.put(displayConnector.getName(), displayObject); + * this.methodMap.put(displayObject, displayMethod); + * } + * } + */ + } + } + } + + /** + * Delivers the correct method to be invoked for an update of the display. + * + * @param clazz + * The class of the plugin. + * @param displayName + * The name within the display-annotation. + * @return The method instance. + */ + private Method getDisplayMethod(final Class<? extends AbstractPlugin> clazz, final String displayName) { + final Method[] methods = clazz.getMethods(); + for (final Method method : methods) { + try { + final Annotation displayAnnot = method.getAnnotation(Analysis.this.classAndMethodContainer.getDisplayAnnotationClass()); + if ((displayAnnot != null) + && (Analysis.this.classAndMethodContainer.getDisplayNameMethod().invoke(displayAnnot, new Object[0]).equals(displayName))) { + // We found the correct method + return method; + } + } catch (final IllegalAccessException ex) { + // Log this exception, but ignore it + Analysis.LOG.info("An error occured while calling a method.", ex); + } catch (final IllegalArgumentException ex) { + // Log this exception, but ignore it + Analysis.LOG.info("An error occured while calling a method.", ex); + } catch (final InvocationTargetException ex) { + // Log this exception, but ignore it + Analysis.LOG.info("An error occured while calling a method.", ex); + } + } + return null; + } + + /** + * Delivers the display object for the given view and the given display. + * + * @param viewName + * The name of the view. + * @param displayName + * The name of the display in the view. + * @return The object for the given display if it exists, null otherwise. + */ + public Object getDisplay(final String viewName, final String displayName) { + return this.displayObjects.get(viewName).get(displayName); + } + + @Override + public void run() { + // Run until we have been interrupted + while (!this.terminated) { + for (final MIView view : Analysis.this.modelProject.getViews()) { + this.displayObjects.get(view.getName()); + for (final MIDisplayConnector displayConnector : view.getDisplayConnectors()) { + // final Object displayObject = viewMap.get(displayConnector.getName()); + // final Object pluginObject = this.pluginMap.get(displayConnector.getDisplay().getParent()); + // Update the display object + // try { + // this.methodMap.get(displayObject).invoke(pluginObject, displayObject); + // } catch (final IllegalAccessException ex) { + // Analysis.LOG.error("An error occured while updating the display.", ex); + // } catch (final IllegalArgumentException ex) { + // Analysis.LOG.error("An error occured while updating the display.", ex); + // } catch (final InvocationTargetException ex) { + // Analysis.LOG.error("An error occured while updating the display.", ex); + // } catch (final NullPointerException ex) { // NOPMD + // Analysis.LOG.error("An error occured while updating the display.", ex); + // } + } + } + + // Wait a little bit. + try { + Thread.sleep(UpdateDisplaysThread.SLEEP_TIME_MS); + } catch (final InterruptedException ex) { + // We have been interrupted. Exit the thread + return; + } + } + + } + + public void terminate() { + this.terminated = true; + } + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java index ce18dee4..209d63b2 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java @@ -20,9 +20,18 @@ package kieker.webgui.common; import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import kieker.analysis.AnalysisController; +import kieker.analysis.AnalysisController.AnalysisControllerWithMapping; +import kieker.analysis.AnalysisControllerThread; +import kieker.analysis.display.HtmlText; +import kieker.analysis.display.Image; +import kieker.analysis.display.PlainText; import kieker.analysis.display.annotation.Display; +import kieker.analysis.model.analysisMetaModel.MIProject; import kieker.analysis.plugin.AbstractPlugin; import kieker.analysis.plugin.annotation.InputPort; import kieker.analysis.plugin.annotation.OutputPort; @@ -57,6 +66,18 @@ public final class ClassAndMethodContainer { */ private static final String MSG_LOAD_EXCEPTION = "An error occured while loading the classes and methods."; + /** + * This is the class equivalence of {@link AnalysisControllerWithMapping}. + */ + private Class<?> analysisControllerWithMappingClass; + /** + * This is the class equivalence of {@link AnalysisController}. + */ + private final Class<?> analysisControllerClass; + /** + * This is the class equivalence of {@link AnalysisControllerThread}. + */ + private final Class<?> analysisControllerThreadClass; /** * This is the class equivalence of {@link AbstractRepository}. */ @@ -101,6 +122,18 @@ public final class ClassAndMethodContainer { * This is the class equivalence of {@link Display}. */ private final Class<? extends Annotation> displayAnnotationClass; + /** + * This is the class equivalence of {@link Image}. + */ + private final Class<?> imageClass; + /** + * This is the class equivalence of {@link PlainText}. + */ + private final Class<?> plainTextClass; + /** + * This is the class equivalence of {@link HtmlText}. + */ + private final Class<?> htmlTextClass; /** * This is the description()-method of the class equivalence of {@link Plugin}. */ @@ -149,6 +182,42 @@ public final class ClassAndMethodContainer { * This is the defaultValue()-method of the class equivalence of {@link Property}. */ private final Method propertyDefaultValueMethod; + /** + * This is the getText()-method of the class equivalence of {@link PlainText}. + */ + private final Method plainTextgetTextMethod; + /** + * This is the getController()-method of the class equivalence of {@link AnalysisControllerWithMapping}. + */ + private final Method analysisControllerWithMappingGetController; + /** + * This is the getPluginMap()-method of the class equivalence of {@link AnalysisControllerWithMapping}. + */ + private final Method analysisControllerWithMappingGetMapping; + /** + * This is the createAnalysisController(MIProject, ClassLoader)-method of the class equivalence of {@link AnalysisControllerWithMapping}. + */ + private final Method analysisControllerCreateAnalysisController; + /** + * This is the start()-method of the class equivalence of {@link AnalysisController}. + */ + private final Method analysisControllerThreadStart; + /** + * This is the terminate()-method of the class equivalence of {@link AnalysisController}. + */ + private final Method analysisControllerThreadTerminate; + /** + * This is the join(long)-method of the class equivalence of {@link AnalysisController}. + */ + private final Method analysisControllerThreadJoin; + /** + * This is the getState()-method of the class equivalence of {@link AnalysisController}. + */ + private Method analysisControllerGetState; + /** + * This is the constructor for {@link AnalysisControllerThread}, which gets an instance of {@link AnalysisController}. + */ + private final Constructor<?> analysisControllerThreadConstructor; /** * Creates a new instance of this class, using the given class loader. @@ -161,18 +230,25 @@ public final class ClassAndMethodContainer { @SuppressWarnings("unchecked") public ClassAndMethodContainer(final ClassLoader classLoader) throws ProjectLoadException { try { - this.abstractFilterPluginClass = classLoader.loadClass(AbstractFilterPlugin.class.getCanonicalName()); - this.abstractReaderPluginClass = classLoader.loadClass(AbstractReaderPlugin.class.getCanonicalName()); - this.abstractRepositoryClass = classLoader.loadClass(AbstractRepository.class.getCanonicalName()); - this.abstractPluginClass = classLoader.loadClass(AbstractPlugin.class.getCanonicalName()); - - this.pluginAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Plugin.class.getCanonicalName()); - this.repositoryAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Repository.class.getCanonicalName()); - this.propertyAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Property.class.getCanonicalName()); - this.outputPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(OutputPort.class.getCanonicalName()); - this.inputPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(InputPort.class.getCanonicalName()); - this.repositoryPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(RepositoryPort.class.getCanonicalName()); - this.displayAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Display.class.getCanonicalName()); + this.analysisControllerWithMappingClass = classLoader.loadClass(AnalysisControllerWithMapping.class.getName()); + + this.analysisControllerClass = classLoader.loadClass(AnalysisController.class.getName()); + this.analysisControllerThreadClass = classLoader.loadClass(AnalysisControllerThread.class.getName()); + this.abstractFilterPluginClass = classLoader.loadClass(AbstractFilterPlugin.class.getName()); + this.abstractReaderPluginClass = classLoader.loadClass(AbstractReaderPlugin.class.getName()); + this.abstractRepositoryClass = classLoader.loadClass(AbstractRepository.class.getName()); + this.abstractPluginClass = classLoader.loadClass(AbstractPlugin.class.getName()); + this.htmlTextClass = classLoader.loadClass(HtmlText.class.getName()); + this.plainTextClass = classLoader.loadClass(PlainText.class.getName()); + this.imageClass = classLoader.loadClass(Image.class.getName()); + + this.pluginAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Plugin.class.getName()); + this.repositoryAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Repository.class.getName()); + this.propertyAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Property.class.getName()); + this.outputPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(OutputPort.class.getName()); + this.inputPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(InputPort.class.getName()); + this.repositoryPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(RepositoryPort.class.getName()); + this.displayAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Display.class.getName()); this.pluginDescriptionMethod = this.pluginAnnotationClass.getMethod("description", new Class<?>[0]); this.repositoryDescriptionMethod = this.repositoryAnnotationClass.getMethod("description", new Class<?>[0]); @@ -186,6 +262,29 @@ public final class ClassAndMethodContainer { this.repositoryPortNameMethod = this.repositoryPortAnnotationClass.getMethod("name", new Class<?>[0]); this.propertyNameMethod = this.propertyAnnotationClass.getMethod("name", new Class<?>[0]); this.propertyDefaultValueMethod = this.propertyAnnotationClass.getMethod("defaultValue", new Class<?>[0]); + this.plainTextgetTextMethod = this.plainTextClass.getMethod("getText", new Class<?>[0]); + this.analysisControllerWithMappingGetController = this.analysisControllerWithMappingClass.getMethod("getController", new Class<?>[0]); + this.analysisControllerWithMappingGetMapping = this.analysisControllerWithMappingClass.getMethod("getPluginMap", new Class<?>[0]); + this.analysisControllerThreadStart = this.analysisControllerThreadClass.getMethod("start", new Class<?>[0]); + this.analysisControllerThreadTerminate = this.analysisControllerThreadClass.getMethod("terminate", new Class<?>[0]); + this.analysisControllerGetState = this.analysisControllerClass.getMethod("getState", new Class<?>[0]); + + // This is a special case as we need to load some additional classes to search for the correct method + final Class<?> miProjectClass = classLoader.loadClass(MIProject.class.getName()); + final Class<?> classLoaderClass = classLoader.loadClass(ClassLoader.class.getName()); + this.analysisControllerCreateAnalysisController = this.analysisControllerClass.getMethod("createAnalysisController", miProjectClass, classLoaderClass); + + // Another special case as the parameter is a long + final Method[] methods = this.analysisControllerThreadClass.getMethods(); + Method joinMethod = null; + for (final Method method : methods) { + if ("join".equals(method.getName())) { + joinMethod = method; + } + } + this.analysisControllerThreadJoin = joinMethod; + + this.analysisControllerThreadConstructor = this.analysisControllerThreadClass.getConstructor(this.analysisControllerClass); } catch (final ClassNotFoundException ex) { ClassAndMethodContainer.LOG.error(ClassAndMethodContainer.MSG_LOAD_EXCEPTION, ex); throw new ProjectLoadException(ClassAndMethodContainer.MSG_LOAD_EXCEPTION, ex); @@ -408,4 +507,232 @@ public final class ClassAndMethodContainer { return this.propertyDefaultValueMethod; } + /** + * The getter-method for the field {@link ClassAndMethodContainer#imageClass}. + * + * @return The current value for the field. + */ + public Class<?> getImageClass() { + return this.imageClass; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#plainTextClass}. + * + * @return The current value for the field. + */ + public Class<?> getPlainTextClass() { + return this.plainTextClass; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#htmlTextClass}. + * + * @return The current value for the field. + */ + public Class<?> getHtmlTextClass() { + return this.htmlTextClass; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#plainTextgetTextMethod}. + * + * @return The current value for the field. + */ + public Method getPlainTextgetTextMethod() { + return this.plainTextgetTextMethod; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerWithMappingGetMapping}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerWithMappingGetMapping() { + return this.analysisControllerWithMappingGetMapping; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerClass}. + * + * @return The current value for the field. + */ + public Class<?> getAnalysisControllerClass() { + return this.analysisControllerClass; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerWithMappingClass}. + * + * @return The current value for the field. + */ + public Class<?> getAnalysisControllerWithMappingClass() { + return this.analysisControllerWithMappingClass; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadClass}. + * + * @return The current value for the field. + */ + public Class<?> getAnalysisControllerThreadClass() { + return this.analysisControllerThreadClass; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerCreateAnalysisController}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerCreateAnalysisController() { + return this.analysisControllerCreateAnalysisController; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerWithMappingGetController}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerWithMappingGetController() { + return this.analysisControllerWithMappingGetController; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadStart}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerThreadStart() { + return this.analysisControllerThreadStart; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadTerminate}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerThreadTerminate() { + return this.analysisControllerThreadTerminate; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadJoin}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerThreadJoin() { + return this.analysisControllerThreadJoin; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadJoin}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerGetState() { + return this.analysisControllerGetState; + } + + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadConstructor}. + * + * @return The current value for the field. + */ + + public Constructor<?> getAnalysisControllerThreadConstructor() { + return this.analysisControllerThreadConstructor; + } + + /** + * This method can be used to invoke a given method with given parameters, without having to mind about the exceptions. If an exception occurs, the given default + * value will be returned. + * + * @param method + * The method to be invoked. + * @param obj + * The object on which the method will be invoked. + * @param defaultReturn + * The default return value in case of an exception. + * @param values + * The parameters for the method. + * @return The result of the invoked method if everything went well, the default value otherwise. + */ + public static Object invokeMethod(final Method method, final Object obj, final Object defaultReturn, final Object... values) { + try { + return method.invoke(obj, values); + } catch (final IllegalAccessException ex) { + ClassAndMethodContainer.LOG.error("An error occured during a reflection method call.", ex); + return defaultReturn; + } catch (final IllegalArgumentException ex) { + ClassAndMethodContainer.LOG.error("An error occured during a reflection method call.", ex); + return defaultReturn; + } catch (final InvocationTargetException ex) { + ClassAndMethodContainer.LOG.error("An error occured during a reflection method call.", ex); + return defaultReturn; + } + } + + /** + * This method can be used to invoke a given constructor with given parameters, without having to mind about the exceptions. If an exception occurs, null will be + * returned. + * + * @param constructor + * The constructor to be invoked. + * @param values + * The parameters for the method. + * @return The result of the invoked method if everything went well, null otherwise. + */ + public static Object invokeConstructor(final Constructor<?> constructor, final Object... values) { + try { + return constructor.newInstance(values); + } catch (final InstantiationException ex) { + ClassAndMethodContainer.LOG.error("An error occured during a reflection constructor call.", ex); + return null; + } catch (final IllegalAccessException ex) { + ClassAndMethodContainer.LOG.error("An error occured during a reflection constructor call.", ex); + return null; + } catch (final IllegalArgumentException ex) { + ClassAndMethodContainer.LOG.error("An error occured during a reflection constructor call.", ex); + return null; + } catch (final InvocationTargetException ex) { + ClassAndMethodContainer.LOG.error("An error occured during a reflection constructor call.", ex); + return null; + } + + } + + /** + * This method can be used to invoke a given method with no parameters, without having to mind about the exceptions. If an exception occurs, the given default + * value will be returned. A call to this method is the same as {@link ClassAndMethodContainer#invokeMethod(Method, Object, Object, Object...)} with + * {@code new Object[0]} as parameters. + * + * @param method + * The method to be invoked. + * @param obj + * The object on which the method will be invoked. + * @param defaultReturn + * The default return value in case of an exception. + * @return The result of the invoked method if everything went well, the default value otherwise. + */ + public static Object invokeMethod(final Method method, final Object obj, final Object defaultReturn) { + return ClassAndMethodContainer.invokeMethod(method, obj, defaultReturn, new Object[0]); + } + + /** + * This method can be used to invoke a given <b>class</b>-method with no parameters, without having to mind about the exceptions. If an exception occurs, the + * given default value will be returned. A call to this method is the same as {@link ClassAndMethodContainer#invokeMethod(Method, Object, Object, Object...)} + * with null as object. + * + * @param method + * The method to be invoked. + * @param defaultReturn + * The default return value in case of an exception. + * @param values + * The parameters for the method. + * @return The result of the invoked method if everything went well, the default value otherwise. + */ + public static Object invokeClassMethod(final Method method, final Object defaultReturn, final Object... values) { + return ClassAndMethodContainer.invokeMethod(method, null, defaultReturn, values); + } + } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java deleted file mode 100644 index af5a7fbd..00000000 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************** - * Copyright 2012 by - * + Christian-Albrechts-University of Kiel - * + Department of Computer Science - * + Software Engineering Group - * and others. - * - * 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.common; - -/** - * This is a simple helper class which can store three values. - * - * @author Nils Christian Ehmke - * @version 1.0 - * - * @param <F> - * The type of the first element. - * @param <S> - * The type of the second element. - * @param <T> - * The type of the third element. - */ -public class Triple<F, S, T> { - /** - * This is the first element. - */ - private F fst; - /** - * This is the second element. - */ - private S snd; - /** - * This is the third element. - */ - private T thd; - - /** - * Creates a new instance of this class with null values stored for the elements. - */ - public Triple() { - // No code necessary - } - - /** - * Creates a new instance of this class using the given values. - * - * @param fst - * The first element to be stored in this object. - * @param snd - * The second element to be stored in this object. - * @param thd - * The third element to be stored in this object. - */ - public Triple(final F fst, final S snd, final T thd) { - this.fst = fst; - this.snd = snd; - this.thd = thd; - } - - /** - * Delivers the first element. - * - * @return The first element. - */ - public F getFst() { - return this.fst; - } - - /** - * Sets the first element to a new value. - * - * @param fst - * The new first element. - */ - public void setFst(final F fst) { - this.fst = fst; - } - - /** - * Delivers the second element. - * - * @return The second element. - */ - public S getSnd() { - return this.snd; - } - - /** - * Sets the second element to a new value. - * - * @param snd - * The new second element. - */ - public void setSnd(final S snd) { - this.snd = snd; - } - - /** - * Delivers the third element. - * - * @return The third element. - */ - public T getThd() { - return this.thd; - } - - /** - * Sets the third element to a new value. - * - * @param thd - * The new third element. - */ - public void setThd(final T thd) { - this.thd = thd; - } - -} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyInstantiatedException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyInstantiatedException.java new file mode 100644 index 00000000..e86ef258 --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyInstantiatedException.java @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright 2012 by + * + Christian-Albrechts-University of Kiel + * + Department of Computer Science + * + Software Engineering Group + * and others. + * + * 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.common.exception; + +/** + * This exception shows that the analysis has not yet been instantiated. + * + * @author Nils Christian Ehmke + * @version 1.0 + */ +public class AnalysisAlreadyInstantiatedException extends Exception { + /** + * The serial version UID. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new instance of this class. + */ + public AnalysisAlreadyInstantiatedException() { + // No code necessary + } + + /** + * Creates a new instance of this class using the given parameters. + * + * @param msg + * The message used for the exception. + */ + public AnalysisAlreadyInstantiatedException(final String msg) { + super(msg); + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyStartedException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyStartedException.java new file mode 100644 index 00000000..8076da12 --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisAlreadyStartedException.java @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright 2012 by + * + Christian-Albrechts-University of Kiel + * + Department of Computer Science + * + Software Engineering Group + * and others. + * + * 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.common.exception; + +/** + * This exception shows that the given project has already been started. + * + * @author Nils Christian Ehmke + * @version 1.0 + */ +public class AnalysisAlreadyStartedException extends Exception { + /** + * The serial version UID. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new instance of this class. + */ + public AnalysisAlreadyStartedException() { + // No code necessary + } + + /** + * Creates a new instance of this class using the given parameters. + * + * @param msg + * The message used for the exception. + */ + public AnalysisAlreadyStartedException(final String msg) { + super(msg); + } + + public AnalysisAlreadyStartedException(final String msg, final Throwable ex) { + super(msg, ex); + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInstantiationException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInstantiationException.java new file mode 100644 index 00000000..e0495a85 --- /dev/null +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisInstantiationException.java @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright 2012 by + * + Christian-Albrechts-University of Kiel + * + Department of Computer Science + * + Software Engineering Group + * and others. + * + * 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.common.exception; + +public class AnalysisInstantiationException extends Exception { + /** + * The serial version UID. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates a new instance of this class. + */ + public AnalysisInstantiationException() { + // No code necessary + } + + /** + * Creates a new instance of this class using the given parameters. + * + * @param msg + * The message used for the exception. + */ + public AnalysisInstantiationException(final String msg) { + super(msg); + } + + /** + * Creates a new instance of this class using the given parameters. + * + * @param msg + * The message used for the exception. + * @param The + * cause for the method. + */ + public AnalysisInstantiationException(final String msg, final Throwable cause) { + super(msg, cause); + } +} diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisNotRunningException.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisNotStartedException.java similarity index 89% rename from Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisNotRunningException.java rename to Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisNotStartedException.java index 78c162ad..419d00c8 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisNotRunningException.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/exception/AnalysisNotStartedException.java @@ -26,7 +26,7 @@ package kieker.webgui.common.exception; * @author Nils Christian Ehmke * @version 1.0 */ -public class AnalysisNotRunningException extends Exception { +public class AnalysisNotStartedException extends Exception { /** * The serial version UID. */ @@ -35,7 +35,7 @@ public class AnalysisNotRunningException extends Exception { /** * Creates a new instance of this class. */ - public AnalysisNotRunningException() { + public AnalysisNotStartedException() { // No code necessary } @@ -45,7 +45,7 @@ public class AnalysisNotRunningException extends Exception { * @param msg * The message used for the exception. */ - public AnalysisNotRunningException(final String msg) { + public AnalysisNotStartedException(final String msg) { super(msg); } } -- GitLab