/src/main/java/org/provarules/service/impl/ProvaServiceImpl.java

https://github.com/prova/prova · Java · 251 lines · 207 code · 23 blank · 21 comment · 55 complexity · b9ced4c81ed5731cc80f966997a3e072 MD5 · raw file

  1. package org.provarules.service.impl;
  2. import org.provarules.api2.ProvaCommunicator;
  3. import org.provarules.api2.ProvaCommunicatorImpl;
  4. import org.provarules.exchange.ProvaSolution;
  5. import org.provarules.kernel2.ProvaConstant;
  6. import org.provarules.kernel2.ProvaList;
  7. import org.provarules.service.EPService;
  8. import org.provarules.service.ProvaService;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import java.io.BufferedReader;
  12. import java.io.PrintWriter;
  13. import java.util.*;
  14. import java.util.concurrent.ConcurrentHashMap;
  15. import java.util.concurrent.ConcurrentMap;
  16. /**
  17. * OSGi Service holding a collection of identifiable Prova engines
  18. *
  19. * @author alex.kozlenkov@googlemail.com
  20. */
  21. public class ProvaServiceImpl implements ProvaService {
  22. private final static Logger log = LoggerFactory.getLogger("service");
  23. private String id;
  24. private ConcurrentMap<String, ProvaCommunicator> engines;
  25. private ConcurrentMap<String, List<String>> topicDestinations = new ConcurrentHashMap<>();
  26. private ConcurrentMap<String, EPService> callbacks = new ConcurrentHashMap<>();
  27. @Override
  28. public void init() {
  29. id = UUID.randomUUID().toString();
  30. engines = new ConcurrentHashMap<>();
  31. System.out.println("Prova Service " + id + " created");
  32. }
  33. @Override
  34. public void destroy() {
  35. if (engines != null) {
  36. for (ProvaCommunicator engine : engines.values())
  37. engine.shutdown();
  38. }
  39. System.out.println("Prova Service " + id + " destroyed");
  40. }
  41. @Override
  42. public String instance(String agent, String rulebase) {
  43. ProvaCommunicator prova;
  44. try {
  45. Map<String, Object> globals = new HashMap<>();
  46. prova = new ProvaCommunicatorImpl(this, agent, null, rulebase, ProvaCommunicatorImpl.SYNC, globals);
  47. engines.put(agent, prova);
  48. } catch (Exception e) {
  49. throw new RuntimeException(e);
  50. }
  51. return agent;
  52. }
  53. @Override
  54. public String instance(String agent, String rulebase, PrintWriter out) {
  55. ProvaCommunicator prova;
  56. try {
  57. Map<String, Object> globals = new HashMap<>();
  58. prova = new ProvaCommunicatorImpl(this, agent, null, rulebase, ProvaCommunicatorImpl.SYNC, globals);
  59. prova.setPrintWriter(out);
  60. engines.put(agent, prova);
  61. } catch (Exception e) {
  62. throw new RuntimeException(e);
  63. }
  64. return agent;
  65. }
  66. @Override
  67. public void release(String agent) {
  68. ProvaCommunicator engine = engines.remove(agent);
  69. if (engine == null)
  70. throw new RuntimeException("No engine instance " + agent);
  71. engine.stop();
  72. }
  73. @Override
  74. public List<ProvaSolution[]> consult(String agent, String src, String key) {
  75. try {
  76. ProvaCommunicator engine = engines.get(agent);
  77. if (engine == null)
  78. throw new RuntimeException("No engine instance " + agent);
  79. return engine.consultSync(src, key, new Object[]{});
  80. } catch (Exception e) {
  81. throw new RuntimeException(e);
  82. }
  83. }
  84. @Override
  85. public List<ProvaSolution[]> consult(String agent, BufferedReader in, String key) {
  86. try {
  87. ProvaCommunicator engine = engines.get(agent);
  88. if (engine == null)
  89. throw new RuntimeException("No engine instance " + agent);
  90. return engine.consultSync(in, key, new Object[]{});
  91. } catch (Exception e) {
  92. throw new RuntimeException(e);
  93. }
  94. }
  95. @Override
  96. public void send(String dest, ProvaList terms) {
  97. final Object verb = ((ProvaConstant) terms.getFixed()[3]).getObject();
  98. if ("present".equals(verb)) {
  99. // Ask the subscriber to start receiving the stream
  100. String topic = ((ProvaList) terms.getFixed()[4]).getFixed()[0].toString();
  101. if (log.isDebugEnabled())
  102. log.debug("Subscriber " + dest + " to receive stream on " + topic);
  103. // Register the mapping
  104. registerMapping(topic, dest);
  105. } else if ("data".equals(verb)) {
  106. // Dispatch a stream to subscribers
  107. if (log.isDebugEnabled())
  108. log.debug("Dispatch data on stream " + dest);
  109. for (String target : topicDestinations.get(dest)) {
  110. ProvaCommunicator engine = engines.get(target);
  111. if (engine == null)
  112. log.error("Subscriber " + target + " not present");
  113. engine.addMsg(terms);
  114. if (log.isDebugEnabled())
  115. log.debug("Sent: " + terms + " to " + target);
  116. }
  117. return;
  118. } else if ("unregister".equals(verb)) {
  119. // Purge the subscription
  120. String topic = ((ProvaList) terms.getFixed()[4]).getFixed()[0].toString();
  121. unregisterMapping(topic, dest);
  122. // This message will be forwarded to the subscriber informing them of lease expiration
  123. }
  124. // else if( "renew".equals(verb) )
  125. // log.info(terms);
  126. ProvaCommunicator engine = engines.get(dest);
  127. if (engine == null)
  128. throw new RuntimeException("No engine instance " + dest);
  129. engine.addMsg(terms);
  130. if (log.isDebugEnabled())
  131. log.debug("Sent: " + terms + " to " + dest);
  132. }
  133. private synchronized void registerMapping(String topic, String dest) {
  134. List<String> list = topicDestinations.computeIfAbsent(topic, k -> new ArrayList<>());
  135. list.add(dest);
  136. }
  137. private synchronized void unregisterMapping(String topic, String dest) {
  138. List<String> list = topicDestinations.get(topic);
  139. if (list == null)
  140. return;
  141. for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
  142. if (dest.equals(iter.next())) {
  143. iter.remove();
  144. return;
  145. }
  146. }
  147. }
  148. @Override
  149. public void setGlobalConstant(String agent, String name, Object value) {
  150. ProvaCommunicator engine = engines.get(agent);
  151. if (engine == null)
  152. throw new RuntimeException("No engine instance " + agent);
  153. engine.setGlobalConstant(name, value);
  154. }
  155. @Override
  156. public void send(String xid, String dest, String agent, String verb, Object content) {
  157. EPService callback = callbacks.get(dest);
  158. if (callback != null && callback != this) {
  159. if (!(content instanceof Map<?, ?>))
  160. throw new IllegalArgumentException();
  161. Map<String, Object> payload = (Map<String, Object>) content;
  162. if ("present".equals(verb)) {
  163. // Ask the subscriber to start receiving the stream
  164. String topic = payload.get("topic").toString();
  165. if (log.isDebugEnabled())
  166. log.debug("Subscriber " + dest + " to receive stream on " + topic);
  167. // Register the mapping
  168. registerMapping(topic, dest);
  169. }
  170. callback.send(xid, dest, agent, verb, payload, this);
  171. } else
  172. send(xid, dest, agent, verb, content, this);
  173. }
  174. @SuppressWarnings("unchecked")
  175. @Override
  176. public void send(String xid, String dest, String agent, String verb, Object content, EPService callback) {
  177. if (callback != this) {
  178. callbacks.putIfAbsent(agent, callback);
  179. }
  180. if ("present".equals(verb)) {
  181. // Ask the subscriber to start receiving the stream
  182. String topic;
  183. if (content instanceof ProvaList) {
  184. topic = ((ProvaConstant) ((ProvaList) content).getFixed()[0]).getObject().toString();
  185. } else {
  186. Map<String, Object> payload = (Map<String, Object>) content;
  187. topic = payload.get("topic").toString();
  188. }
  189. if (log.isDebugEnabled())
  190. log.debug("Subscriber " + dest + " to receive stream on " + topic);
  191. // Register the mapping
  192. registerMapping(topic, dest);
  193. } else if ("data".equals(verb)) {
  194. // Dispatch a stream to subscribers
  195. if (log.isDebugEnabled())
  196. log.debug("Dispatch data on stream " + dest);
  197. for (String target : topicDestinations.get(dest)) {
  198. ProvaCommunicator engine = engines.get(target);
  199. if (engine == null)
  200. log.error("Subscriber " + target + " not present");
  201. else {
  202. engine.addMsg(xid, agent, verb, content);
  203. if (log.isDebugEnabled())
  204. log.debug("Sent: " + content + " to " + target);
  205. }
  206. }
  207. return;
  208. } else if ("unregister".equals(verb)) {
  209. // Purge the subscription
  210. Map<String, Object> payload = (Map<String, Object>) content;
  211. String topic = payload.get("topic").toString();
  212. unregisterMapping(topic, dest);
  213. // This message will be forwarded to the subscriber informing them of lease expiration
  214. }
  215. // else if( "renew".equals(verb) )
  216. // log.info(terms);
  217. ProvaCommunicator engine = engines.get(dest);
  218. if (engine == null)
  219. throw new RuntimeException("No engine instance " + dest);
  220. engine.addMsg(xid, agent, verb, content);
  221. if (log.isDebugEnabled())
  222. log.debug("Sent: " + content + " to " + dest);
  223. }
  224. @Override
  225. public void register(String agent, EPService epService) {
  226. callbacks.putIfAbsent(agent, epService);
  227. }
  228. }