1   /*
2    * Copyright (c)2017 Logic Machine Ltd.
3    *
4    * Logic:Machine Software Development Studio assert their moral right
5    * to be acknowledged as the original authors of this work.
6    *
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as published
9    * by the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU Lesser General Public License for more details.
16   *
17   * For the full text of the license, see the following file:
18   *
19   *     LICENSE_LGPL.txt
20   *
21   * or
22   *
23   *     https://www.logicmachine.co.uk/licenses/rebl/index.html
24   *
25   * You should have received a copy of the GNU Lesser General Public License
26   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
27   *
28   */
29  
30  package org.logicmachine.rebl.unitTest.language.context;
31  
32  import static org.junit.Assert.assertEquals;
33  import static org.junit.Assert.fail;
34  import static org.logicmachine.rebl.common.Constants.ARROW;
35  import static org.logicmachine.rebl.common.Constants.COLON;
36  import static org.logicmachine.rebl.common.Constants.DEFAULT_CHARSET;
37  import static org.logicmachine.rebl.common.Constants.NEWLINE;
38  import static org.logicmachine.rebl.common.i18n.ErrorMessages.DEFAULT_EXCEPTION_HANDLER_MESSAGE_PREFIX;
39  import static org.logicmachine.rebl.common.i18n.ExternalStrings.DEFAULT_SCOPE_NAME;
40  import static org.logicmachine.rebl.common.i18n.ExternalStrings.PARALLEL_SCOPE_ENV_VARIABLE;
41  
42  import java.io.ByteArrayOutputStream;
43  import java.io.IOException;
44  import java.io.PrintStream;
45  import java.io.UnsupportedEncodingException;
46  import java.util.Calendar;
47  import java.util.Collection;
48  import java.util.GregorianCalendar;
49  import java.util.Properties;
50  
51  import org.junit.AfterClass;
52  import org.junit.Ignore;
53  import org.junit.Test;
54  import org.logicmachine.rebl.common.Common;
55  import org.logicmachine.rebl.common.Many;
56  import org.logicmachine.rebl.common.i18n.ExternalStrings;
57  import org.logicmachine.rebl.domain.actions.Callable;
58  import org.logicmachine.rebl.domain.actors.Actor;
59  import org.logicmachine.rebl.domain.entities.ActiveEntity;
60  import org.logicmachine.rebl.domain.entities.Entities;
61  import org.logicmachine.rebl.domain.entities.Entity;
62  import org.logicmachine.rebl.domain.exceptions.BusinessMessage;
63  import org.logicmachine.rebl.domain.exceptions.ExceptionHandler;
64  import org.logicmachine.rebl.domain.exceptions.ExceptionHandlers;
65  import org.logicmachine.rebl.domain.resources.CloseableResource;
66  import org.logicmachine.rebl.domain.resources.Resource;
67  import org.logicmachine.rebl.domain.resources.Resources;
68  import org.logicmachine.rebl.domain.stateMachines.StateMachine;
69  import org.logicmachine.rebl.domain.stateMachines.StateMachines;
70  import org.logicmachine.rebl.domain.transactions.managers.JdbcTransactionAwareScope;
71  import org.logicmachine.rebl.language.Language;
72  import org.logicmachine.rebl.language.context.EnvironmentObject;
73  import org.logicmachine.rebl.language.context.EnvironmentObjects;
74  import org.logicmachine.rebl.language.context.Scope;
75  import org.logicmachine.rebl.monitor.Monitor;
76  import org.logicmachine.rebl.monitor.Monitors;
77  import org.logicmachine.rebl.monitor.impl.DurationMonitor;
78  import org.logicmachine.rebl.monitor.impl.ThroughputMonitor;
79  import org.logicmachine.rebl.unitTest.common.CommonTest.MyActiveEntity;
80  import org.logicmachine.rebl.unitTest.common.CommonTest.UnsuccessfulCallable;
81  import org.logicmachine.rebl.unitTest.domain.actions.MyCallableFunctions;
82  import org.logicmachine.rebl.unitTest.domain.stateMachines.States;
83  
84  
85  @Ignore
86  @SuppressWarnings("javadoc")
87  public abstract class GenericScopeTest<T extends Scope>
88  {
89      protected static final String ACTIVE_ENTITY_KEY_1 = "myActiveEntity1";
90      protected static final String ACTIVE_ENTITY_KEY_2 = "myActiveEntity2";
91      protected static final String ACTIVE_ENTITY_KEY_3 = "myActiveEntity3";
92      protected static final String ERROR_MESSAGE       = "my error message";
93  
94      protected String     key                          = "myKey";
95      protected String     newKey1                      = "newKey1";
96      protected String     newKey2                      = "newKey2";
97  
98      protected Language   language;
99      protected T          defaultScope;
100     protected T          scope;
101 
102 
103     @AfterClass
104     public static void teardown()
105     {
106         Scope.setDefaultScopeType(Scope.class);
107     }
108 
109     @SuppressWarnings("unchecked")
110     public void setupGenericScope()
111     {
112         language     = new Language("test");
113 
114         defaultScope = (T)language.withDefaultScope();
115     }
116 
117     public void setupGenericScope(final String key, final String newKey1, final String newKey2, final Properties properties)
118     {
119         this.key     = key;
120         this.newKey1 = newKey1;
121         this.newKey2 = newKey2;
122 
123         Scope.setScopeInitialisationProperties(key,                             properties);
124         Scope.setScopeInitialisationProperties(newKey1,                         properties);
125         Scope.setScopeInitialisationProperties(newKey2,                         properties);
126         Scope.setScopeInitialisationProperties(DEFAULT_SCOPE_NAME,              properties);
127         Scope.setScopeInitialisationProperties(JdbcTransactionAwareScope.class, properties);
128 
129         setupGenericScope();
130     }
131 
132     @SuppressWarnings("unchecked")
133     protected T createScope()
134     {
135         scope = (T)Scope.newInstance(key);
136 
137         return scope;
138     }
139 
140     public void cleanUpGenericScope()
141     {
142         Common.clearScopes();
143 
144         MyCallableFunctions.reset();
145     }
146 
147     public Language getLanguage()
148     {
149         return language;
150     }
151 
152 
153     @Test
154     public void shouldCreateScopeInstance()
155     {
156         assertEquals("expected correct key",      key,   createScope().key());
157     }
158 
159     @Test
160     public void shouldDetermineDefaultScope()
161     {
162         assertEquals("expected default scope",    true, defaultScope.isDefaultScope());
163     }
164 
165     @Test
166     public void shouldDetermineNonDefaultScope()
167     {
168         final Scope newScope = Scope.newSequentialInstance(key);
169 
170         assertEquals("expected default",          true,  defaultScope.isDefaultScope());
171         assertEquals("expected non-default",      false, newScope.isDefaultScope()    );
172     }
173 
174     @Test
175     public void shouldCreateSequentialScope()
176     {
177         final Scope newScope = Scope.newSequentialInstance(key);
178 
179         assertEquals("expected sequential scope", false, newScope.isParallel());
180     }
181 
182     @Test
183     public void shouldSetSequentialScope()
184     {
185         final Scope newScope = Scope.newInstance(key).sequential();
186 
187         assertEquals("expected parent scope",     false, newScope.withParent().isEmpty());
188 
189         assertEquals("expected sequential scope", false, newScope.isParallel());
190     }
191 
192     @Test
193     public void shouldCreateParallelScope()
194     {
195         final Scope newScope = Scope.newParallelInstance(key);
196 
197         assertEquals("expected parallel scope",   true,  newScope.isParallel());
198 
199         assertEquals("expected no parent scope",  true,  newScope.withParent().isEmpty());
200     }
201 
202     @Test
203     public void shouldSetParallelScope()
204     {
205         final Scope newScope = Scope.newInstance(key).parallel();
206 
207         assertEquals("expected parallel scope",   true,  newScope.isParallel());
208 
209         assertEquals("expected no parent scope",  true,  newScope.withParent().isEmpty());
210     }
211 
212     @Test
213     public void shouldCreateParallelScopeIfTriggerEnvironmentVariableSet()
214     {
215         // PARALLEL_SCOPE_ENV_VARIABLE can either be set within an EnvironmentObject
216         // instance or else as a proper environment variable accessed via a call
217         // to the 'System.getenv()' method.
218 
219         final Scope newScope = Scope.newInstance(key)
220                                     .withEnvironmentObject(new EnvironmentObject(PARALLEL_SCOPE_ENV_VARIABLE, "true"));
221 
222         assertEquals("expected parallel scope",   true,  newScope.isParallel());
223 
224         assertEquals("expected no parent scope",  true,  newScope.withParent().isEmpty());
225     }
226 
227     @Test
228     public void shouldCreateSequentialScopeIfTriggerEnvironmentVariableNotSet()
229     {
230         // PARALLEL_SCOPE_ENV_VARIABLE can either be set within an EnvironmentObject
231         // instance or else as a proper environment variable accessed via a call
232         // to the 'System.getenv()' method.
233 
234         final Scope newScope = Scope.newInstance(key)
235                                     .withEnvironmentObject(new EnvironmentObject(PARALLEL_SCOPE_ENV_VARIABLE, "false"));
236 
237         assertEquals("expected sequential scope", false, newScope.isParallel());
238 
239         assertEquals("expected parent scope",     false, newScope.withParent().isEmpty());
240     }
241 
242     @Test
243     public void shouldConvertParallelScopeToStandalone()
244     {
245         final Scope parallelScope = Scope.newInstance(key).parallel();
246 
247         assertEquals("expected parallel scope",   true,  parallelScope.isParallel());
248 
249         assertEquals("expected no parent scope",  true,  parallelScope.withParent().isEmpty());
250     }
251 
252     @Test
253     public void shouldDefineScopeWithGivenKey()
254     {
255         assertEquals("expected correct key",      key,   Scope.newInstance(key).key());
256     }
257 
258     @Test(expected = IllegalArgumentException.class)
259     public void shouldFailToCreateMultipleScopesWithSameKey()
260     {
261         Scope.newInstance(key).withScope(key);
262     }
263 
264     @Test
265     @SuppressWarnings("unchecked")
266     public void shouldCreateNewScopeWithKey()
267     {
268         final T newScope = (T)Scope.newInstance(key);
269 
270         assertEquals("expected new scope",        false, newScope.isEmpty());
271         assertEquals("expected new scope",        false, newScope.equals(newScope.withScope(newKey1)));
272     }
273 
274     @Test
275     @SuppressWarnings("unchecked")
276     public void shouldCreateNewScopeWithKeyAndActiveEntity()
277     {
278         final ActiveEntity activeEntity = new ActiveEntity("myActiveEntity");
279         final T newScope = (T)Scope.newInstance(key, activeEntity);
280 
281         assertEquals("expected new scope",        false, newScope.isEmpty());
282         assertEquals("expected new scope",        false, newScope.equals(newScope.withScope(newKey1)));
283         assertEquals("expected correct entity",   activeEntity, newScope.withActiveEntity());
284     }
285 
286     @Test
287     @SuppressWarnings("unchecked")
288     public void shouldDefineScope()
289     {
290         assertEquals("expected default",          defaultScope, defaultScope.language().withDefaultScope());
291 
292         final T newScope = (T)Scope.newInstance(key);
293 
294         assertEquals("expected new scope",        newScope,     Common.withScope(key));
295         assertEquals("expected correct parent",   defaultScope, newScope.withParent());
296     }
297 
298     @Test
299     public void defaultScopeShouldHaveNoParent()
300     {
301         assertEquals("expected no parent scope",  true,         Common.withDefaultScope().withParent().isEmpty());
302     }
303 
304     @Test
305     public void shouldHaveParent()
306     {
307         assertEquals("expected correct parent",   defaultScope, defaultScope.withScope(key).withParent());
308     }
309 
310     @Test
311     public void shouldCloseScope()
312     {
313         final Scope newScope = Scope.newInstance(key);
314 
315         assertEquals("expected open scope",       false, newScope.isClosed());
316 
317         newScope.closeScope();
318 
319         assertEquals("expected closed scope",     true,  newScope.isClosed());
320     }
321 
322     @Test
323     public void shouldUnregisterScope()
324     {
325         Scope.newInstance(key);
326 
327         assertEquals("expected default scope",    true,  language.unregisterScope(defaultScope).isEmpty());
328     }
329 
330     @Test
331     @SuppressWarnings("unchecked")
332     public void shouldUnregisterSequentialScopes()
333     {
334         final T outer = (T)Scope.newInstance(key);
335         final T inner = (T)outer.withScope(newKey1);
336 
337         assertEquals("expected outer scope",      true,  language.unregisterScope(inner).equals(outer));
338     }
339 
340 
341 
342     @Test
343     @SuppressWarnings("unchecked")
344     public void shouldInheritConfiguredAttributesFromParentScope()
345     {
346         final T parentScope = (T)Scope.newInstance(key);
347         final T childScope1 = (T)parentScope.withScope(newKey1);
348 
349         assertEquals("expected no exception handlers",        true,  childScope1.withExceptionHandlers().isEmpty()    );
350         assertEquals("expected no environment objects",       true,  childScope1.getEnvironmentObjects().isEmpty()    );
351         assertEquals("expected no resources",                 true,  childScope1.getResources().isEmpty()             );
352         assertEquals("expected no state machines",            true,  childScope1.withStateMachines().isEmpty()        );
353         assertEquals("expected no component package names",   true,  childScope1.withComponentPackageNames().isEmpty());
354         assertEquals("expected no business entities",         true,  childScope1.getEntities(MyEntity.class).getCollection().isEmpty());
355         assertEquals("expected no monitors",                  true,  childScope1.withMonitors().isEmpty()             );
356 
357         childScope1.withExceptionHandlers    (buildExceptionHandlers()               );
358         childScope1.withEnvironmentObjects   (new EnvironmentObject("foo",   "bar"   ),
359                                               new EnvironmentObject("hello", "world"));
360         childScope1.withResources            (buildResources()                       );
361         childScope1.withStateMachines        (buildStateMachines()                   );
362         childScope1.withComponentPackageNames("foo", "bar"                           );
363         childScope1.withMonitors             (new ThroughputMonitor(),
364                                               new DurationMonitor()                  );
365         childScope1.withEntities             (buildEntities()                        );
366 
367         final T childScope2 = (T)childScope1.withScope(newKey2);
368 
369         assertEquals("expected some exception handlers",      false, childScope2.withExceptionHandlers().isEmpty()    );
370         assertEquals("expected some environment objects",     false, childScope2.getEnvironmentObjects().isEmpty()    );
371         assertEquals("expected some state machines",          false, childScope2.withStateMachines().isEmpty()        );
372         assertEquals("expected some component package names", false, childScope2.withComponentPackageNames().isEmpty());
373         assertEquals("expected some business entities",       false, childScope2.getEntities(MyEntity.class)
374                                                                                 .getCollection().isEmpty()            );
375 
376         assertEquals("expected no resources",                 true,  childScope2.getResources().isEmpty()             );
377         assertEquals("expected no monitors",                  true,  childScope2.withMonitors().isEmpty()             );
378     }
379 
380     @Test
381     @SuppressWarnings("unchecked")
382     public void shouldInheritIsParallelAttributeFromParentScope()
383     {
384         final T parentScope = (T)Scope.newInstance(key).parallel();
385         final T childScope1 = (T)parentScope.withScope(newKey1);
386 
387         assertEquals("expected sequential child scope",       false, childScope1.isParallel());
388 
389         parentScope.inheritParallelSetting();
390 
391         final T childScope2 = (T)parentScope.withScope(newKey2);
392 
393         assertEquals("expected parallel child scope",         true,  childScope2.isParallel());
394     }
395 
396 
397 
398     @Test
399     public void shouldAttachExceptionHandlersToScope()
400     {
401         // 3 = (2 explicit exception handlers + 1 default exception handler)
402         assertSize(defaultScope.withExceptionHandlers(buildExceptionHandlers())
403                                .withExceptionHandlers(), 3);
404     }
405 
406     @Test
407     public void shouldAttachExceptionHandlerInstancesToScope()
408     {
409         // 3 = (2 explicit exception handlers + 1 default exception handler)
410         assertSize(defaultScope.withExceptionHandlers(new ExceptionHandler(),
411                                                       new ExceptionHandler())
412                                .withExceptionHandlers(), 3);
413     }
414 
415     @Test
416     public void shouldAttachExceptionHandlerToScope()
417     {
418         // 2 = (1 explicit exception handlers + 1 default exception handler)
419         assertSize(defaultScope.withExceptionHandler(new ExceptionHandler())
420                                .withExceptionHandlers(), 2);
421     }
422 
423     @Test
424     public void shouldGetExceptionHandlers()
425     {
426         // 3 = (2 explicit exception handlers + 1 default exception handler)
427         assertSize(defaultScope.withExceptionHandlers(buildExceptionHandlers())
428                                .withExceptionHandlers(), 3);
429     }
430 
431 
432 
433     @Test
434     public void shouldAttachEnvironmentObjectsToScope()
435     {
436         final EnvironmentObjects environmentObjects = new EnvironmentObjects()
437                                                          .add(new EnvironmentObject("foo",   "bar"  ))
438                                                          .add(new EnvironmentObject("hello", "world"));
439 
440         defaultScope.withEnvironmentObjects(environmentObjects);
441 
442         assertSize(defaultScope.getEnvironmentObjects(),  2);
443         assertSize(defaultScope.withEnvironmentObjects(), 2);
444     }
445 
446     @Test
447     public void shouldAttachEnvironmentObjectInstancesToScope()
448     {
449         assertSize(defaultScope.withEnvironmentObjects(new EnvironmentObject("foo",   "bar"  ),
450                                                        new EnvironmentObject("hello", "world"))
451                                .getEnvironmentObjects(), 2);
452     }
453 
454     @Test
455     public void shouldAttachEnvironmentObjectToScope()
456     {
457         final Calendar now = new GregorianCalendar();
458 
459         assertSize(defaultScope.withEnvironmentObject("currentDate", now).getEnvironmentObjects(), 1);
460 
461         assertEquals("expected correct date", now, defaultScope.getEnvironmentObject("currentDate").value());
462     }
463 
464 
465 
466     @Test
467     public void shouldAttachResourcesToScope()
468     {
469         assertSize(defaultScope.withResources(buildResources())
470                                .getResources(), 2);
471     }
472 
473     @Test
474     public void shouldAttachResourceInstancessToScope()
475     {
476         assertSize(defaultScope.withResources(new Resource("resource1"),
477                                               new Resource("resource2"))
478                                .getResources(), 2);
479     }
480 
481     @Test
482     public void shouldAttachResourceToScope()
483     {
484         assertSize(defaultScope.withResource(new Resource("resource1"))
485                                .getResources(), 1);
486     }
487 
488     @Test
489     public void shouldGetResources()
490     {
491         assertSize(defaultScope.withResources(buildResources())
492                                .getResources(), 2);
493     }
494 
495     @Test
496     public void shouldGetActiveResource()
497     {
498         final Resource resource = new Resource("test");
499         defaultScope.withActiveResource(resource);
500 
501         assertEquals("expected correct resource", resource, defaultScope.withActiveResource());
502         assertEquals("expected correct resource", resource, defaultScope.getActiveResource());
503     }
504 
505 
506 
507     @Test
508     public void shouldAttachStateMachinesToScope()
509     {
510         assertSize(defaultScope.withStateMachines(buildStateMachines())
511                                .withStateMachines(), 2);
512     }
513 
514     @Test
515     public void shouldAttachStateMachineInstancesToScope()
516     {
517         assertSize(defaultScope.withStateMachines(new StateMachine<States>("foo"),
518                                                   new StateMachine<States>("bar"))
519                                .withStateMachines(), 2);
520     }
521 
522     @Test
523     public void shouldAttachStateMachineToScope()
524     {
525         assertSize(defaultScope.withStateMachine(new StateMachine<States>("foo"))
526                                .withStateMachines(), 1);
527     }
528 
529     @Test
530     public void shouldGetStateMachines()
531     {
532         defaultScope.withStateMachines(buildStateMachines());
533 
534         assertEquals("expected correct state machine", true,  null != defaultScope.withStateMachine("sm1" ));
535         assertEquals("expected correct state machine", true,  null != defaultScope.withStateMachine("sm2" ));
536     }
537 
538     @Test(expected = IllegalArgumentException.class)
539     public void shouldNotFindStateMachine()
540     {
541         defaultScope.withStateMachines(buildStateMachines()).withStateMachine("test");
542     }
543 
544 
545 
546     @Test
547     public void shouldAttachEntitiesToScope()
548     {
549         assertSize(defaultScope.withEntities(buildEntities())
550                                .getEntities(MyEntity.class).getCollection(), 2);
551     }
552 
553     @Test
554     public void shouldAttachEntityInstancesToScope()
555     {
556         assertSize(defaultScope.withEntities(new MyEntity(),
557                                              new MyEntity())
558                                .getEntities(MyEntity.class).getCollection(), 2);
559     }
560 
561     @Test
562     public void shouldAttachEntityToScope()
563     {
564         assertSize(defaultScope.withEntity(new MyEntity())
565                                .getEntities(MyEntity.class).getCollection(), 1);
566     }
567 
568     @Test
569     public void shouldGetEntities()
570     {
571         defaultScope.withEntities(buildEntities());
572 
573         assertEquals("expected correct entity", "foo",
574                      defaultScope.findEntityWithinScope(MyEntity.class, "foo").key());
575 
576         assertEquals("expected correct entity", "bar",
577                      defaultScope.findEntityWithinScope(MyEntity.class, "bar").key());
578     }
579 
580 
581 
582     @Test
583     public void shouldAttachComponentPackageNamesToScope()
584     {
585         assertSize(defaultScope.withComponentPackageNames("foo", "bar")
586                                .withComponentPackageNames(), 2);
587     }
588 
589     @Test
590     public void shouldAttachComponentPackageNameToScope()
591     {
592         assertSize(defaultScope.withComponentPackageNames("foo")
593                                .withComponentPackageNames(), 1);
594     }
595 
596 
597 
598     @Test
599     public void shouldAddIndividualMonitors()
600     {
601         defaultScope.withMonitors(new ThroughputMonitor(),
602                                   new DurationMonitor());
603 
604         assertEquals("expected correct monitor count", 2, defaultScope.withMonitors().size());
605     }
606 
607     @Test
608     public void shouldAddMonitors()
609     {
610         defaultScope.withMonitors(new Monitors().add(new ThroughputMonitor())
611                                                 .add(new DurationMonitor()));
612 
613         assertEquals("expected correct monitor count", 2, defaultScope.withMonitors().size());
614     }
615 
616 
617 
618     @Test
619     public void shouldAddComponentPackage()
620     {
621         final String componentPackage = "org.logicmachine.rebl.unitTest.domain.actions";
622 
623         defaultScope.withComponentPackageName(componentPackage);
624 
625         assertEquals("expected correct component package",    true, componentPackage.equals(defaultScope.withComponentPackageNames().get(0).key()));
626     }
627 
628     @Test
629     public void shouldAddListOfComponentPackages()
630     {
631         final String componentPackage1 = "org.logicmachine.rebl.unitTest.domain.actions.first";
632         final String componentPackage2 = "org.logicmachine.rebl.unitTest.domain.actions.second";
633 
634         defaultScope.withComponentPackageNames(componentPackage1, componentPackage2);
635 
636         assertEquals("expected correct component package",    true, componentPackage1.equals(defaultScope.withComponentPackageNames().get(0).key()));
637         assertEquals("expected correct component package",    true, componentPackage2.equals(defaultScope.withComponentPackageNames().get(1).key()));
638     }
639 
640     @Test
641     public void shouldAddListOfComponentPackagesAsColonSeparatedList()
642     {
643         final String componentPackage1 = "org.logicmachine.rebl.unitTest.domain.actions.first";
644         final String componentPackage2 = "org.logicmachine.rebl.unitTest.domain.actions.second";
645         final String componentPackages = componentPackage1 + COLON + componentPackage2;
646 
647         defaultScope.withComponentPackageName(componentPackages);
648 
649         assertEquals("expected correct component package",    true, componentPackage1.equals(defaultScope.withComponentPackageNames().get(0).key()));
650         assertEquals("expected correct component package",    true, componentPackage2.equals(defaultScope.withComponentPackageNames().get(1).key()));
651     }
652 
653     @Test
654     public void shouldDirectlyInvokeCallable()
655     {
656         defaultScope.withComponentPackageName("org.logicmachine.rebl.unitTest.domain.actions")
657                     .withCallable(new Callable("MyCallableFunctions::methodWithArg").withArguments(new Object()));
658 
659         assertEquals("expected correct method to be invoked", true, MyCallableFunctions.methodWithArgCalled());
660     }
661 
662 
663 
664     @Test
665     @SuppressWarnings("unchecked")
666     public void shouldAddAndFindActor()
667     {
668         final Actor actor    = buildActorWithEntities();
669         final T     newScope = (T)Scope.newInstance(key).withActor(actor);
670 
671         actor.withKey("myActor");
672 
673         assertEquals("expected correct active actor",  actor,         newScope.findEntityWithinScope(MyActor.class, "myActor"));
674     }
675 
676     @Test
677     @SuppressWarnings("unchecked")
678     public void shouldSetActor()
679     {
680         final ActiveEntity activeEntity1  = new ActiveEntity("foo");
681         final ActiveEntity activeEntity2  = new ActiveEntity("bar");
682 
683         final Actor        actor          = buildActorWithEntities(activeEntity1, activeEntity2);
684         final T            newScope       = (T)Scope.newInstance(key).withActor(actor);
685 
686         assertEquals("expected correct active actor",  actor,         newScope.withActiveActor());
687         assertEquals("expected correct active entity", activeEntity1, newScope.withActiveEntity("foo"));
688         assertEquals("expected correct active entity", activeEntity2, newScope.withActiveEntity("bar"));
689     }
690 
691     @Test
692     @SuppressWarnings("unchecked")
693     public void shouldAddAndFindActorWithActiveEntity()
694     {
695         final T            newScope       = (T)Scope.newInstance(key);
696         final ActiveEntity activeEntity1  = new ActiveEntity("foo").withScope(newScope);
697         final ActiveEntity activeEntity2  = new ActiveEntity("bar").withScope(newScope);
698         final Actor        actor          = buildActorWithEntities(activeEntity1, activeEntity2);
699 
700         newScope.withActor(actor);
701 
702         assertEquals("expected correct active entity", activeEntity1, actor.withActiveEntity("foo"));
703 
704         assertEquals("expected correct active entity", activeEntity1, newScope.withActiveEntity(actor));
705     }
706 
707     @Test
708     @SuppressWarnings("unchecked")
709     public void shouldAddAndFindActorWithSpecifiedActiveEntity()
710     {
711         final ActiveEntity activeEntity1  = new ActiveEntity("foo");
712         final ActiveEntity activeEntity2  = new ActiveEntity("bar");
713 
714         final Actor        actor          = buildActorWithEntities(activeEntity1, activeEntity2);
715         final T            newScope       = (T)Scope.newInstance(key).withActor(actor);
716 
717         assertEquals("expected correct active entity", activeEntity2, newScope.withActiveEntity(actor, "bar"));
718     }
719 
720     @Test
721     @SuppressWarnings("unchecked")
722     public void shouldSetActiveEntity()
723     {
724         final ActiveEntity activeEntity = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
725         final T            newScope     = (T)Scope.newInstance(key, activeEntity);
726 
727         assertEquals("expected correct entity", activeEntity, newScope.withActiveEntity());
728         assertEquals("expected correct entity", activeEntity, newScope.getActiveEntity());
729     }
730 
731     @Test
732     @SuppressWarnings("unchecked")
733     public void shouldGetActiveEntityViaActor()
734     {
735         final ActiveEntity activeEntity = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
736         final Actor        actor        = new MyActor(activeEntity);
737         final T            newScope     = (T)Scope.newInstance(key);
738 
739         assertEquals("expected correct entity", activeEntity, newScope.withActiveEntity(actor));
740         assertEquals("expected correct entity", activeEntity, newScope.withActiveEntity());
741         assertEquals("expected correct entity", activeEntity, newScope.getActiveEntity());
742     }
743 
744     @Test
745     @SuppressWarnings("unchecked")
746     public void shouldGetSpecificActiveEntityViaActor()
747     {
748         final ActiveEntity activeEntity1 = new ActiveEntity("foo");
749         final ActiveEntity activeEntity2 = new ActiveEntity("bar");
750         final Actor        actor         = new MyActor(activeEntity1, activeEntity2);
751         final T            newScope      = (T)Scope.newInstance(key);
752 
753         assertEquals("expected correct entity", activeEntity1, newScope.withActiveEntity(actor, "foo"));
754         assertEquals("expected correct entity", activeEntity2, newScope.withActiveEntity(actor, "bar"));
755     }
756 
757     @Test
758     public void shouldReturnEmptyActiveEntityForNullActor()
759     {
760         assertEquals("expected empty entity", true, Scope.newInstance(key).withActiveEntity((Actor)null).isEmpty());
761     }
762 
763     @Test
764     public void shouldReturnEmptyActiveEntityForEmptyActor()
765     {
766         assertEquals("expected empty entity", true, Scope.newInstance(key).withActiveEntity(Actor.emptyActor()).isEmpty());
767     }
768 
769 
770 
771     @Test
772     @SuppressWarnings("unchecked")
773     public void shouldAddEntitiesToScope()
774     {
775         final ActiveEntity activeEntity1 = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
776         final ActiveEntity activeEntity2 = new ActiveEntity(ACTIVE_ENTITY_KEY_2);
777         final Entities     entities      = new Entities().add(activeEntity1).add(activeEntity2);
778         final T            newScope      = (T)Scope.newInstance(key);
779 
780         assertEquals("expected correct entities", entities, newScope.addToScope(ActiveEntity.class, entities));
781     }
782 
783     @Test
784     @SuppressWarnings("unchecked")
785     public void shouldFindEntityWithinScope()
786     {
787         final ActiveEntity activeEntity1 = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
788         final ActiveEntity activeEntity2 = new ActiveEntity(ACTIVE_ENTITY_KEY_2);
789         final Entities     entities      = new Entities().add(activeEntity1).add(activeEntity2);
790         final T            newScope      = (T)Scope.newInstance(key);
791 
792         newScope.addToScope(ActiveEntity.class, entities);
793 
794         assertEquals("expected correct entity", activeEntity1, newScope.findEntityWithinScope(ActiveEntity.class, ACTIVE_ENTITY_KEY_1));
795         assertEquals("expected correct entity", activeEntity2, newScope.findEntityWithinScope(ActiveEntity.class, ACTIVE_ENTITY_KEY_2));
796         assertEquals("expected no match",       true,          newScope.findEntityWithinScope(ActiveEntity.class, "NoMatch").isEmpty());
797     }
798 
799 
800 
801     @Test
802     @SuppressWarnings("unchecked")
803     public void shouldWaitForAllParallelActiveEntityInstances()
804     {
805         final ActiveEntity activeEntity1 = new ActiveEntity(ACTIVE_ENTITY_KEY_1).parallel();
806         final ActiveEntity activeEntity2 = new ActiveEntity(ACTIVE_ENTITY_KEY_2).parallel();
807         final ActiveEntity activeEntity3 = new ActiveEntity(ACTIVE_ENTITY_KEY_3).sequential();
808         final T            newScope      = (T)Scope.newInstance(key);
809 
810         newScope.withActiveEntity(activeEntity1);
811         newScope.withActiveEntity(activeEntity2);
812         newScope.withActiveEntity(activeEntity3);
813 
814         activeEntity1.apply();
815         activeEntity2.apply();
816         activeEntity3.apply();
817 
818         Common.waitForAllParallelActiveEntities();
819 
820         assertEquals("expected no parallel instances", false,         Common.hasPendingParallelActiveEntities(newScope));
821     }
822 
823     @Test
824     @SuppressWarnings("unchecked")
825     public void shouldWaitForParallelActiveEntityInstancesForScope()
826     {
827         final ActiveEntity activeEntity1 = new ActiveEntity(ACTIVE_ENTITY_KEY_1).parallel();
828         final ActiveEntity activeEntity2 = new ActiveEntity(ACTIVE_ENTITY_KEY_2).parallel();
829         final ActiveEntity activeEntity3 = new ActiveEntity(ACTIVE_ENTITY_KEY_3).sequential();
830         final T            newScope      = (T)Scope.newInstance(key);
831 
832         newScope.withActiveEntity(activeEntity1);
833         newScope.withActiveEntity(activeEntity2);
834         newScope.withActiveEntity(activeEntity3);
835 
836         activeEntity1.apply();
837         activeEntity2.apply();
838         activeEntity3.apply();
839 
840         Common.waitForParallelActiveEntitiesForScope(newScope);
841 
842         assertEquals("expected no parallel instances", false,         Common.hasPendingParallelActiveEntities(newScope));
843     }
844 
845 
846 
847     @Test
848     public void shouldLogMessage()
849     {
850         assertLogMessageEquals("foo bar", false, false);
851     }
852 
853     @Test
854     public void shouldLogMessageWithLeadingNewline()
855     {
856         assertLogMessageEquals("foo bar", true,  false);
857     }
858 
859     @Test
860     public void shouldLogMessageWithTrailingNewline()
861     {
862         assertLogMessageEquals("foo bar", false, true );
863     }
864 
865 
866 
867     @Test
868     @SuppressWarnings({ "unchecked", "resource" })
869     public void shouldClearDataInScope()
870     {
871         final ActiveEntity        activeEntity1      = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
872         final ActiveEntity        activeEntity2      = new ActiveEntity(ACTIVE_ENTITY_KEY_2);
873         final Entities            entities           = new Entities().add(activeEntity1).add(activeEntity2);
874         final MyCloseableResource resource           = new MyCloseableResource();
875         final T                   newScope           = (T)Scope.newInstance(key);
876 
877         final EnvironmentObjects  environmentObjects = new EnvironmentObjects()
878                                                           .add(new EnvironmentObject("foo",   "bar"  ))
879                                                           .add(new EnvironmentObject("hello", "world"));
880 
881         newScope.withResource(resource);
882         newScope.withExceptionHandler(new MyExceptionHandler());
883         newScope.withEnvironmentObjects(environmentObjects);
884         newScope.addToScope(ActiveEntity.class, entities);
885         newScope.withStateMachine(new StateMachine<States>("foo"));
886         newScope.withComponentPackageNames("foo", "bar");
887         newScope.withActiveEntity(activeEntity1);
888 
889         assertEquals("expected resource",                 1,             newScope.getResources().size());
890         assertEquals("expected exception handler",        1,             newScope.withExceptionHandlers().size());
891         assertEquals("expected environmentObjects",       2,             newScope.getEnvironmentObjects().size());
892         assertEquals("expected resource",                 1,             newScope.getResources().size());
893         assertEquals("expected correct stateMachine",     true,          null != newScope.withStateMachine("foo"));
894         assertEquals("expected correct entity",           activeEntity1, newScope.findEntityWithinScope(ActiveEntity.class, ACTIVE_ENTITY_KEY_1));
895         assertEquals("expected correct entity",           activeEntity2, newScope.findEntityWithinScope(ActiveEntity.class, ACTIVE_ENTITY_KEY_2));
896         assertEquals("expected componentPackageNames",    2,             newScope.withComponentPackageNames().size());
897         assertEquals("expected activeEntity",             activeEntity1, newScope.withActiveEntity());
898 
899         assertEquals("expected parent of current scope",  true,          defaultScope.equals(newScope.clear()));
900 
901         assertEquals("should close resource",             false,         resource.isOpen());
902         assertEquals("expected no resource in scope",     0,             newScope.getResources().size());
903         assertEquals("expected no exception handler",     0,             newScope.withExceptionHandlers().size());
904         assertEquals("expected no environmentObjects",    0,             newScope.getEnvironmentObjects().size());
905         assertEquals("expected no match",                 true,          newScope.findEntityWithinScope(ActiveEntity.class, ACTIVE_ENTITY_KEY_1).isEmpty());
906         assertEquals("expected no match",                 true,          newScope.findEntityWithinScope(ActiveEntity.class, ACTIVE_ENTITY_KEY_2).isEmpty());
907         assertEquals("expected no componentPackageNames", 0,             newScope.withComponentPackageNames().size());
908         assertEquals("expected no match",                 true,          newScope.withActiveEntity().isEmpty());
909 
910         try
911         {
912             newScope.withStateMachine("foo");
913 
914             fail("expected no such state machine to be found");
915         }
916         catch(final IllegalArgumentException iae)
917         {
918             // expected - but to ensure we fully complete this test case
919             // we don't want to add it as an expected exception (within the
920             // Test annotation) because other methods above can also throw
921             // this exception
922 
923             return;
924         }
925         finally
926         {
927             resource.close();
928         }
929 
930         fail("expected IllegalArgumentException");
931     }
932 
933 
934 
935     @Test
936     public void shouldHandleSystemExceptionWithinScope()
937     {
938         // note this scope is parallel to prevent the default exception handler from catching this exception
939         final Scope newScope = Scope.newInstance(key).parallel();
940 
941         final MyExceptionHandler exceptionHandler = new MyExceptionHandler().withScope(newScope);
942 
943         newScope.withExceptionHandler(exceptionHandler).handleException(new Exception());
944 
945         assertEquals("expected system exception to be handled", true, exceptionHandler.isHandled());
946     }
947 
948     @Test
949     public void shouldHandleBusinessExceptionWithinScope()
950     {
951         // note this scope is parallel to prevent the default exception handler from catching this exception
952         final Scope newScope = Scope.newInstance(key).parallel();
953 
954         final BusinessMessage exception = new BusinessMessage("exception");
955 
956         newScope.withExceptionHandler(new MyExceptionHandler().withScope(newScope)).handleException(exception);
957 
958         assertEquals("expected business exception to be handled", true, exception.isHandled());
959     }
960 
961     @Test
962     public void shouldNotHandleSystemException()
963     {
964         // note this scope is parallel to prevent the default exception handler from catching this exception
965         final Scope newScope = Scope.newInstance(key).parallel();
966 
967         final MyExceptionHandler exceptionHandler = new MyExceptionHandler(false).withScope(newScope);
968 
969         newScope.withExceptionHandler(exceptionHandler).handleException(new Exception());
970 
971         assertEquals("expected system exception to be unhandled", false, exceptionHandler.isHandled());
972     }
973 
974     @Test
975     public void shouldNotHandleBusinessException()
976     {
977         // note this scope is parallel to prevent the default exception handler from catching this exception
978         final Scope newScope = Scope.newInstance(key).parallel();
979 
980         final BusinessMessage exception = new BusinessMessage("exception");
981 
982         newScope.withExceptionHandler(new MyExceptionHandler(false).withScope(newScope)).handleException(exception);
983 
984         assertEquals("expected business exception to be unhandled", false, exception.isHandled());
985     }
986 
987     @Test
988     public void shouldInvokeMonitors()
989     {
990         final ActiveEntity activeEntity = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
991 
992         Scope.newInstance(key).withMonitors(new ThroughputMonitor(),
993                                             new DurationMonitor());
994 
995         Common.withDefaultScope().addToScope(ActiveEntity.class, new Entities().add(activeEntity));
996 
997         activeEntity.withScope(defaultScope).apply();
998 
999         for (final Monitor<?> monitor : Common.withDefaultScope().withMonitors())
1000         {
1001             if (monitor instanceof ThroughputMonitor)
1002             {
1003                 assertEquals("expected monitor invocation", true, ((Long)monitor.monitorGet()).longValue() > 0);
1004             }
1005             else if (monitor instanceof DurationMonitor)
1006             {
1007                 assertEquals("expected quick monitor invocation", true, ((Long)monitor.monitorGet()).longValue() >= 0);
1008             }
1009         }
1010     }
1011 
1012     @Test
1013     public void shouldLogMonitorResultsOnScopeClose() throws UnsupportedEncodingException, IOException
1014     {
1015         try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream())
1016         {
1017             Common.withOutputStream(new PrintStream(outputStream, true, ExternalStrings.DEFAULT_CHARACTER_ENCODING));
1018 
1019             final Monitor<?> monitor1 = new DurationMonitor()  .withKey("myDurationMonitor"  );
1020             final Monitor<?> monitor2 = new ThroughputMonitor().withKey("myThroughputMonitor");
1021 
1022             final ActiveEntity activeEntity = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
1023 
1024             final Scope newScope = Scope.newInstance(key).withMonitors(monitor1,
1025                                                                        monitor2);
1026 
1027             newScope.addToScope(ActiveEntity.class, new Entities().add(activeEntity));
1028 
1029             activeEntity.withScope(defaultScope).apply();
1030 
1031             // force the monitors to generate their results
1032             newScope.closeScope();
1033 
1034             final String output = outputStream.toString(DEFAULT_CHARSET);
1035 
1036             assertStringContains(output, "Monitor: myDurationMonitor = "  );
1037             assertStringContains(output, "Monitor: myThroughputMonitor = ");
1038         }
1039     }
1040 
1041 
1042 
1043     @Test
1044     public void shouldGetCurrentlyActiveResource()
1045     {
1046         final Scope    newScope = Common.withDefaultScope();
1047         final Resource resource = new Resource("myResource");
1048 
1049         newScope.withActiveResource(resource);
1050 
1051         assertEquals("expected correct active resource", resource, newScope.withActiveResource());
1052     }
1053 
1054     @Test
1055     public void shouldGetCurrentlyActiveActor()
1056     {
1057         final Scope newScope = Common.withDefaultScope();
1058         final Actor actor    = new Actor()
1059             {
1060                 // dummy actor
1061             };
1062 
1063         actor.withKey("myActor");
1064 
1065         newScope.withActor(actor);
1066 
1067         assertEquals("expected correct active actor", actor, newScope.withActiveActor());
1068     }
1069 
1070     @Test
1071     public void shouldCreateScopeWithActorAndActiveEntity()
1072     {
1073         final ActiveEntity activeEntity = new MyActiveEntity().withKey("myActiveEntity");
1074         final MyActor      actor        = new MyActor(activeEntity).withKey("myActor");
1075         final Scope        newScope     = Scope.newInstance(key);
1076 
1077         newScope.withActor(actor);
1078 
1079         final ActiveEntity currentActiveEntity = newScope.withActiveEntityForActor(MyActor.class, "myActor", "myActiveEntity");
1080 
1081         assertEquals("expected correct active actor",  actor,        newScope.withActiveActor());
1082         assertEquals("expected correct active entity", activeEntity, currentActiveEntity);
1083     }
1084 
1085     @Test
1086     public void shouldCreateScopeWithActiveEntity()
1087     {
1088         final ActiveEntity activeEntity = new MyActiveEntity();
1089         final Scope        newScope     = Scope.newInstance(key, activeEntity);
1090 
1091         assertEquals("expected correct active entity", activeEntity, newScope.withActiveEntity());
1092     }
1093 
1094     @Test
1095     public void shouldGetCurrentlyActiveEntity()
1096     {
1097         final Scope        newScope     = Common.withDefaultScope();
1098         final ActiveEntity activeEntity = new MyActiveEntity();
1099 
1100         newScope.withActiveEntity(activeEntity);
1101 
1102         assertEquals("expected correct active entity", activeEntity, newScope.withActiveEntity());
1103     }
1104 
1105 
1106 
1107     @Test
1108     public void shouldHandleExceptionWithinCallable() throws Exception
1109     {
1110         // should not permit exceptions to bubble up
1111         Scope.process(new UnsuccessfulCallable(), scope);
1112     }
1113 
1114 
1115 
1116     @Test
1117     public void shouldHandleException()
1118     {
1119         assertEquals("should handle exception", true, Common.withDefaultScope().handleException(new Exception(ERROR_MESSAGE)));
1120     }
1121 
1122     @Test
1123     public void shouldHandleBusinessException()
1124     {
1125         assertEquals("should handle exception", true, Common.withDefaultScope().handleException(new BusinessMessage(ERROR_MESSAGE)));
1126     }
1127 
1128     @Test
1129     public void shouldNotHandleNullException()
1130     {
1131         assertEquals("should not handle null exception", false, Common.withDefaultScope().handleException(null));
1132     }
1133 
1134     @Test
1135     public void shouldLogException() throws IOException
1136     {
1137         try (ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
1138              PrintStream           printStream = buildErrorStream(errorStream))
1139         {
1140             Common.withErrorStream(printStream);
1141 
1142             assertEquals("should handle exception", true, Common.withDefaultScope().handleException(new Exception(ERROR_MESSAGE)));
1143 
1144             assertEquals("expected correct error log",
1145                           DEFAULT_EXCEPTION_HANDLER_MESSAGE_PREFIX + ARROW + ERROR_MESSAGE + NEWLINE,
1146                           errorStream.toString(ExternalStrings.DEFAULT_CHARACTER_ENCODING));
1147 
1148             errorStream.close();
1149         }
1150     }
1151 
1152 
1153 
1154     @SuppressWarnings({ "unchecked", "resource" })
1155     protected Scope buildScope()
1156     {
1157         final ActiveEntity activeEntity1 = new ActiveEntity(ACTIVE_ENTITY_KEY_1);
1158         final ActiveEntity activeEntity2 = new ActiveEntity(ACTIVE_ENTITY_KEY_2);
1159         final Entities     entities      = new Entities().add(activeEntity1).add(activeEntity2);
1160         final T            newScope      = (T)Scope.newInstance(key);
1161 
1162         final MyCloseableResource myCloseableResource = new MyCloseableResource().withKey("myCloseableResource");
1163 
1164         final MyExceptionHandler myExceptionHandler   = new MyExceptionHandler().withKey("myExceptionHandler");
1165 
1166         final EnvironmentObjects environmentObjects   = new EnvironmentObjects()
1167                                                           .add(new EnvironmentObject("foo",   "bar"  ))
1168                                                           .add(new EnvironmentObject("hello", "world"));
1169 
1170         newScope.withResource             (myCloseableResource            );
1171         newScope.withExceptionHandler     (myExceptionHandler             );
1172         newScope.withEnvironmentObjects   (environmentObjects             );
1173         newScope.addToScope               (ActiveEntity.class, entities   );
1174         newScope.withStateMachine         (new StateMachine<States>("foo"));
1175         newScope.withComponentPackageNames("foo", "bar"                   );
1176         newScope.withActiveEntity         (activeEntity1                  );
1177 
1178         return newScope;
1179     }
1180 
1181 
1182 
1183     protected static ExceptionHandlers buildExceptionHandlers()
1184     {
1185         return new ExceptionHandlers().add(new ExceptionHandler())
1186                                       .add(new ExceptionHandler());
1187     }
1188 
1189     protected static Resources buildResources()
1190     {
1191         return new Resources().add(new Resource("resource1"))
1192                               .add(new Resource("resource2"));
1193     }
1194 
1195     protected static StateMachines buildStateMachines()
1196     {
1197         return new StateMachines().add(new StateMachine<States>("sm1"))
1198                                   .add(new StateMachine<States>("sm2"));
1199     }
1200 
1201     protected static Entities buildEntities()
1202     {
1203         final Entity entity1 = new MyEntity().withKey("foo");
1204         final Entity entity2 = new MyEntity().withKey("bar");
1205 
1206         return new Entities().add(entity1)
1207                              .add(entity2);
1208     }
1209 
1210     protected static Actor buildActorWithEntities()
1211     {
1212         final ActiveEntity activeEntity1  = new ActiveEntity("foo");
1213         final ActiveEntity activeEntity2  = new ActiveEntity("bar");
1214 
1215         return buildActorWithEntities(activeEntity1, activeEntity2);
1216     }
1217 
1218     protected static Actor buildActorWithEntities(final ActiveEntity activeEntity1, final ActiveEntity activeEntity2)
1219     {
1220         return new MyActor(activeEntity1, activeEntity2);
1221     }
1222 
1223     protected static void assertSize(final Collection<?> collection, final int expectedSize)
1224     {
1225         assertEquals(0 == expectedSize ? "should be empty" : "should not be empty",
1226                      expectedSize,
1227                      collection.size());
1228     }
1229 
1230     protected static void assertStringContains(final String string, final String value)
1231     {
1232         assertEquals("expected string to contain correct value", true, string.contains(value));
1233     }
1234 
1235     protected static PrintStream buildErrorStream(final ByteArrayOutputStream errorStream)
1236     {
1237         try
1238         {
1239             return new PrintStream(errorStream, true, ExternalStrings.DEFAULT_CHARACTER_ENCODING);
1240         }
1241         catch (final UnsupportedEncodingException uee)
1242         {
1243             fail(uee.getMessage());
1244 
1245             return null;
1246         }
1247     }
1248 
1249     protected static void assertLogMessageEquals(final String message, final boolean wantLeadingNewline, final boolean wantTrailingNewline)
1250     {
1251         try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream())
1252         {
1253             String expected = message + NEWLINE;
1254 
1255             Common.withOutputStream(new PrintStream(outputStream, true, ExternalStrings.DEFAULT_CHARACTER_ENCODING));
1256 
1257             if (!wantLeadingNewline && !wantTrailingNewline)
1258             {
1259                 Common.log(message);
1260             }
1261             else if (wantLeadingNewline)
1262             {
1263                 Common.withDefaultScope().logWithLeadingNewline(message);
1264 
1265                 expected = NEWLINE + expected;
1266             }
1267             else if (wantTrailingNewline)
1268             {
1269                 Common.withDefaultScope().logWithTrailingNewline(message);
1270 
1271                 expected += NEWLINE;
1272             }
1273 
1274             assertEquals("expected correct log message", expected, outputStream.toString(DEFAULT_CHARSET));
1275         }
1276         catch (final UnsupportedEncodingException uee)
1277         {
1278             fail(uee.getMessage());
1279         }
1280         catch (final IOException ioe)
1281         {
1282             fail(ioe.getMessage());
1283         }
1284     }
1285 
1286 
1287     protected static class MyActor extends Actor
1288     {
1289         private final Many<ActiveEntity> activeEntities = new Many<>();
1290 
1291 
1292         public MyActor(final ActiveEntity activeEntity)
1293         {
1294             this.activeEntities.add(activeEntity);
1295         }
1296 
1297         public MyActor(final ActiveEntity... activeEntities)
1298         {
1299             this.activeEntities.addAll(activeEntities);
1300         }
1301 
1302         @Override
1303         public MyActor withKey(final Object key)
1304         {
1305             super.withKey(key);
1306 
1307             return this;
1308         }
1309 
1310         @Override
1311         public ActiveEntity getActiveEntity()
1312         {
1313             return activeEntities.iterator().next();
1314         }
1315 
1316         @Override
1317         public Many<ActiveEntity> getActiveEntities()
1318         {
1319             return activeEntities;
1320         }
1321     }
1322 
1323     protected static class MyEntity extends Entity
1324     {
1325         public MyEntity()
1326         {
1327             // empty
1328         }
1329     }
1330 
1331     protected static class MyExceptionHandler extends ExceptionHandler
1332     {
1333         private Scope   scope        = null;
1334         private boolean shouldHandle = true;
1335         private boolean isHandled    = false;
1336 
1337 
1338         public MyExceptionHandler()
1339         {
1340             this(true);
1341         }
1342 
1343         public MyExceptionHandler(final boolean shouldHandle)
1344         {
1345             this.shouldHandle = shouldHandle;
1346         }
1347 
1348         @Override
1349         public MyExceptionHandler withKey(final Object key)
1350         {
1351             super.withKey(key);
1352 
1353             return this;
1354         }
1355 
1356         public MyExceptionHandler withScope(final Scope scope)
1357         {
1358             this.scope = scope;
1359 
1360             return this;
1361         }
1362 
1363         @Override
1364         public boolean handleException(final Exception exception)
1365         {
1366             assertEquals("expected correct active exception handler", this, scope.withActiveExceptionHandler());
1367 
1368             isHandled = shouldHandle;
1369 
1370             return shouldHandle;
1371         }
1372 
1373         @Override
1374         public boolean handleException(final BusinessMessage businessMessage)
1375         {
1376             assertEquals("expected correct active exception handler", this, scope.withActiveExceptionHandler());
1377 
1378             if (shouldHandle)
1379             {
1380                 setHandled(businessMessage);
1381             }
1382 
1383             return businessMessage.isHandled();
1384         }
1385 
1386         public boolean isHandled()
1387         {
1388             return isHandled;
1389         }
1390     }
1391 
1392     protected static class MyCloseableResource extends CloseableResource
1393     {
1394         private boolean isOpen = true;
1395 
1396 
1397         @Override
1398         public void closeResource() throws IOException
1399         {
1400             isOpen = false;
1401         }
1402 
1403         @Override
1404         public MyCloseableResource withKey(final Object key)
1405         {
1406             super.withKey(key);
1407 
1408             return this;
1409         }
1410 
1411         public boolean isOpen()
1412         {
1413             return isOpen;
1414         }
1415     }
1416 }