diff --git a/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactGraph.java b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactGraph.java
new file mode 100644
index 0000000000000000000000000000000000000000..640b3d99526e603c066d272535276b3ecb94cfaa
--- /dev/null
+++ b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactGraph.java
@@ -0,0 +1,290 @@
+package org.universaal.uaalpax.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.collection.DependencyCollectionException;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.graph.DependencyNode;
+import org.universaal.uaalpax.shared.MavenDependencyResolver;
+
+public class ArtifactGraph {
+	// private List<ArtifactNode> buttomNodes;
+	
+	private MavenDependencyResolver dependencyResolver;
+	
+	private Map<ArtifactURL, ArtifactNode> url2nodeMap;
+	
+	public ArtifactGraph(MavenDependencyResolver resolver) {
+		// this.buttomNodes = new LinkedList<ArtifactNode>();
+		this.dependencyResolver = resolver;
+		this.url2nodeMap = new HashMap<ArtifactURL, ArtifactNode>();
+	}
+	
+	// public void addBundle(BundleEntry be, String currentVersion, UAALVersionProvider versionProvider) {
+	// Set<Artifact> bundleArtifacts = getArtifactsOfUrl(be.getLaunchUrl());
+	// // System.out.println("composite contains ");
+	// // for(Artifact a: bundleArtifacts)
+	// // System.out.println("  " + a);
+	//
+	// Set<ArtifactNode> newNodes = new HashSet<ArtifactNode>();
+	//
+	// long resTime = 0;
+	// long lastTime = System.currentTimeMillis();
+	// Set<String> bundleUrls = new HashSet<String>();
+	//
+	// for (Artifact a : bundleArtifacts) {
+	// bundleUrls.add(BundleEntry.stringFromArtifact(a));
+	//
+	// try {
+	// long last = System.currentTimeMillis();
+	// DependencyNode dNode = dependencyResolver.resolve(a);
+	// resTime += (System.currentTimeMillis() - last);
+	//
+	// System.out.println("Tree of Artifact " + a);
+	// ConsoleDependencyGraphDumper dumper = new ConsoleDependencyGraphDumper();
+	// dNode.accept(dumper);
+	//
+	// insertDependencyTree(dNode, null, be, newNodes);
+	// } catch (DependencyCollectionException e) {
+	// // TODO Auto-generated catch block
+	// e.printStackTrace();
+	// } catch (TimeoutException e) {
+	// // TODO Auto-generated catch block
+	// e.printStackTrace();
+	// }
+	// }
+	//
+	// // for(ArtifactNode aNode: newNodes) {
+	// // if(!bundleUrls.contains(aNode.getArtifact()))
+	// // System.out.println("new node " + aNode.getArtifact());
+	// // else
+	// // System.out.println("contained node " + aNode.getArtifact());
+	// // if(!bundleUrls.contains(aNode.getArtifact()) && versionProvider.isIgnoreArtifactOfVersion(launchUrl, version)) {
+	// //
+	// // }
+	// // }
+	//
+	// long compTime = System.currentTimeMillis() - lastTime - resTime;
+	//
+	// System.out.println("resolution took " + resTime);
+	// System.out.println("Comp took " + compTime);
+	// }
+	//
+	// private ArtifactNode insertDependencyTree(DependencyNode dNode, ArtifactNode parent, BundleEntry be, Set<ArtifactNode> newNodes) {
+	// Dependency d = dNode.getDependency();
+	// ArtifactNode aNode = null;
+	//
+	// if (d != null) {
+	// String url = BundleEntry.stringFromArtifact(d.getArtifact());
+	//
+	// aNode = url2nodeMap.get(url);
+	// if (aNode == null) {
+	// aNode = new ArtifactNode(url);
+	// url2nodeMap.put(url, aNode);
+	// newNodes.add(aNode);
+	// }
+	//
+	// if (parent != null)
+	// parent.addChild(aNode);
+	// }
+	//
+	// if (aNode != null)
+	// parent = aNode;
+	//
+	// for (DependencyNode child : dNode.getChildren()) {
+	// insertDependencyTree(child, parent, null, newNodes);
+	// }
+	//
+	// if (aNode != null && be != null)
+	// aNode.addBundleEntry(be);
+	//
+	// return aNode;
+	// }
+	//
+	// private Set<Artifact> getArtifactsOfUrl(String url) {
+	// Artifact a = BundleEntry.artifactFromURL(url);
+	//
+	// if (BundleEntry.isCompositeURL(url)) {
+	// a = dependencyResolver.resolveArtifact(a);
+	// if (a == null)
+	// return new HashSet<Artifact>();
+	//
+	// return readArtifactsFromComposite(a.getFile());
+	// } else {
+	// Set<Artifact> arts = new HashSet<Artifact>(1);
+	// if (a != null)
+	// arts.add(a);
+	// return arts;
+	// }
+	// }
+	//
+	// private Set<Artifact> readArtifactsFromComposite(File file) {
+	// Set<Artifact> arts = new HashSet<Artifact>();
+	// if (!file.exists() || !file.canRead())
+	// return arts; // TODO error message
+	//
+	// try {
+	// BufferedReader br = new BufferedReader(new FileReader(file));
+	// String url;
+	//
+	// while ((url = br.readLine()) != null) {
+	// if (!url.isEmpty())
+	// arts.addAll(getArtifactsOfUrl(url));
+	// }
+	// } catch (FileNotFoundException e) {
+	// return arts;
+	// } catch (IOException e) {
+	// // TODO Auto-generated catch block
+	// return arts;
+	// }
+	//
+	// return arts;
+	// }
+	
+	public ArtifactNode insertDependencyNode(DependencyNode dNode, ArtifactNode parent) {
+		Dependency d = dNode.getDependency();
+		ArtifactNode aNode = null;
+		
+		if (d != null) {
+			ArtifactURL url = BundleEntry.artifactUrlFromArtifact(d.getArtifact());
+			
+			aNode = url2nodeMap.get(url);
+			if (aNode == null) {
+				aNode = new ArtifactNode(url);
+				url2nodeMap.put(url, aNode);
+			}
+			
+			if (parent != null)
+				parent.addChild(aNode);
+		}
+		
+		if (aNode != null)
+			parent = aNode;
+		
+		for (DependencyNode child : dNode.getChildren()) {
+			insertDependencyNode(child, parent);
+		}
+		
+		return aNode;
+	}
+	
+	public void clear() {
+		url2nodeMap.clear();
+	}
+	
+	public void rebuildFromSetInBackground(BundleSet bs) {
+		clear();
+		
+		for (BundleEntry be : bs) {
+			Artifact a = be.toArtifact();
+			
+			try {
+				DependencyNode dNode = dependencyResolver.resolveDependenciesBlocking(a);
+				
+				// System.out.println("Tree of Artifact " + a);
+				// ConsoleDependencyGraphDumper dumper = new ConsoleDependencyGraphDumper();
+				// dNode.accept(dumper);
+				
+				insertDependencyNode(dNode, null);
+			} catch (DependencyCollectionException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+	}
+	
+	public ArtifactNode getNode(String url) {
+		return url2nodeMap.get(url);
+	}
+	
+	public Set<ArtifactURL> checkCanRemove(Set<BundleEntry> bes) {
+		Map<ArtifactURL, BundleEntry> map = new HashMap<ArtifactURL, BundleEntry>();
+		for (BundleEntry be : bes)
+			map.put(be.getArtifactUrl(), be);
+		
+		Set<ArtifactURL> willBeRemoved = new HashSet<ArtifactURL>();
+		
+		for (BundleEntry be : bes) {
+			ArtifactNode root = url2nodeMap.get(be.getArtifactUrl());
+			if (root == null)
+				continue; // no error here
+				
+			for (ArtifactNode parent : root.getParents())
+				checkNodeAndParentsInSet(parent, map, willBeRemoved);
+		}
+		
+		if (willBeRemoved.isEmpty())
+			return null;
+		else
+			return willBeRemoved;
+	}
+	
+	private void checkNodeAndParentsInSet(ArtifactNode node, Map<ArtifactURL, BundleEntry> map, Set<ArtifactURL> willBeRemoved) {
+		if (!map.containsKey(node.getArtifact()))
+			willBeRemoved.add(node.getArtifact());
+		
+		for (ArtifactNode parent : node.getParents())
+			checkNodeAndParentsInSet(parent, map, willBeRemoved);
+	}
+	
+	public Set<ArtifactURL> removeArtifacts(Set<BundleEntry> bes, BundleSet versionBundles) {
+		Map<ArtifactURL, BundleEntry> map = new HashMap<ArtifactURL, BundleEntry>();
+		for (BundleEntry be : bes)
+			map.put(be.getArtifactUrl(), be);
+		
+		if (versionBundles == null)
+			versionBundles = new BundleSet();
+		
+		Set<ArtifactURL> versionSet = new HashSet<ArtifactURL>();
+		for (BundleEntry be : versionBundles)
+			versionSet.add(be.getArtifactUrl());
+		
+		Set<ArtifactURL> toRemove = new HashSet<ArtifactURL>();
+		
+		for (Map.Entry<ArtifactURL, BundleEntry> e : map.entrySet()) {
+			toRemove.remove(e.getKey());
+			
+			ArtifactNode root = url2nodeMap.get(e.getKey());
+			if (root == null)
+				continue;
+			
+			removeNodeAndOnlyOwnChildren(root, toRemove, versionSet);
+		}
+		
+		return toRemove;
+	}
+	
+	private void removeNodeAndOnlyOwnChildren(ArtifactNode node, Set<ArtifactURL> toRemove, Set<ArtifactURL> versionSet) {
+		if (node.getParents().size() > 0 || versionSet.contains(node.getArtifact())) // reached the bottom
+			return;
+		
+		// create copy of node's children
+		Set<ArtifactNode> children = new HashSet<ArtifactNode>();
+		children.addAll(node.getChildren());
+		
+		toRemove.add(node.getArtifact());
+		
+		removeNode(node);
+		
+		for (ArtifactNode child : children)
+			removeNodeAndOnlyOwnChildren(child, toRemove, versionSet);
+	}
+	
+	private void removeNode(ArtifactNode node) {
+		url2nodeMap.remove(node.getArtifact());
+		node.removeSelf();
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		for (ArtifactNode n : url2nodeMap.values())
+			sb.append(n.toString()).append("\n");
+		
+		return sb.toString();
+	}
+}
diff --git a/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactNode.java b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..356667673549f327383ffc2236ffb05de6498673
--- /dev/null
+++ b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactNode.java
@@ -0,0 +1,103 @@
+package org.universaal.uaalpax.model;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+public class ArtifactNode {
+	private ArtifactURL artifact;
+	
+	private Set<ArtifactNode> children;
+	private Set<ArtifactNode> parents;
+	
+	private List<BundleEntry> bundleEntries;
+	
+	public ArtifactNode(ArtifactURL artifact) {
+		this.artifact = artifact;
+		this.children = new HashSet<ArtifactNode>();
+		this.parents = new HashSet<ArtifactNode>();
+		
+		this.bundleEntries = new LinkedList<BundleEntry>();
+	}
+	
+	public List<BundleEntry> getBundleEntries() {
+		return bundleEntries;
+	}
+	
+	public ArtifactURL getArtifact() {
+		return artifact;
+	}
+	
+	public Set<ArtifactNode> getChildren() {
+		return children;
+	}
+	
+	public Set<ArtifactNode> getParents() {
+		return parents;
+	}
+	
+	public void addBundleEntry(BundleEntry be) {
+		bundleEntries.add(be);
+	}
+	
+	public void addChild(ArtifactNode child) {
+		if (children.add(child))
+			child.addParent(this);
+	}
+	
+	private void addParent(ArtifactNode parent) {
+		parents.add(parent);
+	}
+	
+	private void removeChild(ArtifactNode c) {
+		children.remove(c);
+	}
+	
+	private void removeParent(ArtifactNode p) {
+		parents.remove(p);
+	}
+	
+	public void removeSelf() {
+		for(ArtifactNode parent: getParents())
+			parent.removeChild(this);
+		
+		for(ArtifactNode child: getChildren())
+			child.removeParent(this);
+		
+		parents.clear();
+		children.clear();
+		bundleEntries.clear();
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		
+		sb.append(getArtifact()).append("\n");
+		
+		sb.append("parents\n");
+		for (ArtifactNode p : getParents())
+			sb.append("  ").append(p.getArtifact()).append("\n");
+		
+		sb.append("children\n");
+		for (ArtifactNode c : getChildren())
+			sb.append("  ").append(c.getArtifact()).append("\n");
+		
+		sb.append("bundles\n");
+		for (BundleEntry b : getBundleEntries())
+			sb.append("  ").append(b).append("\n");
+		
+		return sb.toString();
+	}
+	
+	@Override
+	public int hashCode() {
+		return artifact.hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		return this == obj; // TODO
+	}
+}
diff --git a/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactURL.java b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactURL.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f5c2667d2cfa0716e7554d1a3db889ff9014558
--- /dev/null
+++ b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/ArtifactURL.java
@@ -0,0 +1,35 @@
+package org.universaal.uaalpax.model;
+
+public final class ArtifactURL implements java.io.Serializable, Comparable<ArtifactURL> {
+	private static final long serialVersionUID = -746998803398536504L;
+	
+	public final String url;
+	
+	public ArtifactURL(String url) {
+		this.url = url;
+	}
+	
+	@Override
+	public int hashCode() {
+		return url.hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this)
+			return true;
+		else if (!(obj instanceof ArtifactURL))
+			return false;
+		
+		return url.equals(((ArtifactURL) obj).url);
+	}
+	
+	@Override
+	public String toString() {
+		return url;
+	}
+
+	public int compareTo(ArtifactURL o) {
+		return this.url.compareTo(o.url);
+	}
+}
diff --git a/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/LaunchURL.java b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/LaunchURL.java
new file mode 100644
index 0000000000000000000000000000000000000000..0cbd3158b2cebff626f3b95a5936ff2bc35d955a
--- /dev/null
+++ b/uAALPaxTab/pax-runner-uaal/pax-runner-uaal-ui/src/main/java/org/universaal/uaalpax/model/LaunchURL.java
@@ -0,0 +1,33 @@
+package org.universaal.uaalpax.model;
+
+public final class LaunchURL implements java.io.Serializable, Comparable<LaunchURL> {
+	public final String url;
+	
+	public LaunchURL(String url) {
+		this.url = url;
+	}
+	
+	@Override
+	public int hashCode() {
+		return url.hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this)
+			return true;
+		else if (!(obj instanceof LaunchURL))
+			return false;
+		
+		return url.equals(((LaunchURL) obj).url);
+	}
+	
+	@Override
+	public String toString() {
+		return url;
+	}
+
+	public int compareTo(LaunchURL o) {
+		return this.url.compareTo(o.url);
+	}
+}