diff --git a/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax b/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax
index 27ecb97ae1b328afa3058cf967266c4439de0d97..4d4bfb3ca66f304cdb3567c36041527d4a69af98 100644
--- a/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax
+++ b/Kieker.WebGUI/bin/data/Bookstore-Example/Bookstore-Example.kax
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Project xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="platform:/resource/Kieker/model/AnalysisMetaModel.ecore">
   <plugins xsi:type="Reader" name="FSReader" classname="kieker.analysis.plugin.reader.filesystem.FSReader">
-    <properties name="inputDirs" value="testdata"/>
-    <properties name="ignoreUnknownRecordTypes" value="false"/>
-    <outputPorts name="monitoringRecords" subscribers="//@plugins.1/@inputPorts.0 //@plugins.4/@inputPorts.0"/>
+    <properties name="inputDirs" value="testdata" description="The name of the input dirs used to read data (multiple dirs are separated by |)."/>
+    <properties name="ignoreUnknownRecordTypes" value="false" description="Ignore unknown records? Aborts if encountered and value is false."/>
+    <outputPorts name="monitoringRecords" subscribers="//@plugins.1/@inputPorts.0 //@plugins.5/@inputPorts.0"/>
   </plugins>
   <plugins xsi:type="Filter" name="MyResponseTimeFilter" classname="kieker.examples.userguide.ch3and4bookstore.MyResponseTimeFilter">
-    <properties name="thresholdNanos" value="1900000"/>
-    <outputPorts name="validResponseTimes" subscribers="//@plugins.5/@inputPorts.0 //@plugins.2/@inputPorts.0"/>
-    <outputPorts name="invalidResponseTimes" subscribers="//@plugins.6/@inputPorts.0 //@plugins.3/@inputPorts.0"/>
+    <properties name="thresholdNanos" value="1900000" description=""/>
+    <outputPorts name="validResponseTimes" subscribers="//@plugins.4/@inputPorts.0 //@plugins.6/@inputPorts.0"/>
+    <outputPorts name="invalidResponseTimes" subscribers="//@plugins.2/@inputPorts.0 //@plugins.3/@inputPorts.0"/>
     <inputPorts name="newResponseTime"/>
   </plugins>
-  <plugins xsi:type="Filter" name="Valid Printer" classname="kieker.examples.userguide.ch3and4bookstore.MyResponseTimeOutputPrinter">
-    <properties name="validOutput" value="true"/>
+  <plugins xsi:type="Filter" name="Invalid Printer" classname="kieker.examples.userguide.ch3and4bookstore.MyResponseTimeOutputPrinter">
+    <properties name="validOutput" value="false" description=""/>
     <inputPorts name="newEvent"/>
   </plugins>
   <plugins xsi:type="Filter" name="Invalid Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
@@ -21,27 +21,22 @@
     <displays name="Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
-  <plugins xsi:type="Filter" name="Global Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
+  <plugins xsi:type="Filter" name="Valid Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
     <outputPorts name="relayedEvents"/>
     <outputPorts name="currentEventCount"/>
     <displays name="Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
-  <plugins xsi:type="Filter" name="Valid Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
+  <plugins xsi:type="Filter" name="Global Counter" classname="kieker.analysis.plugin.filter.forward.CountingFilter">
     <outputPorts name="relayedEvents"/>
     <outputPorts name="currentEventCount"/>
     <displays name="Counter Display"/>
     <inputPorts name="inputEvents"/>
   </plugins>
-  <plugins xsi:type="Filter" name="Invalid Printer" classname="kieker.examples.userguide.ch3and4bookstore.MyResponseTimeOutputPrinter">
-    <properties name="validOutput" value="false"/>
+  <plugins xsi:type="Filter" name="Valid Printer" classname="kieker.examples.userguide.ch3and4bookstore.MyResponseTimeOutputPrinter">
+    <properties name="validOutput" value="true" description=""/>
     <inputPorts name="newEvent"/>
   </plugins>
   <dependencies filePath="BookstoreApplication.jar"/>
   <dependencies filePath="commons-cli-1.2.jar"/>
-  <views name="My View" description="Some amazing view.">
-    <displayConnectors name="Valid Counter Display" display="//@plugins.5/@displays.0"/>
-    <displayConnectors name="Global Counter Display" display="//@plugins.4/@displays.0"/>
-    <displayConnectors name="Invalid Counter Display" display="//@plugins.3/@displays.0"/>
-  </views>
 </Project>
diff --git a/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar b/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar
index f0843203d315bb79a3cb532099ccad9ba42a78a3..be77cbabac36c423e26af3534303762c2d940bef 100644
Binary files a/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar and b/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar differ
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 0b435a3e3ad0ef71faac3e2c0002d7765df6ec1d..dc089c4ccded00a38555ac5af83301316ef17739 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
@@ -53,7 +53,6 @@ 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.reader.AbstractReaderPlugin;
 import kieker.analysis.repository.AbstractRepository;
 import kieker.common.logging.Log;
 import kieker.common.logging.LogFactory;
@@ -811,7 +810,7 @@ public final class CurrentAnalysisEditorBean {
 
 				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);
 			}
 
@@ -1007,7 +1006,7 @@ public final class CurrentAnalysisEditorBean {
 		this.currentAnalysisEditorGraphBean.setCurrentAnalysisEditorBean(this);
 
 		// Initialize the graph
-		this.currentAnalysisEditorGraphBean.initGraph();
+		this.currentAnalysisEditorGraphBean.declareGraph();
 
 		// Initialize the reader, filter and repositories
 		for (final MIPlugin plugin : this.project.getPlugins()) {
@@ -1017,6 +1016,7 @@ public final class CurrentAnalysisEditorBean {
 				this.currentAnalysisEditorGraphBean.addFilter((MIFilter) plugin);
 			}
 		}
+		this.currentAnalysisEditorGraphBean.initGraph();
 		for (final MIRepository repository : this.project.getRepositories()) {
 			this.currentAnalysisEditorGraphBean.addRepository(repository);
 		}
@@ -1030,6 +1030,12 @@ public final class CurrentAnalysisEditorBean {
 			}
 		}
 
+		// TODO Connections between filters and repositories
+
+		this.currentAnalysisEditorGraphBean.initListeners();
+
+		// This command is here necessary because of a current bug
+
 		// Repaint the graph
 		this.currentAnalysisEditorGraphBean.refreshGraph();
 	}
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 b75cfa927331b2fbad5cd685569bb1a1aa2c546f..d311e64a91a601f2e3865f1c3690746d3b1d7da7 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
@@ -59,10 +59,14 @@ public class CurrentAnalysisEditorGraphBean {
 	 * This is the log for errors, exceptions etc.
 	 */
 	private static final Log LOG = LogFactory.getLog(CurrentAnalysisEditorGraphBean.class);
+	/**
+	 * This is the javascript code to declare the visual graph variable.
+	 */
+	private static final String JS_CMD_CREATE_GRAPH_VAR = "var graph = GraphFlow();";
 	/**
 	 * This is the javascript code to initialize the visual graph.
 	 */
-	private static final String JS_CMD_INIT_GRAPH = "var graph = GraphFlow(); graph.initGraph(null);";
+	private static final String JS_CMD_INIT_GRAPH = "graph.initGraph(null);";
 	/**
 	 * This is the javasscript code to add the click listener to the graph.
 	 */
@@ -131,15 +135,29 @@ public class CurrentAnalysisEditorGraphBean {
 		// No code necessary
 	}
 
+	/**
+	 * Declares the the graph variable.
+	 */
+	public void declareGraph() {
+		RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_CREATE_GRAPH_VAR);
+	}
+
 	/**
 	 * Initializes the graph.
 	 */
 	public void initGraph() {
 		RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_INIT_GRAPH);
+
+	}
+
+	/**
+	 * Initializes the listeners for the graph
+	 */
+	public void initListeners() {
 		RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_CLICK_LISTENER);
 		RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_REMOVE_NODE_LISTENER);
 		RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_CREATE_EDGE_LISTENER);
-		// RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_REMOVE_EDGE_LISTENER);
+		RequestContext.getCurrentInstance().execute(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_REMOVE_EDGE_LISTENER);
 	}
 
 	/**
@@ -182,7 +200,8 @@ public class CurrentAnalysisEditorGraphBean {
 	public void addRepository(final MIRepository repository) {
 		final String repoPort = String.format(CurrentAnalysisEditorGraphBean.JS_CMD_PORT, CurrentAnalysisEditorGraphBean.JS_CMD_PORT_TYPE_INPUT,
 				CurrentAnalysisEditorGraphBean.REPOSITORY_INPUT_PORT, "N/A");
-		RequestContext.getCurrentInstance().execute(String.format(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_REPOSITORY, 0, 0, this.assembleGraphString(repository),
+		RequestContext.getCurrentInstance().execute(String.format(CurrentAnalysisEditorGraphBean.JS_CMD_ADD_REPOSITORY, 0, 0,
+				this.assembleGraphString(repository),
 				repoPort));
 	}
 
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 209d63b2dea726cf5318bac525cd0da44f98d248..a9fc87687d650a49b71a7bf2bbd48c9b39e2febe 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/common/ClassAndMethodContainer.java
@@ -214,6 +214,10 @@ public final class ClassAndMethodContainer {
 	 * This is the getState()-method of the class equivalence of {@link AnalysisController}.
 	 */
 	private Method analysisControllerGetState;
+	/**
+	 * This is the description()-method of the class equivalence of {@link Property}.
+	 */
+	private final Method propertyDescriptionMethod;
 	/**
 	 * This is the constructor for {@link AnalysisControllerThread}, which gets an instance of {@link AnalysisController}.
 	 */
@@ -268,6 +272,7 @@ public final class ClassAndMethodContainer {
 			this.analysisControllerThreadStart = this.analysisControllerThreadClass.getMethod("start", new Class<?>[0]);
 			this.analysisControllerThreadTerminate = this.analysisControllerThreadClass.getMethod("terminate", new Class<?>[0]);
 			this.analysisControllerGetState = this.analysisControllerClass.getMethod("getState", new Class<?>[0]);
+			this.propertyDescriptionMethod = this.propertyAnnotationClass.getMethod("description", new Class<?>[0]);
 
 			// This is a special case as we need to load some additional classes to search for the correct method
 			final Class<?> miProjectClass = classLoader.loadClass(MIProject.class.getName());
@@ -633,6 +638,15 @@ public final class ClassAndMethodContainer {
 		return this.analysisControllerGetState;
 	}
 
+	/**
+	 * The getter-method for the field {@link ClassAndMethodContainer#propertyDescriptionMethod}.
+	 * 
+	 * @return The current value for the field.
+	 */
+	public Method getPropertyDescriptionMethod() {
+		return this.propertyDescriptionMethod;
+	}
+
 	/**
 	 * The getter-method for the field {@link ClassAndMethodContainer#analysisControllerThreadConstructor}.
 	 * 
diff --git a/Kieker.WebGUI/src/main/resources/kieker-1.6-SNAPSHOT_emf.jar b/Kieker.WebGUI/src/main/resources/kieker-1.6-SNAPSHOT_emf.jar
index f0843203d315bb79a3cb532099ccad9ba42a78a3..be77cbabac36c423e26af3534303762c2d940bef 100644
Binary files a/Kieker.WebGUI/src/main/resources/kieker-1.6-SNAPSHOT_emf.jar and b/Kieker.WebGUI/src/main/resources/kieker-1.6-SNAPSHOT_emf.jar differ
diff --git a/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml b/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml
index bc81a429ff58670b1bfecf14fd7024a29f59ef8e..4d0ea6b1d48b7b26422276b3570988e38a20d30c 100644
--- a/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml
@@ -120,21 +120,27 @@
                     <p:dataTable editable="true" value="#{currentAnalysisEditorBean.advancedPluginProperties}" var="property" rowIndexVar="rowIndex" emptyMessage="No properties available" rendered="#{not empty currentAnalysisEditorBean.selectedPlugin}">
                         <p:column headerText="Property" style="width:125px">
                             <!-- The first property is always the classname, the second one always the normal name. After that, other properties can follow. -->
-                            <h:outputText value="ClassName" rendered="#{rowIndex == 0}"/>
-                            <h:outputText value="Name" rendered="#{rowIndex == 1}"/>
-                            <h:outputText value="#{property.name}" rendered="#{rowIndex > 1}"/>
+                            <h:outputText id="classNameProperty" value="ClassName" rendered="#{rowIndex == 0}"/>
+                            <h:outputText id="nameProperty" value="Name" rendered="#{rowIndex == 1}"/>
+                            <h:outputText id="normalProperty" value="#{property.name}" rendered="#{rowIndex > 1}"/>
+                            <p:tooltip for="classNameProperty" value="The class name of this component." rendered="#{rowIndex == 0}"/>
+                            <p:tooltip for="nameProperty" value="The name of this component." rendered="#{rowIndex == 1}"/>
+                            <p:tooltip for="normalProperty" value="#{property.description}" rendered="#{rowIndex > 1}"/>
                         </p:column>
 
                         <!-- The classname is not editable, the name is editable with a specific target, other properies are editable normally. -->
                         <p:column headerText="Value" style="width:125px">
-                            <h:outputText value="#{currentAnalysisEditorBean.selectedPlugin.classname}" rendered="#{rowIndex == 0}"/>
-                            <p:inplace editor="true" rendered="#{rowIndex == 1}" >  
+                            <h:outputText id="className" value="#{currentAnalysisEditorBean.selectedPlugin.classname}" rendered="#{rowIndex == 0}"/>
+                            <p:inplace id="nameEditor" editor="true" rendered="#{rowIndex == 1}" >  
                                 <p:inputText value="#{currentAnalysisEditorBean.selectedPlugin.name}" />
                                 <p:ajax event="save" listener="#{currentAnalysisEditorGraphBean.renameNode(currentAnalysisEditorBean.selectedPlugin, currentAnalysisEditorBean.selectedPlugin.name)}" />
                             </p:inplace>  
-                            <p:inplace editor="true" rendered="#{rowIndex > 1}">  
+                            <p:inplace id="normalEditor" editor="true" rendered="#{rowIndex > 1}">  
                                 <p:inputText value="#{property.value}" />
                             </p:inplace>  
+                             <p:tooltip for="className" value="The class name of this component." rendered="#{rowIndex == 0}"/>
+                            <p:tooltip for="nameEditor" value="The name of this component." rendered="#{rowIndex == 1}"/>
+                            <p:tooltip for="normalEditor" value="#{property.description}" rendered="#{rowIndex > 1}"/>
                         </p:column>                       
                     </p:dataTable>
                 </h:form>
diff --git a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
index 2a4d90e24ca209347b13b62142fb837c7f8dff8f..d6940388c279c241d2dd62bbd3405e4b6fbc0bc6 100644
--- a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
+++ b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
@@ -46,19 +46,14 @@ function GraphFlow(){
 	
 	/** Color Palettes */
 	var nodeFillColor = [];
-		//nodeFillColor['Filter'] 	 	= "#DEDEDE";
-		//nodeFillColor['Repository']  	= "#EFAC6A";
-		//nodeFillColor['Reader'] 	 	= "#6AEF73";
 		nodeFillColor['nodeFamily']		= "#DEDEDE";
 	
 	var nodeStrokeColor = [];
-		//nodeStrokeColor['Filter'] 	   	  = "#4D4D4D";
-		//nodeStrokeColor['Repository']  	  = "#735332";
-		//nodeStrokeColor['Reader'] 	      = "#327337";
 		nodeStrokeColor['inputPort']   	  = "#AA0000";
 		nodeStrokeColor['outputPort']	  = "#AA0000";
 		nodeStrokeColor['repositoryPort'] = "#AA0000";
 		nodeStrokeColor['nodeFamily'] = "#4D4D4D";
+		nodeStrokeColor['crossBox'] = "#4D4D4D";
 		
 	var nodeColorFocus	  = "#0098BE",
 		edgeColor 		  = "#114270",
@@ -76,7 +71,8 @@ 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 = [ {
+	var json = [ null, null, null, null, null, null, null, null, null, null, 
+			{
 			  "adjacencies": [], 
 			  "data": {
 				"$dim": 0,
@@ -89,6 +85,13 @@ function GraphFlow(){
 			  "name": "",
 			  "alpha": 0
 		}];
+		
+	/** Used for managing space for node creation/deletion
+		since the array is divided into to parts, adding and removing nodes
+		would cause many costly splices. We a similar approach to ArrayLists. 
+	*/
+	var jsonCapacity = {'occupied' : 0,
+						'max'  : 10};
 
 	/** selected node:	{id : <the id of the selected node, 
 						 from : <the data.$type of the selected node>}
@@ -281,9 +284,7 @@ function GraphFlow(){
 	*/
 	this.refresh = function(){
 		// reload graph
-		fd.loadJSON(json);
-		// restore old node positions
-		restoreNodePositions();
+		fd.loadGraphFlowJSON(json, jsonCapacity.max);
 		fd.plot();
 	}
 	
@@ -366,8 +367,9 @@ function GraphFlow(){
 	this.addEdgeConstraints = function(){
 		addListener("onCreateEdge", 
 		function(sourceFamily, targetFamily, sourcePort, targetPort){
-			// remove Edge if it leads to itself
-			if( sourcePort.id == targetPort.id){
+		
+			// remove Edge if it does not lead to an inputPort
+			if(targetPort.data.$type != "inputPort"){
 				return false;
 			}
 		
@@ -407,7 +409,12 @@ function GraphFlow(){
 	*/
 	this.iterateAllNodes = function(nodeFunction){
 		var node;
-		for(var n=1; n < json.length; n++){
+		for(var n=0, l=jsonCapacity.occupied; n < l; n++){
+			node = json[n];
+			nodeFunction(node);
+		}
+		alert(json.length);
+		for(var n=jsonCapacity.max+1, l= json.length; n < l; n++){
 			node = json[n];
 			nodeFunction(node);
 		}
@@ -423,18 +430,19 @@ function GraphFlow(){
 		nodeStrokeColor['outputPort'] = portColor;
 		nodeStrokeColor['repositoryPort'] = portColor;
 		
-		var node, type;
-		for(var n = 1; n < json.length; n++){
-			node = json[n];
-			type = node.data.$type;
-			
-			node.data.$color = nodeStrokeColor[type];
-			
-			if(type == "nodeFamily" ||type == "crossBox"){
-				node.data.$fillColor = nodeFillColor["nodeFamily"];
-				node.data.$color = nodeStrokeColor["nodeFamily"];
-			}else{
-				node.data.$color = nodeStrokeColor[type];
+		var data;
+		// change family colors
+		for(var n = 0, l = jsonCapacity.occupied; n < l; n++){
+			data = json[n].data;
+			data.$fillColor = nodeFillColor["nodeFamily"];
+			data.$color = nodeStrokeColor["nodeFamily"];
+		}
+		// change port colors
+		for(var n = jsonCapacity.max+1, l = json.length; n < l; n++){
+			data = json[n].data;
+			data.$color = nodeStrokeColor[data.$type];
+			if(data.$type == "crossBox"){
+				data.$fillColor = nodeFillColor["nodeFamily"];
 			}
 		}
 		refresh();
@@ -465,20 +473,6 @@ function GraphFlow(){
 		
 	}*/
 	
-	/**
-	 Moves all nodes to their respective positions, which are stored within
-	 their data. We need this function to dynamically remove graph elements
-	 without losing the node positions.
-	*/
-	function restoreNodePositions(){
-		for (var n = 0; n < json.length; n++){
-			var x = json[n].data.$xPos,
-				y = json[n].data.$yPos,
-				node =  fd.graph.getNode(json[n].id);
-			node.pos.setc(x,y);
-		}
-	}
-	
 	/**
 	Adds a repository node to the graph.
 	@param nodeFamily - describes some properties of the node: (id, name, nodeClass, tooltip)
@@ -516,7 +510,22 @@ function GraphFlow(){
 	 @param inputPortIDs - an array of properties for the input ports (id, name, tooltip)
 	 @param outputPortIDs - an array of properties for the output ports (id, name, tooltip)
 	 */
-	this.addNode = function(xPosition, yPosition, nodeFamily, repositoryPorts, inputPorts, outputPorts, nodeType){
+	this.addNode = function(xPosition, yPosition, nodeFamily, repositoryPorts, inputPorts, outputPorts, nodeType, forced){
+	
+	// check if we have enough space reserved
+	var max = jsonCapacity.max;
+	var occ = jsonCapacity.occupied;
+	if(occ == max){
+		var families = json.slice(0, max);
+		var ports = json.slice(max);
+		
+		for(var n = 0; n < max; n++){
+			families.push(null);
+		}
+		max *= 2;
+		jsonCapacity.max = max;
+		json = families.concat(ports);
+	}
 	
 	var countRepo = 0,
 		countInput = 0,
@@ -557,8 +566,9 @@ function GraphFlow(){
 		  "data": {
 			"$dim": size,					
 			"$type": "nodeFamily",
-			"$jsonIndex": json.length,
+			"$jsonIndex": occ,
 			"$portCount": countRepo+countInput+countOutput,
+			"$portIndex": json.length - max,
 			"$width": width,
 			"$height": height,
 			"$color": strokeColor,
@@ -572,7 +582,7 @@ function GraphFlow(){
 		  "id": nodeFamily.id, 
 		  "name": nodeFamily.name
 	};
-	json.push(newNode);
+	json[occ] = newNode;
 	
 	// add closeButton
 	var closeButton ={
@@ -662,50 +672,53 @@ function GraphFlow(){
 		}
 	}
 	
-	// call listener
-	callListener("onCreateNode", [newNode]);
+		// call listener
+		if(!forced){
+			callListener("onCreateNode", [newNode]);
+		}
+		jsonCapacity.occupied++;
 	}
 
 	/**
 		Removes a Node and all its edges from the graph.
 		@param nodeFamily - the node which is to be removed
 	*/
-	this.removeNode =  function(nodeFamily){
+	this.removeNode =  function(nodeFamily, forced){
 		// call listener
-		var deletionValid = callListener("onRemoveNode", [nodeFamily]);
-		
-		if(!deletionValid){
+		if(!forced && !callListener("onRemoveNode", [nodeFamily])){
 			return;
 		}
 		
-		var deleteFrom = nodeFamily.data.$jsonIndex, 
-			deleteUntil = deleteFrom+ nodeFamily.data.$portCount+1;
-			
+		var deleteFrom = nodeFamily.data.$portIndex + jsonCapacity.max, 
+			deleteUntil = deleteFrom+ nodeFamily.data.$portCount,
+			familyIndex = nodeFamily.data.$jsonIndex,
+			occ = --jsonCapacity.occupied; // decrement occupied spaces
 		
-		// delete nodeFamily and closeButton
+		// delete nodeFamily and close button
+		delete json[familyIndex];
 		delete json[deleteFrom];
-		delete json[deleteFrom+1];
 		
 		// delete ports
-		for(var n = deleteFrom+2;  n <= deleteUntil;  n++){
+		for(var n = deleteFrom+1;  n <= deleteUntil;  n++){
 			var portID = json[n].id;
 			
 			// remove all incoming edges
 			for(var e = 0;  e < json.length;  e++){
 				var incNode = json[e];
 				if(incNode != undefined){
-					removeEdge(incNode.id, portID);	
+					removeEdge(incNode.id, portID, true);	
 				}
 			}
 			
 			delete json[n];
 		}
 		
-		// collapse json array
-		var deletionSum = deleteUntil-deleteFrom+1;
+		// remove space that was used for ports
+		var deletionSum = deleteUntil-deleteFrom+1; 
 		json.splice(deleteFrom, deletionSum);
 		selectedNode = null;
 		
+		/*
 		// update nodeFamily indices
 		for(var n = deleteUntil-deletionSum+1;  n < json.length;  n++){
 			var familyIndex = json[n].data.$jsonIndex;
@@ -713,7 +726,31 @@ function GraphFlow(){
 				json[n].data.$jsonIndex = n;
 			}
 		}
+		*/
+		
+		// update nodeFamily indices and remove the deletion gap
+		// in the array space by shifting all following families up
+		var data;
+		for(var n = familyIndex;  n < occ;  n++){
+			json[n] = json[n+1];
+			data = json[n].data;
+			data.$jsonIndex--
+			data.$portIndex-= deletionSum;
+			
+		}
+		json[occ] = null;
 		
+		
+		// check if we should remove some space
+		var max = jsonCapacity.max;
+		if( (occ*4) < max && max > 10){
+			var ports = json.slice(max);
+			
+			max /= 2;
+			jsonCapacity.max = max;
+			var families = json.slice(0, max);
+			json = families.concat(ports);
+		}
 		return;
 	 }
 	 
@@ -724,20 +761,20 @@ function GraphFlow(){
 		@param y - desired y-Position
 	*/
 	 function moveNode(nodeFamily, x, y){
-		var moveFrom = nodeFamily.data.$jsonIndex, 
-			moveUntil = moveFrom+ nodeFamily.data.$portCount+1,
+		var familyIndex = nodeFamily.data.$jsonIndex,
+			moveFrom = nodeFamily.data.$portIndex+ jsonCapacity.max, 
+			moveUntil = moveFrom+ nodeFamily.data.$portCount,
 			dim = nodeFamily.data.$dim;
 			
 		// set pos of family box
 		nodeFamily.pos.setc(x, y);
-		json[moveFrom].data.$xPos = x;
-		json[moveFrom].data.$yPos = y;
-		moveFrom++;
+		json[familyIndex].data.$xPos = x;
+		json[familyIndex].data.$yPos = y;
 		
 		// set pos of close button
 		var node = fd.graph.getNode(json[moveFrom].id),
-			nodeX = x+ nodeFamily.data.$width/2,
-			nodeY =  y- nodeFamily.data.$height/2;
+			nodeX = x + nodeFamily.data.$width/2,
+			nodeY = y - nodeFamily.data.$height/2;
 			
 		node.pos.setc(nodeX, nodeY);
 		json[moveFrom].data.$xPos = nodeX;
@@ -766,27 +803,40 @@ function GraphFlow(){
    *  @param targetID the id of the node where the edge ends
    *  @return true if the edge was successfully added
    */
-	this.addEdge = function(sourceID, targetID, edgeLabel){
+	this.addEdge = function(sourceID, targetID, edgeLabel, forced){
 		
 		// look up the source node and the nodeFamilys of both nodes
-		var source, sourceFamily, targetFamily, lastFamily, target;
-		for(var n = 0; n< json.length; n++){
-			var loopNode = json[n];
-			if(loopNode.data.$type == "nodeFamily"){
-				lastFamily = loopNode;
+		var source, sourceFamily, targetFamily, target;
+		
+		var sourceFamilyID = sourceID.substring(0, sourceID.indexOf(".")), 
+			targetFamilyID = targetID.substring(0, targetID.indexOf(".")),
+			loopNode;
+		// look for nodefamilies
+		for(var n = 0, l = jsonCapacity.occupied; n < l; n++){
+	
+			loopNode = json[n];
+			
+			if(loopNode.id == sourceFamilyID){
+				sourceFamily = loopNode
 			}
-			else if(loopNode.id == sourceID){
+			if(loopNode.id == targetFamilyID){
+				targetFamily = loopNode
+			}
+		} 
+		
+		// look for ports
+		for(var n = jsonCapacity.max, l = json.length; n < l; n++){
+			loopNode = json[n];
+			
+			if(loopNode.id == sourceID){
 				source = loopNode;
-				sourceFamily = lastFamily;
 			}
-			else if(loopNode.id == targetID){
+			if(loopNode.id == targetID){
 				target = loopNode;
-				targetFamily = lastFamily;
 			}
 		}
-		
 		// call listener if the edge is not connected to the dummy node and check for permission
-		if(sourceID != mouseNode.id && targetID != mouseNode.id){
+		if(!forced && sourceID != mouseNode.id && targetID != mouseNode.id){
 			if (!callListener("onCreateEdge", [sourceFamily, targetFamily, source, target])){
 				return false;
 			}
@@ -830,32 +880,46 @@ function GraphFlow(){
 	@param source the source Node
 	@param targetID the id of the target Node
 	*/
-  this.removeEdge = function(sourceID, targetID){
-	var source, target;
+  this.removeEdge = function(sourceID, targetID, forced){
+	// look up the source node and the nodeFamilys of both nodes
+	var source, sourceFamily, targetFamily, target;
+	
+	var sourceFamilyID = sourceID.substring(0, sourceID.indexOf(".")), 
+		targetFamilyID = targetID.substring(0, targetID.indexOf(".")),
+		loopNode;
 		
-	// look up nodeFamily IDs
-	var sourceFamily, targetFamily, lastFamily;
-		for(var n=0; n< json.length; n++){
-			var loopNode = json[n];
-			if(loopNode != undefined){ // <- this happens on Node Deletion
-				if(loopNode.data.$type == "nodeFamily"){
-					lastFamily = loopNode;
-				}
-				else if(loopNode.id == sourceID){
-					sourceFamily = lastFamily;
-					source = loopNode;
-				}
-				else if(loopNode.id == targetID){
-					targetFamily = lastFamily;
-					target = loopNode;
-				}
+	// look for ports
+	for(var n = jsonCapacity.max, l = json.length; n < l; n++){
+		loopNode = json[n];
+		if(loopNode != undefined){
+			if(loopNode.id == sourceID){
+				source = loopNode;
+			}
+			if(loopNode.id == targetID){
+				target = loopNode;
 			}
 		}
+	}
 		
-	// call listener and ask for permission to delete
-	if(sourceID != mouseNode.id && targetID != mouseNode.id){
-		if(!callListener("onRemoveEdge", [sourceFamily, targetFamily, source, target])){
-			return;
+	if(!forced){
+		// look for nodefamilies
+		for(var n = 0, l = jsonCapacity.occupied; n < l; n++){
+
+			loopNode = json[n];
+			
+			if(loopNode.id == sourceFamilyID){
+				sourceFamily = loopNode
+			}
+			if(loopNode.id == targetFamilyID){
+				targetFamily = loopNode
+			}
+		} 
+	
+		// call listener and ask for permission to delete
+		if(sourceID != mouseNode.id && targetID != mouseNode.id){
+			if(!callListener("onRemoveEdge", [sourceFamily, targetFamily, source, target])){
+				return;
+			}
 		}
 	}
 	
@@ -896,18 +960,6 @@ function GraphFlow(){
 	}
   }
   
-    /**
-	saves the given x, y position of a node
-	@param nodeID - the id of the target node
-	@param x - x-position of the node
-	@param y - y-position of the node
-	*/
-  function saveNodePosition(nodeID, x, y){
-	var node = getNode(nodeID);
-	node.data.$xPos = x;
-	node.data.$yPos = y;
-  }
-  
   /**
   returns a jsonNode by id
   @param nodeID the id of the desired node
@@ -940,13 +992,7 @@ function GraphFlow(){
 			}
 			else{
 				var type = hover.data.$type;
-				
-				if(type == "crossBox"){
-					hover.setData('color', nodeStrokeColor["nodeFamily"], 'end');
-				}
-				else{
-					hover.setData('color', nodeStrokeColor[type], 'end');
-				}
+				hover.setData('color', nodeStrokeColor[type], 'end');
 			}
 			hover = null;
 		}
@@ -1154,8 +1200,8 @@ function GraphFlow(){
 			var pos = eventInfo.getPos();
 			
 			moveNode(node, 
-						   pos.x+mouseNode.data.$dragX,
-							pos.y+mouseNode.data.$dragY);
+					 pos.x+mouseNode.data.$dragX,
+					 pos.y+mouseNode.data.$dragY);
 			callListener("onDragMove", [node, eventInfo, e]);
 			fd.plot();
 			
@@ -1208,7 +1254,7 @@ function GraphFlow(){
 						// add Edge if the selectedNode differs from the clickedNode
 						var newEdgeAdded;
 						if(selectedNode.from == "inputPort"){
-							var label = mouseNode.adjacencies[0].data.$label;
+							var label = selectedNode.label;
 							newEdgeAdded = addEdge(node.id, selectedNode.id, label);
 						}
 						else{
@@ -1241,9 +1287,9 @@ function GraphFlow(){
 		  if(selectedNode != null){
 		  
 			if(selectedNode.from == "inputPort"){
-				removeEdge(mouseNode.id, selectedNode.id);
+				removeEdge(mouseNode.id, selectedNode.id, true);
 			}else{
-				removeEdge(selectedNode.id, mouseNode.id);
+				removeEdge(selectedNode.id, mouseNode.id, true);
 			}
 			
 			selectedNode = null;
@@ -1269,9 +1315,6 @@ function GraphFlow(){
 				return;
 			}
 			
-			// save node position
-			saveNodePosition(node.id, node.pos.x, node.pos.y);
-			
 			domElement.innerHTML = node.name;  
 			
 			// set style for name
@@ -1317,7 +1360,7 @@ function GraphFlow(){
 	  });
 	  
 	  // load JSON data.
-	  fd.loadJSON(json,0);
+	  fd.loadGraphFlowJSON(json,0);
 	  // compute positions
 	  refresh();
 	  // end
@@ -1330,9 +1373,18 @@ function GraphFlow(){
 // test data
 function init(){
 	var graph = GraphFlow();
+	var nodecount=0;
+	graph.addListener("onRightClick", 	function(node, info, e){
+											var node2 = {"id":"Node"+(nodecount++), 
+														  "name":"Supi", 
+														  "nodeClass":"Repository",
+														  "tooltip":"look at me, i'm another node!"};
+											graph.addRepository(100, 0, node2,{"name":"inputPort", "id":"ip1"});
+											graph.refresh();
+										});
 	
 	/** These listeners add a "new"-flag to a freshly added node. New nodes cannot be deleted until saved with a right click **/
-	
+	/*
 	graph.addListener("onCreateNode", 	function(node){
 											node.data.$saved = false;
 										});
@@ -1352,6 +1404,7 @@ function init(){
 											}
 											return true;
 										});
+	*/
 	
 	// adds a listener that removes invalid Edges
 	graph.addEdgeConstraints();
@@ -1391,6 +1444,7 @@ function init(){
 	graph.addReader(0, 100, node3,[{"name":"repoPort", "id":"rp1"}], [{"name":"outputPort", "id":"op1"}]);
 	
 	graph.addEdge("superNode1.rp1", "superNode2.ip1", "I'm a label!");
+	
 	// refresh graph to show the new nodes
 	graph.refresh();
 }
diff --git a/Kieker.WebGUI/src/main/webapp/js/jit.js b/Kieker.WebGUI/src/main/webapp/js/jit.js
index 09d7cb39abcae2b5cf61a8c4b94e1939029b79c0..951e6d3c33d1fa0966b4a5c055d4ba3b18512906 100644
--- a/Kieker.WebGUI/src/main/webapp/js/jit.js
+++ b/Kieker.WebGUI/src/main/webapp/js/jit.js
@@ -3986,7 +3986,7 @@ $jit.Graph = new Class({
     <Graph.Node>
 
   */  
-  addNode: function(obj) { 
+  addNode: function(obj) {
    if(!this.nodes[obj.id]) {  
      var edges = this.edges[obj.id] = {};
      this.nodes[obj.id] = new Graph.Node($.extend({
@@ -4003,6 +4003,15 @@ $jit.Graph = new Class({
     return this.nodes[obj.id];
   },
   
+   /** A slight extension of addNode. Restores the node's positions for GraphFlow graphs */
+   addGraphFlowNode: function(obj) {
+	var node = this.addNode(obj);
+	var x = node.data.$xPos,
+		y = node.data.$yPos;
+	node.pos.setc(x,y);
+    return node;
+  },
+  
     /*
      Method: addAdjacence
     
@@ -7806,7 +7815,7 @@ var Loader = {
                       ans.addAdjacence(json[i], getNode(node), data);
                     }
                   }
-                }
+				}
             })(ans, json);
 
         return ans;
@@ -7941,6 +7950,58 @@ var Loader = {
         this.root = json[i? i : 0].id;
       }
     },
+	
+	/** Shamelessly copied from construct(), but accepts empty nodes as well*/
+	constructGraphFlow: function(json) {
+        var ans = new Graph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
+            //make graph
+            (function (ans, json) {
+                var getNode = function(id) {
+                  for(var i=0, l=json.length; i<l; i++) {
+                    if(json[i] != null && json[i].id == id) {
+                      return json[i];
+                    }
+                  }
+                  // The node was not defined in the JSON
+                  // Let's create it
+                  var newNode = {
+                		"id" : id,
+                		"name" : id
+                	};
+                  return ans.addGraphFlowNode(newNode);
+                };
+
+                for(var i=0, l=json.length; i<l; i++) {
+				  if(json[i] != null){
+                  ans.addGraphFlowNode(json[i]);
+                  var adj = json[i].adjacencies;
+                  if (adj) {
+                    for(var j=0, lj=adj.length; j<lj; j++) {
+                      var node = adj[j], data = {};
+                      if(typeof adj[j] != 'string') {
+                        data = $.merge(node.data, {});
+                        node = node.nodeTo;
+                      }
+                      ans.addAdjacence(json[i], getNode(node), data);
+                    }
+                  }
+                }
+				}
+            })(ans, json);
+
+        return ans;
+    },
+	
+	/** A specialized version that accepts null nodes */
+	loadGraphFlowJSON: function(json, i) {
+      this.json = json;
+      //if they're canvas labels erase them.
+      if(this.labels && this.labels.clearLabels) {
+        this.labels.clearLabels(true);
+      }
+      this.graph = this.constructGraphFlow(json);
+      this.root = json[i].id;
+    },
     
     /*
       Method: toJSON
@@ -17261,7 +17322,7 @@ $jit.FlowGraph = new Class( {
     // initialize extras
     this.initializeExtras();
   },
-
+  
   /* 
     Method: refresh