| Line | Hits | Source |
|---|---|---|
| 1 | /* | |
| 2 | * Created on Jul 31, 2005 | |
| 3 | * | |
| 4 | * Copyright (c) 2005, the JUNG Project and the Regents of the University | |
| 5 | * of California | |
| 6 | * All rights reserved. | |
| 7 | * | |
| 8 | * This software is open-source under the BSD license; see either | |
| 9 | * "license.txt" or | |
| 10 | * http://jung.sourceforge.net/license.txt for a description. | |
| 11 | */ | |
| 12 | package edu.uci.ics.jung.utils; | |
| 13 | ||
| 14 | import java.util.HashMap; | |
| 15 | import java.util.Iterator; | |
| 16 | import java.util.List; | |
| 17 | import java.util.Map; | |
| 18 | import java.util.Set; | |
| 19 | ||
| 20 | import org.apache.commons.collections.IteratorUtils; | |
| 21 | ||
| 22 | import edu.uci.ics.jung.exceptions.FatalException; | |
| 23 | ||
| 24 | /** | |
| 25 | * Represents custom user- and system-level information to extend the definition | |
| 26 | * of a node. This is the easiest way to extend the class without subclassing. | |
| 27 | * | |
| 28 | * This works as a dictionary in order to help ensure that there are | |
| 29 | * possibilities for extending user information to a variety of different sorts | |
| 30 | * of data. (Each provider of information can register their own enhanced | |
| 31 | * information without interfering with other providers.) | |
| 32 | * | |
| 33 | * Some suggested uses of UserData include | |
| 34 | * <ul> | |
| 35 | * <li/>Underlying data references, such as pointers to data sources</li> | |
| 36 | * <li/>Raw data which can be analyzed or used by the constraint and filter systems | |
| 37 | * <li/>Temporary enhanced information which can be used for visualization | |
| 38 | * </ul> | |
| 39 | * | |
| 40 | * Consider a series of nodes that has, among other things, enhanced information | |
| 41 | * about 3D coordinates. This might be stored in the 3DData data structure, | |
| 42 | * which generates itself with an input from a node. | |
| 43 | * | |
| 44 | * Thus the relevant call might be <code>n.setUserInfo ("3DData", new 3DData ( | |
| 45 | * ))</code>. | |
| 46 | * Later, to access this information, the call might be <code>3DData dd = | |
| 47 | * (3DData) n.getUserInfo("3DData").</code> | |
| 48 | * | |
| 49 | * <h3>Shared and Individual Data</h3> | |
| 50 | * Note that the there are no required semantics for the key or the information. | |
| 51 | * However, it is necessary to specify information that is used for SHARED and | |
| 52 | * for INDIVIDUAL data elements. When a new View of a graph is | |
| 53 | * generated, the Node elements inside it are all shallow-copied. The UserInfo | |
| 54 | * that they use, however, is <em>not</em> copied, by default. This is the | |
| 55 | * correct and logical behavior if the UserInfo contains source information. | |
| 56 | * | |
| 57 | * But what when the UserInfo contains transient information, specific to the | |
| 58 | * view, such as graph metrics or coordinates? In that case, the UserInfo would | |
| 59 | * be quite inappropriate to share that information between copies. | |
| 60 | * | |
| 61 | * The solution to this is to add a third flag, "shared", which tells whether | |
| 62 | * the currect data is shared or not. This flag is assigned when the data is | |
| 63 | * added. | |
| 64 | */ | |
| 65 | 179476 | public class DefaultUserData extends UserData implements UserDataFactory |
| 66 | { | |
| 67 | // maps a Key to a Pair( UserData, CopyAction ) | |
| 68 | private Map userDataStorage; | |
| 69 | ||
| 70 | private Map getStorage() { | |
| 71 | 1935347 | if (userDataStorage == null) { |
| 72 | 29072 | userDataStorage = new HashMap(); |
| 73 | } | |
| 74 | 1935347 | return userDataStorage; |
| 75 | } | |
| 76 | ||
| 77 | /** | |
| 78 | * This class actually clones by removing the reference to the copyAction | |
| 79 | * and userData | |
| 80 | */ | |
| 81 | public Object clone() throws CloneNotSupportedException { | |
| 82 | 1761 | DefaultUserData ud = (DefaultUserData) super.clone(); |
| 83 | 1761 | ud.userDataStorage = null; |
| 84 | 1761 | return ud; |
| 85 | } | |
| 86 | ||
| 87 | /** | |
| 88 | * Adds user-level information to the node. Throws an exception if the node | |
| 89 | * already has information associated with it. | |
| 90 | * | |
| 91 | * @param key | |
| 92 | * A unique (per type, not per node) key into the information | |
| 93 | * @param value | |
| 94 | * The extended information associated with the node | |
| 95 | */ | |
| 96 | public void addUserDatum(Object key, Object value, CopyAction shared) { | |
| 97 | 8470 | if (key == null) |
| 98 | 1 | throw new IllegalArgumentException("Key must not be null"); |
| 99 | 8469 | if (!getStorage().containsKey(key)) { |
| 100 | 8467 | getStorage().put(key, new Pair(value, shared)); |
| 101 | } else { | |
| 102 | 2 | throw new IllegalArgumentException("Key <" + key |
| 103 | + "> had already been added to an object with keys " | |
| 104 | + getKeys()); | |
| 105 | } | |
| 106 | 8467 | } |
| 107 | ||
| 108 | /** | |
| 109 | * @return | |
| 110 | */ | |
| 111 | private Set getKeys() { | |
| 112 | 2 | return getStorage().keySet(); |
| 113 | } | |
| 114 | ||
| 115 | /** | |
| 116 | * Uses the CopyAction to determine how each of the user datum elements in | |
| 117 | * udc should be carried over to the this UserDataContiner | |
| 118 | * | |
| 119 | * @param udc | |
| 120 | * The UserDataContainer whose user data is being imported | |
| 121 | */ | |
| 122 | public void importUserData(UserDataContainer udc) { | |
| 123 | 1769 | for (Iterator keyIt = udc.getUserDatumKeyIterator(); keyIt.hasNext();) { |
| 124 | 537 | Object key = keyIt.next(); |
| 125 | 537 | Object value = udc.getUserDatum(key); |
| 126 | 537 | CopyAction action = udc.getUserDatumCopyAction(key); |
| 127 | 537 | Object newValue = action.onCopy(value, udc, this); |
| 128 | try { | |
| 129 | 537 | if (newValue != null) addUserDatum(key, newValue, action); |
| 130 | ||
| 131 | 1 | } catch (IllegalArgumentException iae) { |
| 132 | 1 | List userDataKeys = IteratorUtils.toList(udc |
| 133 | .getUserDatumKeyIterator()); | |
| 134 | 1 | throw new FatalException("Copying <" + key + "> of " |
| 135 | + userDataKeys | |
| 136 | + " into a container that started with some keys ", | |
| 137 | iae); | |
| 138 | 1072 | } |
| 139 | } | |
| 140 | ||
| 141 | 1768 | } |
| 142 | ||
| 143 | /** | |
| 144 | * Changes the user-level information to the object. Equivalent to calling | |
| 145 | * | |
| 146 | * <pre> | |
| 147 | * | |
| 148 | * | |
| 149 | * removeUserDatum( key ); | |
| 150 | * addUserDatum(key, value) | |
| 151 | * | |
| 152 | * | |
| 153 | * </pre> | |
| 154 | * | |
| 155 | * @param key | |
| 156 | * @param value | |
| 157 | */ | |
| 158 | public void setUserDatum(Object key, Object value, CopyAction shared) { | |
| 159 | 22746 | getStorage().put(key, new Pair(value, shared)); |
| 160 | 22746 | } |
| 161 | ||
| 162 | /** | |
| 163 | * Returns UserInfo (if known) for this key, or <em>null</em> if not | |
| 164 | * known. | |
| 165 | * | |
| 166 | * @param key | |
| 167 | */ | |
| 168 | public Object getUserDatum(Object key) { | |
| 169 | 1871988 | Pair p = (Pair) getStorage().get(key); |
| 170 | 1871988 | if (p == null) return null; |
| 171 | 1843999 | return p.getFirst(); |
| 172 | } | |
| 173 | ||
| 174 | /** | |
| 175 | * Removes the Datum (if known) for this key, and returns it. | |
| 176 | * | |
| 177 | * @param key | |
| 178 | */ | |
| 179 | public Object removeUserDatum(Object key) { | |
| 180 | 21344 | Object o = getUserDatum(key); |
| 181 | 21344 | getStorage().remove(key); |
| 182 | 21344 | return o; |
| 183 | } | |
| 184 | ||
| 185 | /** | |
| 186 | * Iterates through the keys to all registered data. Note: there's no easy | |
| 187 | * way to know, looking at a piece of data, whether it is or is not shared. | |
| 188 | * | |
| 189 | * @return Iterator | |
| 190 | */ | |
| 191 | public Iterator getUserDatumKeyIterator() { | |
| 192 | 1777 | return getStorage().keySet().iterator(); |
| 193 | } | |
| 194 | ||
| 195 | /** | |
| 196 | * @see UserDataContainer#containsUserDatumKey(Object) | |
| 197 | */ | |
| 198 | public boolean containsUserDatumKey(Object key) | |
| 199 | { | |
| 200 | 11 | return getStorage().containsKey(key); |
| 201 | } | |
| 202 | ||
| 203 | /** | |
| 204 | * Returns the CopyAction associated with this key. | |
| 205 | * | |
| 206 | * @param key | |
| 207 | * @return CopyAction | |
| 208 | */ | |
| 209 | public CopyAction getUserDatumCopyAction(Object key) { | |
| 210 | 543 | Pair p = (Pair) getStorage().get(key); |
| 211 | 543 | return (CopyAction) p.getSecond(); |
| 212 | } | |
| 213 | ||
| 214 | public UserDataContainer getInstance() | |
| 215 | { | |
| 216 | 179392 | return new DefaultUserData(); |
| 217 | } | |
| 218 | ||
| 219 | } |
|
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |