/** * Copyright (c) 2011-2014, OpenIoT * * This file is part of OpenIoT. * * OpenIoT is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, version 3 of the License. * * OpenIoT is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with OpenIoT. If not, see <http://www.gnu.org/licenses/>. * * Contact: OpenIoT mailto: info@openiot.eu */ package org.openiot.cupus.entity.broker; import com.google.android.gcm.server.Sender; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import org.openiot.cupus.artefact.ActiveSubscription; import org.openiot.cupus.artefact.MemorySubscription; import org.openiot.cupus.artefact.Subscription; import org.openiot.cupus.artefact.TopKWSubscription; import org.openiot.cupus.common.UniqueObject; import org.openiot.cupus.message.InternalMessage; import org.openiot.cupus.message.Message; import org.openiot.cupus.message.external.AnnounceMessage; import org.openiot.cupus.message.external.MobileBrokerDisconnectMessage; import org.openiot.cupus.message.external.MobileBrokerRegisterGCMMessage; import org.openiot.cupus.message.external.MobileBrokerRegisterMessage; import org.openiot.cupus.message.external.PublishMessage; import org.openiot.cupus.message.external.SubscribeMessage; import org.openiot.cupus.message.external.SubscriberDisconnectMessage; import org.openiot.cupus.message.external.SubscriberRegisterMessage; import org.openiot.cupus.message.external.SubscriberUnregisterMessage; import org.openiot.cupus.message.internal.ElasticityReplyMessage; import org.openiot.cupus.message.internal.ErrorMessage; import org.openiot.cupus.message.internal.InfoMessage; import org.openiot.cupus.message.internal.InitialAnnouncementMatchesMessage; import org.openiot.cupus.message.internal.InitialMatchesMessage; import org.openiot.cupus.message.internal.MergeBooleanMatcherMessage; import org.openiot.cupus.message.internal.MergeTopKWMatcherMessage; import org.openiot.cupus.message.internal.SplitBooleanMatcherMessage; import org.openiot.cupus.message.internal.SplitTopKWMatcherMessage; import org.openiot.cupus.message.internal.StartComponentMessage; import org.openiot.cupus.message.internal.SubscriptionStructureMessage; import org.openiot.cupus.util.LogWriter; /** * This is the main cloud-broker class. It represents the cloud-broker which is * instantiated, started and stopped through it. The CloudBroker object starts * the three broker components (MessageReceiver, DeliveryService and (initial) * Matcher) as separate processes and relays the communication between them by * forwarding from input streams to the proper output streams (for example * reading the in from MessageReceiver and sending it to the out of the * DeliveryService for communication between those two components) * * @author Eugen Rozic * */ public class Coordinator { private String brokerName; private String brokerIP; private int brokerPort; private int internalUDPPort; private int queueCapacity; private String APIKey; private LogWriter log; private boolean logWriting = true; private boolean testing = false; private String classpath = null; private Process messageReceiver = null; private MessageReceiverRelay messageReceiverRelay = null; private Process deliveryService = null; private DeliveryServiceRelay deliveryServiceRelay = null; private int maxNumberOfMatchers; private int topKWMaxNumberOfMatchers; private int numberOfMatchers; private int topKWNumberOfMatchers; private Process[] matchers; private Process[] topKWMatchers; private MatcherRelay[] matcherRelays; private MatcherRelay[] topKWMatcherRelays; private int matcherRoundRobin = 0; private int topKWMatcherRoundRobin = 0; private boolean elasticity = false; private double splitThreshold; private double mergeThreshold; private int checkThreshold; private final Object mutexMatcher = new Object(); /** * The main and only constructor. It takes in a configuration file that * specifies all information the broker needs, the broker name and port. * * It then creates the needed components and starts the threads that control * the information flow from and to them. * * @param configFile */ public Coordinator(File configFile, String classpath) { this.classpath = classpath; //reads properties and instantiates and sets everything... try { Properties brokerProps = new Properties(); FileInputStream fileIn = new FileInputStream(configFile); brokerProps.load(fileIn); fileIn.close(); this.brokerName = brokerProps.getProperty("brokerName"); if (this.brokerName == null) { throw new NullPointerException("Name must be defined!"); } this.brokerPort = Integer.parseInt(brokerProps.getProperty("brokerPort")); this.internalUDPPort = Integer.parseInt( brokerProps.getProperty("internalUDPPort")); this.brokerIP = UniqueObject.getLocalIP(); this.queueCapacity = Integer.parseInt(brokerProps.getProperty("queueCapacity")); this.APIKey = brokerProps.getProperty("apikey"); if (brokerProps.getProperty("testing", "false").toLowerCase().equals("false")) { this.testing = false; } else if (brokerProps.getProperty("testing").toLowerCase().equals("true")) { this.testing = true; } else { System.err.println("Config param \"testing\" should be either true or false! Setting to default false."); this.testing = false; } if (brokerProps.getProperty("logWriting", "true").toLowerCase().equals("true")) { this.logWriting = true; } else if (brokerProps.getProperty("logWriting").toLowerCase().equals("false")) { this.logWriting = false; } else { System.err.println("Config param \"logWriting\" should be either true or false! Setting to default true."); this.logWriting = true; } if (brokerProps.getProperty("elasticity", "false").toLowerCase().equals("false")) { this.elasticity = false; } else if (brokerProps.getProperty("elasticity").toLowerCase().equals("true")) { this.elasticity = true; } else { System.err.println("Config param \"elasticity\" should be either true or false! Setting to default false."); this.elasticity = false; } this.maxNumberOfMatchers = numberOfMatchers = Integer.parseInt(brokerProps.getProperty("numberOfBooleanMatchers")); this.topKWMaxNumberOfMatchers = topKWNumberOfMatchers = Integer.parseInt(brokerProps.getProperty("numberOfTopKWMatchers")); if (this.elasticity) { numberOfMatchers = 1; } this.splitThreshold = Double.parseDouble(brokerProps.getProperty("splitThreshold")); this.mergeThreshold = Double.parseDouble(brokerProps.getProperty("mergeThreshold")); this.checkThreshold = Integer.parseInt(brokerProps.getProperty("checkThreshold")); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } log = new LogWriter(this.brokerName + ".log", logWriting, testing); try { initMessageReceiver(); initDeliveryService(); initMatchers(); } catch (Exception e) { e.printStackTrace(); shutdown(); } log.writeToLog("Broker name: " + this.brokerName, true); log.writeToLog("Broker port: " + this.brokerPort, true); if (brokerIP.equals("")) { log.writeToLog("Broker IP address: unidentifiable?!", true); } else { log.writeToLog("Broker IP address: " + this.brokerIP, true); } log.writeToLog("", true); //empty line } /** * Sends the start messages to the MessageReceiver and the DeliveryService * components of the broker so they can start accepting accepting and * processing requests and sending answers to them. */ public void start() { messageReceiverRelay.sendStartMessage(); deliveryServiceRelay.sendStartMessage(); } /** * Kills the broker. It does so by just terminating the process which will * automatically cause all output streams to close which will in turn cause * all input streams on the receiving side to throw an EOFException which * will cause the starting of shutdown of all the components (subprocesses) * this CloudBroker is connected to. */ public void shutdown() { log.writeToLog("Shutting down all Broker components!", true); System.exit(-1); } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** * Starts the MessageReceiver process and a thread to manage it's * input/output. */ private void initMessageReceiver() throws IOException { String[] cmd = new String[]{"java", "-cp", classpath, MessageReceiver.class.getName(), brokerName, brokerIP, Integer.toString(brokerPort), Boolean.toString(testing), Boolean.toString(logWriting)}; ProcessBuilder builder = new ProcessBuilder(cmd).directory(new File(".")).redirectErrorStream(true); messageReceiver = builder.start(); messageReceiverRelay = new MessageReceiverRelay(); new Thread(messageReceiverRelay).start(); messageReceiverRelay.out.flush(); } /** * Starts the DeliveryService process and a thread to manage it's * input/output. */ private void initDeliveryService() throws IOException { String[] cmd = new String[]{"java", "-cp", classpath, DeliveryService.class.getName(), brokerName, brokerIP, Integer.toString(internalUDPPort), Integer.toString(queueCapacity), Boolean.toString(testing), Boolean.toString(logWriting), APIKey}; ProcessBuilder builder = new ProcessBuilder(cmd).directory(new File(".")).redirectErrorStream(true); deliveryService = builder.start(); deliveryServiceRelay = new DeliveryServiceRelay(); new Thread(deliveryServiceRelay).start(); } /** * Starts the Matcher processes and a thread for each to manage it's * input/output. */ private void initMatchers() throws IOException { matchers = new Process[numberOfMatchers]; matcherRelays = new MatcherRelay[numberOfMatchers]; for (int matcherID = 0; matcherID < numberOfMatchers; matcherID++) { String[] cmd = new String[]{"java", "-cp", classpath, BooleanMatcher.class.getName(), Integer.toString(matcherID), Integer.toString(internalUDPPort), Boolean.toString(testing), Boolean.toString(logWriting), Boolean.toString(elasticity), Double.toString(splitThreshold), Double.toString(mergeThreshold), Integer.toString(checkThreshold)}; ProcessBuilder builder = new ProcessBuilder(cmd).directory(new File(".")).redirectErrorStream(true); matchers[matcherID] = builder.start(); MatcherRelay matcherRelay = new MatcherRelay(matchers[matcherID], matcherID); matcherRelays[matcherID] = matcherRelay; new Thread(matcherRelay).start(); matcherRelay.out.flush(); } topKWMatchers = new Process[topKWNumberOfMatchers]; topKWMatcherRelays = new MatcherRelay[topKWNumberOfMatchers]; for (int matcherID = 0; matcherID < topKWNumberOfMatchers; matcherID++) { String[] cmd = new String[]{"java", "-cp", classpath, TopKWMatcher.class.getName(), Integer.toString(matcherID), Integer.toString(internalUDPPort), Boolean.toString(testing), Boolean.toString(logWriting), Boolean.toString(elasticity), Double.toString(splitThreshold), Double.toString(mergeThreshold), Integer.toString(checkThreshold)}; ProcessBuilder builder = new ProcessBuilder(cmd).directory(new File(".")).redirectErrorStream(true); topKWMatchers[matcherID] = builder.start(); MatcherRelay matcherRelay = new MatcherRelay(topKWMatchers[matcherID], matcherID + 100); topKWMatcherRelays[matcherID] = matcherRelay; new Thread(matcherRelay).start(); matcherRelay.out.flush(); } } /** * Starts the additional Matcher process and a thread for each to manage * it's input/output. */ public int initAdditionalBooleanMatcher() throws IOException { synchronized (mutexMatcher) { if (numberOfMatchers + topKWNumberOfMatchers + 1 < maxNumberOfMatchers) { Process[] newMatchers = new Process[numberOfMatchers + 1]; MatcherRelay[] newRelays = new MatcherRelay[numberOfMatchers + 1]; for (int i = 0; i < numberOfMatchers; i++) { newMatchers[i] = matchers[i]; newRelays[i] = matcherRelays[i]; } int matcherID = numberOfMatchers; String[] cmd = new String[]{"java", "-cp", classpath, BooleanMatcher.class.getName(), Integer.toString(matcherID), Integer.toString(internalUDPPort), Boolean.toString(testing), Boolean.toString(logWriting), Boolean.toString(elasticity), Double.toString(splitThreshold), Double.toString(mergeThreshold), Integer.toString(checkThreshold)}; ProcessBuilder builder = new ProcessBuilder(cmd).directory(new File(".")).redirectErrorStream(true); newMatchers[matcherID] = builder.start(); MatcherRelay matcherRelay = new MatcherRelay(newMatchers[matcherID], matcherID); newRelays[matcherID] = matcherRelay; new Thread(matcherRelay).start(); matcherRelay.out.flush(); matchers = newMatchers; matcherRelays = newRelays; numberOfMatchers++; return matcherID; } else { return -1; } } } /** * Starts the additional Matcher process and a thread for each to manage * it's input/output. */ public int initAdditionalTopKWMatcher() throws IOException { synchronized (mutexMatcher) { if (numberOfMatchers + topKWNumberOfMatchers + 1 < topKWMaxNumberOfMatchers) { Process[] newMatchers = new Process[topKWNumberOfMatchers + 1]; MatcherRelay[] newRelays = new MatcherRelay[topKWNumberOfMatchers + 1]; for (int i = 0; i < topKWNumberOfMatchers; i++) { newMatchers[i] = topKWMatchers[i]; newRelays[i] = topKWMatcherRelays[i]; } int matcherID = topKWNumberOfMatchers; String[] cmd = new String[]{"java", "-cp", classpath, TopKWMatcher.class.getName(), Integer.toString(matcherID), Integer.toString(internalUDPPort), Boolean.toString(testing), Boolean.toString(logWriting), Boolean.toString(elasticity), Double.toString(splitThreshold), Double.toString(mergeThreshold), Integer.toString(checkThreshold)}; ProcessBuilder builder = new ProcessBuilder(cmd).directory(new File(".")).redirectErrorStream(true); newMatchers[matcherID] = builder.start(); MatcherRelay matcherRelay = new MatcherRelay(newMatchers[matcherID], matcherID); newRelays[matcherID] = matcherRelay; new Thread(matcherRelay).start(); matcherRelay.out.flush(); topKWMatchers = newMatchers; topKWMatcherRelays = newRelays; topKWNumberOfMatchers++; return matcherID; } else { return -1; } } } /** * Removes the Matcher process */ public boolean removeBooleanMatcher(int matcherID) { //synchronized (mutexMatcher) { if (numberOfMatchers > 1) { Process[] newMatchers = new Process[numberOfMatchers - 1]; MatcherRelay[] newRelays = new MatcherRelay[numberOfMatchers - 1]; for (int i = 0; i < matcherID; i++) { newMatchers[i] = matchers[i]; newRelays[i] = matcherRelays[i]; } for (int i = matcherID + 1; i < numberOfMatchers; i++) { newMatchers[i - 1] = matchers[i]; newRelays[i - 1] = matcherRelays[i]; newRelays[i - 1].setMatcherId(i - 1); } matchers = newMatchers; matcherRelays = newRelays; numberOfMatchers--; matcherRoundRobin = matcherRoundRobin % numberOfMatchers; return true; } else { return false; } //} } /** * Removes the Matcher process */ public boolean removeTopKWMatcher(int matcherID) { synchronized (mutexMatcher) { if (topKWNumberOfMatchers > 1) { Process[] newMatchers = new Process[topKWNumberOfMatchers - 1]; MatcherRelay[] newRelays = new MatcherRelay[topKWNumberOfMatchers - 1]; for (int i = 0; i < matcherID; i++) { newMatchers[i] = topKWMatchers[i]; newRelays[i] = topKWMatcherRelays[i]; } for (int i = matcherID + 1; i < topKWNumberOfMatchers; i++) { newMatchers[i - 1] = topKWMatchers[i]; newRelays[i - 1] = topKWMatcherRelays[i]; newRelays[i - 1].setMatcherId(i - 1); } topKWMatchers = newMatchers; topKWMatcherRelays = newRelays; topKWNumberOfMatchers--; topKWMatcherRoundRobin = topKWMatcherRoundRobin % topKWNumberOfMatchers; return true; } else { return false; } } } /** * Convinience method to send a message to an output stream... */ private void sendMessage(Object msg, ObjectOutputStream out) { try { out.writeObject(msg); out.flush(); } catch (IOException e) { log.error("Sending message failed: " + e.getMessage()); this.shutdown(); } } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** * Manages the in/out streams of the messageReceiver subprocess... */ private class MessageReceiverRelay implements Runnable { ObjectInputStream in; ObjectOutputStream out; public MessageReceiverRelay() { try { // catches both the stdout and stderr of the subprocess out = new ObjectOutputStream( messageReceiver.getOutputStream()); out.flush(); in = new ObjectInputStream(messageReceiver.getInputStream()); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); Coordinator.this.shutdown(); } } @Override public void run() { while (true) { Object objIn = null; try { objIn = in.readObject(); } catch (Exception e) { System.out.println(e.getClass()); for (StackTraceElement s : e.getStackTrace()) { System.out.println(s.toString()); } log.error("Unable to read from MessageReceiver's input stream! " + e.getMessage()); Coordinator.this.shutdown(); return; } if (objIn instanceof InternalMessage) { if (objIn instanceof InitialMatchesMessage) { //forward to deliveryService to send the initial notify msgs sendMessage(objIn, deliveryServiceRelay.out); } else if (objIn instanceof InitialAnnouncementMatchesMessage) { //forward to deliveryService to send the initial announcement msgs sendMessage(objIn, deliveryServiceRelay.out); } else if (objIn instanceof ErrorMessage) { log.error(((ErrorMessage) objIn).getContents()); } else if (objIn instanceof InfoMessage) { log.writeToLog(((InfoMessage) objIn).getContents()); } else { log.error("Unexpected internal message received from MessageReceiver - " + objIn.getClass().getName()); } } else if (objIn instanceof Message) { //System.out.println("CloudBroker!" + objIn.getClass()); if (objIn instanceof SubscriberRegisterMessage) { //forward to deliveryService to establish a connection sendMessage(objIn, deliveryServiceRelay.out); } else if (objIn instanceof SubscriberDisconnectMessage) { //forward to deliveryService to kill the queue sendMessage(objIn, deliveryServiceRelay.out); } else if (objIn instanceof SubscriberUnregisterMessage) { //forward to deliveryService to kill and remove the queue sendMessage(objIn, deliveryServiceRelay.out); //forward to all Matchers to remove all subscribers subscriptions for (int i = 0; i < numberOfMatchers; i++) { sendMessage(objIn, matcherRelays[i].out); } } else if (objIn instanceof MobileBrokerRegisterMessage) { //forward to deliveryService to establish a connection sendMessage(objIn, deliveryServiceRelay.out); } else if (objIn instanceof MobileBrokerRegisterGCMMessage) { //forward to deliveryService to establish a connection sendMessage(objIn, deliveryServiceRelay.out); } else if (objIn instanceof MobileBrokerDisconnectMessage) { //forward to deliveryService to kill the queue sendMessage(objIn, deliveryServiceRelay.out); } else if (objIn instanceof SubscribeMessage) { synchronized (mutexMatcher) { SubscribeMessage msg = (SubscribeMessage) objIn; log.writeToLog("Received " + (msg.isUnsubscribe() ? "unsubscription " : "subscription ") + msg.getSubscription() + "."); //forward to a matcher to process... if (msg.getSubscription() instanceof TopKWSubscription) { sendMessage(objIn, topKWMatcherRelays[topKWMatcherRoundRobin].out); topKWMatcherRoundRobin = (topKWMatcherRoundRobin + 1) % topKWNumberOfMatchers; } else { sendMessage(objIn, matcherRelays[matcherRoundRobin].out); matcherRoundRobin = (matcherRoundRobin + 1) % numberOfMatchers; } } } else if (objIn instanceof PublishMessage) { synchronized (mutexMatcher) { PublishMessage msg = (PublishMessage) objIn; log.writeToLog("Received " + (msg.isUnpublish() ? "unpublication " : "publication ") + msg.getPublication() + "."); //forward to all matchers to process... for (int i = 0; i < numberOfMatchers; i++) { sendMessage(objIn, matcherRelays[i].out); } for (int i = 0; i < topKWNumberOfMatchers; i++) { sendMessage(objIn, topKWMatcherRelays[i].out); } } } else if (objIn instanceof AnnounceMessage) { synchronized (mutexMatcher) { AnnounceMessage msg = (AnnounceMessage) objIn; log.writeToLog("Received " + (msg.isRevokeAnnouncement() ? "revoke announcement " : "announcement ") + msg.getAnnouncement() + "."); //forward to all matchers to process... for (int i = 0; i < numberOfMatchers; i++) { sendMessage(objIn, matcherRelays[i].out); } for (int i = 0; i < topKWNumberOfMatchers; i++) { sendMessage(objIn, topKWMatcherRelays[i].out); } } } else { log.error("Unexpected external message received from MessageReceiver - " + objIn.getClass().getName()); } } else { log.error("Object received from the MessageReceiver is not of class Message" + " or InternalMessage! (" + objIn.getClass().getName() + " instead: " + objIn.toString() + " ). Ignoring..."); } } } /** * Sends a start message to the MessageReceiver components of the cloud * broker. It should make the MessageReceiver start the thread that * listens for incoming connection requests from subscribers and * publishers. */ void sendStartMessage() { try { out.writeObject(new StartComponentMessage()); out.flush(); } catch (IOException e) { //if messageReceiver found terminated shut everything down... log.error("MessageReceiver found dead while sending the start message."); Coordinator.this.shutdown(); } } } /** * Manages the in/out streams of the deliveryService subprocess... */ private class DeliveryServiceRelay implements Runnable { ObjectInputStream in; ObjectOutputStream out; InputStreamReader ba; public DeliveryServiceRelay() { try { // catches both the stdout and stderr of the subprocess out = new ObjectOutputStream( deliveryService.getOutputStream()); out.flush(); in = new ObjectInputStream( deliveryService.getInputStream()); //ba = new InputStreamReader(deliveryService.getInputStream()); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); Coordinator.this.shutdown(); } } @Override public void run() { while (true) { Object objIn = null; try { objIn = in.readObject(); //char[] a = new char[2000]; //ba.read(a); //System.out.println(a); } catch (Exception e) { try { while (in.available() > 0) { System.out.println(in.read()); } } catch (IOException ex) { } System.out.println(e.toString()); for (StackTraceElement s : e.getStackTrace()) { System.out.println(s.toString()); } log.error("Unable to read from DeliveryService's input stream! " + e.getMessage()); Coordinator.this.shutdown(); return; } if (objIn instanceof InternalMessage) { if (objIn instanceof ErrorMessage) { log.error(((ErrorMessage) objIn).getContents()); } else if (objIn instanceof InfoMessage) { log.writeToLog(((InfoMessage) objIn).getContents()); } else { log.error("Unexpected internal message received from DeliveryService - " + objIn.getClass().getName()); } } else if (objIn instanceof Message) { if (objIn instanceof SubscriberDisconnectMessage) { log.writeToLog("Subscriber " + ((SubscriberDisconnectMessage) objIn).getEntityName() + " disconnected from broker!"); //forward to messageReceiver to kill the SubForBroker sendMessage(objIn, messageReceiverRelay.out); } else if (objIn instanceof MobileBrokerDisconnectMessage) { log.writeToLog("Mobile broker " + ((MobileBrokerDisconnectMessage) objIn).getEntityName() + " disconnected from broker!"); //forward to messageReceiver to kill the SubForBroker sendMessage(objIn, messageReceiverRelay.out); } else { log.error("Unexpected external message received from DeliveryService - " + objIn.getClass().getName()); } } else { log.error("Object received from the DeliveryService is not of class Message" + " or InternalMessage! (" + objIn.getClass().getName() + " instead). Ignoring..."); } } } /** * Sends a start message to the DeliveryService components of the cloud * broker. It should make the DeliveryService start the thread that * listens for incoming connection requests from subscribers. */ void sendStartMessage() { try { out.writeObject(new StartComponentMessage()); out.flush(); } catch (IOException e) { //if deliveryService found terminated shut everything down... log.error("DeliveryService found dead while sending the start message."); Coordinator.this.shutdown(); } } } /** * Manages the in/out streams of the rootMatcher subprocess... */ private class MatcherRelay implements Runnable { ObjectInputStream in; ObjectOutputStream out; InternalMessage elasticityMessage = null; private int matcherID; boolean running = true; public MatcherRelay(Process matcher, int matcherID) { this.matcherID = matcherID; try { // catches both the stdout and stderr of the subprocess out = new ObjectOutputStream( matcher.getOutputStream()); out.flush(); in = new ObjectInputStream( matcher.getInputStream()); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); Coordinator.this.shutdown(); } } @Override public void run() { while (running) { Object objIn = null; try { objIn = in.readObject(); } catch (Exception e) { System.out.println(e.getMessage()); for (StackTraceElement s : e.getStackTrace()) { System.out.println(s.toString()); } log.error("Unable to read from Matcher " + matcherID + "'s input stream! " + e.getMessage()); Coordinator.this.shutdown(); return; } if (objIn instanceof InternalMessage) { if (objIn instanceof ErrorMessage) { log.error(((ErrorMessage) objIn).getContents()); } else if (objIn instanceof InfoMessage) { log.writeToLog(((InfoMessage) objIn).getContents()); } else if (objIn instanceof SplitBooleanMatcherMessage) { long start = System.currentTimeMillis(); try { int success = initAdditionalBooleanMatcher(); if (success != -1) { synchronized (mutexMatcher) { MatcherRelay newRelay = matcherRelays[success]; List<Subscription> subs = ((SplitBooleanMatcherMessage) objIn).getSubscriptions(); //System.out.println("PRETPLATE=" + subs.size() + " MatcherID=" + (numberOfMatchers - 1)); for (int i = 0; i < subs.size(); i++) { SubscribeMessage subMess = new SubscribeMessage(subs.get(i), false); sendMessage(subMess, newRelay.out); } sendMessage(new ElasticityReplyMessage(true), out); //System.out.println("SPLIT;" + matcherID + ";" + (System.currentTimeMillis() - start) + ";" + matcherRelays.length + ";true;" + System.currentTimeMillis() / 1000); } } else { sendMessage(new ElasticityReplyMessage(false), out); //System.out.println("SPLIT;" + matcherID + ";" + (System.currentTimeMillis() - start) + ";" + matcherRelays.length + ";false;" + System.currentTimeMillis() / 1000); } } catch (Exception e) { sendMessage(new ElasticityReplyMessage(false), out); //System.out.println("SPLIT;" + matcherID + ";" + (System.currentTimeMillis() - start) + ";" + matcherRelays.length + ";false;" + System.currentTimeMillis() / 1000); } } else if (objIn instanceof MergeBooleanMatcherMessage) { long start = System.currentTimeMillis(); synchronized (mutexMatcher) { if (removeBooleanMatcher(matcherID)) { List<Subscription> subs = ((MergeBooleanMatcherMessage) objIn).getSubscriptions(); for (int i = 0; i < subs.size(); i++) { SubscribeMessage subMess = new SubscribeMessage(subs.get(i), false); sendMessage(subMess, matcherRelays[matcherRoundRobin].out); matcherRoundRobin = (matcherRoundRobin + 1) % numberOfMatchers; } sendMessage(new ElasticityReplyMessage(true), out); try { in.close(); out.close(); running = false; log.writeToLog("Matcher " + matcherID + "merged with other matchers "); } catch (Exception e) { System.out.println(e.getMessage()); for (StackTraceElement s : e.getStackTrace()) { System.out.println(s.toString()); } log.error("During merge of the matcher " + matcherID + "connections shutted down" + e.getMessage()); } //System.out.println("MERGE;" + matcherID + ";" + (System.currentTimeMillis() - start) + ";" + matcherRelays.length + ";true;" + System.currentTimeMillis() / 1000); } else { sendMessage(new ElasticityReplyMessage(false), out); //System.out.println("MERGE;" + matcherID + ";" + (System.currentTimeMillis() - start) + ";" + matcherRelays.length + ";false;" + System.currentTimeMillis() / 1000); } } } else if (objIn instanceof SplitTopKWMatcherMessage) { try { int success = initAdditionalTopKWMatcher(); if (success != -1) { MatcherRelay newRelay = topKWMatcherRelays[success]; List<Subscription> subs = ((SplitTopKWMatcherMessage) objIn).getSubscriptions(); //System.out.println("PRETPLATE=" + subs.size() + " MatcherID=" + (topKWNumberOfMatchers - 1)); for (int i = 0; i < subs.size(); i++) { SubscribeMessage subMess = new SubscribeMessage(subs.get(i), false); sendMessage(subMess, newRelay.out); } sendMessage(new ElasticityReplyMessage(true), out); } else { sendMessage(new ElasticityReplyMessage(false), out); } } catch (Exception e) { sendMessage(new ElasticityReplyMessage(false), out); } } else if (objIn instanceof MergeTopKWMatcherMessage) { if (removeTopKWMatcher(matcherID)) { List<Subscription> subs = ((MergeTopKWMatcherMessage) objIn).getSubscriptions(); synchronized (mutexMatcher) { for (int i = 0; i < subs.size(); i++) { SubscribeMessage subMess = new SubscribeMessage(subs.get(i), false); sendMessage(subMess, topKWMatcherRelays[topKWMatcherRoundRobin].out); topKWMatcherRoundRobin = (topKWMatcherRoundRobin + 1) % topKWNumberOfMatchers; } } try { in.close(); out.close(); running = false; log.writeToLog("TopKWMatcher " + matcherID + "merged with other matchers "); } catch (Exception e) { System.out.println(e.getMessage()); for (StackTraceElement s : e.getStackTrace()) { System.out.println(s.toString()); } log.error("During merge of the topKW matcher " + matcherID + "connections shutted down" + e.getMessage()); } } else { sendMessage(new ElasticityReplyMessage(false), out); } } else { log.error("Unexpected internal message received from Matcher - " + objIn.getClass().getName()); } } else if (objIn instanceof Message) { log.error("Unexpected external message received from Matcher - " + objIn.getClass().getName()); } else { log.error("Object received from the Matcher is not of class Message" + " or InternalMessage! (" + objIn.getClass().getName() + " instead). Ignoring..."); } } } public void setMatcherId(int id) { matcherID = id; } } }