001 package toolbus.matching; 002 003 import java.util.ArrayList; 004 import java.util.HashMap; 005 import java.util.HashSet; 006 import java.util.Iterator; 007 import java.util.LinkedList; 008 import java.util.List; 009 import java.util.Map; 010 import java.util.Set; 011 012 import toolbus.TBTermFactory; 013 import toolbus.atom.Atom; 014 import toolbus.atom.msg.RecMsg; 015 import toolbus.atom.msg.SndMsg; 016 import toolbus.atom.note.SndNote; 017 import toolbus.atom.note.Subscribe; 018 import toolbus.process.ProcessInstance; 019 import toolbus.util.collections.ConcurrentHashMap; 020 import aterm.ATerm; 021 022 /** 023 * This store keeps track of all links between sending and receiving communication atoms. 024 * 025 * @author Arnold Lankamp 026 */ 027 public class MatchStore{ 028 private final static List<RecMsg> NOMESSAGEPARTNERS = new ArrayList<RecMsg>(0); 029 private final static Set<ProcessInstance> NONOTEPARTNERS = new HashSet<ProcessInstance>(0); 030 031 private final TBTermFactory tbFactory; 032 private volatile List<Atom> atomSet; 033 034 private final ConcurrentHashMap<ATerm, List<ATerm>> messageLinks; 035 private final ConcurrentHashMap<ATerm, List<ATerm>> noteLinks; 036 037 private final Map<ATerm, List<RecMsg>> messageMappings; 038 private final Map<ATerm, Map<ProcessInstance, MappingRefCount>> noteMappings; 039 040 private final Object messageLock = new Object(); 041 private final Object noteLock = new Object(); 042 043 /** 044 * Constructor. 045 * 046 * @param tbTermFactory 047 * The term factory to use for matching. 048 */ 049 public MatchStore(TBTermFactory tbTermFactory){ 050 super(); 051 052 this.tbFactory = tbTermFactory; 053 054 messageLinks = new ConcurrentHashMap<ATerm, List<ATerm>>(); 055 noteLinks = new ConcurrentHashMap<ATerm, List<ATerm>>(); 056 057 messageMappings = new HashMap<ATerm, List<RecMsg>>(); 058 noteMappings = new HashMap<ATerm, Map<ProcessInstance, MappingRefCount>>(); 059 } 060 061 /** 062 * Initializes this match store with the given set of atoms. 063 * 064 * @param atomSet 065 * The complete collection of atoms, for which the relations must to be calculated. 066 */ 067 public void initialize(List<Atom> atomSet){ 068 this.atomSet = atomSet; 069 070 calculateMatches(); 071 } 072 073 /** 074 * Staticly determains all (potential) relations between the atoms. 075 */ 076 private void calculateMatches(){ 077 List<ATerm> receiveMessages = new LinkedList<ATerm>(); 078 List<ATerm> subscribeNotes = new LinkedList<ATerm>(); 079 080 Iterator<Atom> atomsIteratorForRecMsg = atomSet.iterator(); 081 while(atomsIteratorForRecMsg.hasNext()){ 082 Atom atom = atomsIteratorForRecMsg.next(); 083 if(atom instanceof RecMsg){ 084 addReceiveMessagePattern((RecMsg) atom, receiveMessages); 085 }else if(atom instanceof Subscribe){ 086 addSubscribeNotePattern((Subscribe) atom, subscribeNotes); 087 } 088 } 089 090 Iterator<Atom> atomsIteratorForSndMsg = atomSet.iterator(); 091 while(atomsIteratorForSndMsg.hasNext()){ 092 Atom atom = atomsIteratorForSndMsg.next(); 093 if(atom instanceof SndMsg){ 094 addSendMessagePattern((SndMsg) atom, receiveMessages); 095 }else if(atom instanceof SndNote){ 096 addSendNotePattern((SndNote) atom, subscribeNotes); 097 } 098 } 099 } 100 101 /** 102 * Indexes the given receive message atom. 103 * 104 * @param message 105 * The receive message atom. 106 * @param receiveMessages 107 * The list to add the message's match pattern to. 108 */ 109 private void addReceiveMessagePattern(RecMsg message, List<ATerm> receiveMessages){ 110 ATerm matchPattern = message.msg; 111 receiveMessages.add(matchPattern); 112 messageLinks.put(matchPattern, new ArrayList<ATerm>()); 113 } 114 115 /** 116 * Indexes the given send message atom. NOTE: All receive message atoms need to have been added 117 * prior to the invokation of this method, otherwise the the ToolBus may exhibit undefined 118 * runtime behaviour. 119 * 120 * @param message 121 * The send message atom. 122 * @param receiveMessages 123 * The complete list of receive messages. 124 */ 125 private void addSendMessagePattern(SndMsg message, List<ATerm> receiveMessages){ 126 ATerm matchPattern = message.msg; 127 128 Iterator<ATerm> receiveMessagePatternIterator = receiveMessages.iterator(); 129 while(receiveMessagePatternIterator.hasNext()){ 130 ATerm receiveMessagePattern = receiveMessagePatternIterator.next(); 131 132 if(tbFactory.mightMatch(matchPattern, receiveMessagePattern)){ 133 List<ATerm> sendMessageList = messageLinks.get(receiveMessagePattern); 134 sendMessageList.add(matchPattern); 135 } 136 } 137 } 138 139 /** 140 * Indexes the given subscribe atom. 141 * 142 * @param subscribeNote 143 * The subscribe atom. 144 * @param subscribeNotes 145 * The list to add the subscribe's match pattern to. 146 */ 147 private void addSubscribeNotePattern(Subscribe subscribeNote, List<ATerm> subscribeNotes){ 148 ATerm matchPattern = subscribeNote.notePattern; 149 subscribeNotes.add(matchPattern); 150 noteLinks.put(matchPattern, new ArrayList<ATerm>()); 151 } 152 153 /** 154 * Indexes the given send note atom. NOTE: All subscribe atoms need to have been added prior to 155 * the invokation of this method, otherwise the the ToolBus may exhibit undefined runtime 156 * behaviour. 157 * 158 * @param message 159 * The send note atom. 160 * @param subscribeNotes 161 * The complete list of subscribes. 162 */ 163 private void addSendNotePattern(SndNote message, List<ATerm> subscribeNotes){ 164 ATerm matchPattern = message.notePattern; 165 166 Iterator<ATerm> subscribeNotePatternIterator = subscribeNotes.iterator(); 167 while(subscribeNotePatternIterator.hasNext()){ 168 ATerm subscribeNotePattern = subscribeNotePatternIterator.next(); 169 170 if(tbFactory.mightMatch(matchPattern, subscribeNotePattern)){ 171 List<ATerm> sendNoteList = noteLinks.get(subscribeNotePattern); 172 sendNoteList.add(matchPattern); 173 } 174 } 175 } 176 177 /** 178 * Registers the given, instantiated, receive message atom. 179 * 180 * @param receiveMessage 181 * The receive message atom to register. 182 */ 183 public void registerReceiveMessage(RecMsg receiveMessage){ 184 List<ATerm> matches = messageLinks.get(receiveMessage.msg); 185 if(matches == null) return; 186 187 Iterator<ATerm> matchesIterator = matches.iterator(); 188 189 synchronized(messageLock){ 190 while(matchesIterator.hasNext()){ 191 ATerm pattern = matchesIterator.next(); 192 List<RecMsg> receiveMessageList = messageMappings.get(pattern); 193 if(receiveMessageList == null){ 194 receiveMessageList = new LinkedList<RecMsg>(); 195 messageMappings.put(pattern, receiveMessageList); 196 } 197 receiveMessageList.add(receiveMessage); 198 } 199 } 200 } 201 202 /** 203 * Deregisteres the given, instantiated, receive message atom. 204 * 205 * @param receiveMessage 206 * The receive message atom to deregister. 207 */ 208 public void deregisterReceiveMessage(RecMsg receiveMessage){ 209 List<ATerm> matches = messageLinks.get(receiveMessage.msg); 210 if(matches == null) return; 211 212 Iterator<ATerm> matchesIterator = matches.iterator(); 213 214 synchronized(messageLock){ 215 while(matchesIterator.hasNext()){ 216 ATerm pattern = matchesIterator.next(); 217 List<RecMsg> receiveMessageList = messageMappings.get(pattern); 218 receiveMessageList.remove(receiveMessage); 219 } 220 } 221 } 222 223 /** 224 * Gathers the potential partners for the given send message pattern. 225 * 226 * @param pattern 227 * The send message pattern. 228 * @return The collections of potentially matching partners. 229 */ 230 public List<RecMsg> getPossibleMessagePartners(ATerm pattern){ 231 List<RecMsg> recMessages; 232 233 synchronized(messageLock){ 234 recMessages = messageMappings.get(pattern); 235 } 236 237 if(recMessages == null) return NOMESSAGEPARTNERS; 238 239 return recMessages; 240 } 241 242 /** 243 * Reference count structure. 244 * 245 * @author Arnold Lankamp 246 */ 247 private static class MappingRefCount{ 248 public int nrOfMappings; 249 } 250 251 /** 252 * Registers the given, instantiated, subscribe atom. 253 * 254 * @param subscribeNote 255 * The subscribe atom to register. 256 */ 257 public void registerSubscribeNote(Subscribe subscribeNote){ 258 List<ATerm> matches = noteLinks.get(subscribeNote.notePattern); 259 if(matches == null) return; 260 261 Iterator<ATerm> matchesIterator = matches.iterator(); 262 263 synchronized(noteLock){ 264 while(matchesIterator.hasNext()){ 265 ProcessInstance pi = subscribeNote.getProcess(); 266 267 ATerm pattern = matchesIterator.next(); 268 Map<ProcessInstance, MappingRefCount> subscribeMappingsMap = noteMappings.get(pattern); 269 if(subscribeMappingsMap == null){ 270 subscribeMappingsMap = new HashMap<ProcessInstance, MappingRefCount>(4); 271 noteMappings.put(pattern, subscribeMappingsMap); 272 273 274 MappingRefCount mrc = new MappingRefCount(); 275 mrc.nrOfMappings = 1; 276 subscribeMappingsMap.put(pi, mrc); 277 }else{ 278 MappingRefCount existingValue = subscribeMappingsMap.get(pi); 279 if(existingValue != null){ 280 existingValue.nrOfMappings++; 281 }else{ 282 MappingRefCount mrc = new MappingRefCount(); 283 mrc.nrOfMappings = 1; 284 subscribeMappingsMap.put(pi, mrc); 285 } 286 } 287 } 288 } 289 } 290 291 /** 292 * Deregisters the given, instantiated, subscribe atom. 293 * 294 * @param subscribeNote 295 * The subscribe atom to deregister. 296 */ 297 public void deregisterSubscribeNote(Subscribe subscribeNote){ 298 List<ATerm> matches = noteLinks.get(subscribeNote.notePattern); 299 if(matches == null) return; 300 301 Iterator<ATerm> matchesIterator = matches.iterator(); 302 303 synchronized(noteLock){ 304 while(matchesIterator.hasNext()){ 305 ATerm pattern = matchesIterator.next(); 306 Map<ProcessInstance, MappingRefCount> subscribeMappingsMap = noteMappings.get(pattern); 307 308 MappingRefCount mapping = subscribeMappingsMap.get(subscribeNote.getProcess()); 309 if((--mapping.nrOfMappings) == 0){ 310 subscribeMappingsMap.remove(mapping); 311 } 312 } 313 } 314 } 315 316 /** 317 * Gathers the potential partners for the given send note pattern. 318 * 319 * @param pattern 320 * The send message pattern. 321 * @return The collections of potentially matching partners. 322 */ 323 public Set<ProcessInstance> getPossibleNotePartners(ATerm pattern){ 324 synchronized(noteLock){ 325 Map<ProcessInstance, MappingRefCount> subNotesMappings = noteMappings.get(pattern); 326 if(subNotesMappings == null) return NONOTEPARTNERS; 327 328 return subNotesMappings.keySet(); 329 } 330 } 331 332 /** 333 * Dumps a list of partnerless communication atoms to standard out. 334 */ 335 public void printPartnerlessCommunicationAtoms(){ 336 printPartnerlessSenders(); 337 printPartnerlessReceivers(); 338 } 339 340 /** 341 * Gathers a list of partnerless message sending atoms. 342 * 343 * @return A list of partnerless message sending atoms. 344 */ 345 public List<SndMsg> findPartnerlessSendMessageAtoms(){ 346 List<SndMsg> deadSendMessageAtoms = new ArrayList<SndMsg>(); 347 348 List<ATerm> receiveMessages = new LinkedList<ATerm>(); 349 350 Iterator<Atom> atomsIteratorForRecMsg = atomSet.iterator(); 351 while(atomsIteratorForRecMsg.hasNext()){ 352 Atom atom = atomsIteratorForRecMsg.next(); 353 if(atom instanceof RecMsg){ 354 receiveMessages.add(((RecMsg) atom).msg); 355 } 356 } 357 358 Iterator<Atom> atomsIteratorForSndMsg = atomSet.iterator(); 359 while(atomsIteratorForSndMsg.hasNext()){ 360 Atom atom = atomsIteratorForSndMsg.next(); 361 362 if(atom instanceof SndMsg){ 363 SndMsg sendMessage = (SndMsg) atom; 364 ATerm matchPattern = sendMessage.msg; 365 366 boolean added = false; 367 368 Iterator<ATerm> receiveMessagePatternIterator = receiveMessages.iterator(); 369 while(receiveMessagePatternIterator.hasNext()){ 370 ATerm receiveMessagePattern = receiveMessagePatternIterator.next(); 371 372 if(tbFactory.mightMatch(matchPattern, receiveMessagePattern)){ 373 added = true; 374 break; 375 } 376 } 377 378 if(!added) deadSendMessageAtoms.add(sendMessage); 379 } 380 } 381 382 return deadSendMessageAtoms; 383 } 384 385 /** 386 * Gathers a list of partnerless note sending atoms. 387 * 388 * @return A list of partnerless note sending atoms. 389 */ 390 public List<SndNote> findPartnerlessSendNoteAtoms(){ 391 List<SndNote> deadSendNoteAtoms = new ArrayList<SndNote>(); 392 393 List<ATerm> subscribeNotes = new LinkedList<ATerm>(); 394 395 Iterator<Atom> atomsIteratorForRecMsg = atomSet.iterator(); 396 while(atomsIteratorForRecMsg.hasNext()){ 397 Atom atom = atomsIteratorForRecMsg.next(); 398 if(atom instanceof Subscribe){ 399 subscribeNotes.add(((Subscribe) atom).notePattern); 400 } 401 } 402 403 Iterator<Atom> atomsIteratorForSndMsg = atomSet.iterator(); 404 while(atomsIteratorForSndMsg.hasNext()){ 405 Atom atom = atomsIteratorForSndMsg.next(); 406 407 if(atom instanceof SndNote){ 408 SndNote sendNote = (SndNote) atom; 409 ATerm matchPattern = sendNote.notePattern; 410 411 boolean added = false; 412 413 Iterator<ATerm> subscribeNotePatternIterator = subscribeNotes.iterator(); 414 while(subscribeNotePatternIterator.hasNext()){ 415 ATerm subscribeNotePattern = subscribeNotePatternIterator.next(); 416 417 if(tbFactory.mightMatch(matchPattern, subscribeNotePattern)){ 418 added = true; 419 break; 420 } 421 } 422 423 if(!added) deadSendNoteAtoms.add(sendNote); 424 } 425 } 426 427 return deadSendNoteAtoms; 428 } 429 430 /** 431 * Gathers a list of partnerless message receiving atoms. 432 * 433 * @return A list of partnerless message receiving atoms. 434 */ 435 public List<RecMsg> findPartnerLessReceiveMessageAtoms(){ 436 List<RecMsg> deadReceiveMessageAtoms = new ArrayList<RecMsg>(); 437 438 Iterator<Atom> atomsIterator = atomSet.iterator(); 439 while(atomsIterator.hasNext()){ 440 Atom atom = atomsIterator.next(); 441 if(atom instanceof RecMsg){ 442 RecMsg recMsg = (RecMsg) atom; 443 444 if(messageLinks.get(recMsg.msg).isEmpty()){ 445 deadReceiveMessageAtoms.add(recMsg); 446 } 447 } 448 } 449 450 return deadReceiveMessageAtoms; 451 } 452 453 /** 454 * Gathers a list of partnerless subscribe atoms. 455 * 456 * @return A list of partnerless subscribe atoms. 457 */ 458 public List<Subscribe> findPartnerlessSubscribeAtoms(){ 459 List<Subscribe> deadSubscribeAtoms = new ArrayList<Subscribe>(); 460 461 Iterator<Atom> atomsIterator = atomSet.iterator(); 462 while(atomsIterator.hasNext()){ 463 Atom atom = atomsIterator.next(); 464 465 if(atom instanceof Subscribe){ 466 Subscribe subscribe = (Subscribe) atom; 467 468 if(noteLinks.get(subscribe.notePattern).isEmpty()){ 469 deadSubscribeAtoms.add(subscribe); 470 } 471 } 472 } 473 474 return deadSubscribeAtoms; 475 } 476 477 /** 478 * Dumps a list of partnerless sending atoms to standard out. 479 */ 480 private void printPartnerlessSenders(){ 481 List<SndMsg> deadSendMessageAtoms = findPartnerlessSendMessageAtoms(); 482 List<SndNote> deadSendNoteAtoms = findPartnerlessSendNoteAtoms(); 483 484 List<Atom> deadSendAtoms = new ArrayList<Atom>(); 485 deadSendAtoms.addAll(deadSendMessageAtoms); 486 deadSendAtoms.addAll(deadSendNoteAtoms); 487 488 Set<Atom> partnerlessAtoms = new HashSet<Atom>(); 489 490 Iterator<Atom> deadSendAtomsIterator = deadSendAtoms.iterator(); 491 while(deadSendAtomsIterator.hasNext()){ 492 partnerlessAtoms.add(deadSendAtomsIterator.next()); 493 } 494 495 if((partnerlessAtoms.size()) == 0){ 496 System.out.println("No partnerless send atoms found."); 497 }else{ 498 System.out.println("Partnerless send atoms:"); 499 System.out.println("{"); 500 501 Iterator<Atom> partnerlessMessagesIterator = partnerlessAtoms.iterator(); 502 while(partnerlessMessagesIterator.hasNext()){ 503 Atom sendAtom = partnerlessMessagesIterator.next(); 504 System.out.println("\t"+sendAtom.getPosInfo()+"\t\t: "+sendAtom); 505 } 506 507 System.out.println("}"); 508 } 509 } 510 511 /** 512 * Dumps a list of partnerless receiving atoms to standard out. 513 */ 514 private void printPartnerlessReceivers(){ 515 List<RecMsg> partnerlessReceiveMessageAtoms = findPartnerLessReceiveMessageAtoms(); 516 List<Subscribe> partnerlessSubscribeAtoms = findPartnerlessSubscribeAtoms(); 517 518 List<Atom> partnerlessReceivers = new ArrayList<Atom>(); 519 partnerlessReceivers.addAll(partnerlessReceiveMessageAtoms); 520 partnerlessReceivers.addAll(partnerlessSubscribeAtoms); 521 522 if(partnerlessReceivers.size() == 0){ 523 System.out.println("No partnerless receivers found."); 524 }else{ 525 System.out.println("Partnerless receive atoms:"); 526 System.out.println("{"); 527 528 Iterator<Atom> partnerlessReceiversIterator = partnerlessReceivers.iterator(); 529 while(partnerlessReceiversIterator.hasNext()){ 530 Atom atom = partnerlessReceiversIterator.next(); 531 532 System.out.println("\t"+atom.getPosInfo()+"\t\t: "+atom); 533 } 534 535 System.out.println("}"); 536 } 537 } 538 }