> {
+ void execute(BlackboardServerHandler handler, BlackboardJob job) throws Exception;
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerActionExecutor.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerActionExecutor.java
new file mode 100644
index 0000000..6f278aa
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerActionExecutor.java
@@ -0,0 +1,119 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * A BlackboardServerActionExecutor dispatches the execution of server side blackboard actions.
+ *
+ *
+ * The primary responsibility of this class is to organize the actions, dispatch the action when called, and transform
+ * exceptions into blackboard 'failures'.
+ *
+ *
+ *
+ * The action executor is synchronous. It's responsibility of the actual action implementations to put the jobs in
+ * background, if needed.
+ *
+ *
+ * @author marko
+ *
+ * @param
+ */
+public class BlackboardServerActionExecutor> {
+ private static final Log log = LogFactory.getLog(BlackboardServerActionExecutor.class); // NOPMD by marko on 11/24/08 5:02 PM
+
+ /**
+ * set by spring, so key has to be string
+ */
+ private Map> actionMap;
+
+ /**
+ * used to set bb msg status as done, failed etc.
+ */
+ private BlackboardServerHandler blackboardHandler;
+
+ /**
+ * used to exploit static enum declaration for runtime checks of allowed types.
+ */
+ private Class actionType;
+
+ /**
+ * if true, the executor will allow for an incomplete implementation of actions. If false, it an exception will be
+ * thrown if not all actions are implemented, according to the actionType enum.
+ */
+ private boolean incomplete = false;
+
+ @PostConstruct
+ public void check() {
+ for (String key : actionMap.keySet())
+ Enum.valueOf(actionType, key);
+
+ if (!incomplete)
+ for (X en : actionType.getEnumConstants())
+ if (actionMap.get(en.toString()) == null)
+ throw new IllegalArgumentException("action " + en + " not declared in action map. Action is mandatory");
+ }
+
+ /**
+ * Executes a blackboard job, watching for
+ *
+ * @param job
+ */
+ public void execute(final BlackboardJob job) {
+ try {
+ final X label = Enum.valueOf(actionType, job.getAction());
+
+ final BlackboardServerAction action = actionMap.get(label.toString());
+ if (action != null) {
+ action.execute(blackboardHandler, job);
+ } else {
+ log.warn("Cannot find action handler for blackboard action: " + label);
+ throw new IllegalArgumentException("Cannot find action handler for blackboard action: " + label);
+ }
+ } catch (final Throwable e) {
+ log.warn("got some exception during blackboard handler execution", e);
+ blackboardHandler.failed(job, e);
+ }
+ }
+
+ public BlackboardServerHandler getBlackboardHandler() {
+ return blackboardHandler;
+ }
+
+ @Required
+ public void setBlackboardHandler(final BlackboardServerHandler blackboardHandler) {
+ this.blackboardHandler = blackboardHandler;
+ }
+
+ public Class getActionType() {
+ return actionType;
+ }
+
+ @Required
+ public void setActionType(final Class actionType) {
+ this.actionType = actionType;
+ }
+
+ public Map> getActionMap() {
+ return actionMap;
+ }
+
+ public void setActionMap(Map> actionMap) {
+ this.actionMap = actionMap;
+ }
+
+ public boolean isIncomplete() {
+ return incomplete;
+ }
+
+ public void setIncomplete(boolean incomplete) {
+ this.incomplete = incomplete;
+ }
+
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerExecutorNotificationHandler.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerExecutorNotificationHandler.java
new file mode 100644
index 0000000..00f93cc
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerExecutorNotificationHandler.java
@@ -0,0 +1,52 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * In most cases a service just dispatches every incoming blackboard execution request to the blackboard server
+ * executor, so that the right action call back will be called.
+ *
+ *
+ * This bean will wrap a BlackboardServerExecutor as a BlackboardNotificationHandler so that it can be installed as a
+ * notification handler of a server.
+ *
+ * @author marko
+ *
+ * @param
+ */
+public class BlackboardServerExecutorNotificationHandler> extends AbstractBlackboardNotificationHandler {
+
+ private BlackboardServerActionExecutor blackboardExecutor;
+
+ @PostConstruct
+ public void init() {
+ setBlackboardHandler(blackboardExecutor.getBlackboardHandler());
+ }
+
+ @Override
+ protected void processJob(final BlackboardJob job) {
+ blackboardExecutor.execute(job);
+ }
+
+ public BlackboardServerActionExecutor getBlackboardExecutor() {
+ return blackboardExecutor;
+ }
+
+ public void setBlackboardExecutor(BlackboardServerActionExecutor blackboardExecutor) {
+ this.blackboardExecutor = blackboardExecutor;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see eu.dnetlib.enabling.tools.blackboard.AbstractBlackboardNotificationHandler#setBlackboardHandler(eu.dnetlib.enabling.tools.blackboard.BlackboardHandler)
+ *
+ * Redefined here to avoid inheriting the @Required property. It simplifies the spring config for an
+ * unnecessarry property, since we can get it from the blackboardExecutor.
+ */
+ @Override
+ public void setBlackboardHandler(BlackboardServerHandler handler) {
+ super.setBlackboardHandler(handler);
+ }
+
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerHandler.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerHandler.java
new file mode 100644
index 0000000..5782d00
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/BlackboardServerHandler.java
@@ -0,0 +1,37 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+/**
+ * Helper component used to bridge the high level blackboard job handling from the low level blackboard protocol based
+ * on notifications and blackboard messages.
+ *
+ * @author marko
+ *
+ */
+public interface BlackboardServerHandler extends BlackboardHandler {
+ /**
+ * Sets the ongoing action status to the given job, publishing this new state.
+ *
+ * @param job
+ * blackboard job
+ */
+ void ongoing(BlackboardJob job);
+
+ /**
+ * Sets the "failed" action status to the given job, publishing this new state along with the error message obtained
+ * from the exception.
+ *
+ * @param job
+ * blackboard job
+ * @param exception
+ * exception which caused the failure
+ */
+ void failed(BlackboardJob job, Throwable exception);
+
+ /**
+ * Set the "done" action status to the given job, publishing the new state.
+ *
+ * @param job
+ * blackboard job
+ */
+ void done(BlackboardJob job);
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/DeletingBlackboardNotificationHandler.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/DeletingBlackboardNotificationHandler.java
new file mode 100644
index 0000000..707cb15
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/DeletingBlackboardNotificationHandler.java
@@ -0,0 +1,70 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import javax.annotation.Resource;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import eu.dnetlib.miscutils.jaxb.JaxbFactory;
+
+/**
+ * This BB handler deletes completed (successful or unsuccessful) blackboard messages after dispatching. Job should be registered to only
+ * one "deleting BB handler".
+ *
+ * @author marko
+ *
+ */
+public class DeletingBlackboardNotificationHandler extends BlackboardNotificationHandler {
+
+ /**
+ * Logger.
+ */
+ private static final Log log = LogFactory.getLog(DeletingBlackboardNotificationHandler.class); // NOPMD by marko on 11/24/08 5:02 PM
+
+ /**
+ * blackboard message factory.
+ */
+ @Resource(name = "blackboardMessageFactory")
+ private JaxbFactory messageFactory;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see eu.dnetlib.enabling.tools.blackboard.BlackboardNotificationHandler#processJob(eu.dnetlib.enabling.tools.blackboard.BlackboardJob)
+ */
+ @Override
+ protected void processJob(final BlackboardJob job) {
+
+ if (getListeners().containsKey(job.getId()) && job.isCompleted()) {
+ if (log.isDebugEnabled()) {
+ log.debug(serializeBlackBoardMessage(job));
+ }
+ getBlackboardHandler().delete(job);
+ }
+ super.processJob(job);
+ }
+
+ /**
+ * Helper method, serializes a Blackboard message using a blackboardMessageFactory.
+ *
+ * @param job
+ * @return
+ */
+ private String serializeBlackBoardMessage(final BlackboardJob job) {
+ try {
+ return getMessageFactory().serialize(job.getMessage());
+ } catch (JAXBException e) {
+ return "cannot serialize blackboard message: " + e.getMessage();
+ }
+ }
+
+ public void setMessageFactory(final JaxbFactory messageFactory) {
+ this.messageFactory = messageFactory;
+ }
+
+ public JaxbFactory getMessageFactory() {
+ return messageFactory;
+ }
+
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandler.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandler.java
new file mode 100644
index 0000000..dc6fbac
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandler.java
@@ -0,0 +1,22 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+
+/**
+ * Each service may have a chain of NotificationHandlers, which process incoming notifications.
+ *
+ * @author marko
+ *
+ */
+public interface NotificationHandler {
+ /**
+ * Incoming notification received.
+ *
+ * @param subscrId subscriptionId
+ * @param topic topic
+ * @param rsId resource id
+ * @param profile resource profile
+ */
+ void notified(String subscrId, final String topic, final String rsId, final String profile);
+
+
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChain.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChain.java
new file mode 100644
index 0000000..9661c22
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChain.java
@@ -0,0 +1,14 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+/**
+ * Invokes a chain of notification handlers for each incoming notification. Normally an instance of this class is
+ * registered as the notification handler for a given service.
+ *
+ * @author marko
+ *
+ */
+public interface NotificationHandlerChain extends NotificationHandler {
+
+ public void delegateNotification(final String subscrId, final String topic, final String rsId, final String profile, final NotificationHandler handler);
+
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainImpl.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainImpl.java
new file mode 100644
index 0000000..d2a504c
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainImpl.java
@@ -0,0 +1,104 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import java.util.Collection;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.core.task.TaskExecutor;
+
+import eu.dnetlib.enabling.actions.AbstractSubscriptionAction;
+import eu.dnetlib.enabling.tools.Enableable;
+import eu.dnetlib.enabling.tools.EnableableEnumerator;
+
+public class NotificationHandlerChainImpl implements NotificationHandlerChain {
+
+ /**
+ * logger.
+ */
+ private static final Log log = LogFactory.getLog(NotificationHandlerChain.class); // NOPMD by marko on 11/24/08 5:02 PM
+
+ /**
+ * notification handler chain.
+ */
+ private Collection handlers;
+
+ /**
+ * task executor used for invoking the handlers.
+ */
+ private TaskExecutor handlerExecutor;
+
+ @Resource
+ private NotificationHistory notificationHistory;
+
+ @Resource
+ private EnableableEnumerator enableableEnumerator;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see eu.dnetlib.enabling.tools.blackboard.NotificationHandler#notified(java.lang.String, java.lang.String,
+ * java.lang.String, java.lang.String)
+ */
+ @Override
+ public void notified(final String subscrId, final String topic, final String rsId, final String profile) {
+
+ for (final NotificationHandler handler : handlers) {
+
+ try {
+ if (handler instanceof AbstractSubscriptionAction)
+ if (topic.startsWith(((AbstractSubscriptionAction) handler).getTopicPrefix()))
+ if (!((Enableable) handler).isEnabled()) {
+ for (Map.Entry entry : enableableEnumerator.getAllEnableables().entrySet()) {
+ if (entry.getValue() == handler) {
+ NotificationInfo info = new NotificationInfo();
+ info.setName(entry.getKey());
+ info.setProfile(profile);
+ info.setRsId(rsId);
+ info.setSubscrId(subscrId);
+ info.setTopic(topic);
+ notificationHistory.saveNotification(info);
+ }
+ }
+ continue;
+ }
+
+ delegateNotification(subscrId, topic, rsId, profile, handler);
+ } catch (final RuntimeException e) {
+ log.fatal("error processing notification handler " + handler, e);
+ }
+ }
+ }
+
+ @Override
+ public void delegateNotification(final String subscrId, final String topic, final String rsId, final String profile, final NotificationHandler handler) {
+
+ handlerExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ handler.notified(subscrId, topic, rsId, profile);
+ }
+ });
+ }
+
+ public Collection getHandlers() {
+ return handlers;
+ }
+
+ @Required
+ public void setHandlers(final Collection handlers) {
+ this.handlers = handlers;
+ }
+
+ public TaskExecutor getHandlerExecutor() {
+ return handlerExecutor;
+ }
+
+ @Required
+ public void setHandlerExecutor(TaskExecutor handlerExecutor) {
+ this.handlerExecutor = handlerExecutor;
+ }
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHistory.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHistory.java
new file mode 100644
index 0000000..9978225
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHistory.java
@@ -0,0 +1,37 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import java.util.Map;
+
+public interface NotificationHistory {
+
+ /**
+ * Return a saved notification associated to a bean and to a rsId.
+ *
+ * @param name
+ * @return
+ */
+ public NotificationInfo obtainNotification(String bean, String rsId);
+
+ /**
+ * Save a notification.
+ *
+ * @param info
+ */
+ void saveNotification(NotificationInfo info);
+
+
+ /**
+ * Return all saved notifications.
+ *
+ * @return
+ */
+ Map> obtainAllNotifications();
+
+ /**
+ * Remove a saved notifications.
+ *
+ * @return
+ */
+ public void clearNotification(String bean, String rsId);
+
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHistoryImpl.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHistoryImpl.java
new file mode 100644
index 0000000..9098475
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationHistoryImpl.java
@@ -0,0 +1,39 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class NotificationHistoryImpl implements NotificationHistory {
+
+ private Map> notifications = new HashMap>();
+
+ @Override
+ public NotificationInfo obtainNotification(String bean, String rsId) {
+ if (!notifications.containsKey(bean))
+ return null;
+ return notifications.get(bean).get(rsId);
+ }
+
+ @Override
+ public void saveNotification(NotificationInfo info) {
+ String bean = info.getName();
+ String rsId = info.getRsId();
+
+ if (!notifications.containsKey(bean))
+ notifications.put(bean, new HashMap());
+
+ notifications.get(bean).put(rsId, info);
+ }
+
+ @Override
+ public Map> obtainAllNotifications() {
+ return notifications;
+ }
+
+ @Override
+ public void clearNotification(String bean, String rsId) {
+ if (notifications.containsKey(bean))
+ notifications.get(bean).remove(rsId);
+ }
+}
diff --git a/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationInfo.java b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationInfo.java
new file mode 100644
index 0000000..624a17f
--- /dev/null
+++ b/dnet-core-components/src/main/java/eu/dnetlib/enabling/tools/blackboard/NotificationInfo.java
@@ -0,0 +1,74 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import eu.dnetlib.miscutils.datetime.DateUtils;
+
+public class NotificationInfo {
+ private String name;
+ private String subscrId;
+ private String topic;
+ private String rsId;
+ private String profile;
+ private String date;
+
+ public NotificationInfo() {
+ this.date = DateUtils.now_ISO8601();
+ }
+
+ public NotificationInfo(String name, String subscrId, String topic, String rsId, String profile) {
+ super();
+ this.name = name;
+ this.subscrId = subscrId;
+ this.topic = topic;
+ this.rsId = rsId;
+ this.profile = profile;
+ this.date = DateUtils.now_ISO8601();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSubscrId() {
+ return subscrId;
+ }
+
+ public void setSubscrId(String subscrId) {
+ this.subscrId = subscrId;
+ }
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public String getRsId() {
+ return rsId;
+ }
+
+ public void setRsId(String rsId) {
+ this.rsId = rsId;
+ }
+
+ public String getProfile() {
+ return profile;
+ }
+
+ public void setProfile(String profile) {
+ this.profile = profile;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public void setDate(String date) {
+ this.date = date;
+ }
+}
diff --git a/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/applicationContext-enableable.xml b/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/applicationContext-enableable.xml
new file mode 100644
index 0000000..b62693a
--- /dev/null
+++ b/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/applicationContext-enableable.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/applicationContext-schedulable.xml b/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/applicationContext-schedulable.xml
new file mode 100644
index 0000000..afedb18
--- /dev/null
+++ b/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/applicationContext-schedulable.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/blackboard/applicationContext-blackboard-tools.xml b/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/blackboard/applicationContext-blackboard-tools.xml
new file mode 100644
index 0000000..3f13985
--- /dev/null
+++ b/dnet-core-components/src/main/resources/eu/dnetlib/enabling/tools/blackboard/applicationContext-blackboard-tools.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dnet-core-components/src/test/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainTest.java b/dnet-core-components/src/test/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainTest.java
new file mode 100644
index 0000000..cd7c7b9
--- /dev/null
+++ b/dnet-core-components/src/test/java/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainTest.java
@@ -0,0 +1,104 @@
+package eu.dnetlib.enabling.tools.blackboard;
+
+import javax.annotation.Resource;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(value = SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class NotificationHandlerChainTest {
+
+ public class RecJob implements Runnable {
+
+ private int times;
+ private int num;
+
+ public RecJob(int num, int times) {
+ this.num = num;
+ this.times = times;
+ }
+
+ @Override
+ public void run() {
+ System.out.println("starting " + num);
+ if(times >= 0)
+ executor.execute(new RecJob(num + 1, times - 1));
+ try {
+ Thread.sleep(4000);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ System.out.println("thread finished - " + num);
+ }
+
+ }
+
+ private static final class Job implements Runnable {
+ private final int value;
+
+ public Job(final int i) {
+ value = i;
+ }
+
+ @Override
+ public void run() {
+ System.out.println("thread started - " + value);
+ try {
+ Thread.sleep(4000);
+ } catch (final InterruptedException e) {
+ //
+ }
+ System.out.println("thread finished - " + value);
+ }
+ }
+
+ @Resource
+ private transient ThreadPoolTaskExecutor executor;
+
+ @Test
+ public void testDelegateNotification() throws InterruptedException {
+ System.out.println(executor);
+
+ System.out.println("executing");
+
+ for (int i = 0; i < 100; i++)
+ executor.execute(new Job(i));
+
+ System.out.println("executed - waiting");
+ Thread.sleep(2000);
+
+ System.out.println("active count: " + executor.getActiveCount());
+ System.out.println("current pool size: " + executor.getCorePoolSize());
+ System.out.println("pool size " + executor.getPoolSize());
+
+ Thread.sleep(3000);
+
+ System.out.println("ok");
+ }
+
+ @Test
+ public void testRecursive() throws InterruptedException {
+
+ for (int i = 0; i < 4; i++)
+ executor.execute(new RecJob(i * 10, 4));
+
+
+ System.out.println("executed - waiting");
+ Thread.sleep(2000);
+
+ System.out.println("active count: " + executor.getActiveCount());
+ System.out.println("current pool size: " + executor.getCorePoolSize());
+ System.out.println("pool size " + executor.getPoolSize());
+
+ Thread.sleep(3000);
+
+ System.out.println("ok");
+ }
+
+}
diff --git a/dnet-core-components/src/test/java/eu/dnetlib/miscutils/iterators/xml/IterableXmlParserTest.java b/dnet-core-components/src/test/java/eu/dnetlib/miscutils/iterators/xml/IterableXmlParserTest.java
index 4e4e777..080888d 100644
--- a/dnet-core-components/src/test/java/eu/dnetlib/miscutils/iterators/xml/IterableXmlParserTest.java
+++ b/dnet-core-components/src/test/java/eu/dnetlib/miscutils/iterators/xml/IterableXmlParserTest.java
@@ -83,7 +83,7 @@ public class IterableXmlParserTest {
parser = new IterableXmlParser(element, stream);
int count = 0;
for (String xml : parser) {
- System.out.println(xml);
+ //System.out.println(xml);
Document doc = reader.read(new StringReader(xml));
assertNotNull(doc);
assertNotNull(doc.selectSingleNode("//" + element));
diff --git a/dnet-core-components/src/test/resources/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainTest-context.xml b/dnet-core-components/src/test/resources/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainTest-context.xml
new file mode 100644
index 0000000..6579c11
--- /dev/null
+++ b/dnet-core-components/src/test/resources/eu/dnetlib/enabling/tools/blackboard/NotificationHandlerChainTest-context.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 812bddd..c58e1cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -269,6 +269,11 @@
spring-tx
${spring.version}
+
+ org.springframework
+ spring-context-support
+ ${spring.version}
+