From 9df9eb298dc8cfd17288c93dcd7d1f67c9e8554c Mon Sep 17 00:00:00 2001
From: Nils Christian Ehmke <nie@informatik.uni-kiel.de>
Date: Tue, 29 May 2012 11:43:13 +0200
Subject: [PATCH] Connections between plugins now possible; Repositories are
 visible and selectable

---
 .../session/CurrentWorkSpaceProjectBean.java  | 138 +++++++++++++-
 .../common/ConnectionFilterToFilter.java      | 168 ++++++++++++++++++
 .../common/ConnectionFilterToRepository.java  | 138 ++++++++++++++
 .../converter/MIPluginStringConverter.java    |  65 +++++++
 .../converter/MIPortStringConverter.java      |  65 +++++++
 .../src/main/webapp/ProjectWorkSpace.xhtml    |  12 ++
 .../webapp/dialogs/connectionDialog.xhtml     | 163 +++++++++++++++--
 7 files changed, 734 insertions(+), 15 deletions(-)
 create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToFilter.java
 create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToRepository.java
 create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java
 create mode 100644 Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java

diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java
index 331409fb..755583bd 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java
@@ -28,6 +28,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.faces.application.FacesMessage;
 import javax.faces.application.FacesMessage.Severity;
@@ -41,6 +42,7 @@ import kieker.analysis.model.analysisMetaModel.MIFilter;
 import kieker.analysis.model.analysisMetaModel.MIInputPort;
 import kieker.analysis.model.analysisMetaModel.MIOutputPort;
 import kieker.analysis.model.analysisMetaModel.MIPlugin;
+import kieker.analysis.model.analysisMetaModel.MIPort;
 import kieker.analysis.model.analysisMetaModel.MIProject;
 import kieker.analysis.model.analysisMetaModel.MIProperty;
 import kieker.analysis.model.analysisMetaModel.MIRepository;
@@ -53,12 +55,15 @@ import kieker.analysis.plugin.reader.AbstractReaderPlugin;
 import kieker.analysis.repository.AbstractRepository;
 import kieker.analysis.repository.annotation.Repository;
 import kieker.common.configuration.Configuration;
+import kieker.webgui.common.ConnectionFilterToFilter;
 import kieker.webgui.common.FSManager;
 import kieker.webgui.common.Pair;
 import kieker.webgui.common.PluginFinder;
 import kieker.webgui.common.exception.LibraryAlreadyExistingException;
 import kieker.webgui.common.exception.NewerProjectException;
 
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
 import org.primefaces.event.FileUploadEvent;
 import org.primefaces.model.UploadedFile;
 
@@ -113,7 +118,11 @@ public final class CurrentWorkSpaceProjectBean {
 	 */
 	private final List<Class<AbstractReaderPlugin>> availableReaders = Collections.synchronizedList(new ArrayList<Class<AbstractReaderPlugin>>());
 
+	private final ConcurrentHashMap<String, MIPlugin> pluginMap = new ConcurrentHashMap<String, MIPlugin>();
+	private final ConcurrentHashMap<String, MIPort> portMap = new ConcurrentHashMap<String, MIPort>();
 	private MIPlugin selectedPlugin;
+	private final List<ConnectionFilterToFilter> connections = new ArrayList<ConnectionFilterToFilter>();
+	private MIRepository selectedRepository;
 
 	/**
 	 * Creates a new instance of this class.
@@ -144,6 +153,7 @@ public final class CurrentWorkSpaceProjectBean {
 		// Remember the given parameters
 		this.project = project;
 		this.projectName = projectName;
+		this.getConnectionsFromProject();
 
 		if (this.project != null) {
 			// Remember the current time! This is important for the later comparison of the time stamps.
@@ -154,6 +164,8 @@ public final class CurrentWorkSpaceProjectBean {
 			this.addLibrariesToModel();
 			// Load the available readers, filters and repositories
 			this.loadToolPalette();
+			// Load the hashmaps to get the plugins and ports
+			this.intializeHashMaps();
 		}
 
 		// Now deliver the correct navigation page
@@ -166,6 +178,20 @@ public final class CurrentWorkSpaceProjectBean {
 		return navigationPage;
 	}
 
+	private void intializeHashMaps() {
+		for (final MIPlugin plugin : this.project.getPlugins()) {
+			this.pluginMap.put(plugin.toString(), plugin);
+			for (final MIPort port : plugin.getOutputPorts()) {
+				this.portMap.put(port.toString(), port);
+			}
+			if (plugin instanceof MIFilter) {
+				for (final MIPort port : ((MIFilter) plugin).getInputPorts()) {
+					this.portMap.put(port.toString(), port);
+				}
+			}
+		}
+	}
+
 	/**
 	 * This method loads the list of available readers, filters and repositories, using the current libraries within the model.
 	 */
@@ -273,6 +299,7 @@ public final class CurrentWorkSpaceProjectBean {
 		this.classLoader = null;
 		this.selectedPlugin = null;
 		this.timeStamp = 0;
+		this.pluginMap.clear();
 
 		return CurrentWorkSpaceProjectBean.PAGE_PROJECT_OVERVIEW;
 	}
@@ -543,6 +570,7 @@ public final class CurrentWorkSpaceProjectBean {
 		this.fillPorts(clazz, plugin);
 		// Add it to the project
 		this.project.getPlugins().add(plugin);
+		this.pluginMap.put(plugin.toString(), plugin);
 	}
 
 	/**
@@ -553,17 +581,24 @@ public final class CurrentWorkSpaceProjectBean {
 	 */
 	public void removePlugin(final MIPlugin plugin) {
 		this.project.getPlugins().remove(plugin);
+		this.pluginMap.remove(plugin.toString());
 		if (this.selectedPlugin == plugin) {
 			this.selectedPlugin = null;
 		}
 	}
 
-	public MIPlugin getSelectedPlugin() {
-		return this.selectedPlugin;
+	public EObject getSelectedPlugin() {
+		return (this.selectedPlugin != null) ? this.selectedPlugin : this.selectedRepository;
 	}
 
 	public void setSelectedPlugin(final MIPlugin selectedPlugin) {
 		this.selectedPlugin = selectedPlugin;
+		this.selectedRepository = null;
+	}
+
+	public void setSelectedRepository(final MIRepository selectedRepository) {
+		this.selectedRepository = selectedRepository;
+		this.selectedPlugin = null;
 	}
 
 	/**
@@ -577,11 +612,100 @@ public final class CurrentWorkSpaceProjectBean {
 		// Add the name-property as a string
 		result.add("Name");
 		// Get the original properties of the plugin
-		result.addAll(this.selectedPlugin.getProperties());
+		if (this.selectedPlugin != null) {
+			result.addAll(this.selectedPlugin.getProperties());
+		} else {
+			result.addAll(this.selectedRepository.getProperties());
+		}
 
 		return result;
 	}
 
+	/**
+	 * This method delivers a list containing all available filters within the model instance. It is the same as calling project.getPlugins() but instead this method
+	 * returns only instances of {@link MIFilter}.
+	 * 
+	 * @return A list with the available filters.
+	 */
+	public List<MIPlugin> getFilters() {
+		final EList<MIPlugin> plugins = this.project.getPlugins();
+		final List<MIPlugin> filter = new ArrayList<MIPlugin>();
+
+		for (final MIPlugin plugin : plugins) {
+			if (plugin instanceof MIFilter) {
+				filter.add(plugin);
+			}
+		}
+
+		return filter;
+	}
+
+	/**
+	 * This method extracts the connections between the filters from the current main project.
+	 */
+	private void getConnectionsFromProject() {
+		this.connections.clear();
+
+		if (this.project != null) {
+			final EList<MIPlugin> mPlugins = this.project.getPlugins();
+			for (final MIPlugin mPlugin : mPlugins) {
+				final EList<MIOutputPort> mOutputPorts = mPlugin.getOutputPorts();
+				for (final MIOutputPort mOutputPort : mOutputPorts) {
+					final EList<MIInputPort> mInputPorts = mOutputPort.getSubscribers();
+					for (final MIInputPort mInputPort : mInputPorts) {
+						this.connections.add(new ConnectionFilterToFilter(mPlugin, mInputPort.getParent(), mInputPort, mOutputPort));
+					}
+				}
+			}
+		}
+
+	}
+
+	/**
+	 * Delivers the connections (between the filters) within the current main project.
+	 * 
+	 * @return A list containing all available connections.
+	 */
+	public List<ConnectionFilterToFilter> getConnections() {
+		return this.connections;
+	}
+
+	/**
+	 * Delivers the valid connections (between the filters) within the current main project.
+	 * 
+	 * @return A list containing all available and valid connections.
+	 */
+	public List<ConnectionFilterToFilter> getValidConnections() {
+		final List<ConnectionFilterToFilter> validConnections = new ArrayList<ConnectionFilterToFilter>();
+		final List<ConnectionFilterToFilter> availableConnections = this.getConnections();
+
+		for (final ConnectionFilterToFilter connection : availableConnections) {
+			if (connection.isValid()) {
+				validConnections.add(connection);
+			}
+		}
+
+		return validConnections;
+	}
+
+	/**
+	 * This method adds an empty connection to the current main project.
+	 */
+	public void addConnection() {
+		this.connections.add(new ConnectionFilterToFilter(null, null, null, null));
+	}
+
+	/**
+	 * This method "submits" the current connections to the main project (In other words: The connections will be stored within the main project).
+	 */
+	public void submitConnections() {
+		for (final ConnectionFilterToFilter connection : this.connections) {
+			if (connection.isValid()) {
+				connection.getOutputPort().getSubscribers().add(connection.getInputPort());
+			}
+		}
+	}
+
 	/**
 	 * This method shows the current user a message by using the growl-component of PrimeFaces.
 	 * 
@@ -594,4 +718,12 @@ public final class CurrentWorkSpaceProjectBean {
 		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, "", msg));
 	}
 
+	public MIPlugin getPluginByName(final String string) {
+		return this.pluginMap.get(string);
+	}
+
+	public MIPort getPortByName(final String string) {
+		return this.portMap.get(string);
+	}
+
 }
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToFilter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToFilter.java
new file mode 100644
index 00000000..62c47144
--- /dev/null
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToFilter.java
@@ -0,0 +1,168 @@
+/***************************************************************************
+ * 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;
+
+import kieker.analysis.model.analysisMetaModel.MIInputPort;
+import kieker.analysis.model.analysisMetaModel.MIOutputPort;
+import kieker.analysis.model.analysisMetaModel.MIPlugin;
+
+/**
+ * This class is a helper class containing a connection between two filters.
+ * 
+ * @author Nils Christian Ehmke
+ * @version 1.0
+ */
+public class ConnectionFilterToFilter {
+
+	/**
+	 * The source filter.
+	 */
+	private MIPlugin source;
+	/**
+	 * The destination filter.
+	 */
+	private MIPlugin destination;
+	/**
+	 * The input port which will be used from the destination.
+	 */
+	private MIInputPort inputPort;
+	/**
+	 * The output port which will be used from the source.
+	 */
+	private MIOutputPort outputPort;
+
+	/**
+	 * Creates a new instance of this class using the given parameters.
+	 * 
+	 * @param source
+	 *            The source filter.
+	 * @param destination
+	 *            The destination filter.
+	 * @param inputPort
+	 *            The input port which will be used from the destination.
+	 * @param outputPort
+	 *            The output port which will be used from the source.
+	 */
+	public ConnectionFilterToFilter(final MIPlugin source, final MIPlugin destination, final MIInputPort inputPort, final MIOutputPort outputPort) {
+		this.source = source;
+		this.destination = destination;
+		this.inputPort = inputPort;
+		this.outputPort = outputPort;
+	}
+
+	/**
+	 * Delivers the current destination.
+	 * 
+	 * @return The destination filter.
+	 */
+	public MIPlugin getDestination() {
+		return this.destination;
+	}
+
+	/**
+	 * Sets the new destination.
+	 * 
+	 * @param destination
+	 *            The new destination filter.
+	 */
+	public void setDestination(final MIPlugin destination) {
+		this.destination = destination;
+		// Make sure that the output port is always valid - if necessary even null.
+		if (this.destination == null) {
+			this.outputPort = null;
+		}
+	}
+
+	/**
+	 * Delivers the current input port.
+	 * 
+	 * @return The input port which will be used from the destination.
+	 */
+	public MIInputPort getInputPort() {
+		return this.inputPort;
+	}
+
+	/**
+	 * Sets the input port to a new value.
+	 * 
+	 * @param inputPort
+	 *            The new input port which will be used from the destination.
+	 */
+	public void setInputPort(final MIInputPort inputPort) {
+		this.inputPort = inputPort;
+	}
+
+	/**
+	 * Delivers the current output port.
+	 * 
+	 * @return The output port which will be used from the source.
+	 */
+	public MIOutputPort getOutputPort() {
+		return this.outputPort;
+	}
+
+	/**
+	 * Sets the new output port.
+	 * 
+	 * @param outputPort
+	 *            The new output port which will be used from the source.
+	 */
+	public void setOutputPort(final MIOutputPort outputPort) {
+		this.outputPort = outputPort;
+	}
+
+	/**
+	 * Delivers the source filter.
+	 * 
+	 * @return The source filter.
+	 */
+	public MIPlugin getSource() {
+		return this.source;
+	}
+
+	/**
+	 * Sets the source filter to a new value.
+	 * 
+	 * @param source
+	 *            The new source filter.
+	 */
+	public void setSource(final MIPlugin source) {
+		this.source = source;
+		// Make sure that the input port is always valid - if necessary even null.
+		if (this.source == null) {
+			this.inputPort = null;
+		}
+	}
+
+	/**
+	 * Checks whether the current configuration is valid. The configuration is valid if and only if: All four components are not null, the ports exist and are
+	 * compatible.
+	 * 
+	 * @return true if and only if all four components are not null, the ports exist and are compatible.
+	 */
+	public boolean isValid() {
+		if ((this.source == null) || (this.destination == null) || (this.inputPort == null) || (this.outputPort == null)) {
+			return false;
+		}
+		// TODO: This is currently not necessarily valid
+		return true;
+	}
+}
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToRepository.java b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToRepository.java
new file mode 100644
index 00000000..604a813f
--- /dev/null
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ConnectionFilterToRepository.java
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * 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;
+
+import kieker.analysis.model.analysisMetaModel.MIPlugin;
+import kieker.analysis.model.analysisMetaModel.MIRepository;
+import kieker.analysis.model.analysisMetaModel.MIRepositoryConnector;
+
+/**
+ * This class is a helper class containing a connection between a filter and a repository.
+ * 
+ * @author Nils Christian Ehmke
+ * @version 1.0
+ */
+public class ConnectionFilterToRepository {
+
+	/**
+	 * The source filter.
+	 */
+	private MIPlugin source;
+	/**
+	 * The destination repository.
+	 */
+	private MIRepository destination;
+	/**
+	 * The repository port which will be used from the source.
+	 */
+	private MIRepositoryConnector outputPort;
+
+	/**
+	 * Creates a new instance of this class using the given parameters.
+	 * 
+	 * @param source
+	 *            The source filter.
+	 * @param destination
+	 *            The destination repository.
+	 * @param repositoryPort
+	 *            The repository port which will be used from the source.
+	 */
+	public ConnectionFilterToRepository(final MIPlugin source, final MIRepository destination, final MIRepositoryConnector outputPort) {
+		this.source = source;
+		this.destination = destination;
+		this.outputPort = outputPort;
+	}
+
+	/**
+	 * Delivers the current destination.
+	 * 
+	 * @return The destination filter.
+	 */
+	public MIRepository getDestination() {
+		return this.destination;
+	}
+
+	/**
+	 * Sets the new destination.
+	 * 
+	 * @param destination
+	 *            The new destination filter.
+	 */
+	public void setDestination(final MIRepository destination) {
+		this.destination = destination;
+	}
+
+	/**
+	 * Delivers the current output port.
+	 * 
+	 * @return The output port which will be used from the source.
+	 */
+	public MIRepositoryConnector getOutputPort() {
+		return this.outputPort;
+	}
+
+	/**
+	 * Sets the new output port.
+	 * 
+	 * @param outputPort
+	 *            The new output port which will be used from the source.
+	 */
+	public void setOutputPort(final MIRepositoryConnector outputPort) {
+		this.outputPort = outputPort;
+	}
+
+	/**
+	 * Delivers the source filter.
+	 * 
+	 * @return The source filter.
+	 */
+	public MIPlugin getSource() {
+		return this.source;
+	}
+
+	/**
+	 * Sets the source filter to a new value.
+	 * 
+	 * @param source
+	 *            The new source filter.
+	 */
+	public void setSource(final MIPlugin source) {
+		this.source = source;
+		// Make sure that the input port is always valid - if necessary even null.
+		if (this.source == null) {
+			this.outputPort = null;
+		}
+	}
+
+	/**
+	 * Checks whether the current configuration is valid. The configuration is valid if and only if: All four components are not null, the ports exist and are
+	 * compatible.
+	 * 
+	 * @return true if and only if all four components are not null, the ports exist and are compatible.
+	 */
+	public boolean isValid() {
+		if ((this.source == null) || (this.destination == null) || (this.outputPort == null)) {
+			return false;
+		}
+		// TODO: This is currently not necessarily valid
+		return true;
+	}
+}
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java
new file mode 100644
index 00000000..95e6e74b
--- /dev/null
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * 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.converter;
+
+import javax.el.ELResolver;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.convert.FacesConverter;
+
+import kieker.webgui.beans.session.CurrentWorkSpaceProjectBean;
+
+/**
+ * This converter can be used to convert a given plugin model instance to a string and vice versa (It uses the object's toString-method).
+ * 
+ * @author Nils Christian Ehmke
+ * @version 1.0
+ */
+@FacesConverter(value = MIPluginStringConverter.NAME)
+public class MIPluginStringConverter implements Converter {
+	/**
+	 * This is the name of this converter.
+	 */
+	public static final String NAME = "kieker.webgui.converter.MIPluginStringConverter";
+
+	/**
+	 * Creates a new instance of this class.
+	 */
+	public MIPluginStringConverter() {
+		/* No code necessary. */
+	}
+
+	@Override
+	public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) {
+		final ELResolver el = FacesContext.getCurrentInstance()
+				.getApplication().getELResolver();
+		final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance()
+				.getELContext(), null, "currentWorkSpaceProjectBean");
+
+		return bean.getPluginByName(string);
+	}
+
+	@Override
+	public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) {
+		return o.toString();
+	}
+}
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java
new file mode 100644
index 00000000..cc8e2c89
--- /dev/null
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * 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.converter;
+
+import javax.el.ELResolver;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.convert.FacesConverter;
+
+import kieker.webgui.beans.session.CurrentWorkSpaceProjectBean;
+
+/**
+ * This converter can be used to convert a given port model instance to a string and vice versa (It uses the object's toString-method).
+ * 
+ * @author Nils Christian Ehmke
+ * @version 1.0
+ */
+@FacesConverter(value = MIPortStringConverter.NAME)
+public class MIPortStringConverter implements Converter {
+	/**
+	 * This is the name of this converter.
+	 */
+	public static final String NAME = "kieker.webgui.converter.MIPortStringConverter";
+
+	/**
+	 * Creates a new instance of this class.
+	 */
+	public MIPortStringConverter() {
+		/* No code necessary. */
+	}
+
+	@Override
+	public Object getAsObject(final FacesContext fc, final UIComponent uic, final String string) {
+		final ELResolver el = FacesContext.getCurrentInstance()
+				.getApplication().getELResolver();
+		final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance()
+				.getELContext(), null, "currentWorkSpaceProjectBean");
+
+		return bean.getPortByName(string);
+	}
+
+	@Override
+	public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) {
+		return o.toString();
+	}
+}
diff --git a/Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml b/Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml
index b9b2db04..28864518 100644
--- a/Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/ProjectWorkSpace.xhtml
@@ -71,6 +71,18 @@
                                 <p:commandLink ajax="true" value="Remove" action="#{currentWorkSpaceProjectBean.removePlugin(plugin)}"  update=":propertiesForm :centerForm"/>
                             </div>
                         </ui:repeat>
+                        <ui:repeat value="#{currentWorkSpaceProjectBean.project.repositories}" var="repository" varStatus="counter">
+                            <p:remoteCommand name="setRepository#{counter.index}" action="#{currentWorkSpaceProjectBean.setSelectedRepository(repository)}" update=":propertiesForm"/>
+                            <!-- Netbeans reports an error here, but the code does still work though... -->
+                            <div onclick="setRepository#{counter.index}();" class="ui-panel ui-widget ui-widget-content ui-corner-all block draggable" id="#{stringToIDBean.stringToID(repository)}" >
+                                <div class="ui-panel-titlebar ui-widget-header ui-corner-all">
+                                    <h:outputText style="font-weight: bold" value="#{repository.getName()}"/>
+                                </div>
+                                <p:commandLink ajax="true" value="Connections" update=":connectionDialogForm" onclick="connectionDialog.show();"/>
+                                <br/>
+                                <p:commandLink ajax="true" value="Remove" action="#{currentWorkSpaceProjectBean.removeRepository(repository)}"  update=":propertiesForm :centerForm"/>
+                            </div>
+                        </ui:repeat>
                     </div>
                 </h:form> 
             </p:layoutUnit>                 
diff --git a/Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml b/Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml
index 689a674e..e3d74ef3 100644
--- a/Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/dialogs/connectionDialog.xhtml
@@ -1,15 +1,154 @@
-<ui:composition 
-    xmlns="http://www.w3.org/1999/xhtml"
-    xmlns:h="http://java.sun.com/jsf/html"
-    xmlns:ui="http://java.sun.com/jsf/facelets"
-    xmlns:f="http://java.sun.com/jsf/core"
-    xmlns:p="http://primefaces.org/ui"
-    xmlns:c="http://java.sun.com/jsp/jstl/core">     
-
-    <p:dialog id="connectionDialog" header="Manage Connections" resizable="false" modal="true" widgetVar="connectionDialog">
-        <h:form id="connectionDialogForm" rendered="#{not empty currentWorkSpaceProjectBean.project}">
-           
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+                xmlns:h="http://java.sun.com/jsf/html"
+                xmlns:ui="http://java.sun.com/jsf/facelets"
+                xmlns:f="http://java.sun.com/jsf/core"
+                xmlns:p="http://primefaces.org/ui"
+                xmlns:c="http://java.sun.com/jsp/jstl/core">
+
+    <p:dialog id="connectionDialog" header="Manage Connections"
+              resizable="false" modal="true" widgetVar="connectionDialog">
+        <h:form id="connectionDialogForm"
+                rendered="#{not empty currentWorkSpaceProjectBean.project}">
+
+            <p:tabView>
+                <p:tab title="Plugin -> Plugin Connections">
+                    <p:commandButton value="Add Connection" ajax="true"
+                                     action="#{currentWorkSpaceProjectBean.addConnection()}"
+                                     update=":connectionDialogForm" />
+                    <br />
+                    <br />
+                    <p:dataTable value="#{currentWorkSpaceProjectBean.connections}"
+                                 var="connection" paginator="true" rows="10"
+                                 paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}">
+
+                        <p:column headerText="Source" style="width:125px">
+                            <p:cellEditor>
+                                <f:facet name="output">
+                                    <h:outputText
+                                        value="#{empty connection.source ? 'N/A' : connection.source.name}" />
+                                </f:facet>
+                                <f:facet name="input">
+                                    <p:selectOneMenu converter="kieker.webgui.converter.MIPluginStringConverter"
+                                                     value="#{connection.source}" effectDuration="100">
+                                        <f:selectItem value="#{null}" itemLabel="N/A" itemValue="#{null}" />
+                                        <f:selectItems
+                                            value="#{currentWorkSpaceProjectBean.project.plugins}" 
+                                            var="plugin" itemLabel="#{plugin.name}" itemValue="#{plugin}" />
+                                        <p:ajax event="change" update="validColumn outputPortsList" />
+                                    </p:selectOneMenu>
+                                </f:facet>
+                            </p:cellEditor>
+                        </p:column>
+
+                        <p:column headerText="Output Port" style="width:125px">
+                            <p:cellEditor>
+                                <f:facet name="output">
+                                    <h:outputText
+                                        value="#{empty connection.outputPort ? 'N/A' : connection.outputPort.name}" />
+                                </f:facet>
+                                <f:facet name="input">
+                                    <h:form id="outputPortsList">
+                                        <p:selectOneMenu rendered="#{not empty connection.source}" converter="kieker.webgui.converter.MIPortStringConverter"
+                                                         value="#{connection.outputPort}" effectDuration="100">
+                                            <f:selectItem value="#{null}" itemLabel="N/A"
+                                                          itemValue="#{null}" />
+                                            <f:selectItems value="#{connection.source.outputPorts}"
+                                                           var="port" itemLabel="#{port.name}" itemValue="#{port}" />
+                                            <p:ajax event="change" update="validColumn" />
+                                        </p:selectOneMenu>
+                                    </h:form>
+                                </f:facet>
+                            </p:cellEditor>
+                        </p:column>
+
+                        <p:column headerText="Destination" style="width:125px">
+                            <p:cellEditor>
+                                <f:facet name="output">
+                                    <h:outputText
+                                        value="#{empty connection.destination ? 'N/A' : connection.destination.name}" />
+                                </f:facet>
+                                <f:facet name="input">
+                                    <p:selectOneMenu converter="kieker.webgui.converter.MIPluginStringConverter"
+                                                     value="#{connection.destination}" effectDuration="100">
+                                        <f:selectItem value="#{null}" itemLabel="N/A"
+                                                      itemValue="#{null}" />
+                                        <f:selectItems value="#{currentWorkSpaceProjectBean.filters}"
+                                                       var="plugin" itemLabel="#{plugin.name}" itemValue="#{plugin}" />
+                                        <p:ajax event="change" update="validColumn inputPortsList" />
+                                    </p:selectOneMenu>
+                                </f:facet>
+                            </p:cellEditor>
+                        </p:column>
+
+                        <p:column headerText="Input Port" style="width:125px">
+                            <p:cellEditor>
+                                <f:facet name="output">
+                                    <h:outputText
+                                        value="#{empty connection.inputPort ? 'N/A' : connection.inputPort.name}" />
+                                </f:facet>
+                                <f:facet name="input">
+                                    <h:form id="inputPortsList">
+                                        <p:selectOneMenu rendered="#{not empty connection.destination}" converter="kieker.webgui.converter.MIPortStringConverter"
+                                                         value="#{connection.inputPort}" effectDuration="100">
+                                            <f:selectItem value="#{null}" itemLabel="N/A"
+                                                          itemValue="#{null}" />
+                                            <f:selectItems value="#{connection.destination.inputPorts}"
+                                                           var="port" itemLabel="#{port.name}" itemValue="#{port}" />
+                                            <p:ajax event="change" update="validColumn" />
+                                        </p:selectOneMenu>
+                                    </h:form>
+                                </f:facet>
+                            </p:cellEditor>
+                        </p:column>
+
+                        <p:column id="validColumn" headerText="Valid" style="width:50px">
+                            <h:outputText value="#{connection.valid ? 'True' : 'False'}" />
+                        </p:column>
+
+                        <p:column headerText="Options" style="width:50px">
+                            <p:rowEditor />
+                        </p:column>
+                    </p:dataTable>
+                </p:tab>
+
+                <p:tab title="Plugin -> Repository Connections">
+<p:commandButton value="Add Connection" ajax="true"
+                                     action="#{currentWorkSpaceProjectBean.addConnection()}"
+                                     update=":connectionDialogForm" />
+                    <br />
+                    <br />
+                    <p:dataTable value="#{currentWorkSpaceProjectBean.connections}"
+                                 var="connection" paginator="true" rows="10"
+                                 paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}">
+
+                        <p:column headerText="Source" style="width:125px">
+                         
+                        </p:column>
+
+                        <p:column headerText="Repository Port" style="width:125px">
+                            
+                        </p:column>
+
+                        <p:column headerText="Destination" style="width:125px">
+                            
+                        </p:column>
+
+                        <p:column id="validColumn" headerText="Valid" style="width:50px">
+
+                        </p:column>
+
+                        <p:column headerText="Options" style="width:50px">
+                            <p:rowEditor />
+                        </p:column>
+                    </p:dataTable>
+                </p:tab>
+            </p:tabView>
+            <br />
+            <hr />
+            <div style="text-align: right">
+                <p:commandButton value="Ok" action="#{currentWorkSpaceProjectBean.submitConnections()}" oncomplete="connectionDialog.hide();" />
+            </div>
         </h:form>
     </p:dialog>
     <!-- ******************************************************************************** -->
-</ui:composition>
\ No newline at end of file
+</ui:composition>
-- 
GitLab