/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
package Sirius.server.middleware.impls.proxy;
import Sirius.server.Server;
import Sirius.server.ServerExit;
import Sirius.server.ServerExitError;
import Sirius.server.ServerStatus;
import Sirius.server.ServerType;
import Sirius.server.Shutdown;
import Sirius.server.property.ServerProperties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.MissingResourceException;
import de.cismet.cids.server.CallServerService;
import de.cismet.cids.server.ServerSecurityManager;
import de.cismet.cids.server.ws.rest.RESTfulSerialInterfaceConnector;
import de.cismet.cids.server.ws.rest.RESTfulService;
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
public final class StartProxy {
//~ Static fields/initializers ---------------------------------------------
private static final transient Logger LOG = Logger.getLogger(StartProxy.class);
private static StartProxy instance;
//~ Instance fields --------------------------------------------------------
private final transient CallServerService callServer;
private final transient String siriusRegistryIP;
private final transient Server serverInfo;
private final transient ServerStatus status;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new StartProxy object.
*
* @param configFile DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
* @throws IllegalStateException DOCUMENT ME!
*/
private StartProxy(final String configFile) throws ServerExitError {
if (LOG.isDebugEnabled()) {
LOG.debug("creating new StartProxy: " + configFile); // NOI18N
}
// initialise server properties
final ServerProperties properties = initServerProperties(configFile);
// init log4j
final String fileName = properties.getLog4jPropertyFile();
if ((fileName != null) && !fileName.isEmpty()) {
try {
PropertyConfigurator.configure(fileName);
} catch (final Exception e) {
LOG.warn("could not initialise Log4J", e); // NOI18N
}
}
if ("proxy".equalsIgnoreCase(properties.getStartMode())) {
if (LOG.isInfoEnabled()) {
LOG.info("<CS> INFO: starting RESTful pass-through proxy");
}
siriusRegistryIP = null;
serverInfo = null;
status = null;
if (!properties.isRestEnabled()) {
throw new IllegalStateException("if the startmode is proxy then REST must be enabled"); // NOI18N
}
if (LOG.isInfoEnabled()) {
LOG.info("<CS> INFO: pass-through url: " + properties.getServerProxyURL());
}
callServer = new RESTfulSerialInterfaceConnector(properties.getServerProxyURL());
RESTfulService.up(properties);
} else {
// init server registry ip
siriusRegistryIP = initServerRegistryIP(properties);
// TODO: why sout???
System.out.println("<CS> INFO: siriusRegistryIP:: " + siriusRegistryIP); // NOI18N
System.out.println("<CS> INFO: configFile:: " + configFile); // NOI18N
if (LOG.isInfoEnabled()) {
LOG.info("<CS> INFO: siriusRegistryIP:: " + siriusRegistryIP); // NOI18N
LOG.info("<CS> INFO: configFile:: " + configFile); // NOI18N
}
// create a securitymanager if it is not registered yet
try {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new ServerSecurityManager());
}
} catch (final Exception e) {
final String message = "could not create security manager"; // NOI18N
LOG.fatal(message, e);
throw new ServerExitError(message, e);
}
// init server
serverInfo = initServer(properties);
// init RMI registry
final Registry rmiRegistry = initRegistry(Integer.valueOf(serverInfo.getRMIPort()));
// create and bind callserver instance
callServer = createAndBindProxy(properties);
status = new ServerStatus();
// bring up the RESTful Service after initialisation if rest is enabled
if (properties.isRestEnabled()) {
try {
RESTfulService.up(properties);
} catch (final ServerExitError e) {
LOG.error("could not bring up RESTful interface", e); // NOI18N
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<CS> RMIRegistry does exist..."); // NOI18N
final String[] list;
try {
list = rmiRegistry.list();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.length; i++) {
sb.append('\t').append(list[i]);
}
if (LOG.isDebugEnabled()) {
LOG.debug(" Info <CS> Already registered with RMIRegistry: " + sb.toString()); // NOI18N
}
} catch (final Exception ex) {
if (LOG.isDebugEnabled()) {
LOG.debug("cannot list registered services", ex); // NOI18N
}
}
}
}
}
//~ Methods ----------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @param configFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
*/
private ServerProperties initServerProperties(final String configFile) throws ServerExitError {
try {
return new ServerProperties(configFile);
} catch (final FileNotFoundException ex) {
final String message = "given configFile does not exist: " + configFile; // NOI18N
LOG.fatal(message, ex);
throw new ServerExitError(message, ex);
} catch (final IOException ex) {
final String message = "error while reading config: " + configFile; // NOI18N
LOG.fatal(message, ex);
throw new ServerExitError(message, ex);
}
}
/**
* DOCUMENT ME!
*
* @param properties DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
*/
private String initServerRegistryIP(final ServerProperties properties) throws ServerExitError {
try {
final String[] ips = properties.getRegistryIps();
if (ips.length == 0) {
final String message = "registry IPs not set in config file, server exit"; // NOI18N
LOG.fatal(message);
throw new ServerExitError(message);
} else {
final String ip = ips[0];
if (LOG.isInfoEnabled()) {
LOG.info("using registry ip: " + ip); // NOI18N
}
return ip;
}
} catch (final MissingResourceException mre) {
final String message = "<CS> FATAL: value for key '" + mre.getMessage() + "' is missing"; // NOI18N
// TODO: why serr???
System.err.println(message);
LOG.fatal(message, mre);
throw new ServerExitError(mre);
}
}
/**
* DOCUMENT ME!
*
* @param properties DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
*/
private Server initServer(final ServerProperties properties) throws ServerExitError {
try {
String rmiPort;
try {
rmiPort = properties.getRMIRegistryPort();
} catch (final MissingResourceException mre) {
final String warning = "<CS> WARN: value for key " + mre.getMessage() + " is missing"; // NOI18N
// TODO: why serr???
System.err.println(warning);
LOG.warn(warning, mre);
// defaulting to standard port 1099
final String message = "<CS> INFO: set default RMI port: 1099"; // NOI18N
System.out.println(message);
if (LOG.isInfoEnabled()) {
LOG.info(message);
}
rmiPort = "1099"; // NOI18N
}
return new Server(
ServerType.CALLSERVER,
properties.getServerName(),
InetAddress.getLocalHost().getHostAddress(),
rmiPort,
String.valueOf(properties.getServerPort()));
} catch (final UnknownHostException e) {
final String message = "SEVERE: could not find host address for localhost"; // NOI18N
LOG.fatal(message, e);
throw new ServerExitError(message, e);
}
}
/**
* DOCUMENT ME!
*
* @param port DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
*/
private Registry initRegistry(final int port) throws ServerExitError {
try {
if (LOG.isDebugEnabled()) {
LOG.debug("<CS> DEBUG: getRMIRegistry on port " + port); // NOI18N
}
return LocateRegistry.getRegistry(port);
} catch (final RemoteException e) {
// no registry present, create new registry on rmiPort
final String info = "<CS> INFO: no RMIRegistry on port " + port + " available"; // NOI18N
final String message = "<CS> INFO: create RMIRegistry on port " + port; // NOI18N
// TODO: why serr???
System.out.println(e.getMessage() + " \n" + info); // NOI18N
System.out.println(message);
if (LOG.isInfoEnabled()) {
LOG.info(info, e);
LOG.info(message);
}
try {
return LocateRegistry.createRegistry(port);
} catch (final RemoteException ex) {
final String fatal = "SEVERE: cannot create registry on port: " + port; // NOI18N
LOG.fatal(fatal, ex);
throw new ServerExitError(fatal, ex);
}
}
}
/**
* DOCUMENT ME!
*
* @param properties DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
*/
private ProxyImpl createAndBindProxy(final ServerProperties properties) throws ServerExitError {
try {
final ProxyImpl proxy = new ProxyImpl(properties);
Naming.bind("//" + siriusRegistryIP + ":" + serverInfo.getRMIPort() + "/callServer", proxy); // NOI18N
return proxy;
} catch (final RemoteException ex) {
final String fatal = "cannot create callserver implementation"; // NOI18N
LOG.fatal(fatal, ex);
throw new ServerExitError(fatal, ex);
} catch (final AlreadyBoundException e) {
final String fatal = "cannot bind callserver"; // NOI18N
LOG.fatal(fatal, e);
throw new ServerExitError(fatal, e);
} catch (final MalformedURLException e) {
final String fatal = "cannot bind callserver"; // NOI18N
LOG.fatal(fatal, e);
throw new ServerExitError(fatal, e);
}
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws IllegalStateException DOCUMENT ME!
*/
public static synchronized StartProxy getInstance() throws IllegalStateException {
if (instance == null) {
throw new IllegalStateException("startproxy not up yet"); // NOI18N
}
return instance;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws IllegalStateException DOCUMENT ME!
*/
public static synchronized StartProxy getServerInstance() throws IllegalStateException {
return getInstance();
}
/**
* DOCUMENT ME!
*
* @param configFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
*/
public static synchronized StartProxy getInstance(final String configFile) throws ServerExitError {
if (LOG.isDebugEnabled()) {
LOG.debug("getInstance for configfile: " + configFile + " :: instance already present? " + instance); // NOI18N
}
if (instance == null) {
instance = new StartProxy(configFile);
}
return instance;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public ServerStatus getStatus() {
return status;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public CallServerService getCallServer() {
return callServer;
}
/**
* DOCUMENT ME!
*
* @throws ServerExit Throwable DOCUMENT ME!
* @throws ServerExitError DOCUMENT ME!
*/
public synchronized void shutdown() throws ServerExit, ServerExitError {
if (LOG.isDebugEnabled()) {
LOG.debug("shutdown proxy: " + this); // NOI18N
}
try {
final Shutdown shutdown = Shutdown.createShutdown(this);
shutdown.shutdown();
if (callServer instanceof ProxyImpl) {
final ProxyImpl proxyimpl = (ProxyImpl)callServer;
proxyimpl.unregisterAsObserver(siriusRegistryIP + ":" + serverInfo.getServerPort()); // NOI18N
proxyimpl.getNameServer()
.unregisterServer(
serverInfo.getType(),
serverInfo.getName(),
serverInfo.getIP(),
serverInfo.getServerPort());
RESTfulService.down();
try {
if (LOG.isDebugEnabled()) {
LOG.debug("unbind callserver"); // NOI18N
}
Naming.unbind("//" + siriusRegistryIP + ":" + serverInfo.getRMIPort() + "/callServer"); // NOI18N
} catch (final NotBoundException e) {
LOG.warn("callserver not available (anymore), probably already unbound", e); // NOI18N
}
} else {
RESTfulService.down();
}
final String message = "Server shutdown success"; // NOI18N
if (LOG.isInfoEnabled()) {
LOG.info(message);
}
// TODO: a throwable is thrown to indicate success?! This is bad code style. Refactor
throw new ServerExit(message);
} catch (final Exception e) {
final String message = "Server shutdown failure, integrity no longer guaranteed"; // NOI18N
LOG.fatal(message, e);
throw new ServerExitError(message, e);
} finally {
instance = null;
}
}
/**
* DOCUMENT ME!
*
* @param args DOCUMENT ME!
*
* @throws ServerExitError DOCUMENT ME!
*/
public static void main(final String[] args) throws ServerExitError {
if (args == null) {
throw new ServerExitError("no cli params"); // NOI18N
} else if (args.length < 1) {
throw new ServerExitError("too few arguments"); // NOI18N
}
StartProxy.getInstance(args[0]);
}
}