View Javadoc

1   package nl.tudelft.goal.ut2004.floydwarshall;
2   
3   import java.lang.ref.WeakReference;
4   import java.util.HashMap;
5   import java.util.Map;
6   import java.util.Set;
7   import java.util.logging.Logger;
8   
9   import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
10  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
11  import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.MapPointListObtained;
12  
13  /**
14   * Cache for {@link FloydWarshallMap}s. Because FloydWarshallMaps consume a fair
15   * amount of memory it is better to share this map between bots. As long as a
16   * bot has a reference to a SharedFloydWarshallMap that map will remain in
17   * memory.
18   * 
19   * A maps identity is based on the lexographically smallest unrealID and the
20   * badEdgeflag. As such the FloydWarshallMapCache can handle different maps at
21   * the same time.
22   * 
23   * @author mpkorstanje
24   * 
25   */
26  public final class FloydWarshallMapCache {
27  
28  	/**
29  	 * Singleton instance of this cache.
30  	 */
31  	private static FloydWarshallMapCache instance;
32  
33  	/**
34  	 * Cache for {@link FloydWarshallMap}s.
35  	 */
36  	private final Map<MapKey, WeakReference<FloydWarshallMap>> cache = new HashMap<MapKey, WeakReference<FloydWarshallMap>>();
37  
38  	/**
39  	 * A map can be uniquely identified by its badedge flag and a navpoint id
40  	 * (which includes the map name). To make identification consistent we use
41  	 * the smallest id.
42  	 * 
43  	 * @author mpkorstanje
44  	 * 
45  	 */
46  	private static final class MapKey {
47  
48  		@Override
49  		public String toString() {
50  			return "MapKey [id=" + id + ", badEdgeFlag=" + badEdgeFlag + "]";
51  		}
52  
53  		/**
54  		 * The smallest navpoint id.
55  		 */
56  		private final String id;
57  
58  		/**
59  		 * The prohibeted edges in this map.
60  		 */
61  		private final int badEdgeFlag;
62  
63  		public MapKey(Map<UnrealId, NavPoint> map, int badEdgeFlag) {
64  			this.id = getSmallest(map.keySet());
65  			this.badEdgeFlag = badEdgeFlag;
66  		}
67  
68  		private String getSmallest(Set<UnrealId> set) {
69  
70  			if (set.isEmpty()) {
71  				return null;
72  			}
73  
74  			String smallestString = set.iterator().next().getStringId();
75  			for (UnrealId candidate : set) {
76  				String candidateString = candidate.getStringId();
77  				if (candidateString.compareTo(smallestString) < 0) {
78  					smallestString = candidateString;
79  				}
80  
81  			}
82  
83  			return smallestString;
84  		}
85  
86  		@Override
87  		public int hashCode() {
88  			final int prime = 31;
89  			int result = 1;
90  			result = prime * result + badEdgeFlag;
91  			result = prime * result + ((id == null) ? 0 : id.hashCode());
92  			return result;
93  		}
94  
95  		@Override
96  		public boolean equals(Object obj) {
97  			if (this == obj)
98  				return true;
99  			if (obj == null)
100 				return false;
101 			if (!(obj instanceof MapKey))
102 				return false;
103 			MapKey other = (MapKey) obj;
104 			if (badEdgeFlag != other.badEdgeFlag)
105 				return false;
106 			if (id == null) {
107 				if (other.id != null)
108 					return false;
109 			} else if (!id.equals(other.id))
110 				return false;
111 			return true;
112 		}
113 
114 	}
115 
116 	/**
117 	 * Private constructor for singleton.
118 	 */
119 	private FloydWarshallMapCache() {
120 
121 	}
122 
123 	public synchronized FloydWarshallMap createMap(MapPointListObtained event, int badEdgeFlag, Logger log) {
124 		MapKey key = new MapKey(event.getNavPoints(), badEdgeFlag);
125 		FloydWarshallMap sharedMap = null;
126 
127 		// Check if map has been cached.
128 		if (cache.containsKey(key)) {
129 			sharedMap = cache.get(key).get();
130 		}
131 
132 		// Even if entry exist, weak reference might still be null.
133 		if (sharedMap != null) {
134 			log.info("Map exists for " + key);	
135 		} else {
136 			log.info("Creating new map for " + key);
137 			sharedMap = new FloydWarshallMap(badEdgeFlag, log);
138 			sharedMap.performFloydWarshall(event);
139 			cache.put(key, new WeakReference<FloydWarshallMap>(sharedMap));
140 		} 
141 		
142 		return sharedMap;
143 	}
144 
145 	public synchronized static FloydWarshallMapCache getInstance() {
146 		if (instance == null) {
147 			instance = new FloydWarshallMapCache();
148 		}
149 		return instance;
150 	}
151 
152 }