/* * 2012-3 Red Hat Inc. and/or its affiliates and other contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.overlord.rtgov.epn.embedded; import java.text.MessageFormat; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.overlord.rtgov.epn.AbstractEPNManager; import org.overlord.rtgov.epn.Channel; import org.overlord.rtgov.epn.EPNContainer; import org.overlord.rtgov.epn.EventList; import org.overlord.rtgov.epn.Network; import org.overlord.rtgov.epn.Node; /** * This class provides the embedded implementation of * the EPN Manager. * */ public class EmbeddedEPNManager extends AbstractEPNManager { private static final Logger LOG=Logger.getLogger(EmbeddedEPNManager.class.getName()); private static final int MAX_THREADS = 10; private ExecutorService _executor=Executors.newFixedThreadPool(MAX_THREADS); private EPNContainer _container=new EmbeddedEPNContainer(); private java.util.Map<String,java.util.List<EmbeddedChannel>> _entryPoints= new java.util.HashMap<String,java.util.List<EmbeddedChannel>>(); /** * {@inheritDoc} */ protected EPNContainer getContainer() { return (_container); } /** * This method provides access to the registered channels against subjects. * * @return The entry points */ protected java.util.Map<String,java.util.List<EmbeddedChannel>> getEntryPoints() { return (_entryPoints); } /** * {@inheritDoc} */ @Override protected void currentNetworkChanged(Network oldNet, Network newNet) { super.currentNetworkChanged(oldNet, newNet); if (oldNet != null) { unregisterEntryPoints(oldNet); } if (newNet != null) { registerEntryPoints(newNet); } } /** * This method unregisters the entry points associated with the supplied * network. * * @param network The network */ protected void unregisterEntryPoints(Network network) { synchronized (_entryPoints) { for (String subject : network.subjects()) { java.util.List<EmbeddedChannel> channels=_entryPoints.get(subject); if (channels != null) { for (EmbeddedChannel ch : channels) { if (ch.getNetworkName().equals(network.getName())) { channels.remove(ch); if (channels.size() == 0) { _entryPoints.remove(subject); } break; } } } } } } /** * This method registers the network's entry point against its * list of subscription subjects. * * @param network The network */ protected void registerEntryPoints(Network network) { synchronized (_entryPoints) { for (String subject : network.subjects()) { java.util.List<EmbeddedChannel> channels=_entryPoints.get(subject); if (channels == null) { channels = new java.util.ArrayList<EmbeddedChannel>(); _entryPoints.put(subject, channels); } java.util.List<Node> nodes=network.getNodesForSubject(subject); if (nodes != null) { for (Node node : nodes) { channels.add(new EmbeddedChannel(network, node, subject)); } } } } } /** * {@inheritDoc} */ public void publish(String subject, java.util.List<? extends java.io.Serializable> events) throws Exception { publish(subject, new EventList(events)); } /** * This method publishes the event list to the specific subject. * * @param subject The subject * @param events The events * @throws Exception Failed to publish events */ protected void publish(String subject, EventList events) throws Exception { synchronized (_entryPoints) { java.util.List<EmbeddedChannel> channels=_entryPoints.get(subject); if (channels != null) { for (EmbeddedChannel channel : channels) { channel.send(events); } } } } /** * {@inheritDoc} */ public void close() throws Exception { // TODO: Should be configurable?? _executor.awaitTermination(5, TimeUnit.SECONDS); } /** * The embedded implementation of the EPNContainer. * */ protected class EmbeddedEPNContainer implements EPNContainer { /** * {@inheritDoc} */ public Channel getChannel(Network network, String source, String dest) throws Exception { return (new EmbeddedChannel(network, network.getNode(dest), source)); } /** * {@inheritDoc} */ public Channel getNotificationChannel(Network network, String subject) throws Exception { return (new EmbeddedChannel(network, subject)); } /** * {@inheritDoc} */ public Channel getChannel(String subject) throws Exception { return (new EmbeddedChannel(subject)); } /** * {@inheritDoc} */ public void send(EventList events, List<Channel> channels) throws Exception { for (Channel channel : channels) { if (channel instanceof EmbeddedChannel) { ((EmbeddedChannel)channel).send(events); } else { LOG.severe(MessageFormat.format( java.util.PropertyResourceBundle.getBundle( "epn-container-embedded.Messages").getString("EPN-CONTAINER-EMBEDDED-1"), channel)); } } } } /** * This is the embedded implementation of the Channel interface. * */ protected class EmbeddedChannel implements Channel { private Network _network=null; private Node _node=null; private String _source=null; private String _subject=null; private boolean _notification=false; /** * The constructor for publishing events between nodes in a network. * * @param network The network * @param node The node * @param source The source node name */ public EmbeddedChannel(Network network, Node node, String source) { _network = network; _node = node; _source = source; } /** * The constructor for the notification channel. * * @param network The network * @param subject The subject */ public EmbeddedChannel(Network network, String subject) { _network = network; _subject = subject; _notification = true; _source = subject; } /** * The constructor for publishing on a subject between networks. * * @param subject The subject */ public EmbeddedChannel(String subject) { _subject = subject; _source = subject; } /** * This method determines whether this channel is used for * notifications. * * @return Whether this is a notification channel */ public boolean isNotificationChannel() { return (_notification); } /** * This method returns the network name. * * @return The network name */ protected String getNetworkName() { return (_network.getName()); } /** * This method returns the network version. * * @return The network version */ protected String getVersion() { return (_network.getVersion()); } /** * This method returns the node name. * * @return The node name */ protected String getNodeName() { return (_node.getName()); } /** * {@inheritDoc} */ public void send(EventList events) throws Exception { if (isNotificationChannel()) { notifyListeners(_subject, events); } else { send(events, -1); } } /** * {@inheritDoc} */ public void send(EventList events, int retriesLeft) throws Exception { if (_subject != null) { publish(_subject, events); } else { if (retriesLeft == -1) { retriesLeft = _node.getMaxRetries(); } _executor.execute(new EPNTask(_network, _node, _source, events, retriesLeft, this)); } } /** * {@inheritDoc} */ public void close() throws Exception { } } /** * This class implements the task for dispatching the event list * to the node. * */ protected class EPNTask implements Runnable { private Network _network=null; private Node _node=null; private String _source=null; private EventList _events=null; private int _retriesLeft=0; private EmbeddedChannel _channel=null; /** * This is the constructor for the task. * * @param network The network * @param node The node * @param source The source name * @param events The list of events * @param retriesLeft The number of retries left * @param channel The channel */ public EPNTask(Network network, Node node, String source, EventList events, int retriesLeft, EmbeddedChannel channel) { _network = network; _node = node; _source = source; _events = events; _retriesLeft = retriesLeft; _channel = channel; } /** * {@inheritDoc} */ public void run() { EventList retries=null; try { retries = process(_network, _node, _source, _events, _retriesLeft); } catch (Exception e) { LOG.log(Level.SEVERE, java.util.PropertyResourceBundle.getBundle( "epn-container-embedded.Messages").getString("EPN-CONTAINER-EMBEDDED-2"), e); retries = _events; } if (retries != null) { if (_retriesLeft > 0) { try { _channel.send(retries, _retriesLeft-1); } catch (Exception e) { LOG.log(Level.SEVERE, java.util.PropertyResourceBundle.getBundle( "epn-container-embedded.Messages").getString("EPN-CONTAINER-EMBEDDED-3"), e); } } else { // TODO: Should this be reported via the manager? LOG.severe(java.util.PropertyResourceBundle.getBundle( "epn-container-embedded.Messages").getString("EPN-CONTAINER-EMBEDDED-4")); } } } } }