001 package nl.cwi.sen1.visbase.rstorecontainer; 002 003 import java.util.ArrayList; 004 import java.util.LinkedHashMap; 005 import java.util.List; 006 import java.util.Map; 007 import java.util.NoSuchElementException; 008 import java.util.TreeSet; 009 010 import nl.cwi.sen1.relationstores.types.RStore; 011 import nl.cwi.sen1.relationstores.types.RTuple; 012 import nl.cwi.sen1.relationstores.types.RTupleRtuples; 013 import nl.cwi.sen1.visbase.rstorecontainer.datatypes.FactInfo; 014 import nl.cwi.sen1.visbase.rstorecontainer.datatypes.FactInfoList; 015 016 import org.apache.commons.logging.Log; 017 import org.apache.commons.logging.LogFactory; 018 019 import aterm.pure.ATermApplImpl; 020 021 /** 022 * Keeps track of the Rtuples associated to a RStore. Manages the identifiers. 023 */ 024 public class RStoreTracker { 025 private static final Log m_log = LogFactory.getLog(RStoreContainer.class); 026 027 private RStore m_RStore; 028 029 private Map<Integer, RTuple> m_loadedRTuplesMap; 030 031 private Map<String, Integer> m_identifiedRTuplesMap; 032 033 /** 034 * Default Constructor. Reads all RTuple (facts) from the given RStore 035 * 036 * @param rStore 037 * 038 * @throws RuntimeException 039 * if rStore input is null 040 */ 041 public RStoreTracker(RStore rStore) { 042 if (rStore == null) { 043 throw new RuntimeException("RStore input should not be null"); 044 } 045 046 updateRStore(rStore); 047 } 048 049 /** 050 * Updates this tracker with the given RStore 051 * 052 * @param rStore 053 */ 054 private void updateRStore(RStore rStore) { 055 m_RStore = rStore; 056 057 m_identifiedRTuplesMap = new LinkedHashMap<String, Integer>(); 058 m_loadedRTuplesMap = new LinkedHashMap<Integer, RTuple>(); 059 060 RTupleRtuples rTuples = rStore.getRtuples(); 061 062 final int numRTuples = rTuples.getLength(); 063 064 for (int tupleNum = 0; tupleNum < numRTuples; tupleNum++) { 065 RTuple rTuple = rTuples.getRTupleAt(tupleNum); 066 067 if (rTuple != null) { 068 registerNewRTuple(rTuple); 069 } 070 } 071 } 072 073 /** 074 * Updates this tracker with new, deleted or updated facts 075 * 076 * @param updatedRStore 077 * @return list of ID's of facts that where updated 078 */ 079 public synchronized List<Integer> update(RStore updatedRStore) { 080 List<Integer> updatedFactIds = new ArrayList<Integer>(); 081 082 RTupleRtuples rTuples = updatedRStore.getRtuples(); 083 084 final int numRTuples = rTuples.getLength(); 085 086 for (int tupleNum = 0; tupleNum < numRTuples; tupleNum++) { 087 RTuple rTuple = rTuples.getRTupleAt(tupleNum); 088 089 if (rTuple != null) { 090 final String identifier = createIdentifierForRTuple(rTuple); 091 092 // Check if a RTuple already existed with this identifier 093 if (m_identifiedRTuplesMap.containsKey(identifier)) { 094 /* RTuple exists */ 095 096 Integer existingId = m_identifiedRTuplesMap.get(identifier); 097 098 if (m_log.isDebugEnabled()) { 099 m_log.info("RTuple already exists for identidier: " 100 + identifier + "(id: " + existingId + ")"); 101 } 102 103 RTuple existingRTuple = m_loadedRTuplesMap.get(existingId); 104 105 boolean rTuplesDifferFromEachOther = diffRtuples( 106 existingRTuple, rTuple); 107 108 if (rTuplesDifferFromEachOther) { 109 if (m_log.isInfoEnabled()) { 110 m_log 111 .info("Replacing existing RTuple with new RTuple"); 112 } 113 114 updatedFactIds.add(existingId); 115 116 // Replace existing loaded RTuple with new RTuple 117 m_loadedRTuplesMap.put(existingId, rTuple); 118 } 119 } 120 } 121 } 122 123 // Replace current RStore with new RStore, which ensures that all added 124 // and removed relations are updated 125 updateRStore(updatedRStore); 126 127 return updatedFactIds; 128 } 129 130 /** 131 * Simple getter 132 * 133 * @return the RStore object belonging to this Fact Tracker 134 */ 135 public RStore getRStore() { 136 return m_RStore; 137 } 138 139 /** 140 * Simple getter 141 * 142 * @param id 143 * @return the RTuple belonging to the id (null if it doesn't exist) 144 */ 145 public RTuple getRTuple(int id) { 146 RTuple rTuple = m_loadedRTuplesMap.get(new Integer(id)); 147 148 if (rTuple == null) { 149 if (m_log.isWarnEnabled()) { 150 m_log.warn("RTuple fact doesn't exist for id: " + id 151 + ". Valid ID's are: " + m_loadedRTuplesMap.keySet()); 152 } 153 } 154 155 return rTuple; 156 } 157 158 /** 159 * Creates a list of FactInfo objects containing the descriptive data from 160 * the found facts (using the RTuples in the RStore). 161 * 162 * @return A FactInfoList object containing information about all the facts 163 * in the RStore. 164 */ 165 public FactInfoList getFactInfoFromRStore() { 166 167 FactInfoList factInfoList = new FactInfoList(); 168 169 RTupleRtuples rTuples = m_RStore.getRtuples(); 170 171 final int numRTuples = rTuples.getLength(); 172 for (int tupleNum = 0; tupleNum < numRTuples; tupleNum++) { 173 RTuple rTuple = rTuples.getRTupleAt(tupleNum); 174 175 if (rTuple != null) { 176 FactInfo factInfo = new FactInfo(tupleNum + 1, rTuple); 177 178 factInfoList.addFactInfoToList(factInfo); 179 } 180 } 181 182 return factInfoList; 183 } 184 185 /** 186 * Checks if RTuples differ from eachother 187 * 188 * @param existingRTuple 189 * @param newRTuple 190 * @return <b>true</b> if RTuples are <b>NOT equal</b> 191 * 192 * @throws RuntimeException 193 * if input is null 194 */ 195 public static boolean diffRtuples(RTuple existingRTuple, RTuple newRTuple) { 196 boolean result_not_equal; 197 198 if (existingRTuple == null) { 199 throw new RuntimeException( 200 "existingRTuple input should not be null"); 201 } 202 if (newRTuple == null) { 203 throw new RuntimeException("newRTuple input should not be null"); 204 } 205 206 result_not_equal = !existingRTuple.equals(newRTuple); 207 208 m_log.debug("existingRTuple is " + (result_not_equal ? "NOT" : "") 209 + " EQUAL to newRTuple"); 210 211 return result_not_equal; 212 } 213 214 /** 215 * Registers 216 * 217 * @param rTuple 218 * @throws RuntimeException 219 * if rtuple is null 220 */ 221 protected void registerNewRTuple(RTuple rTuple) { 222 if (rTuple == null) { 223 throw new RuntimeException("RTuple input should not be null"); 224 } 225 226 /* RTuple is new, generate new number identidfier */ 227 228 // Create identification for this RTuple 229 final String identifier = createIdentifierForRTuple(rTuple); 230 231 // Use a TreeSet to sort the Keys (whe want to have the highest) 232 TreeSet<Integer> existingIds = new TreeSet<Integer>(m_loadedRTuplesMap 233 .keySet()); 234 235 Integer lastId = null; 236 237 try { 238 lastId = existingIds.last(); 239 } catch (NoSuchElementException ex) { 240 lastId = new Integer(0); 241 } 242 243 Integer newId = new Integer(lastId.intValue() + 1); 244 245 // while (m_loadedRTuplesMap.containsKey(newId)) { 246 // if (m_log.isWarnEnabled()) { 247 // m_log.warn("Key already existed in m_loadedRTuplesMap: " 248 // + newId + ". *generating a new one*"); 249 // } 250 // 251 // newId = new Integer(newId.intValue() + 1); 252 // } 253 254 if (m_log.isDebugEnabled()) { 255 m_log.debug("Identified new RTuple. id:" + newId + ", identifier: " 256 + identifier); 257 } 258 259 // Register new RTuple 260 m_identifiedRTuplesMap.put(identifier, newId); 261 m_loadedRTuplesMap.put(newId, rTuple); 262 } 263 264 /** 265 * Used to create a textual identifier for a RTuple 266 * 267 * @param rTuple 268 * @return the identifier (name + "-" + rType) 269 * @throws RuntimeException 270 * if rtuple is null 271 */ 272 public static String createIdentifierForRTuple(RTuple rTuple) { 273 if (rTuple == null) { 274 throw new RuntimeException("RTuple input should not be null"); 275 } 276 277 final String m_name = ((ATermApplImpl) rTuple.getVariable() 278 .getArgument(0)).getName(); 279 // TODO is it wise to use the toString() method 280 final String m_rType = rTuple.getRtype().toString(); 281 282 final String identifier = m_name + "-" + m_rType; 283 284 return identifier; 285 } 286 }