• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /barrelfish-2018-10-04/usr/eclipseclp/Visualisation/src/com/parctechnologies/eclipse/visualisation/
1// BEGIN LICENSE BLOCK
2// Version: CMPL 1.1
3//
4// The contents of this file are subject to the Cisco-style Mozilla Public
5// License Version 1.1 (the "License"); you may not use this file except
6// in compliance with the License.  You may obtain a copy of the License
7// at www.eclipse-clp.org/license.
8//
9// Software distributed under the License is distributed on an "AS IS"
10// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11// the License for the specific language governing rights and limitations
12// under the License.
13//
14// The Original Code is  The ECLiPSe Constraint Logic Programming System.
15// The Initial Developer of the Original Code is  Cisco Systems, Inc.
16// Portions created by the Initial Developer are
17// Copyright (C) 2006 Cisco Systems, Inc.  All Rights Reserved.
18//
19// Contributor(s):
20//
21// END LICENSE BLOCK
22
23package com.parctechnologies.eclipse.visualisation;
24import java.util.Map;
25import java.util.HashMap;
26import java.util.List;
27import java.util.LinkedList;
28import java.util.Iterator;
29import java.io.Serializable;
30import java.lang.ref.*;
31
32/**
33 * A classd designed to act as a Symbolic Reference to objects.
34 *
35 * Intended primarily to be used in the recording and playback of commands.
36 *
37 */
38public class SymRef implements Serializable {
39    /** defines the root of the symbolic heirarchy */
40    public static final SymRef ROOT = new SymRef();
41
42    protected List path;
43
44    /**
45     * Private constructor for the ROOT SymRef
46     */
47    private SymRef() {
48	this.path = new LinkedList();
49	this.path.add("ROOT");
50    }
51
52
53    /**
54     * Private constructor to turn a path into a SymRef
55     */
56    private SymRef(List path) {
57	this.path = path;
58    }
59
60    /**
61     * Holds the root of the tree
62     */
63    private static Node root = new Node();
64
65
66    /**
67     * Constructs a top level SymRef.
68     * This is shorthand for calling
69     * <CODE>SymRef(value, SymRef.ROOT, childName)</CODE>
70     * @param value The object to be refered to by this SymRef
71     * @param childName An object identifying the child
72     */
73    public SymRef(SymRefable value, Object childName) {
74	this.path = Node.put(childName, value);
75    }
76
77    /**
78     * Constructs a child SymRef
79     * @param value The object to be refered to by this SymRef
80     * @param parentRef The SymRef of the parent object (if applicable)
81     * @param childName An object identifying the child
82     */
83    public SymRef(SymRefable value, SymRef parentRef, Object childName) {
84	this.path = Node.addChild(parentRef.path, childName, value);
85    }
86
87
88    /**
89     * @return The SymRef of the root top level object
90     */
91    public SymRef getRoot() {
92	// make a new path with just the top most element of this symref
93	List newPath = new LinkedList();
94	newPath.add(this.path.get(0));
95	return new SymRef(newPath);
96    }
97
98
99    /**
100     * Returns the string representation of the symRef
101     */
102    public String toString() {
103	StringBuffer sb = new StringBuffer();
104	for(Iterator it = path.iterator(); it.hasNext(); ) {
105	    sb.append("/").append(it.next());
106	}
107	return sb.toString();
108    }
109
110    /**
111     * Handles the equality testing of symbolic keys
112     */
113    public boolean equals(Object o) {
114	if (o instanceof SymRef) {
115	    return toString().equals(((SymRef)o).toString());
116	} else {
117	    return false;
118	}
119    }
120
121    /**
122     * Handles the hashing of SymRefs
123     */
124    public int hashCode() {
125	return toString().hashCode();
126    }
127
128    /**
129     * Looks up the value of a SymRef
130     */
131    public static synchronized SymRefable get(SymRef key) throws InvalidSymRefException {
132	if ( Node.containsKey(key.path) ) {
133	    SymRefable value = (Node.findNode(key.path).get());
134	    if (value != null) {
135		return value;
136	    } else {
137		if (DebuggingSupport.logMessages) {
138		    DebuggingSupport.
139			logMessage(key,
140				   "SymRef has been garbage collected=" +
141				   key);
142		}
143	    }
144	}
145	throw new InvalidSymRefException(key);
146    }
147
148
149
150    /**
151     * Internal SymRef tree structure
152     */
153    private static class Node {
154	public Node parent;
155	public Object id;
156	public Reference val_ref;
157
158	public Map children;
159
160	public Node() {
161	    this(null, null, null);
162	}
163
164	public Node(Node parent,
165		    Object id,
166		    Object value) {
167	    this.parent = parent;
168	    this.id = id;
169	    this.val_ref = new WeakReference(value);
170	    children = new HashMap();
171	    if (parent != null && parent.children != null) {
172		parent.children.put(id, this);
173	    }
174	}
175
176	/**
177	 * Returns the object stored in this node
178	 */
179	public final SymRefable get() {
180	    return (SymRefable)(val_ref.get());
181	}
182
183	/**
184	 * Insert a value into the root of the tree, possibly overwritting
185	 * existing sub-trees
186	 */
187	public static List put(Object id, Object val) {
188	    if (DebuggingSupport.logMessages) {
189		DebuggingSupport.
190		    logMessage(null,
191			       "put id=" + id +
192			       " val=" + val);
193	    }
194	    Node newNode = new Node(root, id, val);
195	    List newPath = new LinkedList();
196	    newPath.add(id);
197	    return newPath;
198	}
199
200	/**
201	 * Add a value as a child of the given path.
202	 * This call will not overwrite any existing children
203	 * @return The path to the child
204	 */
205	public static List addChild(List parentPath, Object id, Object val) {
206	    Node parent = root.findNode(parentPath);
207	    if (DebuggingSupport.logMessages) {
208		DebuggingSupport.
209		    logMessage(null,
210			       "addChild parentPath=" + parentPath +
211			       " id=" + id +
212			       " val=" + val);
213	    }
214	    if (parent == null) {
215		if (DebuggingSupport.logMessages) {
216		    DebuggingSupport.
217			logMessage(null,
218				   "addChild unable to find parent path=" +
219				   parentPath);
220		}
221		return null;
222	    }
223	    String newId = id.toString() + "_" + parent.children.size();
224	    Node newNode = new Node(parent, newId, val);
225	    List newPath = new LinkedList(parentPath);
226	    newPath.add(newId);
227	    return newPath;
228	}
229
230
231	/**
232	 * @return true iff the given key(path) exists in the tree
233	 */
234	public static boolean containsKey(List list) {
235	    return (root.matchKey(list) == list.size());
236	}
237
238	/**
239	 * returns the number of elements of the path (list) that were
240	 * sucessfully matched
241	 */
242	public static int matchKey(List list) {
243	    Node node = root;
244	    final int size = list.size();
245	    int i = 0 ;
246	    for(Iterator it = list.iterator(); it.hasNext(); i++ ) {
247		Object id = it.next();
248		// check for match in current nodes children
249		if (node.children.containsKey(id)) {
250		    node = (Node)node.children.get(id);
251		} else {
252		    break;
253		}
254	    }
255	    return i;
256	}
257
258	/**
259	 * returns the node at the end of this path, if it was
260	 * sucessfully matched
261	 */
262	public static Node findNode(List list) {
263	    Node node = root;
264	    final int size = list.size();
265	    for(Iterator it = list.iterator(); it.hasNext(); ) {
266		Object id = it.next();
267		// check for match in current nodes children
268		if (node.children.containsKey(id)) {
269		    node = (Node)node.children.get(id);
270		} else {
271		    return null;
272		}
273	    }
274	    return node;
275	}
276
277
278
279
280    }
281
282}
283
284