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 }