1 |
| package org.drools.reteoo; |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| |
11 |
| |
12 |
| |
13 |
| |
14 |
| |
15 |
| |
16 |
| |
17 |
| |
18 |
| |
19 |
| |
20 |
| |
21 |
| |
22 |
| |
23 |
| |
24 |
| |
25 |
| |
26 |
| |
27 |
| |
28 |
| |
29 |
| |
30 |
| |
31 |
| |
32 |
| |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| |
40 |
| |
41 |
| |
42 |
| |
43 |
| import java.beans.PropertyChangeEvent; |
44 |
| import java.beans.PropertyChangeListener; |
45 |
| import java.lang.reflect.InvocationTargetException; |
46 |
| import java.lang.reflect.Method; |
47 |
| import java.util.ArrayList; |
48 |
| import java.util.HashMap; |
49 |
| import java.util.Iterator; |
50 |
| import java.util.LinkedList; |
51 |
| import java.util.List; |
52 |
| import java.util.Map; |
53 |
| |
54 |
| import org.drools.FactException; |
55 |
| import org.drools.FactHandle; |
56 |
| import org.drools.NoSuchFactHandleException; |
57 |
| import org.drools.NoSuchFactObjectException; |
58 |
| import org.drools.RuleBase; |
59 |
| import org.drools.WorkingMemory; |
60 |
| import org.drools.event.WorkingMemoryEventListener; |
61 |
| import org.drools.event.WorkingMemoryEventSupport; |
62 |
| import org.drools.spi.AgendaFilter; |
63 |
| import org.drools.spi.AsyncExceptionHandler; |
64 |
| import org.drools.util.IdentityMap; |
65 |
| import org.drools.util.PrimitiveLongMap; |
66 |
| import org.drools.util.PrimitiveLongStack; |
67 |
| |
68 |
| |
69 |
| |
70 |
| |
71 |
| |
72 |
| |
73 |
| |
74 |
| class WorkingMemoryImpl |
75 |
| implements |
76 |
| WorkingMemory, |
77 |
| PropertyChangeListener |
78 |
| { |
79 |
| |
80 |
| |
81 |
| |
82 |
| private static final Class[] ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES = new Class[]{PropertyChangeListener.class}; |
83 |
| |
84 |
| |
85 |
| |
86 |
| |
87 |
| |
88 |
| |
89 |
| private final Object[] addRemovePropertyChangeListenerArgs = new Object[]{this}; |
90 |
| |
91 |
| |
92 |
| private final Map joinMemories = new HashMap( ); |
93 |
| |
94 |
| |
95 |
| private final Map applicationData = new HashMap( ); |
96 |
| |
97 |
| |
98 |
| private final PrimitiveLongMap objects = new PrimitiveLongMap( 32, |
99 |
| 8 ); |
100 |
| |
101 |
| |
102 |
| private final Map handles = new IdentityMap( ); |
103 |
| private final PrimitiveLongStack factHandlePool = new PrimitiveLongStack( ); |
104 |
| |
105 |
| |
106 |
| private final WorkingMemoryEventSupport eventSupport = new WorkingMemoryEventSupport( this ); |
107 |
| |
108 |
| |
109 |
| private final RuleBaseImpl ruleBase; |
110 |
| |
111 |
| |
112 |
| private final Agenda agenda; |
113 |
| |
114 |
| |
115 |
| private boolean firing; |
116 |
| |
117 |
| |
118 |
| |
119 |
| |
120 |
| |
121 |
| |
122 |
| |
123 |
| |
124 |
| |
125 |
| |
126 |
| |
127 |
71
| public WorkingMemoryImpl(RuleBaseImpl ruleBase)
|
128 |
| { |
129 |
71
| this.ruleBase = ruleBase;
|
130 |
71
| this.agenda = new Agenda( this,
|
131 |
| ruleBase.getConflictResolver( ) ); |
132 |
| } |
133 |
| |
134 |
| |
135 |
| |
136 |
| |
137 |
| |
138 |
3
| public void addEventListener(WorkingMemoryEventListener listener)
|
139 |
| { |
140 |
3
| this.eventSupport.addEventListener( listener );
|
141 |
| } |
142 |
| |
143 |
0
| public void removeEventListener(WorkingMemoryEventListener listener)
|
144 |
| { |
145 |
0
| this.eventSupport.removeEventListener( listener );
|
146 |
| } |
147 |
| |
148 |
2
| public List getEventListeners()
|
149 |
| { |
150 |
2
| return eventSupport.getEventListeners( );
|
151 |
| } |
152 |
| |
153 |
| |
154 |
| |
155 |
| |
156 |
| |
157 |
| |
158 |
872
| FactHandle newFactHandle()
|
159 |
| { |
160 |
872
| if ( !this.factHandlePool.isEmpty( ) )
|
161 |
| { |
162 |
0
| return this.ruleBase.getFactHandleFactory( ).newFactHandle( this.factHandlePool.pop( ) );
|
163 |
| } |
164 |
| else |
165 |
| { |
166 |
872
| return this.ruleBase.getFactHandleFactory( ).newFactHandle( );
|
167 |
| } |
168 |
| } |
169 |
| |
170 |
| |
171 |
| |
172 |
| |
173 |
39488
| public Map getApplicationDataMap()
|
174 |
| { |
175 |
39488
| return this.applicationData;
|
176 |
| } |
177 |
| |
178 |
| |
179 |
| |
180 |
| |
181 |
1
| public void setApplicationData(String name,
|
182 |
| Object value) |
183 |
| { |
184 |
| |
185 |
1
| Map applicationDataDefintions = this.ruleBase.getApplicationData( );
|
186 |
1
| Class type = (Class) applicationDataDefintions.get( name );
|
187 |
1
| if ( ( type == null ) )
|
188 |
| { |
189 |
0
| throw new RuntimeException( "Unexpected application data [" + name + "]" );
|
190 |
| } |
191 |
1
| else if ( !type.isInstance( value ) )
|
192 |
| { |
193 |
0
| throw new RuntimeException( "Illegal class for application data. " +
|
194 |
| "Expected [" + type.getName() + "], " + |
195 |
| "found [" + value.getClass().getName() + "]." ); |
196 |
| |
197 |
| } |
198 |
| else |
199 |
| { |
200 |
1
| this.applicationData.put( name,
|
201 |
| value ); |
202 |
| } |
203 |
| } |
204 |
| |
205 |
| |
206 |
| |
207 |
| |
208 |
51
| public Object getApplicationData(String name)
|
209 |
| { |
210 |
51
| return this.applicationData.get( name );
|
211 |
| } |
212 |
| |
213 |
| |
214 |
| |
215 |
| |
216 |
| |
217 |
| |
218 |
| |
219 |
7080
| protected Agenda getAgenda()
|
220 |
| { |
221 |
7080
| return this.agenda;
|
222 |
| } |
223 |
| |
224 |
| |
225 |
| |
226 |
| |
227 |
2
| public void clearAgenda()
|
228 |
| { |
229 |
2
| this.agenda.clearAgenda( );
|
230 |
| } |
231 |
| |
232 |
| |
233 |
| |
234 |
| |
235 |
2
| public RuleBase getRuleBase()
|
236 |
| { |
237 |
2
| return this.ruleBase;
|
238 |
| } |
239 |
| |
240 |
16
| public synchronized void fireAllRules(AgendaFilter agendaFilter) throws FactException
|
241 |
| { |
242 |
| |
243 |
| |
244 |
| |
245 |
| |
246 |
| |
247 |
16
| if ( !firing )
|
248 |
| { |
249 |
16
| try
|
250 |
| { |
251 |
16
| firing = true;
|
252 |
| |
253 |
16
| while ( !agenda.isEmpty( ) )
|
254 |
| { |
255 |
378
| agenda.fireNextItem( agendaFilter );
|
256 |
| } |
257 |
| } |
258 |
| finally |
259 |
| { |
260 |
16
| firing = false;
|
261 |
| } |
262 |
| } |
263 |
| } |
264 |
| |
265 |
| |
266 |
| |
267 |
| |
268 |
16
| public void fireAllRules() throws FactException
|
269 |
| { |
270 |
16
| fireAllRules( null );
|
271 |
| } |
272 |
| |
273 |
| |
274 |
| |
275 |
| |
276 |
84673
| public Object getObject(FactHandle handle) throws NoSuchFactObjectException
|
277 |
| { |
278 |
84673
| Object object = this.objects.get( ((FactHandleImpl) handle).getId( ) );
|
279 |
| |
280 |
84673
| if ( object == null )
|
281 |
| { |
282 |
0
| throw new NoSuchFactObjectException( handle );
|
283 |
| } |
284 |
| |
285 |
84673
| return object;
|
286 |
| } |
287 |
| |
288 |
| |
289 |
| |
290 |
| |
291 |
361
| public FactHandle getFactHandle(Object object) throws NoSuchFactHandleException
|
292 |
| { |
293 |
361
| FactHandle factHandle = (FactHandle) this.handles.get( object );
|
294 |
| |
295 |
361
| if ( factHandle == null )
|
296 |
| { |
297 |
0
| throw new NoSuchFactHandleException( object );
|
298 |
| } |
299 |
| |
300 |
361
| return factHandle;
|
301 |
| } |
302 |
| |
303 |
1
| public List getFactHandles()
|
304 |
| { |
305 |
1
| return new ArrayList( this.handles.values( ) );
|
306 |
| } |
307 |
| |
308 |
| |
309 |
| |
310 |
| |
311 |
23
| public List getObjects()
|
312 |
| { |
313 |
23
| return new ArrayList( this.objects.values( ) );
|
314 |
| } |
315 |
| |
316 |
0
| public List getObjects(Class objectClass)
|
317 |
| { |
318 |
0
| List matching = new LinkedList( );
|
319 |
0
| Iterator objIter = this.objects.values( ).iterator( );
|
320 |
0
| Object obj;
|
321 |
0
| while ( objIter.hasNext( ) )
|
322 |
| { |
323 |
0
| obj = objIter.next( );
|
324 |
| |
325 |
0
| if ( objectClass.isInstance( obj ) )
|
326 |
| { |
327 |
0
| matching.add( obj );
|
328 |
| } |
329 |
| } |
330 |
| |
331 |
0
| return matching;
|
332 |
| } |
333 |
| |
334 |
| |
335 |
| |
336 |
| |
337 |
8
| public boolean containsObject(FactHandle handle)
|
338 |
| { |
339 |
8
| return this.objects.containsKey( ((FactHandleImpl) handle).getId( ) );
|
340 |
| } |
341 |
| |
342 |
| |
343 |
| |
344 |
| |
345 |
873
| public FactHandle assertObject(Object object) throws FactException
|
346 |
| { |
347 |
873
| return assertObject( object,
|
348 |
| false ); |
349 |
| } |
350 |
| |
351 |
873
| public synchronized FactHandle assertObject(Object object,
|
352 |
| boolean dynamic) throws FactException |
353 |
| { |
354 |
873
| FactHandle handle = (FactHandle) handles.get( object );
|
355 |
| |
356 |
873
| if ( handle != null )
|
357 |
| { |
358 |
1
| return handle;
|
359 |
| } |
360 |
| |
361 |
872
| handle = newFactHandle( );
|
362 |
| |
363 |
872
| putObject( handle,
|
364 |
| object ); |
365 |
| |
366 |
872
| if ( dynamic )
|
367 |
| { |
368 |
0
| addPropertyChangeListener( object );
|
369 |
| } |
370 |
| |
371 |
872
| this.agenda.setMode( Agenda.ASSERT );
|
372 |
872
| ruleBase.assertObject( handle,
|
373 |
| object, |
374 |
| this ); |
375 |
| |
376 |
872
| eventSupport.fireObjectAsserted( handle,
|
377 |
| object ); |
378 |
872
| this.agenda.setMode( Agenda.NONE );
|
379 |
872
| return handle;
|
380 |
| } |
381 |
| |
382 |
0
| private void addPropertyChangeListener(Object object)
|
383 |
| { |
384 |
0
| try
|
385 |
| { |
386 |
0
| Method method = object.getClass( ).getMethod( "addPropertyChangeListener",
|
387 |
| ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES ); |
388 |
| |
389 |
0
| method.invoke( object,
|
390 |
| addRemovePropertyChangeListenerArgs ); |
391 |
| } |
392 |
| catch ( NoSuchMethodException e ) |
393 |
| { |
394 |
0
| System.err.println( "Warning: Method addPropertyChangeListener not found"
|
395 |
| + " on the class " + object.getClass( ) |
396 |
| + " so Drools will be unable to process JavaBean" |
397 |
| + " PropertyChangeEvents on the asserted Object" ); |
398 |
| } |
399 |
| catch ( IllegalArgumentException e ) |
400 |
| { |
401 |
0
| System.err.println( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass( ) + " does not take" + " a simple PropertyChangeListener argument" + " so Drools will be unable to process JavaBean"
|
402 |
| + " PropertyChangeEvents on the asserted Object" ); |
403 |
| } |
404 |
| catch ( IllegalAccessException e ) |
405 |
| { |
406 |
0
| System.err.println( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass( ) + " is not public" + " so Drools will be unable to process JavaBean" + " PropertyChangeEvents on the asserted Object" );
|
407 |
| } |
408 |
| catch ( InvocationTargetException e ) |
409 |
| { |
410 |
0
| System.err.println( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass( ) + " threw an InvocationTargetException" + " so Drools will be unable to process JavaBean"
|
411 |
| + " PropertyChangeEvents on the asserted Object: " + e.getMessage( ) ); |
412 |
| } |
413 |
| catch ( SecurityException e ) |
414 |
| { |
415 |
0
| System.err.println( "Warning: The SecurityManager controlling the class " + object.getClass( ) + " did not allow the lookup of a" + " addPropertyChangeListener method" + " so Drools will be unable to process JavaBean"
|
416 |
| + " PropertyChangeEvents on the asserted Object: " + e.getMessage( ) ); |
417 |
| } |
418 |
| } |
419 |
| |
420 |
54
| private void removePropertyChangeListener(FactHandle handle) throws NoSuchFactObjectException
|
421 |
| { |
422 |
54
| Object object = null;
|
423 |
54
| try
|
424 |
| { |
425 |
54
| object = getObject( handle );
|
426 |
| |
427 |
54
| Method mehod = handle.getClass( ).getMethod( "removePropertyChangeListener",
|
428 |
| ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES ); |
429 |
| |
430 |
0
| mehod.invoke( handle,
|
431 |
| addRemovePropertyChangeListenerArgs ); |
432 |
| } |
433 |
| catch ( NoSuchMethodException e ) |
434 |
| { |
435 |
| |
436 |
| |
437 |
| |
438 |
| |
439 |
| } |
440 |
| catch ( IllegalArgumentException e ) |
441 |
| { |
442 |
0
| System.err.println( "Warning: The removePropertyChangeListener method" + " on the class " + object.getClass( ) + " does not take" + " a simple PropertyChangeListener argument" + " so Drools will be unable to stop processing JavaBean"
|
443 |
| + " PropertyChangeEvents on the retracted Object" ); |
444 |
| } |
445 |
| catch ( IllegalAccessException e ) |
446 |
| { |
447 |
0
| System.err.println( "Warning: The removePropertyChangeListener method" + " on the class " + object.getClass( ) + " is not public" + " so Drools will be unable to stop processing JavaBean" + " PropertyChangeEvents on the retracted Object" );
|
448 |
| } |
449 |
| catch ( InvocationTargetException e ) |
450 |
| { |
451 |
0
| System.err.println( "Warning: The removePropertyChangeL istener method" + " on the class " + object.getClass( ) + " threw an InvocationTargetException" + " so Drools will be unable to stop processing JavaBean"
|
452 |
| + " PropertyChangeEvents on the retracted Object: " + e.getMessage( ) ); |
453 |
| } |
454 |
| catch ( SecurityException e ) |
455 |
| { |
456 |
0
| System.err.println( "Warning: The SecurityManager controlling the class " + object.getClass( ) + " did not allow the lookup of a" + " removePropertyChangeListener method" + " so Drools will be unable to stop processing JavaBean"
|
457 |
| + " PropertyChangeEvents on the retracted Object: " + e.getMessage( ) ); |
458 |
| } |
459 |
| } |
460 |
| |
461 |
| |
462 |
| |
463 |
| |
464 |
| |
465 |
| |
466 |
| |
467 |
| |
468 |
| |
469 |
1193
| Object putObject(FactHandle handle,
|
470 |
| Object object) |
471 |
| { |
472 |
1193
| Object oldValue = this.objects.put( ((FactHandleImpl) handle).getId( ),
|
473 |
| object ); |
474 |
| |
475 |
1193
| this.handles.put( object,
|
476 |
| handle ); |
477 |
| |
478 |
1193
| return oldValue;
|
479 |
| } |
480 |
| |
481 |
370
| Object removeObject(FactHandle handle)
|
482 |
| { |
483 |
370
| Object object = this.objects.remove( ((FactHandleImpl) handle).getId( ) );
|
484 |
| |
485 |
370
| this.handles.remove( object );
|
486 |
| |
487 |
370
| return object;
|
488 |
| } |
489 |
| |
490 |
| |
491 |
| |
492 |
| |
493 |
54
| public synchronized void retractObject(FactHandle handle) throws FactException
|
494 |
| { |
495 |
54
| removePropertyChangeListener( handle );
|
496 |
| |
497 |
54
| this.agenda.setMode( Agenda.RETRACT );
|
498 |
| |
499 |
54
| ruleBase.retractObject( handle,
|
500 |
| this ); |
501 |
| |
502 |
54
| Object oldObject = removeObject( handle );
|
503 |
| |
504 |
54
| factHandlePool.push( ((FactHandleImpl) handle).getId( ) );
|
505 |
| |
506 |
54
| eventSupport.fireObjectRetracted( handle,
|
507 |
| oldObject ); |
508 |
54
| this.agenda.setMode( Agenda.NONE );
|
509 |
| |
510 |
54
| ((FactHandleImpl) handle).invalidate( );
|
511 |
| } |
512 |
| |
513 |
| |
514 |
| |
515 |
| |
516 |
316
| public synchronized void modifyObject(FactHandle handle,
|
517 |
| Object object) throws FactException |
518 |
| { |
519 |
316
| Object originalObject = removeObject( handle );
|
520 |
| |
521 |
316
| if ( originalObject == null )
|
522 |
| { |
523 |
0
| throw new NoSuchFactObjectException( handle );
|
524 |
| } |
525 |
| |
526 |
316
| putObject( handle,
|
527 |
| object ); |
528 |
| |
529 |
316
| this.agenda.setMode( Agenda.MODIFY );
|
530 |
| |
531 |
316
| this.ruleBase.retractObject( handle,
|
532 |
| this ); |
533 |
| |
534 |
316
| this.ruleBase.assertObject( handle,
|
535 |
| object, |
536 |
| this ); |
537 |
| |
538 |
316
| this.agenda.removeMarkedItemsFromAgenda( );
|
539 |
| |
540 |
316
| this.agenda.setMode( Agenda.NONE );
|
541 |
| |
542 |
| |
543 |
| |
544 |
| |
545 |
316
| this.eventSupport.fireObjectModified( handle,
|
546 |
| originalObject, |
547 |
| object ); |
548 |
| } |
549 |
| |
550 |
| |
551 |
| |
552 |
| |
553 |
| |
554 |
| |
555 |
| |
556 |
| |
557 |
| |
558 |
| |
559 |
3557
| public JoinMemory getJoinMemory(JoinNode node)
|
560 |
| { |
561 |
3557
| JoinMemory memory = (JoinMemory) this.joinMemories.get( node );
|
562 |
| |
563 |
3557
| if ( memory == null )
|
564 |
| { |
565 |
52
| memory = new JoinMemory( node.getTupleDeclarations( ),
|
566 |
| node.getCommonDeclarations( ) ); |
567 |
| |
568 |
52
| this.joinMemories.put( node,
|
569 |
| memory ); |
570 |
| } |
571 |
| |
572 |
3557
| return memory;
|
573 |
| } |
574 |
| |
575 |
59894
| public WorkingMemoryEventSupport getEventSupport()
|
576 |
| { |
577 |
59894
| return eventSupport;
|
578 |
| } |
579 |
| |
580 |
| |
581 |
| |
582 |
| |
583 |
| |
584 |
| |
585 |
| |
586 |
1
| public void setAsyncExceptionHandler(AsyncExceptionHandler handler)
|
587 |
| { |
588 |
1
| this.agenda.setAsyncExceptionHandler( handler );
|
589 |
| } |
590 |
| |
591 |
0
| public void dumpMemory()
|
592 |
| { |
593 |
0
| Iterator it = this.joinMemories.keySet( ).iterator( );
|
594 |
0
| while ( it.hasNext( ) )
|
595 |
| { |
596 |
0
| ((JoinMemory) this.joinMemories.get( it.next( ) )).dump( );
|
597 |
| } |
598 |
| |
599 |
| } |
600 |
| |
601 |
0
| public void propertyChange(PropertyChangeEvent event)
|
602 |
| { |
603 |
0
| Object object = event.getSource( );
|
604 |
| |
605 |
0
| try
|
606 |
| { |
607 |
0
| modifyObject( getFactHandle( object ),
|
608 |
| object ); |
609 |
| } |
610 |
| catch ( NoSuchFactHandleException e ) |
611 |
| { |
612 |
| |
613 |
| } |
614 |
| catch ( FactException e ) |
615 |
| { |
616 |
0
| throw new RuntimeException( e.getMessage( ) );
|
617 |
| } |
618 |
| } |
619 |
| } |