package cgl.iotcloud.core.transport; import cgl.iotcloud.core.Configuration; import cgl.iotcloud.core.msg.MessageContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.*; public abstract class AbstractTransport implements Transport { private static Logger LOG = LoggerFactory.getLogger(AbstractTransport.class); /** * Id of the site */ protected String siteId; /** * This gateway is connected to these brokers */ protected List<BrokerHost> brokerHosts = new ArrayList<BrokerHost>(); /** * Every transport has a list of applications. A group has specific channels registers to * it by the sensors */ protected Map<String, ChannelGroup> groups = new ConcurrentHashMap<String, ChannelGroup>(); /** * The transport specific configurations */ protected Map transportConfiguration; protected ExecutorService executorService; /** * The index is used to pick the next broker available */ private int consumerIndex = 0; private int producerIndex = 0; @Override public void configure(String siteId, Map properties) { this.siteId = siteId; this.transportConfiguration = (Map)properties.get(Configuration.TRANSPORT_PROPERTIES); Object urlProp = transportConfiguration.get(TransportConstants.PROP_URLS); if (urlProp == null || !(urlProp instanceof List)) { String message = "Url is required by the Transport"; LOG.error(message); throw new RuntimeException(message); } for (Object o : (List)urlProp) { if (o instanceof String) { String url = (String) o; brokerHosts.add(new BrokerHost(url)); } else { LOG.error("Each broker URL should be a string"); throw new RuntimeException("Each broker URL should be a string"); } } Map threads = (Map) transportConfiguration.get(TransportConstants.THREAD_PROPERTY); if (threads != null) { int core = (Integer) threads.get(TransportConstants.CORE_PROPERTY); int max = (Integer) threads.get(TransportConstants.MAX_PROPERTY); executorService = new ThreadPoolExecutor(core, max, 5000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1024)); } configureTransport(); } public abstract void configureTransport(); @Override public void registerChannel(ChannelName name, Channel channel) { // check to see if we already have a group for this channel String groupName = getGroupName(channel, name); ChannelGroup group = groups.get(groupName); if (group == null) { if (channel.getDirection() == Direction.OUT) { group = new ChannelGroup(groupName, getPrefix(channel, name), brokerHosts, this, producerIndex); incrementProducerIndex(); } else { group = new ChannelGroup(groupName, getPrefix(channel, name), brokerHosts, this, consumerIndex); incrementConsumerIndex(); } groups.put(groupName, group); } group.addChannel(channel); } @Override public void unRegisterChannel(ChannelName name, Channel channel) { // check to see if we already have a group for this channel String groupName = getGroupName(channel, name); ChannelGroup group = groups.get(groupName); if (group == null) { String msg = "Trying to un-register a channel which doesn't exist"; LOG.error(msg); throw new RuntimeException(msg); } group.removeChannel(channel); } public ChannelGroup getChannelGroup(ChannelName name, Channel channel) { String groupName = getGroupName(channel, name); return groups.get(groupName); } /** * If the channel is grouped we will create a name with Channel name and sensor group * If the channel is not grouped, we will create a name with channel name and sensor ID which is unique, * this group will only have a single channel * @param channel channel * @param channelName channel name * @return a group name */ protected String getPrefix(Channel channel, ChannelName channelName) { if (channel.isGrouped()) { return siteId + "." + channelName.getSensorName(); } else { return siteId + "." + channelName.getSensorName() + "." + channel.getSensorID(); } } /** * If the channel is grouped we will create a name with Channel name and sensor group * If the channel is not grouped, we will create a name with channel name and sensor ID which is unique, * this group will only have a single channel * @param channel channel * @param channelName channel name * @return a group name */ protected String getGroupName(Channel channel, ChannelName channelName) { if (channel.isGrouped()) { return siteId + "." + channelName.getSensorName() + "." + channelName.getChannelName(); } else { return siteId + "." + channelName.getSensorName() + "." + channel.getSensorID() + channelName.getChannelName(); } } public abstract Manageable registerProducer(BrokerHost host, String prefix, Map channelConf, BlockingQueue<MessageContext> queue); public abstract Manageable registerConsumer(BrokerHost host, String prefix, Map channelConf, BlockingQueue<MessageContext> queue); @Override public void start() { for (ChannelGroup group : groups.values()) { group.start(); } } @Override public void stop() { for (ChannelGroup group : groups.values()) { group.stop(); } } private void incrementConsumerIndex() { if (consumerIndex == brokerHosts.size() - 1) { consumerIndex = 0; } else { consumerIndex++; } } private void incrementProducerIndex() { if (producerIndex == brokerHosts.size() - 1) { producerIndex = 0; } else { producerIndex++; } } }