diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java index 5640055a32106de2bd592fe4076becaffa8125d6..fafdd177d9d242475e2c7feabc07df5f1a59785e 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/application/ProjectsBean.java @@ -40,6 +40,7 @@ import kieker.webgui.beans.view.CurrentProjectOverviewBean; import kieker.webgui.common.ACManager; import kieker.webgui.common.FSManager; import kieker.webgui.common.exception.ProjectAlreadyExistingException; +import kieker.webgui.common.exception.ProjectLoadException; /** * The {@link ProjectsBean} is a JSF managed bean to manage a list with all application wide available projects. It provides methods to receive this list as well as @@ -150,13 +151,12 @@ public final class ProjectsBean { * The name of the project to be opened. * @return Either the model instance if the loading was successful or null otherwise. In the latter case, the user will be informed via the growl-component. */ - public MIProject openProject(final String project) { + public MIProject openProject(final String project) throws ProjectLoadException { try { return FSManager.getInstance().openProject(project); } catch (final IOException ex) { ProjectsBean.LOG.error("An error occured while loading the project.", ex); - ProjectsBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the project."); - return null; + throw new ProjectLoadException("An error occured while loading the project.", ex); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBean.java index dc089c4ccded00a38555ac5af83301316ef17739..d25d44a7fc9222827b85f03c18aa59d072c09dbc 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBean.java @@ -22,12 +22,12 @@ package kieker.webgui.beans.view; import java.io.IOException; import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -53,6 +53,8 @@ import kieker.analysis.model.analysisMetaModel.MIRepositoryConnector; import kieker.analysis.model.analysisMetaModel.impl.MAnalysisMetaModelFactory; import kieker.analysis.plugin.AbstractPlugin; import kieker.analysis.plugin.annotation.Property; +import kieker.analysis.plugin.filter.AbstractFilterPlugin; +import kieker.analysis.plugin.reader.AbstractReaderPlugin; import kieker.analysis.repository.AbstractRepository; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; @@ -74,9 +76,13 @@ import org.eclipse.emf.ecore.EObject; /** * The {@link CurrentAnalysisEditorBean} contains the necessary data behind an instance of the analysis editor. It provides various methods to manipulate the current - * project, as the analysis editor is the most important part of the whole application.<br> + * project, as the analysis editor is the most important part of the whole application. The connection to the graph within the editor is done via another bean (the + * {@link CurrentAnalysisEditorGraphBean}).<br> * The class is a JSF managed bean with view scope to make sure that one user (even in one session) can open multiple projects at a time without causing any - * problems. + * problems.<br> + * If editing this class as a programmer keep in mind that the class makes excessive use of java reflection (via {@link ClassAndMethodContainer}) to use the correct + * classes within every project. It doesn't really use the classes loaded by the WebGUI-ClassLoader. This results also in some methods which returns elements from + * the type {@link Object} instead of more specific types to avoid incompatibilities between the multiple loaded classes. * * @author Nils Christian Ehmke * @version 1.0 @@ -85,49 +91,66 @@ import org.eclipse.emf.ecore.EObject; @ViewScoped public final class CurrentAnalysisEditorBean { /** - * This is the log for errors, exceptions etc. + * This field contains the log-object for the whole class, which will be used to log all important errors and exceptions which occur. */ private static final Log LOG = LogFactory.getLog(CurrentAnalysisEditorBean.class); /** - * This is the factory which will be used to create new components for the project. + * This field contains the factory, which will be used to create the new components for the project. */ private final MIAnalysisMetaModelFactory factory = new MAnalysisMetaModelFactory(); /** - * This is the actual model instance. It is the in-memory-model of the current (session) user. + * This field contains the actual model instance, representing the in-memory model of the current view. */ private MIProject project; /** - * This is the corresponding class loader to the project. It contains always the libraries within the lib-folder of the project. + * This is the corresponding class loader to the project. It contains always the libraries within the lib-folder of the project and additionaly the kieker + * library by default. */ private ClassLoader classLoader; /** - * This is the corresponding class loader to the project. It contains always the correct class loader. + * This is the plugin finder for the current project. It contains always a reference to the correct {@link CurrentAnalysisEditorBean#classLoader} to be able to + * locate the available plugins and repositories. */ private PluginFinder pluginFinder; + /** + * This component contains the classes and methods loaded with the specific project class loader. + */ + private ClassAndMethodContainer classAndMethodContainer; /** * This is the name of the stored project. It can be used as an identifier within the FS-Manager */ private String projectName; /** - * This is the time stamp of the moment, the project was loaded or last saved. It can be used to check whether the project has been modified in the meanwhile. + * This is the time stamp of the moment, the project was loaded or last saved. It can be used to check whether the project has been modified externally in the + * meanwhile. */ private long timeStamp; /** - * This list contains the available repositories for the current project. + * This flag determines whether the project has been modified internally and can be used to warn the user about unsaved changes. + */ + private boolean modified; + /** + * This list contains the available repositories for the current project. Keep in mind: The list doesn't really contain classes from the type + * {@code AbstractRepository}, as the repositories are loaded with the specific project class loader. This is just possible as the generic-classes work + * internally with {@code Object}. */ - private final List<Class<?>> availableRepositories = Collections.synchronizedList(new ArrayList<Class<?>>()); + private final List<Class<AbstractRepository>> availableRepositories = Collections.synchronizedList(new ArrayList<Class<AbstractRepository>>()); /** - * This list contains the available filters for the current project. + * This list contains the available filters for the current project. Keep in mind: The list doesn't really contain classes from the type + * {@code AbstractFilterPlugin}, as the repositories are loaded with the specific project class loader. This is just possible as the generic-classes work + * internally with {@code Object}. */ - private final List<Class<?>> availableFilters = Collections.synchronizedList(new ArrayList<Class<?>>()); + private final List<Class<AbstractFilterPlugin>> availableFilters = Collections.synchronizedList(new ArrayList<Class<AbstractFilterPlugin>>()); /** - * This list contains the available readers for the current project. + * This list contains the available readers for the current project. Keep in mind: The list doesn't really contain classes from the type + * {@code AbstractReaderPlugin}, as the repositories are loaded with the specific project class loader. This is just possible as the generic-classes work + * internally with {@code Object}. */ - private final List<Class<?>> availableReaders = Collections.synchronizedList(new ArrayList<Class<?>>()); + private final List<Class<AbstractReaderPlugin>> availableReaders = Collections.synchronizedList(new ArrayList<Class<AbstractReaderPlugin>>()); /** - * This field contains the currently selected node (this can either be a plugin or a repository). + * This field contains the currently selected component (this can either be a plugin ({@link MIPlugin}) or a repository ({@link MIRepository})). */ - private EObject selectedNode; + private EObject selectedComponent; @ManagedProperty(value = "#{projectsBean}") private ProjectsBean projectsBean; @@ -135,10 +158,8 @@ public final class CurrentAnalysisEditorBean { @ManagedProperty(value = "#{currentAnalysisEditorGraphBean}") private CurrentAnalysisEditorGraphBean currentAnalysisEditorGraphBean; - private ClassAndMethodContainer classAndMethodContainer; - /** - * Creates a new instance of this class. + * Creates a new instance of this class. <b>Do not call this constructor manually. It will only be accessed by JSF.</b> */ public CurrentAnalysisEditorBean() { // No code necessary @@ -209,73 +230,67 @@ public final class CurrentAnalysisEditorBean { /** * 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 initialize() throws ProjectLoadException { + public void initialize() { synchronized (this) { - // Make sure that the initialization will only be done for the init request. - if (!FacesContext.getCurrentInstance().isPostback()) { - this.project = this.projectsBean.openProject(this.projectName); - - if (this.project != null) { + try { + // Make sure that the initialization will only be done for the init request. During all other requests, the method call have to be ignored. + if (!FacesContext.getCurrentInstance().isPostback()) { + // Load the project itself + this.project = this.projectsBean.openProject(this.projectName); // Remember the current time! This is important for the later comparison of the time stamps. this.resetTimeStamp(); // Update the class loader and the specific classes used within various methods in this bean this.reloadClassLoader(); this.reloadClassesAndMethods(); // Add the libraries within the lib-folder to the current model - this.addLibrariesToModel(); + this.initializeModelLibraries(); // Load the available readers, filters and repositories - this.loadToolPalette(); + this.initializeToolPalette(); + // The project hasn't been modified (yet) + this.modified = false; } + } catch (final ProjectLoadException ex) { + CurrentAnalysisEditorBean.LOG.error("An error occured while loading the project.", ex); + CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the project."); } } } - private void reloadClassesAndMethods() throws ProjectLoadException { - this.classAndMethodContainer = new ClassAndMethodContainer(this.classLoader); - } - /** - * This method loads the list of available readers, filters and repositories, using the current libraries within the model. + * This method reloads the field containing the methods and classes, using the current class loader. + * + * @throws ProjectLoadException + * If one or more of the classes and methods necessary for {@link ClassAndMethodContainer} could not be found using the given class loader. */ - private void loadToolPalette() { - synchronized (this) { - // Clean our tool palette - this.availableFilters.clear(); - this.availableReaders.clear(); - this.availableRepositories.clear(); - - // Make sure there is a project. - if (this.project != null) { - // Run through all libraries - for (final MIDependency lib : this.project.getDependencies()) { - this.addToToolPalette(lib); - } - this.addKiekerToToolPalette(); - } - } - } - - private void addKiekerToToolPalette() { + private void reloadClassesAndMethods() throws ProjectLoadException { synchronized (this) { - this.addToToolPalette(FSManager.getInstance().getKiekerURL()); + this.classAndMethodContainer = new ClassAndMethodContainer(this.classLoader); } } /** - * This method adds all available readers, filters and repositories within the given library to the lists of this bean. + * This method loads the list of available readers, filters and repositories, using the current libraries within the model. * - * @param lib - * The library used to load the plugins and repositories. + * @throws ProjectLoadException */ - private void addToToolPalette(final MIDependency lib) { + private void initializeToolPalette() throws ProjectLoadException { synchronized (this) { try { - this.addToToolPalette(FSManager.getInstance().getURL(lib, this.projectName)); + // Clean our tool palette + this.availableFilters.clear(); + this.availableReaders.clear(); + this.availableRepositories.clear(); + + // Run through all libraries and add their content to our lists + for (final MIDependency lib : this.project.getDependencies()) { + this.addContentsToToolPalette(FSManager.getInstance().getURL(lib, this.projectName)); + } + // Run also through the kieker library + this.addContentsToToolPalette(FSManager.getInstance().getKiekerURL()); } catch (final MalformedURLException ex) { - ex.printStackTrace(); + CurrentAnalysisEditorBean.LOG.error("A library could not be loaded correctly.", ex); + throw new ProjectLoadException("A library could not be loaded correctly.", ex); } } } @@ -286,33 +301,40 @@ public final class CurrentAnalysisEditorBean { * @param url * The library url used to load the plugins and repositories. */ - private void addToToolPalette(final URL url) { - final List<Class<?>> repositories = this.pluginFinder.getAllRepositoriesWithinJar(url); - final List<Class<?>> plugins = this.pluginFinder.getAllPluginsWithinJar(url); - // Now run through the available classes and add all non-abstract classes to our lists - for (final Class<?> repository : repositories) { - if (!Modifier.isAbstract(repository.getModifiers())) { - this.availableRepositories.add(repository); + @SuppressWarnings("unchecked") + private void addContentsToToolPalette(final URL url) { + synchronized (this) { + // Get all repositories and plugins within the given library + final List<Class<AbstractRepository>> repositories = this.pluginFinder.getAllRepositoriesWithinJar(url); + final List<Class<AbstractPlugin>> plugins = this.pluginFinder.getAllPluginsWithinJar(url); + + // Now run through the available classes and add all non-abstract classes to our lists + for (final Class<AbstractRepository> repository : repositories) { + if (!Modifier.isAbstract(repository.getModifiers())) { + this.availableRepositories.add(repository); + } } - } - for (final Class<?> plugin : plugins) { - if (!Modifier.isAbstract(plugin.getModifiers())) { - // The following cast results in the unchecked-cast-warnings, but we know that the cast should be correct. - if (this.classAndMethodContainer.getAbstractFilterPluginClass().isAssignableFrom(plugin)) { - this.availableFilters.add(plugin); - } else { - if (this.classAndMethodContainer.getAbstractReaderPluginClass().isAssignableFrom(plugin)) { - this.availableReaders.add(plugin); + + for (final Class<?> plugin : plugins) { + if (!Modifier.isAbstract(plugin.getModifiers())) { + // The following cast results in the unchecked-cast-warnings, but we know that the cast should be correct. + if (this.classAndMethodContainer.getAbstractFilterPluginClass().isAssignableFrom(plugin)) { + this.availableFilters.add((Class<AbstractFilterPlugin>) plugin); + } else { + if (this.classAndMethodContainer.getAbstractReaderPluginClass().isAssignableFrom(plugin)) { + this.availableReaders.add((Class<AbstractReaderPlugin>) plugin); + } } } } + } } /** * This method takes all libraries from the lib-folder and adds them to the in-memory-model. */ - private void addLibrariesToModel() { + private void initializeModelLibraries() { synchronized (this) { final List<MIDependency> libs = FSManager.getInstance().getModelLibraries(this.projectName); // Add them, but remove all existing dependencies so far to avoid double entries. This also makes sure that the model - after it has been opened - points @@ -327,6 +349,7 @@ public final class CurrentAnalysisEditorBean { * project. * * @throws ProjectLoadException + * If something went wrong. */ private void reloadClassLoader() throws ProjectLoadException { synchronized (this) { @@ -334,11 +357,9 @@ public final class CurrentAnalysisEditorBean { try { this.pluginFinder = new PluginFinder(this.classLoader); } catch (final ClassNotFoundException ex) { - CurrentAnalysisEditorBean.LOG.error("Could not load classes.", ex); - throw new ProjectLoadException(); + throw new ProjectLoadException("Could not load classes.", ex); } catch (final NullPointerException ex) { - CurrentAnalysisEditorBean.LOG.error("Invalid class loader", ex); - throw new ProjectLoadException(); + throw new ProjectLoadException("Invalid class loader.", ex); } } } @@ -376,76 +397,62 @@ public final class CurrentAnalysisEditorBean { /** * This method can be used to get the description of an {@link AbstractPlugin}- or an {@link AbstractRepository}-class. The description is read via the - * annotation. + * annotation using the java reflection API. * * @param clazz * The class whose description should be extracted. * @return The description for the class or a substitute if none is available. This is in either case human readable. */ public String getDescription(final Class<?> clazz) { - try { - // Get the two potential annotations - final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); - final Annotation annotationRepository = clazz.getAnnotation(this.classAndMethodContainer.getRepositoryAnnotationClass()); - - // Now check which one of them is available - if ((annotationPlugin == null) || ((String) this.classAndMethodContainer.getPluginDescriptionMethod().invoke(annotationPlugin, new Object[0])).isEmpty()) { - if ((annotationRepository == null) - || ((String) this.classAndMethodContainer.getRepositoryDescriptionMethod().invoke(annotationRepository, new Object[0])).isEmpty()) { - // None. Deliver a human readable substitute. - return "No description available"; - } else { - return (String) this.classAndMethodContainer.getRepositoryDescriptionMethod().invoke(annotationRepository, new Object[0]); - } + // Get the two potential annotations + final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); + final Annotation annotationRepository = clazz.getAnnotation(this.classAndMethodContainer.getRepositoryAnnotationClass()); + + final Method pluginDescrMethod = this.classAndMethodContainer.getPluginDescriptionMethod(); + final Method repoDescrMethod = this.classAndMethodContainer.getRepositoryDescriptionMethod(); + + // Now check which one of them is available + if ((annotationPlugin == null) || ((String) ClassAndMethodContainer.invokeMethod(pluginDescrMethod, annotationPlugin, "")).isEmpty()) { + if ((annotationRepository == null) || ((String) ClassAndMethodContainer.invokeMethod(repoDescrMethod, annotationRepository, "")).isEmpty()) { + // None. Deliver a human readable substitute. + return "No description available"; } else { - return (String) this.classAndMethodContainer.getPluginDescriptionMethod().invoke(annotationPlugin, new Object[0]); + return (String) ClassAndMethodContainer.invokeMethod(repoDescrMethod, annotationRepository, "No description available"); } - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - return "No description available"; - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - return "No description available"; - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - return "No description available"; + } else { + return (String) ClassAndMethodContainer.invokeMethod(pluginDescrMethod, annotationPlugin, "No description available"); } } + /** + * Delivers the properties of the given class, using the annotations and the java reflection API. + * + * @param clazz + * The class whose properties will be delivered. + * @return A list of properties. It contains instances of {@link Property} - but those from the project class loader. + */ public List<Annotation> getProperties(final Class<?> clazz) { - final List<Annotation> result = new ArrayList<Annotation>(); + // Get the two potential annotations + final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); + final Annotation annotationRepository = clazz.getAnnotation(this.classAndMethodContainer.getRepositoryAnnotationClass()); - try { - // Get the two potential annotations - final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); - final Annotation annotationRepository = clazz.getAnnotation(this.classAndMethodContainer.getRepositoryAnnotationClass()); + final Annotation[] properties; - final Annotation[] properties; - - // Now check which one of them is available - if (annotationPlugin == null) { - if (annotationRepository == null) { - // None. - properties = new Property[0]; - } else { - properties = (Annotation[]) this.classAndMethodContainer.getRepositoryConfigurationMethod().invoke(annotationRepository, new Object[0]); - } + // Now check which one of them is available + if (annotationPlugin == null) { + if (annotationRepository == null) { + // None. + properties = new Property[0]; } else { - properties = (Annotation[]) this.classAndMethodContainer.getPluginConfigurationMethod().invoke(annotationPlugin, new Object[0]); - } - - for (final Annotation property : properties) { - result.add(property); + properties = (Annotation[]) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getRepositoryConfigurationMethod(), + annotationRepository, new Property[0]); } - - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); + } else { + properties = (Annotation[]) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getPluginConfigurationMethod(), + annotationPlugin, new Property[0]); } - return result; + + return Arrays.asList(properties); } /** @@ -480,24 +487,17 @@ public final class CurrentAnalysisEditorBean { public List<Annotation> getOutputPorts(final Class<?> clazz) { final List<Annotation> result = new ArrayList<Annotation>(); - try { - // Get the potential annotation - final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); + // Get the potential annotation + final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); - // Now check whether it is available - if (annotationPlugin != null) { - for (final Annotation oPort : (Annotation[]) this.classAndMethodContainer.getPluginOutputPortsMethod().invoke(annotationPlugin, new Object[0])) { - result.add(oPort); - } + // Now check whether it is available + if (annotationPlugin != null) { + for (final Annotation oPort : (Annotation[]) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getPluginOutputPortsMethod(), + annotationPlugin, new Annotation[0])) { + result.add(oPort); } - - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); } + return result; } @@ -510,26 +510,28 @@ public final class CurrentAnalysisEditorBean { */ public List<Annotation> getRepositoryPorts(final Class<?> clazz) { final List<Annotation> result = new ArrayList<Annotation>(); - try { - // Get the potential annotation - final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); - // Now check whether it is available - if (annotationPlugin != null) { - for (final Annotation rPort : (Annotation[]) this.classAndMethodContainer.getPluginRepositoryPortsMethod().invoke(annotationPlugin, new Object[0])) { - result.add(rPort); - } + // Get the potential annotation + final Annotation annotationPlugin = clazz.getAnnotation(this.classAndMethodContainer.getPluginAnnotationClass()); + + // Now check whether it is available + if (annotationPlugin != null) { + for (final Annotation rPort : (Annotation[]) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getPluginRepositoryPortsMethod(), + annotationPlugin, new Annotation[0])) { + result.add(rPort); } - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.warn("Could not invoke method", ex); } + return result; } + /** + * Searches for displays within the given class and returns them. + * + * @param clazz + * The class to be analyzed. + * @return A list containing the available displays. + */ public List<Annotation> getDisplays(final Class<?> clazz) { final List<Annotation> result = new ArrayList<Annotation>(); @@ -550,9 +552,8 @@ public final class CurrentAnalysisEditorBean { * * @param event * The upload event. - * @throws ProjectLoadException */ - public void handleFileUpload(final FileUploadEvent event) throws ProjectLoadException { + public void handleFileUpload(final FileUploadEvent event) { // Get the file from the event final UploadedFile file = event.getFile(); @@ -567,25 +568,32 @@ public final class CurrentAnalysisEditorBean { } // Update our class loader and the available plugins & repositories this.reloadClassLoader(); - this.addToToolPalette(lib); + this.reloadClassesAndMethods(); + this.addContentsToToolPalette(FSManager.getInstance().getURL(lib, this.projectName)); } catch (final LibraryAlreadyExistingException ex) { CurrentAnalysisEditorBean.LOG.info("A library with the same name exists already.", ex); CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_WARN, "A library with the same name exists already."); } catch (final IOException ex) { CurrentAnalysisEditorBean.LOG.error("An error occured while uploading the library.", ex); CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while uploading the library."); + } catch (final ProjectLoadException ex) { + CurrentAnalysisEditorBean.LOG.error("An error occured while uploading the library.", ex); + CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while uploading the library."); } } /** - * This method delivers the available libraries of this project as a pair of strings. The first element is the name of the library, the second one te size in - * MiBytes as human readable string. + * This method delivers the available libraries of this project as a pair of strings. The first element is the name of the library, the second one the size in + * MiBytes as human readable string. The first element is always the kieker-library. * * @return The available libraries. */ public List<Pair<String, String>> getLibraries() { synchronized (this) { - return FSManager.getInstance().getLibraries(this.projectName); + final List<Pair<String, String>> result = FSManager.getInstance().getLibraries(this.projectName); + result.add(0, new Pair<String, String>("Kieker", "N/A")); + + return result; } } @@ -594,7 +602,7 @@ public final class CurrentAnalysisEditorBean { * * @return A list with all readers. */ - public final List<Class<?>> getAvailableReaders() { + public final List<Class<AbstractReaderPlugin>> getAvailableReaders() { return this.availableReaders; } @@ -603,7 +611,7 @@ public final class CurrentAnalysisEditorBean { * * @return A list with all filter. */ - public final List<Class<?>> getAvailableFilters() { + public final List<Class<AbstractFilterPlugin>> getAvailableFilters() { return this.availableFilters; } @@ -612,7 +620,7 @@ public final class CurrentAnalysisEditorBean { * * @return A list with all repositories. */ - public final List<Class<?>> getAvailableRepositories() { + public final List<Class<AbstractRepository>> getAvailableRepositories() { return this.availableRepositories; } @@ -629,6 +637,7 @@ public final class CurrentAnalysisEditorBean { CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_INFO, "Project saved."); // Update the time stamp! this.resetTimeStamp(); + this.modified = false; } catch (final IOException ex) { CurrentAnalysisEditorBean.LOG.error("An error occured while saving the project.", ex); CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while saving the project."); @@ -642,196 +651,95 @@ public final class CurrentAnalysisEditorBean { } /** - * This method fills the displays of the given plugin. In other words: It tries to instantiate the given class and to extract the displays. If the instantiation - * fails (for various reasons), the method informs the user and executes normally - without an exception. + * This method fills the displays of the given plugin. In other words: It tries to extract the list of displays from the given class (using the annotations) and + * to convert them into model instances. * * @param clazz * The class to be used as a base. * @param plugin * The plugin to be filled. - * @return true iff the plugin has been intialized properly. */ - private boolean fillDisplays(final Class<AbstractPlugin> clazz, final MIPlugin plugin) { + private void fillDisplays(final Class<AbstractPlugin> clazz, final MIPlugin plugin) { synchronized (this) { - try { - // Get the displays and convert them into model instances - final List<Annotation> displays = this.getDisplays(clazz); - for (final Annotation display : displays) { - final MIDisplay mDisplay = this.factory.createDisplay(); - mDisplay.setName((String) this.classAndMethodContainer.getDisplayNameMethod().invoke(display, new Object[0])); - plugin.getDisplays().add(mDisplay); - } - - return true; - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the displays of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the displays of the plugin."); - return false; - } catch (final ClassCastException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the displays of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the displays of the plugin."); - return false; - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the displays of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the displays of the plugin."); - return false; - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the displays of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the displays of the plugin."); - return false; + // Get the displays and convert them into model instances + final List<Annotation> displays = this.getDisplays(clazz); + for (final Annotation display : displays) { + final MIDisplay mDisplay = this.factory.createDisplay(); + mDisplay.setName((String) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getDisplayNameMethod(), display, "N/A")); + plugin.getDisplays().add(mDisplay); } } } /** - * This method fills the ports of the given plugin. In other words: It tries to instantiate the given class and to extract the ports. If the instantiation fails - * (for various reasons), the method informs the user and executes normally - without an exception. + * This method fills the ports of the given plugin. In other words: It tries to extract the list of ports from the given class (using the annotations) and + * to convert them into model instances. * * @param clazz * The class to be used as a base. * @param plugin * The plugin to be filled. - * @return true iff the plugin has been intialized properly. */ - private boolean fillPorts(final Class<AbstractPlugin> clazz, final MIPlugin plugin) { + private void fillPorts(final Class<AbstractPlugin> clazz, final MIPlugin plugin) { synchronized (this) { - try { - // Get the ports - final List<Annotation> inputPorts = this.getInputPorts(clazz); - final List<Annotation> outputPorts = this.getOutputPorts(clazz); - final List<Annotation> repositoryPorts = this.getRepositoryPorts(clazz); - - // Add input ports - if (plugin instanceof MIFilter) { - for (final Annotation inputPort : inputPorts) { - final MIInputPort mInputPort = this.factory.createInputPort(); - mInputPort.setName((String) this.classAndMethodContainer.getInputPortNameMethod().invoke(inputPort, new Object[0])); - mInputPort.setParent((MIFilter) plugin); - } - } - - // Add output ports. - for (final Annotation outputPort : outputPorts) { - final MIOutputPort mOutputPort = this.factory.createOutputPort(); - mOutputPort.setName((String) this.classAndMethodContainer.getOutputPortNameMethod().invoke(outputPort, new Object[0])); - mOutputPort.setParent(plugin); + // Get the ports + final List<Annotation> inputPorts = this.getInputPorts(clazz); + final List<Annotation> outputPorts = this.getOutputPorts(clazz); + final List<Annotation> repositoryPorts = this.getRepositoryPorts(clazz); + + // Add input ports + if (plugin instanceof MIFilter) { + for (final Annotation inputPort : inputPorts) { + final MIInputPort mInputPort = this.factory.createInputPort(); + mInputPort.setName((String) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getInputPortNameMethod(), inputPort, "N/A")); + mInputPort.setParent((MIFilter) plugin); } + } - // Add repository ports. - for (final Annotation repositoryPort : repositoryPorts) { - final MIRepositoryConnector mConnector = this.factory.createRepositoryConnector(); - mConnector.setName((String) this.classAndMethodContainer.getRepositoryPortNameMethod().invoke(repositoryPort, new Object[0])); - plugin.getRepositories().add(mConnector); - } + // Add output ports. + for (final Annotation outputPort : outputPorts) { + final MIOutputPort mOutputPort = this.factory.createOutputPort(); + mOutputPort.setName((String) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getOutputPortNameMethod(), outputPort, "N/A")); + mOutputPort.setParent(plugin); + } - return true; - - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the ports of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the ports of the plugin."); - return false; - } catch (final ClassCastException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the ports of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the ports of the plugin."); - return false; - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the ports of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the ports of the plugin."); - return false; - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the ports of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the ports of the plugin."); - return false; + // Add repository ports. + for (final Annotation repositoryPort : repositoryPorts) { + final MIRepositoryConnector mConnector = this.factory.createRepositoryConnector(); + mConnector.setName((String) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getRepositoryPortNameMethod(), repositoryPort, + "N/A")); + plugin.getRepositories().add(mConnector); } } } /** - * This method fills the properties of the given repository. In other words: It tries to instantiate the given class and to extract the configuration keys. If - * the instantiation fails (for various reasons), the method informs the user and executes normally - without an exception. + * This method fills the properties of the given repository or plugin. In other words: It tries to extract the list of properties from the given class (using the + * annotations) and to convert them into model instances. * * @param clazz * The class to be used as a base. - * @param repository - * The repository to be filled. - * @return true iff the repository has been intialized properly. + * @param component + * The component to be filled. */ - private boolean fillProperties(final Class<AbstractRepository> clazz, final MIRepository repository) { - try { - // Get the default configuration and use it to initialize the model repository - final List<Annotation> properties = this.getProperties(clazz); + private void fillProperties(final Class<?> clazz, final EObject component) { + // Get the default configuration and use it to initialize the model repository + final List<Annotation> properties = this.getProperties(clazz); - for (final Annotation property : properties) { - final MIProperty mProperty = this.factory.createProperty(); + for (final Annotation property : properties) { + final MIProperty mProperty = this.factory.createProperty(); - mProperty.setName((String) this.classAndMethodContainer.getPropertyNameMethod().invoke(property, new Object[0])); - mProperty.setValue((String) this.classAndMethodContainer.getPropertyDefaultValueMethod().invoke(property, new Object[0])); + mProperty.setName((String) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getPropertyNameMethod(), property, "N/A")); + mProperty.setValue((String) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getPropertyDefaultValueMethod(), property, "N/A")); + mProperty.setDescription((String) ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getPropertyDefaultValueMethod(), property, "N/A")); - repository.getProperties().add(mProperty); + if (component instanceof MIPlugin) { + ((MIPlugin) component).getProperties().add(mProperty); + } else { + ((MIRepository) component).getProperties().add(mProperty); } - - return true; - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the repository.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the repository."); - return false; - } catch (final ClassCastException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the repository.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the repository."); - return false; - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the repository.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the repository."); - return false; - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the repository.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the repository."); - return false; } - } - /** - * This method fills the properties of the given plugin. In other words: It tries to instantiate the given class and to extract the configuration keys. If - * the instantiation fails (for various reasons), the method informs the user and executes normally - without an exception. - * - * @param clazz - * The class to be used as a base. - * @param plugin - * The plugin to be filled. - * @return true iff the plugin has been intialized properly. - */ - private boolean fillProperties(final Class<AbstractPlugin> clazz, final MIPlugin plugin) { - try { - // Get the default configuration and use it to initialize the model plugin - final List<Annotation> properties = this.getProperties(clazz); - - for (final Annotation property : properties) { - final MIProperty mProperty = this.factory.createProperty(); - - mProperty.setName((String) this.classAndMethodContainer.getPropertyNameMethod().invoke(property, new Object[0])); - mProperty.setValue((String) this.classAndMethodContainer.getPropertyDefaultValueMethod().invoke(property, new Object[0])); - mProperty.setDescription((String) this.classAndMethodContainer.getPropertyDescriptionMethod().invoke(property, new Object[0])); - plugin.getProperties().add(mProperty); - } - - return true; - } catch (final IllegalAccessException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the plugin."); - return false; - } catch (final ClassCastException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the plugin."); - return false; - } catch (final IllegalArgumentException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the plugin."); - return false; - } catch (final InvocationTargetException ex) { - CurrentAnalysisEditorBean.LOG.error("An error occured while loading the properties of the plugin.", ex); - CurrentAnalysisEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An errcor occured while loading the properties of the plugin."); - return false; - } } /** @@ -846,15 +754,13 @@ public final class CurrentAnalysisEditorBean { repository.setClassname(clazz.getName()); repository.setName(clazz.getSimpleName()); - final boolean check = this.fillProperties(clazz, repository); - // Make sure that everything has been loaded correctly. If something went wrong, we don't add the component to our model - if (check) { - synchronized (this) { - // Add it to the project - and to the graph - this.project.getRepositories().add(repository); - this.currentAnalysisEditorGraphBean.addRepository(repository); - this.currentAnalysisEditorGraphBean.refreshGraph(); - } + this.fillProperties(clazz, repository); + synchronized (this) { + // Add it to the project - and to the graph + this.project.getRepositories().add(repository); + this.currentAnalysisEditorGraphBean.addRepository(repository); + this.currentAnalysisEditorGraphBean.refreshGraph(); + this.modified = true; } } @@ -875,25 +781,22 @@ public final class CurrentAnalysisEditorBean { plugin.setClassname(clazz.getName()); plugin.setName(clazz.getSimpleName()); - boolean check = true; - check &= this.fillProperties(clazz, plugin); - check &= this.fillPorts(clazz, plugin); - check &= this.fillDisplays(clazz, plugin); + this.fillProperties(clazz, plugin); + this.fillPorts(clazz, plugin); + this.fillDisplays(clazz, plugin); - // Make sure that everything has been loaded correctly. If something went wrong, we don't add the component to our model - if (check) { - synchronized (this) { - // Add it to the project - this.project.getPlugins().add(plugin); + synchronized (this) { + // Add it to the project + this.project.getPlugins().add(plugin); - // Add the element to the graph - if (plugin instanceof MIReader) { - this.currentAnalysisEditorGraphBean.addReader((MIReader) plugin); - } else { - this.currentAnalysisEditorGraphBean.addFilter((MIFilter) plugin); - } - this.currentAnalysisEditorGraphBean.refreshGraph(); + // Add the element to the graph + if (plugin instanceof MIReader) { + this.currentAnalysisEditorGraphBean.addReader((MIReader) plugin); + } else { + this.currentAnalysisEditorGraphBean.addFilter((MIFilter) plugin); } + this.currentAnalysisEditorGraphBean.refreshGraph(); + this.modified = true; } } @@ -904,7 +807,7 @@ public final class CurrentAnalysisEditorBean { */ public EObject getSelectedPlugin() { synchronized (this) { - return this.selectedNode; + return this.selectedComponent; } } @@ -924,10 +827,10 @@ public final class CurrentAnalysisEditorBean { result.add("ClassName"); // Get the original properties of the plugin - if (this.selectedNode instanceof MIPlugin) { - result.addAll(((MIPlugin) this.selectedNode).getProperties()); + if (this.selectedComponent instanceof MIPlugin) { + result.addAll(((MIPlugin) this.selectedComponent).getProperties()); } else { - result.addAll(((MIRepository) this.selectedNode).getProperties()); + result.addAll(((MIRepository) this.selectedComponent).getProperties()); } return result; @@ -973,11 +876,11 @@ public final class CurrentAnalysisEditorBean { */ public String getCurrentPluginName() { synchronized (this) { - if (this.selectedNode != null) { - if (this.selectedNode instanceof MIPlugin) { - return ((MIPlugin) this.selectedNode).getName(); + if (this.selectedComponent != null) { + if (this.selectedComponent instanceof MIPlugin) { + return ((MIPlugin) this.selectedComponent).getName(); } else { - return ((MIRepository) this.selectedNode).getName(); + return ((MIRepository) this.selectedComponent).getName(); } } else { return ""; @@ -1016,12 +919,12 @@ public final class CurrentAnalysisEditorBean { this.currentAnalysisEditorGraphBean.addFilter((MIFilter) plugin); } } - this.currentAnalysisEditorGraphBean.initGraph(); + for (final MIRepository repository : this.project.getRepositories()) { this.currentAnalysisEditorGraphBean.addRepository(repository); } - // Now initialize the connections between filters + // Now initialize the connections between filters... for (final MIPlugin plugin : this.project.getPlugins()) { for (final MIOutputPort oPort : plugin.getOutputPorts()) { for (final MIInputPort iPort : oPort.getSubscribers()) { @@ -1030,11 +933,18 @@ public final class CurrentAnalysisEditorBean { } } - // TODO Connections between filters and repositories + // ...and between filters and repositories + for (final MIPlugin plugin : this.project.getPlugins()) { + for (final MIRepositoryConnector rPort : plugin.getRepositories()) { + // It is possible that the connected repository is null, if it hasn't been set yet. Check this. + if (rPort.getRepository() != null) { + this.currentAnalysisEditorGraphBean.addConnection(plugin, rPort.getRepository(), rPort); + } + } + } this.currentAnalysisEditorGraphBean.initListeners(); - - // This command is here necessary because of a current bug + this.currentAnalysisEditorGraphBean.addEdgeConstraints(); // Repaint the graph this.currentAnalysisEditorGraphBean.refreshGraph(); @@ -1042,7 +952,7 @@ public final class CurrentAnalysisEditorBean { public void nodeSelected(final EObject node) { synchronized (this) { - this.selectedNode = node; + this.selectedComponent = node; } } @@ -1079,8 +989,8 @@ public final class CurrentAnalysisEditorBean { } // Unselect the currently selected node if it is the one which has just been removed - if (this.selectedNode == node) { - this.selectedNode = null; // NOPMD + if (this.selectedComponent == node) { + this.selectedComponent = null; // NOPMD } } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorGraphBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorGraphBean.java index d311e64a91a601f2e3865f1c3690746d3b1d7da7..f687baf0f7849060b53f3e50730435111a74cc3f 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorGraphBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorGraphBean.java @@ -64,9 +64,9 @@ public class CurrentAnalysisEditorGraphBean { */ private static final String JS_CMD_CREATE_GRAPH_VAR = "var graph = GraphFlow();"; /** - * This is the javascript code to initialize the visual graph. + * This is the javascript code to add edge constraints to the graph. */ - private static final String JS_CMD_INIT_GRAPH = "graph.initGraph(null);"; + private static final String JS_CMD_ADD_EDGE_CONSTRAINTS = "graph.addEdgeConstraints()"; /** * This is the javasscript code to add the click listener to the graph. */ @@ -143,15 +143,7 @@ public class CurrentAnalysisEditorGraphBean { } /** - * Initializes the graph. - */ - public void initGraph() { - RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_INIT_GRAPH); - - } - - /** - * Initializes the listeners for the graph + * Initializes the listeners for the graph. */ public void initListeners() { RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_CLICK_LISTENER); @@ -160,6 +152,13 @@ public class CurrentAnalysisEditorGraphBean { RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_REMOVE_EDGE_LISTENER); } + /** + * Adds the edge constraints to the graph. + */ + public void addEdgeConstraints() { + RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_EDGE_CONSTRAINTS); + } + /** * Refreshes the graph after changes have been made. */ @@ -222,6 +221,21 @@ public class CurrentAnalysisEditorGraphBean { this.assembleGraphPortID(destination, inputPort), "")); } + /** + * This method adds a connection between a filter and a repository to the graph. + * + * @param source + * The source plugin. + * @param repository + * The destination repository. + * @param port + * The repository port. + */ + public void addConnection(final MIPlugin source, final MIRepository destination, final MIRepositoryConnector port) { + RequestContext.getCurrentInstance().execute(String.format(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_EDGE, this.assembleGraphPortID(source, port), + this.assembleGraphPortID(destination), "")); + } + /** * This method assembles the string containing the given ports. * @@ -251,8 +265,8 @@ public class CurrentAnalysisEditorGraphBean { /** * This method assembles the string containing the available repository ports of the given plugin. * - * @param plugin - * The plugin whose repository ports will be used. + * @param ports + * The ports which will be used. * @return A string containing the JS commands to create the repository ports. */ private String assembleGraphRepositoryPortString(final EList<MIRepositoryConnector> ports) { @@ -308,6 +322,30 @@ public class CurrentAnalysisEditorGraphBean { return this.componentMap.get(plugin) + "." + this.componentMap.get(port); } + /** + * This method assembles the ID of the port for the graph based on the given parameters. + * + * @param plugin + * The parent plugin of the port. + * @param port + * The port itself. + * @return The ID for the port within the graph + */ + private Object assembleGraphPortID(final MIPlugin plugin, final MIRepositoryConnector port) { + return this.componentMap.get(plugin) + "." + this.componentMap.get(port); + } + + /** + * This method assembles the ID of the port for the graph based on the given parameters. + * + * @param repository + * The parent repository of the port. + * @return The ID for the port within the graph + */ + private Object assembleGraphPortID(final MIRepository repository) { + return this.componentMap.get(repository) + "." + CurrentAnalysisEditorGraphBean.REPOSITORY_INPUT_PORT; + } + /** * Assembles a human-readable string of the given repository, which can also be used as a graph ID. * @@ -375,6 +413,10 @@ public class CurrentAnalysisEditorGraphBean { } } + /** + * This is the action which can be called from the javascript code to show that an edge has been created. It informs the connected + * {@link CurrentAnalysisEditorBean} about this. + */ public void edgeCreated() { // Get the parameters final Map<String, String> paramMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap(); @@ -407,6 +449,10 @@ public class CurrentAnalysisEditorGraphBean { } } + /** + * This is the action which can be called from the javascript code to show that an edge has been removed. It informs the connected + * {@link CurrentAnalysisEditorBean} about this. + */ public void edgeRemoved() { // Get the parameters final Map<String, String> paramMap = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap(); diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitEditorBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitEditorBean.java index a6df7f6bbbbf934189723bd059f82b92a3bf5fc1..c624674d414f8bd6bf4bf609d128f21a45a437a0 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitEditorBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentCockpitEditorBean.java @@ -49,6 +49,7 @@ import kieker.webgui.beans.application.ProjectsBean; import kieker.webgui.common.FSManager; import kieker.webgui.common.Global; import kieker.webgui.common.exception.NewerProjectException; +import kieker.webgui.common.exception.ProjectLoadException; import org.primefaces.context.RequestContext; import org.primefaces.event.TabChangeEvent; @@ -123,14 +124,19 @@ public class CurrentCockpitEditorBean { */ public void initalize() { synchronized (this) { - // Make sure that the initialization will only be done for the init request. - if (!FacesContext.getCurrentInstance().isPostback()) { - // Remember the given parameters - this.project = this.projectsBean.openProject(this.projectName); - if (this.project != null) { - // Remember the current time! This is important for the later comparison of the time stamps. - this.resetTimeStamp(); + try { + // Make sure that the initialization will only be done for the init request. + if (!FacesContext.getCurrentInstance().isPostback()) { + // Remember the given parameters + this.project = this.projectsBean.openProject(this.projectName); + if (this.project != null) { + // Remember the current time! This is important for the later comparison of the time stamps. + this.resetTimeStamp(); + } } + } catch (final ProjectLoadException ex) { + CurrentCockpitEditorBean.LOG.error("An error occured while loading the project.", ex); + CurrentCockpitEditorBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the project."); } } } 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 a0ca75275615f8a6cfc2716acee079bca030794f..a3bf7c1e568d43e5c05dcc5c3ef55278a684c0ff 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 @@ -39,6 +39,7 @@ import kieker.webgui.common.exception.AnalysisAlreadyStartedException; import kieker.webgui.common.exception.AnalysisInstantiationException; import kieker.webgui.common.exception.AnalysisNotInstantiatedException; import kieker.webgui.common.exception.AnalysisNotStartedException; +import kieker.webgui.common.exception.ProjectLoadException; /** * /** @@ -112,10 +113,15 @@ public class CurrentControllerBean { */ public void initalize() { synchronized (this) { - // Make sure that the initialization will only be done for the init request. - if (!FacesContext.getCurrentInstance().isPostback()) { - // Remember the given parameters - this.project = this.projectsBean.openProject(this.projectName); + try { + // Make sure that the initialization will only be done for the init request. + if (!FacesContext.getCurrentInstance().isPostback()) { + // Remember the given parameters + this.project = this.projectsBean.openProject(this.projectName); + } + } catch (final ProjectLoadException ex) { + CurrentControllerBean.LOG.error("An error occured while loading the project.", ex); + CurrentControllerBean.showMessage(FacesMessage.SEVERITY_ERROR, "An error occured while loading the project."); } } } 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 7ca079972a0865c7e0ecb24a17cfd8a8df71ab62..d4d764f07b2265976ef12e99bf69e7ac9ad3239e 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ACManager.java @@ -24,7 +24,6 @@ import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; import kieker.analysis.AnalysisController; -import kieker.analysis.model.analysisMetaModel.MIProject; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; import kieker.webgui.common.exception.AnalysisAlreadyInstantiatedException; @@ -139,10 +138,11 @@ public final class ACManager { 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); + FSManager.getInstance().openProject(project); + FSManager.getInstance().getClassLoader(project); - this.analyses.put(project, new Analysis(classLoader, modelProject)); + // TODO + // this.analyses.put(project, new Analysis(classLoader, modelProject)); } else { throw new AnalysisAlreadyInstantiatedException("The analysis has already been initialized."); } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java index 614566c39b48aa8f799c633387f94edb13b254ec..78a0f65bb7a5c36a253a83cc732bc6d0041642cd 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/Analysis.java @@ -1,5 +1,6 @@ package kieker.webgui.common; +import java.io.File; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -8,9 +9,6 @@ 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; @@ -26,17 +24,17 @@ public class Analysis { 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 modelProject; private final Object analysisController; private final Object analysisControllerThread; private final UpdateDisplaysThread updateDisplaysThread; - public Analysis(final ClassLoader classLoader, final MIProject modelProject) throws AnalysisInstantiationException { + public Analysis(final ClassLoader classLoader, final File projectFile) throws AnalysisInstantiationException { try { - this.modelProject = modelProject; this.classAndMethodContainer = new ClassAndMethodContainer(classLoader); final Method createMethod = this.classAndMethodContainer.getAnalysisControllerCreateAnalysisController(); + this.modelProject = ClassAndMethodContainer.invokeClassMethod(this.classAndMethodContainer.getAnalysisControllerLoadFromFile(), null, projectFile); final Object controllerAndMapping = ClassAndMethodContainer.invokeClassMethod(createMethod, null, this.modelProject, classLoader); this.analysisController = ClassAndMethodContainer.invokeMethod(this.classAndMethodContainer.getAnalysisControllerWithMappingGetController(), controllerAndMapping, null); @@ -76,7 +74,7 @@ public class Analysis { synchronized (this) { try { this.classAndMethodContainer.getAnalysisControllerThreadTerminate().invoke(this.analysisControllerThread, new Object[0]); - this.updateDisplaysThread.terminate(); + // this.updateDisplaysThread.terminate(); this.classAndMethodContainer.getAnalysisControllerThreadJoin().invoke(this.analysisControllerThread, Analysis.MAX_THREAD_WAIT_TIME_MS); this.updateDisplaysThread.join(Analysis.MAX_THREAD_WAIT_TIME_MS); @@ -137,40 +135,40 @@ public class Analysis { @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()); + // 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); - * } - * } - */ - } - } + // 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); + * } + * } + */ + // } + // } } /** @@ -222,35 +220,35 @@ public class Analysis { @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); - // } - } - } + // 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; - } - } + // 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/ClassAndMethodContainer.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java index a9fc87687d650a49b71a7bf2bbd48c9b39e2febe..d1c0410cb3b5c429cef8e9b62f76cb1c8f419aea 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java @@ -19,6 +19,7 @@ ***************************************************************************/ package kieker.webgui.common; +import java.io.File; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -218,6 +219,10 @@ public final class ClassAndMethodContainer { * This is the description()-method of the class equivalence of {@link Property}. */ private final Method propertyDescriptionMethod; + /** + * This is the loadFromFile(File)-method of the class equivalence of {@link AnalysisController}. + */ + private final Method analysisControllerLoadFromFile; /** * This is the constructor for {@link AnalysisControllerThread}, which gets an instance of {@link AnalysisController}. */ @@ -276,8 +281,9 @@ public final class ClassAndMethodContainer { // 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); + this.analysisControllerLoadFromFile = this.analysisControllerClass.getMethod("loadFromFile", File.class); + + this.analysisControllerCreateAnalysisController = this.analysisControllerClass.getMethod("createAnalysisController", miProjectClass, ClassLoader.class); // Another special case as the parameter is a long final Method[] methods = this.analysisControllerThreadClass.getMethods(); @@ -652,11 +658,19 @@ public final class ClassAndMethodContainer { * * @return The current value for the field. */ - public Constructor<?> getAnalysisControllerThreadConstructor() { return this.analysisControllerThreadConstructor; } + /** + * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerLoadFromFile}. + * + * @return The current value for the field. + */ + public Method getAnalysisControllerLoadFromFile() { + return this.analysisControllerLoadFromFile; + } + /** * 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. diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java index 01d1053d600fbbbf404535aa22463e31026e3ed4..58c79d606c123a067a22634ba5a52eb87237cde7 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/FSManager.java @@ -211,6 +211,12 @@ public final class FSManager { // NOCS (Class Data Abstraction Coupling, Class F } } + public Object openProject(final String project, final ClassAndMethodContainer classAndMethodContainer) { + // TODO Correct and synchronize + // return ClassAndMethodContainer.invokeClassMethod(this.classAndMethodContainer.getAnalysisControllerLoadFromFile(), null, projectFile); + return null; + } + /** * This method tries to save the given project. * diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java index 7a987557970c813bbc3bc330c31cf65bd5d7a85b..c55b64de2f5a8f93a2a3f279f055ace818a91df0 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/PluginFinder.java @@ -26,6 +26,8 @@ import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; +import kieker.analysis.plugin.AbstractPlugin; +import kieker.analysis.repository.AbstractRepository; import kieker.webgui.common.exception.ProjectLoadException; /** @@ -59,19 +61,19 @@ public final class PluginFinder { * The url for the jar. * @return A list containing all available repository-classes or null, if an exception occurred. */ - public List<Class<?>> getAllRepositoriesWithinJar(final URL url) { + public List<Class<AbstractRepository>> getAllRepositoriesWithinJar(final URL url) { // Get a list containing all available classes within the given jar final List<Class<?>> clazzes = this.getAllClassesWithinJar(url); - List<Class<?>> result = null; + List<Class<AbstractRepository>> result = null; if (clazzes != null) { - result = new ArrayList<Class<?>>(); + result = new ArrayList<Class<AbstractRepository>>(); for (final Class<?> clazz : clazzes) { // This is the cast resulting in an unchecked cast warning. if (clazz.isAnnotationPresent(this.classAndMethodContainer.getRepositoryAnnotationClass()) && this.classAndMethodContainer.getAbstractRepositoryClass().isAssignableFrom(clazz)) { - result.add(clazz); + result.add((Class<AbstractRepository>) clazz); } } } @@ -89,17 +91,17 @@ public final class PluginFinder { * The class loader used to load the classes. * @return A list containing all available plugin-classes or null, if an exception occurred. */ - public List<Class<?>> getAllPluginsWithinJar(final URL url) { + public List<Class<AbstractPlugin>> getAllPluginsWithinJar(final URL url) { final List<Class<?>> clazzes = this.getAllClassesWithinJar(url); - List<Class<?>> result = null; + List<Class<AbstractPlugin>> result = null; if (clazzes != null) { - result = new ArrayList<Class<?>>(); + result = new ArrayList<Class<AbstractPlugin>>(); for (final Class<?> clazz : clazzes) { // This is the cast resulting in an unchecked cast warning. if (clazz.isAnnotationPresent(this.classAndMethodContainer.getPluginAnnotationClass()) && this.classAndMethodContainer.getAbstractPluginClass().isAssignableFrom(clazz)) { - result.add(clazz); + result.add((Class<AbstractPlugin>) clazz); } } } diff --git a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js index d6940388c279c241d2dd62bbd3405e4b6fbc0bc6..fbd72d47c530cd4b5117320aa1eeb5d20b6b0cf1 100644 --- a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js +++ b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js @@ -71,20 +71,7 @@ function GraphFlow(){ /** This array stores all Nodes and is initialized with a dummy, used for drawing edges between a node and the mousepointer. */ - var json = [ null, null, null, null, null, null, null, null, null, null, - { - "adjacencies": [], - "data": { - "$dim": 0, - "$type": "none", - "&xPos": 0, - "&typeSelected" : null, - "&yPos": 0, - }, - "id": "#DUMMY_MOUSE_NODE", - "name": "", - "alpha": 0 - }]; + var json; /** Used for managing space for node creation/deletion since the array is divided into to parts, adding and removing nodes @@ -1023,15 +1010,24 @@ function GraphFlow(){ }); } - /** Initializes the Graph */ - this.initGraph = function(graph){ - - if(graph != null){ - json = graph; - } + this.initGraph = function(){ + json = [ null, null, null, null, null, null, null, null, null, null, + { + "adjacencies": [], + "data": { + "$dim": 0, + "$type": "none", + "&xPos": 0, + "&typeSelected" : null, + "&yPos": 0, + }, + "id": "#DUMMY_MOUSE_NODE", + "name": "", + "alpha": 0 + }]; fd = new $jit.FlowGraph({ //id of the visualization container @@ -1360,13 +1356,15 @@ function GraphFlow(){ }); // load JSON data. - fd.loadGraphFlowJSON(json,0); + fd.loadGraphFlowJSON(json,jsonCapacity.max); // compute positions refresh(); // end //alert("final wut:"+fd.nodeSizeModifier); } + // initialize graph + initGraph(); return this; } @@ -1428,9 +1426,6 @@ function init(){ [{"name":"outputPort", "id":"op1"}]); - // create graph - graph.initGraph(null); - // add nodes after graph creation var node2 = {"id":"superNode2", "name":"Super Repo", diff --git a/Kieker.WebGUI/src/main/webapp/js/jit.js b/Kieker.WebGUI/src/main/webapp/js/jit.js index 951e6d3c33d1fa0966b4a5c055d4ba3b18512906..0ef47b2612181d96a5d1eb17f87daccc3df8d166 100644 --- a/Kieker.WebGUI/src/main/webapp/js/jit.js +++ b/Kieker.WebGUI/src/main/webapp/js/jit.js @@ -18082,7 +18082,7 @@ $jit.FlowGraph.$extend = true; // add the label // apparently this throws an error on FireFox... - /*var label = adj.data.$label; + var label = adj.data.$label; if(label != undefined){ var ctx = canvas.getCtx(); ctx.font = (1.23 * dim)+"px Arial"; @@ -18090,7 +18090,7 @@ $jit.FlowGraph.$extend = true; var midX = (from.x + to.x - ctx.measureText(label).width) / 2, midY = (from.y + to.y -dim) / 2; ctx.fillText(label, midX, midY); - }*/ + } }, 'contains': function(adj, pos) { return false;