diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java index 6026779558d1c4bd3936fb3be0b26eabf1b704c1..3563e52116c7949d06307da733d14b9748a8964c 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisCockpitProjectBean.java @@ -88,7 +88,9 @@ public class CurrentAnalysisCockpitProjectBean { * @return The stored instance of {@link DashboardModel}. */ public DashboardModel getModel() { - return this.model; + synchronized (this) { + return this.model; + } } /** @@ -98,7 +100,9 @@ public class CurrentAnalysisCockpitProjectBean { * The new dashboard model to be stored in this bean. */ public void setModel(final DashboardModel model) { - this.model = model; + synchronized (this) { + this.model = model; + } } /** @@ -141,11 +145,17 @@ public class CurrentAnalysisCockpitProjectBean { } public String updateDisplay(final String displayName) { - try { - return ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName).toString(); - } catch (final NullPointerException ex) { - return "N/A"; + synchronized (this) { + if ((this.activeView != null) && (this.projectName != null)) { + try { + return ACManager.getInstance().getDisplay(this.projectName, this.activeView.getName(), displayName).toString(); + } catch (final NullPointerException ex) { // NOPMD + // No code necessary + } + } } + + return "N/A"; } /** @@ -162,11 +172,26 @@ public class CurrentAnalysisCockpitProjectBean { return CurrentAnalysisCockpitProjectBean.PAGE_PROJECT_OVERVIEW; } + /** + * Delivers the currently active view. + * + * @return The active view. + */ public MIView getActiveView() { - return this.activeView; + synchronized (this) { + return this.activeView; + } } + /** + * Sets the active view to a new value. + * + * @param activeView + * The new active view. + */ public void setActiveView(final MIView activeView) { - this.activeView = activeView; + synchronized (this) { + this.activeView = activeView; + } } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java index 2e403f75e0fe1b5c0cb2b0b22f9c92c653262ae7..e669bdef451454c39535f5af8cd3936bb7154fa4 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisControllerProjectBean.java @@ -142,16 +142,11 @@ public class CurrentAnalysisControllerProjectBean { } } + /** + * This method cleans the current analysis instance. + */ public void cleanAnalysis() { - try { - ACManager.getInstance().cleanAnalysisController(this.projectName); - } catch (final AnalysisNotInstantiatedException e) { - CurrentAnalysisControllerProjectBean.showMessage(FacesMessage.SEVERITY_WARN, "The analysis has not been instantiated yet."); - } catch (final AnalysisNotRunningException e) { - CurrentAnalysisControllerProjectBean.showMessage(FacesMessage.SEVERITY_WARN, "The analysis has not been started yet."); - } catch (final InterruptedException e) { - CurrentAnalysisControllerProjectBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occurred while cleaning the analysis."); - } + ACManager.getInstance().cleanAnalysisController(this.projectName); } /** diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java index a9003389fea8cdf4ecf32fce4ed2c4ac8dc3aaec..682589dff78560b4dbee98f69780280d85419acf 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentAnalysisViewWorkSpaceProjectBean.java @@ -235,11 +235,13 @@ public class CurrentAnalysisViewWorkSpaceProjectBean { final List<Pair<MIPlugin, Class<AbstractPlugin>>> result = new ArrayList<Pair<MIPlugin, Class<AbstractPlugin>>>(); synchronized (this) { - for (final MIPlugin plugin : this.project.getPlugins()) { - try { - result.add(new Pair<MIPlugin, Class<AbstractPlugin>>(plugin, (Class<AbstractPlugin>) this.classLoader.loadClass(plugin.getClassname()))); - } catch (final ClassNotFoundException ex) { - // TODO Catch + if (this.project != null) { + for (final MIPlugin plugin : this.project.getPlugins()) { + try { + result.add(new Pair<MIPlugin, Class<AbstractPlugin>>(plugin, (Class<AbstractPlugin>) this.classLoader.loadClass(plugin.getClassname()))); + } catch (final ClassNotFoundException ex) { + // TODO Catch + } } } } @@ -255,9 +257,11 @@ public class CurrentAnalysisViewWorkSpaceProjectBean { */ public void addView(final String viewName) { synchronized (this) { - final MIView view = this.factory.createView(); - view.setName(viewName); - this.project.getViews().add(view); + if (this.project != null) { + final MIView view = this.factory.createView(); + view.setName(viewName); + this.project.getViews().add(view); + } } } 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 15fb3c3570f20d19fc48e97ebaa8a2b277366c49..bcdaed2d374d2162a6d9fa9fde9f581854e26fa0 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java @@ -33,6 +33,8 @@ 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; @@ -105,8 +107,8 @@ public final class ACManager { currController.getSnd().join(ACManager.MAX_THREAD_WAIT_TIME_MS); currController.getThd().join(ACManager.MAX_THREAD_WAIT_TIME_MS); } - } catch (final NullPointerException ex) { - throw new AnalysisNotRunningException(); + } catch (final NullPointerException ex) { // NOPMD + throw new AnalysisNotRunningException(); // NOPMD } } @@ -134,11 +136,18 @@ public final class ACManager { currController.getThd().start(); } } catch (final NullPointerException ex) { - throw new AnalysisNotInstantiatedException(); + throw new AnalysisNotInstantiatedException(); // NOPMD } } - public void cleanAnalysisController(final String project) throws AnalysisNotInstantiatedException, AnalysisNotRunningException, InterruptedException { + /** + * This method cleans the analysis controller of the given project. In other words: The potential running instance is stopped and removed. After a call to this + * method, the project can be restarted. Potential exceptions will be ignored + * + * @param project + * 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 { @@ -146,8 +155,12 @@ public final class ACManager { this.stopAnalysisController(project); this.analysisController.remove(project); } - } catch (final NullPointerException ex) { - throw new AnalysisNotInstantiatedException(); + } catch (final NullPointerException ex) { // NOPMD + // No code necessary + } catch (final AnalysisNotRunningException ex) { // NOPMD + // No code necessary + } catch (final InterruptedException ex) { // NOPMD + // No code necessary } } @@ -221,9 +234,23 @@ public final class ACManager { 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) { - // TODO Catch exceptions - return this.analysisController.get(project).getThd().getDisplay(viewName, displayName); + try { + return this.analysisController.get(project).getThd().getDisplay(viewName, displayName); + } catch (final NullPointerException ex) { // NOPMD + return null; + } } /** @@ -270,8 +297,8 @@ public final class ACManager { } /** - * This helper thread is used to update the available displays of the ACManager at regular intervals. <b>Important:</b> If the interrupt-method of the thread is - * being called, it will be terminated. + * 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. * * @author Nils Christian Ehmke * @version 1.0 @@ -282,30 +309,108 @@ public final class ACManager { * 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; - private final Map<String, Map<String, AbstractDisplay>> displayObjects = new ConcurrentHashMap<String, Map<String, AbstractDisplay>>(); + /** + * 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>(); + /** + * 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 hashmap and the necessary objects + // Initialize the hashmaps and the necessary objects for (final MIView view : this.myProject.getViews()) { final Map<String, AbstractDisplay> viewMap = new ConcurrentHashMap<String, AbstractDisplay>(); this.displayObjects.put(view.getName(), viewMap); for (final MIDisplay display : view.getDisplays()) { - // TODO Use correct display object - viewMap.put(display.getName(), new PlainText()); + final Method displayMethod = UpdateDisplaysThread.getDisplayMethod(this.myPluginMap.get(display.getParent()).getClass(), display.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(display.getName(), displayObject); + } + } } } } + /** + * 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; + } + } + 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); } @@ -320,21 +425,14 @@ public final class ACManager { final AbstractDisplay displayObject = viewMap.get(display.getName()); final AbstractPlugin pluginObject = this.myPluginMap.get(display.getParent()); // Update the display object - final Method[] methods = pluginObject.getClass().getMethods(); - for (final Method method : methods) { - final Display displayAnnot = method.getAnnotation(Display.class); - if ((displayAnnot != null) && displayAnnot.name().equals(display.getName())) { - // We found the correct method - try { - method.invoke(pluginObject, displayObject); - } catch (final IllegalAccessException e) { - e.printStackTrace(); - } catch (final IllegalArgumentException e) { - e.printStackTrace(); - } catch (final InvocationTargetException e) { - e.printStackTrace(); - } - } + try { + this.methodMap.get(displayObject).invoke(pluginObject, displayObject); + } catch (final IllegalAccessException ex) { // NOPMD + // No code necessary + } catch (final IllegalArgumentException e) { // NOPMD + // No code necessary + } catch (final InvocationTargetException e) { // NOPMD + // No code necessary } } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java index 0ee851c073d5aa80bbbc4a5eac7f7bec9f2708ca..1f40c2ff668c03b1305a9e98973156f3139eae0e 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Triple.java @@ -1,3 +1,23 @@ +/*************************************************************************** + * 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; /**