/*
* Copyright 2012-2015, the original author or authors.
*
* 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 com.flipkart.phantom.runtime.impl.server.netty;
import com.flipkart.phantom.netty.uds.OioServerSocketChannel;
import com.flipkart.phantom.netty.uds.OioServerSocketChannelFactory;
import com.flipkart.phantom.runtime.impl.server.concurrent.NamedThreadFactory;
import org.jboss.netty.bootstrap.Bootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.newsclub.net.unix.AFUNIXSocketAddress;
import org.springframework.util.Assert;
import org.trpr.platform.core.impl.logging.LogFactory;
import org.trpr.platform.core.spi.logging.Logger;
import org.trpr.platform.runtime.impl.config.FileLocator;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* <code>UDSNetworkServer</code> is a concrete implementation of the {@link AbstractNettyNetworkServer}
* for Unix Domain Sockets. Uses {@link OioServerSocketChannel} for UDS channels. Note that this server
* has to be initialized with a UDS socket file rather than a port no.
*
* @author devashishshankar
* @version 1.0, 19 Apr, 2013
*/
public class UDSNettyServer extends AbstractNettyNetworkServer {
/** Logger for this class*/
private static final Logger LOGGER = LogFactory.getLogger(UDSNettyServer.class);
/** The default counts (invalid one) for server and worker pool counts*/
private static final int INVALID_POOL_SIZE = -1;
/** The default directory name containing junix native libraries*/
private static final String DEFAULT_JUNIX_NATIVE_DIRECTORY = "uds-lib";
/** The System property to be set with Junix native lib path*/
private static final String JUNIX_LIB_SYSTEM_PROPERTY = "org.newsclub.net.unix.library.path";
/** The server and worker thread pool sizes*/
private int serverPoolSize = INVALID_POOL_SIZE;
private int workerPoolSize = INVALID_POOL_SIZE;
/** The server and worker ExecutorService instances*/
private ExecutorService serverExecutors;
private ExecutorService workerExecutors;
/** The directory name containing junix native libraries*/
private String junixNativeLibDirectoryName = DEFAULT_JUNIX_NATIVE_DIRECTORY;
/** The name of the socket file for this server (UDS) */
private String socketName;
/** The directory containing the socket file */
private String socketDir;
/** The socket file */
private File socketFile;
/**
* Interface method implementation. Returns {@link TRANSMISSION_PROTOCOL#UDS (Unix domain Sockets)
* @see com.flipkart.sp.runtime.spi.server.NetworkServer#getTransmissionProtocol()
*/
public TransmissionProtocol getTransmissionProtocol() {
return TRANSMISSION_PROTOCOL.UDS;
}
/**
* Interface method implementation. Creates server and worker thread pools if required and then calls {@link #afterPropertiesSet()} on the super class
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
File[] junixDirectories = FileLocator.findDirectories(this.junixNativeLibDirectoryName,null);
if(junixDirectories==null || junixDirectories.length==0) {
throw new RuntimeException("Did not find junixDirectory: "+junixNativeLibDirectoryName);
}
LOGGER.info("Found junixDirectory: "+junixDirectories[0].getAbsolutePath());
System.setProperty(JUNIX_LIB_SYSTEM_PROPERTY,junixDirectories[0].getAbsolutePath());
//Required properties
Assert.notNull(this.socketDir, "socketDir is a required property for UDSNetworkServer");
Assert.notNull(this.socketName, "socketName is a required property for UDSNetworkServer");
//Create the socket file
this.socketFile = new File(new File(this.socketDir), this.socketName);
//Create socket address
LOGGER.info("Socket file: "+this.socketFile.getAbsolutePath());
try {
this.socketAddress = new AFUNIXSocketAddress(this.socketFile);
} catch (IOException e) {
throw new RuntimeException("Error creating Socket Address. ",e);
}
if (this.getServerExecutors() == null) { // no executors have been set for server listener
if (this.getServerPoolSize() != UDSNettyServer.INVALID_POOL_SIZE) { // thread pool size has been set. create and use a fixed thread pool
this.setServerExecutors(Executors.newFixedThreadPool(this.getServerPoolSize(), new NamedThreadFactory("UDSServer-Listener")));
} else { // default behavior of creating and using a cached thread pool
this.setServerExecutors(Executors.newCachedThreadPool(new NamedThreadFactory("UDSServer-Listener")));
}
}
if (this.getWorkerExecutors() == null) { // no executors have been set for workers
if (this.getWorkerPoolSize() != UDSNettyServer.INVALID_POOL_SIZE) { // thread pool size has been set. create and use a fixed thread pool
this.setWorkerExecutors(Executors.newFixedThreadPool(this.getWorkerPoolSize(), new NamedThreadFactory("UDSServer-Worker")));
}else { // default behavior of creating and using a cached thread pool
this.setWorkerExecutors(Executors.newCachedThreadPool(new NamedThreadFactory("UDSServer-Worker")));
}
}
super.afterPropertiesSet();
LOGGER.info("UDS Server startup complete");
}
@Override
public String getServerType() {
return "UDS Netty Service";
}
@Override
public String getServerEndpoint() {
return this.socketDir + this.socketFile.getAbsolutePath();
}
/**
* Overriden super class method. Returns a readable string for this UDSNetworkServer
* @see java.lang.Object#toString()
*/
public String toString(){
return "UDSNetworkServer [socketFile=" + socketFile.getAbsolutePath() + "] " + this.getPipelineFactory();
}
/**
* Interface method implementation. Creates and returns a Netty ServerBootstrap instance
* @see com.flipkart.phantom.runtime.impl.server.netty.AbstractNettyNetworkServer#createServerBootstrap()
*/
protected Bootstrap createServerBootstrap() throws RuntimeException {
Assert.notNull(this.socketFile, "Socket File should not be null");
OioServerSocketChannelFactory serverSocketChannelFactory = new OioServerSocketChannelFactory(this.getServerExecutors(), this.getWorkerExecutors());
serverSocketChannelFactory.setSocketFile(this.socketFile);
return new ServerBootstrap(serverSocketChannelFactory);
}
/**
* Abstract method implementation. Creates and returns a Netty Channel from the ServerBootstrap that was
* previously created in {@link UDSNettyServer#createServerBootstrap()}
* @see com.flipkart.phantom.runtime.impl.server.netty.AbstractNettyNetworkServer#createChannel()
*/
protected Channel createChannel() throws RuntimeException {
if (this.getServerBootstrap() == null) {
throw new RuntimeException("Error creating Channel. Bootstrap instance cannot be null. See UDSNetworkServer#createServerBootstrap()");
}
return ((ServerBootstrap)this.serverBootstrap).bind(this.socketAddress);
}
/** Start Getter/Setter methods */
public int getServerPoolSize() {
return this.serverPoolSize;
}
public void setServerPoolSize(int serverPoolSize) {
this.serverPoolSize = serverPoolSize;
}
public int getWorkerPoolSize() {
return this.workerPoolSize;
}
public void setWorkerPoolSize(int workerPoolSize) {
this.workerPoolSize = workerPoolSize;
}
public ExecutorService getServerExecutors() {
return this.serverExecutors;
}
public void setServerExecutors(ExecutorService serverExecutors) {
this.serverExecutors = serverExecutors;
}
public ExecutorService getWorkerExecutors() {
return this.workerExecutors;
}
public void setWorkerExecutors(ExecutorService workerExecutors) {
this.workerExecutors = workerExecutors;
}
public String getSocketDir() {
return socketDir;
}
public void setSocketDir(String socketDir) {
this.socketDir = socketDir;
}
public String getSocketName() {
return socketName;
}
public void setSocketName(String socketName) {
this.socketName = socketName;
}
public String getJunixNativeLibDirectoryName() {
return junixNativeLibDirectoryName;
}
public void setJunixNativeLibDirectoryName(String junixNativeLibDirectoryName) {
this.junixNativeLibDirectoryName = junixNativeLibDirectoryName;
}
/** End Getter/Setter methods */
}