package ibis.ipl.server; import ibis.ipl.registry.ControlPolicy; import ibis.ipl.registry.central.server.CentralRegistryService; import ibis.ipl.registry.gossip.BootstrapService; import ibis.ipl.support.management.ManagementService; import ibis.smartsockets.SmartSocketsProperties; import ibis.smartsockets.direct.DirectSocketAddress; import ibis.smartsockets.hub.Hub; import ibis.smartsockets.hub.servicelink.ServiceLink; import ibis.smartsockets.virtual.VirtualSocketFactory; import ibis.util.ClassLister; import ibis.util.TypedProperties; import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Main Ibis Server class. * * @ibis.experimental */ public final class Server implements ServerInterface { public static final String ADDRESS_LINE_PREFIX = "IBIS SERVER RUNNING ON: "; public static final String ADDRESS_LINE_POSTFIX = "EOA"; private static final Logger logger = LoggerFactory.getLogger(Server.class); private final VirtualSocketFactory virtualSocketFactory; private final Hub hub; private final ServerConnectionHandler connectionHandler; private final DirectSocketAddress address; private final CentralRegistryService registryService; private final BootstrapService bootstrapService; private final ManagementService managementService; // services specified by user (either in jars or loaded over the network) private final Map<String, Service> services; private final boolean hubOnly; private final boolean remote; public Server(Properties properties) throws Exception { this(properties, null); } /** * Create a server with the given server properties. */ public Server(Properties properties, ControlPolicy policy) throws Exception { services = new HashMap<String, Service>(); // get default properties. TypedProperties typedProperties = ServerProperties .getHardcodedProperties(); // add specified properties typedProperties.addProperties(properties); if (logger.isDebugEnabled()) { TypedProperties serverProperties = typedProperties .filter("ibis.server"); logger.debug("Settings for server:\n" + serverProperties); } // create the virtual socket factory ibis.smartsockets.util.TypedProperties smartProperties = new ibis.smartsockets.util.TypedProperties(); smartProperties.putAll(SmartSocketsProperties.getDefaultProperties()); String hubs = typedProperties .getProperty(ServerProperties.HUB_ADDRESSES); if (hubs != null) { smartProperties.put(SmartSocketsProperties.HUB_ADDRESSES, hubs); } String hubAddressFile = typedProperties .getProperty(ServerProperties.HUB_ADDRESS_FILE); if (hubAddressFile != null) { smartProperties.put(SmartSocketsProperties.HUB_ADDRESS_FILE, hubAddressFile); } // if (typedProperties.getBooleanProperty(ServerProperties.PRINT_STATS)) { // smartProperties.put(SmartSocketsProperties.HUB_STATISTICS, "true"); // smartProperties.put(SmartSocketsProperties.HUB_STATS_INTERVAL, // "60000"); // } hubOnly = typedProperties.getBooleanProperty(ServerProperties.HUB_ONLY); remote = typedProperties.getBooleanProperty(ServerProperties.REMOTE); String vizInfo = properties.getProperty(ServerProperties.VIZ_INFO); if (hubOnly) { if (vizInfo != null) { smartProperties.put(SmartSocketsProperties.HUB_VIZ_INFO, vizInfo); } virtualSocketFactory = null; smartProperties.put(SmartSocketsProperties.HUB_PORT, typedProperties.getProperty(ServerProperties.PORT)); hub = new Hub(smartProperties); address = hub.getHubAddress(); connectionHandler = null; registryService = null; bootstrapService = null; managementService = null; } else { if (vizInfo == null) { vizInfo = "S^Ibis Server^Ibis Server"; } smartProperties.put(SmartSocketsProperties.HUB_VIZ_INFO, vizInfo); // create server socket hub = null; smartProperties.put(SmartSocketsProperties.PORT_RANGE, typedProperties.getProperty(ServerProperties.PORT)); if (typedProperties.getBooleanProperty(ServerProperties.START_HUB)) { smartProperties.put(SmartSocketsProperties.START_HUB, "true"); smartProperties .put(SmartSocketsProperties.HUB_DELEGATE, "true"); } // create a factory, or get an existing one from SmartSockets VirtualSocketFactory factory = VirtualSocketFactory .getSocketFactory("ibis"); if (factory == null) { factory = VirtualSocketFactory.getOrCreateSocketFactory("ibis", smartProperties, true); } else if (hubs != null) { factory.addHubs(hubs.split(",")); } this.virtualSocketFactory = factory; address = virtualSocketFactory.getLocalHost(); try { ServiceLink sl = virtualSocketFactory.getServiceLink(); if (sl != null) { if (typedProperties .getBooleanProperty(ServerProperties.START_HUB)) { if (!sl.registerProperty("smartsockets.viz", "invisible")) { sl.updateProperty("smartsockets.viz", "invisible"); } } else { if (!sl.registerProperty("smartsockets.viz", vizInfo)) { sl.updateProperty("smartsockets.viz", vizInfo); } } } else { logger .warn("could not set smartsockets viz property: could not get smartsockets service link"); } } catch (Throwable e) { logger.warn("could not register smartsockets viz property", e); } // create default services registryService = new CentralRegistryService(typedProperties, virtualSocketFactory, policy); services.put(registryService.getServiceName(), registryService); bootstrapService = new BootstrapService(typedProperties, virtualSocketFactory); services.put(bootstrapService.getServiceName(), bootstrapService); managementService = new ManagementService(typedProperties, virtualSocketFactory); services.put(managementService.getServiceName(), managementService); // create user specified services ClassLister classLister = ClassLister.getClassLister(null); Class<?>[] serviceClassList; if (typedProperties.containsKey(ServerProperties.SERVICES)) { String[] services = typedProperties .getStringList(ServerProperties.SERVICES); if (services == null) { serviceClassList = classLister.getClassList("Ibis-Service", Service.class).toArray(new Class[0]); } else { serviceClassList = new Class[services.length]; for (int i = 0; i < services.length; i++) { serviceClassList[i] = Class.forName(services[i]); } } } else { serviceClassList = classLister.getClassList("Ibis-Service", Service.class).toArray(new Class[0]); } for (int i = 0; i < serviceClassList.length; i++) { try { Service service = (Service) serviceClassList[i] .getConstructor( new Class[] { TypedProperties.class, VirtualSocketFactory.class }) .newInstance( new Object[] { typedProperties, virtualSocketFactory }); services.put(service.getServiceName(), service); } catch (InvocationTargetException e) { if (e.getCause() == null) { logger.warn("Could not create service " + serviceClassList[i] + ":", e); } else { logger.warn("Could not create service " + serviceClassList[i] + ":", e.getCause()); } } catch (Throwable e) { logger.warn("Could not create service " + serviceClassList[i] + ":", e); } } // start handling remote requests connectionHandler = new ServerConnectionHandler(this, factory); } } /* * (non-Javadoc) * * @see ibis.ipl.server.ServerInterface#getRegistryService() */ public CentralRegistryService getRegistryService() { return registryService; } BootstrapService getBootstrapService() { return bootstrapService; } /* * (non-Javadoc) * * @see ibis.ipl.server.ServerInterface#getManagementService() */ public ManagementService getManagementService() { return managementService; } /* * (non-Javadoc) * * @see ibis.ipl.server.ServerInterface#getAddress() */ public String getAddress() { return address.toString(); } /* * (non-Javadoc) * * @see ibis.ipl.server.ServerInterface#getServiceNames() */ public String[] getServiceNames() { return services.keySet().toArray(new String[0]); } /* * (non-Javadoc) * * @see ibis.ipl.server.ServerInterface#getHubs() */ public String[] getHubs() { DirectSocketAddress[] hubs; if (hubOnly) { hubs = hub.knownHubs(); } else { hubs = virtualSocketFactory.getKnownHubs(); } ArrayList<String> result = new ArrayList<String>(); if (hubs != null) { for (DirectSocketAddress hub : hubs) { result.add(hub.toString()); } } return result.toArray(new String[0]); } /* * (non-Javadoc) * * @seeibis.ipl.server.ServerInterface#addHubs(ibis.smartsockets.direct. * DirectSocketAddress) */ public void addHubs(DirectSocketAddress... hubAddresses) { if (hubOnly) { hub.addHubs(hubAddresses); } else { virtualSocketFactory.addHubs(hubAddresses); } } /* * (non-Javadoc) * * @see ibis.ipl.server.ServerInterface#addHubs(java.lang.String) */ public void addHubs(String... hubAddresses) { if (hubOnly) { hub.addHubs(hubAddresses); } else { virtualSocketFactory.addHubs(hubAddresses); } } public String toString() { if (hubOnly) { return "Hub running on " + getAddress(); } String message = "Ibis server running on " + getAddress() + "\nList of Services:"; for (Service service : services.values()) { message += "\n " + service.toString(); } return message; } /* * (non-Javadoc) * * @see ibis.ipl.server.ServerInterface#end(long) */ public void end(long timeout) { long deadline = System.currentTimeMillis() + timeout; if (timeout == 0) { deadline = Long.MAX_VALUE; } else if (timeout == -1) { deadline = 0; } if (connectionHandler != null) { connectionHandler.end(); } for (Service service : services.values()) { service.end(deadline); } if (hubOnly) { hub.end(); } else { virtualSocketFactory.end(); } } private boolean hasRemote() { return remote; } private static void printUsage(PrintStream out) { out.println("Start a server for Ibis."); out.println(); out.println("USAGE: ibis-server [OPTIONS]"); out.println(); out.println("--no-hub\t\t\tDo not start a hub."); out .println("--hub-only\t\t\tOnly start a hub, not the rest of the server."); out .println("--hub-addresses HUB[,HUB]\tAdditional hubs to connect to."); out .println("--hub-address-file [FILE_NAME]\tWrite the addresses of the hub to the given"); out.println("\t\t\t\tfile. The file is deleted on exit."); out.println("--port PORT\t\t\tPort used for the server."); out .println("--remote\t\t\tListen to commands for this server on stdin."); out.println(); out.println("Output Options:"); out.println("--events\t\t\tPrint events."); out .println("--errors\t\t\tPrint details of errors (such as stacktraces)."); out.println("--stats\t\t\t\tPrint statistics once in a while."); out.println("--help | -h | /?\t\tThis message."); } private void waitUntilFinished() { try { int read = 0; while (read != -1) { read = System.in.read(); } } catch (IOException e) { // IGNORE } } private static class Shutdown extends Thread { private final Server server; Shutdown(Server server) { this.server = server; } public void run() { server.end(-1); } } /** * Run the ibis server */ public static void main(String[] args) { TypedProperties properties = new TypedProperties(); properties.putAll(System.getProperties()); for (int i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("--no-hub")) { properties.setProperty(ServerProperties.START_HUB, "false"); } else if (args[i].equalsIgnoreCase("--hub-only")) { properties.setProperty(ServerProperties.HUB_ONLY, "true"); } else if (args[i].equalsIgnoreCase("--hub-addresses")) { i++; properties.setProperty(ServerProperties.HUB_ADDRESSES, args[i]); } else if (args[i].equalsIgnoreCase("--hub-address-file")) { i++; properties.setProperty(ServerProperties.HUB_ADDRESS_FILE, args[i]); } else if (args[i].equalsIgnoreCase("--port")) { i++; properties.put(ServerProperties.PORT, args[i]); } else if (args[i].equalsIgnoreCase("--events")) { properties.setProperty(ServerProperties.PRINT_EVENTS, "true"); } else if (args[i].equalsIgnoreCase("--errors")) { properties.setProperty(ServerProperties.PRINT_ERRORS, "true"); } else if (args[i].equalsIgnoreCase("--stats")) { properties.setProperty(ServerProperties.PRINT_STATS, "true"); } else if (args[i].equalsIgnoreCase("--remote")) { properties.setProperty(ServerProperties.REMOTE, "true"); } else if (args[i].equalsIgnoreCase("--help") || args[i].equalsIgnoreCase("-help") || args[i].equalsIgnoreCase("-h") || args[i].equalsIgnoreCase("/?")) { printUsage(System.err); System.exit(0); } else { System.err.println("Unknown argument: " + args[i]); printUsage(System.err); System.exit(1); } } Server server = null; try { server = new Server(properties); } catch (Throwable t) { System.err.println("Could not start Server"); t.printStackTrace(); System.exit(1); } /* Don't remember what this was for. Maybe just a test? System.out.println("Server started"); server.end(0); System.out.println("Server stopped"); try { server = new Server(properties); } catch (Throwable t) { System.err.println("Could not start Server"); t.printStackTrace(); System.exit(1); } System.out.println("Server started"); */ // register shutdown hook try { Runtime.getRuntime().addShutdownHook(new Shutdown(server)); } catch (Exception e) { System.err.println("warning: could not registry shutdown hook"); } if (server.hasRemote()) { System.out.println(ADDRESS_LINE_PREFIX + server.getAddress() + ADDRESS_LINE_POSTFIX); System.out.flush(); server.waitUntilFinished(); } else { System.err.println(server.toString()); String knownHubs = null; while (true) { String[] hubs = server.getHubs(); if (hubs.length != 0) { String newKnownHubs = hubs[0].toString(); for (int i = 1; i < hubs.length; i++) { newKnownHubs += "," + hubs[i].toString(); } if (!newKnownHubs.equals(knownHubs)) { knownHubs = newKnownHubs; System.err.println("Known hubs now: " + knownHubs); } } try { Thread.sleep(1000); } catch (InterruptedException e) { return; } } } server.end(-1); } public VirtualSocketFactory getSocketFactory() { return virtualSocketFactory; } }