DefaultNodeMainExecutor.java
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 Google Inc.
00003  * 
00004  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
00005  * use this file except in compliance with the License. You may obtain a copy of
00006  * the License at
00007  * 
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00013  * License for the specific language governing permissions and limitations under
00014  * the License.
00015  */
00016 
00017 package org.ros.node;
00018 
00019 import com.google.common.base.Preconditions;
00020 import com.google.common.collect.BiMap;
00021 import com.google.common.collect.HashBiMap;
00022 import com.google.common.collect.HashMultimap;
00023 import com.google.common.collect.Lists;
00024 import com.google.common.collect.Maps;
00025 import com.google.common.collect.Multimap;
00026 import com.google.common.collect.Multimaps;
00027 
00028 import org.apache.commons.logging.Log;
00029 import org.apache.commons.logging.LogFactory;
00030 import org.ros.concurrent.DefaultScheduledExecutorService;
00031 import org.ros.namespace.GraphName;
00032 
00033 import java.util.Collection;
00034 import java.util.concurrent.ExecutorService;
00035 import java.util.concurrent.ScheduledExecutorService;
00036 
00042 public class DefaultNodeMainExecutor implements NodeMainExecutor {
00043 
00044   private static final boolean DEBUG = false;
00045   private static final Log log = LogFactory.getLog(DefaultNodeMainExecutor.class);
00046 
00047   private final NodeFactory nodeFactory;
00048   private final ScheduledExecutorService scheduledExecutorService;
00049   private final Multimap<GraphName, ConnectedNode> connectedNodes;
00050   private final BiMap<Node, NodeMain> nodeMains;
00051 
00052   private class RegistrationListener implements NodeListener {
00053     @Override
00054     public void onStart(ConnectedNode connectedNode) {
00055       registerNode(connectedNode);
00056     }
00057 
00058     @Override
00059     public void onShutdown(Node node) {
00060     }
00061 
00062     @Override
00063     public void onShutdownComplete(Node node) {
00064       unregisterNode(node);
00065     }
00066 
00067     @Override
00068     public void onError(Node node, Throwable throwable) {
00069       log.error("Node error.", throwable);
00070       unregisterNode(node);
00071     }
00072   }
00073 
00080   public static NodeMainExecutor newDefault() {
00081     return newDefault(new DefaultScheduledExecutorService());
00082   }
00083 
00088   public static NodeMainExecutor newDefault(ScheduledExecutorService executorService) {
00089     return new DefaultNodeMainExecutor(new DefaultNodeFactory(executorService), executorService);
00090   }
00091 
00098   private DefaultNodeMainExecutor(NodeFactory nodeFactory,
00099       ScheduledExecutorService scheduledExecutorService) {
00100     this.nodeFactory = nodeFactory;
00101     this.scheduledExecutorService = scheduledExecutorService;
00102     connectedNodes =
00103         Multimaps.synchronizedMultimap(HashMultimap.<GraphName, ConnectedNode>create());
00104     nodeMains = Maps.synchronizedBiMap(HashBiMap.<Node, NodeMain>create());
00105     Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
00106       @Override
00107       public void run() {
00108         DefaultNodeMainExecutor.this.shutdown();
00109       }
00110     }));
00111   }
00112 
00113   @Override
00114   public ScheduledExecutorService getScheduledExecutorService() {
00115     return scheduledExecutorService;
00116   }
00117 
00118   @Override
00119   public void execute(final NodeMain nodeMain, final NodeConfiguration nodeConfiguration,
00120       final Collection<NodeListener> nodeListeners) {
00121     // NOTE(damonkohler): To avoid a race condition, we have to make our copy
00122     // of the NodeConfiguration in the current thread.
00123     final NodeConfiguration nodeConfigurationCopy = NodeConfiguration.copyOf(nodeConfiguration);
00124     nodeConfigurationCopy.setDefaultNodeName(nodeMain.getDefaultNodeName());
00125     Preconditions.checkNotNull(nodeConfigurationCopy.getNodeName(), "Node name not specified.");
00126     if (DEBUG) {
00127       log.info("Starting node: " + nodeConfigurationCopy.getNodeName());
00128     }
00129     scheduledExecutorService.execute(new Runnable() {
00130       @Override
00131       public void run() {
00132         Collection<NodeListener> nodeListenersCopy = Lists.newArrayList();
00133         nodeListenersCopy.add(new RegistrationListener());
00134         nodeListenersCopy.add(nodeMain);
00135         if (nodeListeners != null) {
00136           nodeListenersCopy.addAll(nodeListeners);
00137         }
00138         // The new Node will call onStart().
00139         Node node = nodeFactory.newNode(nodeConfigurationCopy, nodeListenersCopy);
00140         nodeMains.put(node, nodeMain);
00141       }
00142     });
00143   }
00144 
00145   @Override
00146   public void execute(NodeMain nodeMain, NodeConfiguration nodeConfiguration) {
00147     execute(nodeMain, nodeConfiguration, null);
00148   }
00149 
00150   @Override
00151   public void shutdownNodeMain(NodeMain nodeMain) {
00152     Node node = nodeMains.inverse().get(nodeMain);
00153     if (node != null) {
00154       safelyShutdownNode(node);
00155     }
00156   }
00157 
00158   @Override
00159   public void shutdown() {
00160     synchronized (connectedNodes) {
00161       for (ConnectedNode connectedNode : connectedNodes.values()) {
00162         safelyShutdownNode(connectedNode);
00163       }
00164     }
00165   }
00166 
00173   private void safelyShutdownNode(Node node) {
00174     boolean success = true;
00175     try {
00176       node.shutdown();
00177     } catch (Exception e) {
00178       // Ignore spurious errors during shutdown.
00179       log.error("Exception thrown while shutting down node.", e);
00180       // We don't expect any more callbacks from a node that throws an exception
00181       // while shutting down. So, we unregister it immediately.
00182       unregisterNode(node);
00183       success = false;
00184     }
00185     if (success) {
00186       log.info("Shutdown successful.");
00187     }
00188   }
00189 
00196   private void registerNode(ConnectedNode connectedNode) {
00197     GraphName nodeName = connectedNode.getName();
00198     synchronized (connectedNodes) {
00199       for (ConnectedNode illegalConnectedNode : connectedNodes.get(nodeName)) {
00200         System.err.println(String.format(
00201             "Node name collision. Existing node %s (%s) will be shutdown.", nodeName,
00202             illegalConnectedNode.getUri()));
00203         illegalConnectedNode.shutdown();
00204       }
00205       connectedNodes.put(nodeName, connectedNode);
00206     }
00207   }
00208 
00215   private void unregisterNode(Node node) {
00216     connectedNodes.get(node.getName()).remove(node);
00217     nodeMains.remove(node);
00218   }
00219 }


rosjava_core
Author(s):
autogenerated on Wed Aug 26 2015 16:06:49