#1:
net.engio.mbassy.bus.BusConfiguration has only one default constructor:
public BusConfiguration() {
super();
this.numberOfMessageDispatchers = 2;
this.maximumNumberOfPendingMessages = Integer.MAX_VALUE;
this.executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(), DaemonThreadFactory);
}
so, when i construct it and i want to set it's executor to another executor, i have to first get the default one and shutdown it. the code is tedious:
BusConfiguration eventBusConfig = new BusConfiguration();
// used in synchronous environment only!
eventBusConfig.setMaximumNumberOfPendingMessages(1);
eventBusConfig.setNumberOfMessageDispatchers(0);
ExecutorService defaultExecutor = eventBusConfig.getExecutor();
defaultExecutor.shutdown();
try {
defaultExecutor.awaitTermination(1, TimeUnit.MINUTES);
}
catch (InterruptedException e) {
logger.error("Fail to closed default executor service!", e);
// ignored
}
eventBusConfig.setExecutor(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(), new ThreadFactory()
{
@Override
public Thread newThread(Runnable r) {
Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setDaemon(true);
return thread;
}
}));
eventBusConfig.setMetadataReader(new SubscribeConfigChangedMedataReader());
this.eventBus = new MBassador<>(eventBusConfig);
may be it need more suitable design, for example: move the code in constructor to Default() method:
public static BusConfiguration Default() {
BusConfiguration defaultConfig = new BusConfiguration();
// initialize default value
return defaultConfig;
}
#2:
the test case: src\test\java\org\mbassy\ConcurrentSetTest.java has a method called testIteratorCleanup():
@Test
public void testIteratorCleanup(){
final HashSet<Object> persistingCandidates = new HashSet<Object>();
final ConcurrentSet<Object> testSet = new ConcurrentSet<Object>();
Random rand = new Random();
for (int i = 0; i < numberOfElements; i++) {
Object candidate = new Object();
if (rand.nextInt() % 3 == 0) {
persistingCandidates.add(candidate);
}
testSet.add(candidate);
}
// this will remove all objects that have not been inserted into the set of persisting candidates
runGC();
ConcurrentExecutor.runConcurrent(new Runnable() {
@Override
public void run() {
for (Object testObject : testSet) {
// do nothing
// just iterate to trigger automatic clean up
System.currentTimeMillis();
}
}
}, numberOfThreads);
assertEquals(persistingCandidates.size(), testSet.size());
for (Object test : testSet) {
assertTrue(persistingCandidates.contains(test));
}
}
in my machine(windows 8 x64 + jdk 1.7_10), this test case will fail due to GC threads is running slowly. i have to add some time-pause to get around it.
@Test
public void testIteratorCleanup() throws Exception{
final HashSet<Object> persistingCandidates = new HashSet<Object>();
final ConcurrentSet<Object> testSet = new ConcurrentSet<Object>();
Random rand = new Random();
for (int i = 0; i < numberOfElements; i++) {
Object candidate = new Object();
if (rand.nextInt() % 3 == 0) {
persistingCandidates.add(candidate);
}
testSet.add(candidate);
}
// this will remove all objects that have not been inserted into the set of persisting candidates
runGC();
// add this to prevent some case that GC Threads are processed too slow.
Thread.sleep(2000);
ConcurrentExecutor.runConcurrent(new Runnable() {
@Override
public void run() {
for (Object testObject : testSet) {
// do nothing
// just iterate to trigger automatic clean up
System.currentTimeMillis();
}
}
}, numberOfThreads);
assertEquals(persistingCandidates.size(), testSet.size());
for (Object test : testSet) {
assertTrue(persistingCandidates.contains(test));
}
}
#3
i think it may be a good idea to add Custome annotation that can subscribe the event. for example, change @handle's defination, let it can annotate to another Custome annotation that can subscribe event:
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Target(value = {ElementType.METHOD,ElementType.ANNOTATION_TYPE})
public @interface Handler {}
then, i can define my custome event handle annotation:
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Target(value = {ElementType.METHOD})
@Handle
public @interface ConfigChangedEventHandle