/*
* Copyright (C) 2006-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.jlan.app;
import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.alfresco.jlan.debug.Debug;
import org.alfresco.jlan.debug.DebugConfigSection;
import org.alfresco.jlan.ftp.FTPConfigSection;
import org.alfresco.jlan.netbios.server.NetBIOSNameServer;
import org.alfresco.jlan.netbios.win32.Win32NetBIOS;
import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection;
import org.alfresco.jlan.server.NetworkServer;
import org.alfresco.jlan.server.config.ServerConfiguration;
import org.alfresco.jlan.smb.server.CIFSConfigSection;
import org.alfresco.jlan.smb.server.SMBServer;
import org.tanukisoftware.wrapper.WrapperListener;
import org.tanukisoftware.wrapper.WrapperManager;
/**
* JLAN Server Service Class
*
* @author gkspencer
*/
public class JLANServerService implements WrapperListener, Runnable {
// Default configuration file name
private static final String DEFAULT_CONFIGFILENAME = "jlanserver.xml";
// Server shutdown flag
private boolean m_shutdown;
// Server configuration
private ServerConfiguration m_config;
// Thread used to start the various servers
private Thread m_serverThread;
/**
* Service start requested
*
* @param args String[]
* @return Integer
*/
public Integer start(String[] args) {
// Indicate that startup will take a short while
WrapperManager.signalStarting(20000);
// Command line parameter should specify the configuration file
PrintStream out = System.out;
String fileName = null;
if (args.length < 1) {
// Search for a default configuration file in the users home directory
fileName = System.getProperty("user.home") + File.separator + DEFAULT_CONFIGFILENAME;
}
else
fileName = args[0];
// Load the configuration
m_config = null;
try {
// Create an XML configuration
m_config = new XMLServerConfiguration();
m_config.loadConfiguration(fileName);
}
catch (Exception ex) {
// Failed to load server configuration
out.println("%% Failed to load server configuration");
ex.printStackTrace(out);
return new Integer(2);
}
// Check if the local IP address returns a valid value, '127.0.0.1' indicates a mis-configuration in the hosts file
try {
// Get the local address
String localAddr = InetAddress.getLocalHost().getHostAddress();
if ( localAddr.equals("127.0.0.1")) {
out.println("%% Local IP address resolves to 127.0.0.1, this may be caused by a mis-configured hosts file");
return new Integer(3);
}
}
catch (UnknownHostException ex) {
// Failed to get local host IP address details
out.println("%% Failed to get local IP address details");
ex.printStackTrace(out);
return new Integer(4);
}
// NetBIOS name server, SMB, FTP and NFS servers
try {
// Create the SMB server and NetBIOS name server, if enabled
if ( m_config.hasConfigSection( CIFSConfigSection.SectionName)) {
// Get the CIFS server configuration
CIFSConfigSection cifsConfig = (CIFSConfigSection) m_config.getConfigSection( CIFSConfigSection.SectionName);
// Load the Win32 NetBIOS library
//
// For some strange reason the native code loadLibrary() call hangs if done later by the SMBServer.
// Forcing the Win32NetBIOS class to load here and run the static initializer fixes the problem.
if ( cifsConfig.hasWin32NetBIOS())
Win32NetBIOS.LanaEnumerate();
// Create the NetBIOS name server if NetBIOS SMB is enabled
if (cifsConfig.hasNetBIOSSMB())
m_config.addServer( createNetBIOSServer(m_config));
// Create the SMB server
m_config.addServer( createSMBServer(m_config));
}
// Create the FTP server, if enabled
if ( m_config.hasConfigSection( FTPConfigSection.SectionName)) {
// Create the FTP server
m_config.addServer( createFTPServer( m_config));
}
// Create the NFS server and mount server, if enabled
if ( m_config.hasConfigSection( NFSConfigSection.SectionName)) {
// Get the NFS server configuration
NFSConfigSection nfsConfig = (NFSConfigSection) m_config.getConfigSection( NFSConfigSection.SectionName);
// Check if the port mapper is enabled
if ( nfsConfig.hasNFSPortMapper())
m_config.addServer( createNFSPortMapper( m_config));
// Create the mount server
m_config.addServer( createNFSMountServer( m_config));
// Create the NFS server
m_config.addServer( createNFSServer( m_config));
}
// Start the configured servers in a seperate thread
m_serverThread = new Thread(this);
m_serverThread.start();
}
catch (Exception ex) {
out.println("%% Server error");
ex.printStackTrace(out);
return new Integer(5);
}
// Indicate that the service started
return null;
}
/**
* Service stop requested
*
* @param exitCode int
* @return int
*/
public int stop(int exitCode) {
// Set the shutdown flag
m_shutdown = true;
// Get the debug configuration
DebugConfigSection dbgConfig = (DebugConfigSection) m_config.getConfigSection( DebugConfigSection.SectionName);
// Check if the server list is valid
if ( m_config.numberOfServers() > 0) {
// Shutdown the servers
for ( int i = 0; i < m_config.numberOfServers(); i++) {
// Indicate that the service is stopping
WrapperManager.signalStopping(5000);
// Get the current server
NetworkServer server = m_config.getServer(i);
// DEBUG
if ( Debug.EnableInfo && dbgConfig != null && dbgConfig.hasDebug())
Debug.println("Shutting server " + server.getProtocolName() + " ...");
// Start the server
m_config.getServer(i).shutdownServer(false);
}
}
// Indicate that the service is stopped
WrapperManager.signalStopped(5000);
// Return the status code
return exitCode;
}
/**
* Handle control events
*
* @param event int
*/
public void controlEvent(int event) {
// Check if the wrapper manager is handling events
if ( WrapperManager.isControlledByNativeWrapper() == false) {
// The wrapper manager is not handling events, handle it here
if ( event == WrapperManager.WRAPPER_CTRL_C_EVENT ||
event == WrapperManager.WRAPPER_CTRL_CLOSE_EVENT ||
event == WrapperManager.WRAPPER_CTRL_SHUTDOWN_EVENT) {
// Stop the service
WrapperManager.stop(0);
}
}
}
/**
* Main application startup
*
* @param args String[]
*/
public static void main(String[] args) {
// Start the main JLAN Server application via the service wrapper
WrapperManager.start( new JLANServerService(), args);
}
/**
* Create the SMB server
*
* @param config ServerConfiguration
* @return NetworkServer
* @exception Exception
*/
protected final static NetworkServer createSMBServer(ServerConfiguration config)
throws Exception {
// Create an SMB server
return new SMBServer(config);
}
/**
* Create the NetBIOS name server
*
* @param config ServerConfiguration
* @return NetworkServer
* @exception Exception
*/
protected final static NetworkServer createNetBIOSServer(ServerConfiguration config)
throws Exception {
// Create a NetBIOS name server
return new NetBIOSNameServer(config);
}
/**
* Create the FTP server
*
* @param config ServerConfiguration
* @return NetworkServer
* @exception Exception
*/
protected final static NetworkServer createFTPServer(ServerConfiguration config)
throws Exception {
// Create an FTP server
return createServer( "org.alfresco.jlan.ftp.FTPServer", config);
}
/**
* Create the NFS server
*
* @param config ServerConfiguration
* @return NetworkServer
* @exception Exception
*/
protected final static NetworkServer createNFSServer(ServerConfiguration config)
throws Exception {
// Create the NFS server instance
return createServer( "org.alfresco.jlan.oncrpc.nfs.NFSServer", config);
}
/**
* Create the NFS mount server
*
* @param config ServerConfiguration
* @return NetworkServer
* @exception Exception
*/
protected final static NetworkServer createNFSMountServer(ServerConfiguration config)
throws Exception {
// Create the mount server instance
return createServer( "org.alfresco.jlan.oncrpc.mount.MountServer", config);
}
/**
* Create the NFS port mapper server
*
* @param config ServerConfiguration
* @return NetworkServer
*/
protected final static NetworkServer createNFSPortMapper(ServerConfiguration config)
throws Exception {
// Create the port mapper server instance
return createServer( "org.alfresco.jlan.oncprc.portmap.PortMapperServer", config);
}
/**
* Create a network server using reflection
*
* @param className String
* @param config ServerConfiguration
* @return NetworkServer
* @exception Exception
*/
protected final static NetworkServer createServer(String className, ServerConfiguration config)
throws Exception {
// Create the server instance using reflection
NetworkServer srv = null;
// Find the server constructor
Class<?>[] classes = new Class[1];
classes[0] = ServerConfiguration.class;
Constructor<?> srvConstructor = Class.forName(className).getConstructor(classes);
// Create the network server
Object[] args = new Object[1];
args[0] = config;
srv = (NetworkServer) srvConstructor.newInstance(args);
// Return the network server instance
return srv;
}
/**
* Thread method
*/
public void run() {
// Check if there are any servers configured
if ( m_config.numberOfServers() > 0) {
// Clear the shutdown flag
m_shutdown = false;
// Get the debug configuration
DebugConfigSection dbgConfig = (DebugConfigSection) m_config.getConfigSection( DebugConfigSection.SectionName);
// Start the servers
for ( int i = 0; i < m_config.numberOfServers(); i++) {
// Indicate that the servers are starting
WrapperManager.signalStarting(10000);
// Get the current server
NetworkServer server = m_config.getServer(i);
// DEBUG
if ( Debug.EnableInfo && dbgConfig != null && dbgConfig.hasDebug())
Debug.println("Starting server " + server.getProtocolName() + " ...");
// Start the server
m_config.getServer(i).startServer();
}
// Wait for shutdown request
while ( m_shutdown == false) {
try {
Thread.sleep(250);
}
catch (Exception ex) {
}
}
}
}
}