/*
* Copyright (C) 2013 Google Inc.
*
* 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.ros.internal.xmlrpc.webserver;
import static org.jboss.netty.channel.Channels.pipeline;
import org.apache.commons.logging.Log;
import org.apache.xmlrpc.server.XmlRpcStreamServer;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.ChannelGroupFuture;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.ros.exception.RosRuntimeException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.ScheduledExecutorService;
/**
* An Apache XMLRPC webserver based on Netty.
*
* @author Keith M. Hughes
*/
public class NettyXmlRpcWebServer {
/**
* Port for the web server.
*/
private int port;
/**
* Address for the web server.
*/
private InetAddress address;
/**
* Server handler for web sockets.
*/
private Channel serverChannel;
/**
* All channels we know about in the server.
*/
private ChannelGroup allChannels;
/**
* Factory for all channels coming into the server.
*/
private NioServerSocketChannelFactory channelFactory;
/**
* Threadpool for all threads.
*/
private ScheduledExecutorService threadPool;
/**
* Logger for the web server.
*/
private Log log;
/**
* Bootstrap for the server.
*/
private ServerBootstrap bootstrap;
/**
* Handler for any requests coming into the server.
*/
private NettyXmlRpcWebServerHandler serverHandler;
/**
* The bridge to the Apache XML RPC code.
*/
private XmlRpcStreamServer xmlRpcServer = new XmlRpcServerClientConnectionServer();
public NettyXmlRpcWebServer(int port, InetAddress address, ScheduledExecutorService threadPool,
Log log) {
this.address = address;
this.port = port;
this.log = log;
this.threadPool = threadPool;
serverHandler = new NettyXmlRpcWebServerHandler(this);
}
/**
* Start the web server up.
*/
public void start() {
allChannels = new DefaultChannelGroup("Apache XML-RPC Netty server");
channelFactory = new NioServerSocketChannelFactory(threadPool, threadPool);
bootstrap = new ServerBootstrap(channelFactory);
// Set up the event pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
// pipeline.addLast("aggregator", new
// HttpChunkAggregator(4615604));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("handler", serverHandler);
return pipeline;
}
});
serverChannel = bootstrap.bind(new InetSocketAddress(port));
allChannels.add(serverChannel);
}
/**
* Shut the web server down.
*/
public void shutdown() {
if (allChannels != null) {
ChannelGroupFuture future = allChannels.close();
future.awaitUninterruptibly();
channelFactory = null;
allChannels = null;
bootstrap.shutdown();
bootstrap = null;
}
}
/**
* Get the Apache XML RPC server associated with this web server.
*
* @return the Apache XML RPC server associated with this web server
*/
public XmlRpcStreamServer getXmlRpcServer() {
return xmlRpcServer;
}
/**
* A new channel was opened. Register it so it can be properly shut down.
*
* @param channel
*/
public void channelOpened(Channel channel) {
allChannels.add(channel);
}
/**
* Get the socket port for the web server.
*
* @return the socket port
*/
public int getPort() {
if (serverChannel != null) {
SocketAddress localAddress = serverChannel.getLocalAddress();
if (localAddress != null) {
InetSocketAddress addr = (InetSocketAddress) localAddress;
return addr.getPort();
}
SocketAddress remoteAddress = serverChannel.getRemoteAddress();
if (remoteAddress != null) {
InetSocketAddress addr = (InetSocketAddress) remoteAddress;
return addr.getPort();
}
throw new RosRuntimeException("No known address type for XMLRPC web server");
} else {
throw new RosRuntimeException("XMLRPC server not started up yet, port not available");
}
}
/**
* Return the log for the web server.
*
* @return the log
*/
public Log getLog() {
return log;
}
}