All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prompto.server.AppServer Maven / Gradle / Ivy

There is a newer version: 0.1.57
Show newest version
package prompto.server;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletHolder;

import prompto.cloud.Cloud;
import prompto.config.IConfigurationReader;
import prompto.config.IDebugConfiguration;
import prompto.config.IServerConfiguration;
import prompto.config.ServerConfiguration;
import prompto.config.YamlConfigurationReader;
import prompto.debug.DebugEventServlet;
import prompto.debug.DebugRequestServlet;
import prompto.debug.HttpServletDebugRequestListener;
import prompto.debug.IDebugEventAdapter;
import prompto.debug.ProcessDebugger;
import prompto.debug.WebSocketDebugEventAdapter;
import prompto.declaration.IMethodDeclaration;
import prompto.error.ReadWriteError;
import prompto.error.TerminatedError;
import prompto.grammar.Identifier;
import prompto.libraries.Libraries;
import prompto.runtime.ApplicationContext;
import prompto.runtime.Context;
import prompto.runtime.Interpreter;
import prompto.runtime.Standalone;
import prompto.security.auth.source.IAuthenticationSource;
import prompto.server.JettyServer.WebSiteContext;
import prompto.utils.JarLoader;
import prompto.utils.CmdLineParser;
import prompto.utils.ErrorLogger;
import prompto.utils.Logger;
import prompto.utils.OutLogger;
import prompto.value.DocumentValue;

public class AppServer {
	
	static final Logger logger = new Logger();
	
	public static final String WEB_SERVER_SUCCESSFULLY_STARTED = "Web server successfully started on port ";
	
	static JettyServer jettyServer;

	public static void main(String[] args) {
		main(args, null);
	}
	
	public static void main(String[] args, Consumer afterStart) {
		try {
			IServerConfiguration config = loadConfiguration(args);
			main(config, null, null, null, afterStart);
		} catch(Throwable t) {
			logger.error(()->"Uncaught exception!", t);
		}
	}

	public static  void main(T config, Runnable serverPrepared, Runnable serverStarted, Runnable serverStopped, Consumer afterStart) throws Throwable {
		installCloudJARs();
		initialize(config);
		run(config, serverPrepared, serverStarted, serverStopped);
		if(afterStart!=null)
			afterStart.accept(config);
	}

	private static void installCloudJARs() throws Exception {
		Cloud cloud = Cloud.current();
		if(cloud==null)
			return;
		installCloudJARs(cloud);
	}
	
	public static void installCloudJARs(Cloud cloud) throws Exception {
		Collection urls = cloud.getJarURLs();
		if(urls==null)
			return;
		JarLoader.addURLs(urls);
	}
	
	public static void initialize(IServerConfiguration config) throws Throwable {
		ServerIdentifierProcessor.register();
		Standalone.initialize(config);
	}

	public static IServerConfiguration loadConfiguration(String[] args) throws Exception {
		Map argsMap = CmdLineParser.read(args);
		IConfigurationReader reader = Standalone.readerFromArgs(argsMap);
		IServerConfiguration config = new ServerConfiguration(reader, argsMap);
		return config.withRuntimeLibs(()->Libraries.getPromptoLibraries(Libraries.class, AppServer.class));
	}

	private static void run(IServerConfiguration config, Runnable serverPrepared, Runnable serverStarted, Runnable serverStopped) throws Throwable {
		Runnable stopped = ()->{ 
			if(serverStopped != null)
				serverStopped.run();
			ApplicationContext.get().notifyCompleted(); 
		};
		startServer(config, (jetty, list)->prepareWebHandlers(jetty, list), serverPrepared, serverStarted, stopped);
	}

	static int startServer(IServerConfiguration config, BiConsumer handler, Runnable serverPrepared, Runnable serverStarted, Runnable serverStopped) throws Throwable {
		IDebugConfiguration debug = config.getDebugConfiguration();
		if(debug==null)
			return doStartServer(config, handler, ApplicationContext.get(), null, serverPrepared, serverStarted, serverStopped);
		else {
			ProcessDebugger debugger = Standalone.startProcessDebugger(debug);
			Context context = ApplicationContext.get().newLocalContext();
			return doStartServer(config, handler, context, debugger, AppServer::serverPrepared, ()->serverStarted(context), ()->serverStopped(serverStopped));			
		}
	}
	
	static void serverPrepared() {
		if(Standalone.getDebugRequestListener() instanceof HttpServletDebugRequestListener)
			((HttpServletDebugRequestListener)Standalone.getDebugRequestListener()).wire();
		if(Standalone.getDebugEventAdapter() instanceof WebSocketDebugEventAdapter)
			((WebSocketDebugEventAdapter)Standalone.getDebugEventAdapter()).wire();
	}
	
	static void serverStarted(Context context) {
		context.notifyCompleted();
	}
	
	static void serverStopped(Runnable runnable) {
		ApplicationContext.get().notifyCompleted();
		Standalone.stopProcessDebugger();
		if(runnable!=null)
			runnable.run();
	}
	
	static int doStartServer(IServerConfiguration config, BiConsumer handler, Context context, ProcessDebugger debugger, Runnable serverPrepared, Runnable serverStarted, Runnable serverStopped) throws Throwable {
		logger.info(()->"Starting web server on port " + config.getHttpConfiguration().getPort() + "...");
		jettyServer = new JettyServer(config);
		jettyServer.prepare(handler);
		if(serverPrepared!=null)
			serverPrepared.run();
		AppServer.start(serverStopped);
		final int port = jettyServer.getHttpPort();
		System.out.println(WEB_SERVER_SUCCESSFULLY_STARTED + port); // CodeFactory launcher listens to System.out 
		logger.info(()->WEB_SERVER_SUCCESSFULLY_STARTED + port);
		if(!config.useConsole()) {
			OutLogger.install();
			ErrorLogger.install();
		}
		IDebugEventAdapter adapter = startDebugSession(debugger, context);
		callServerAboutToStart(config, context);
		if(serverStarted!=null)
			serverStarted.run();
		if(adapter!=null)
			adapter.onProcessReadyEvent();
		return port;
	}
	
	
	private static IDebugEventAdapter startDebugSession(ProcessDebugger debugger, Context context) {
		IDebugEventAdapter adapter = Standalone.getDebugEventAdapter();
		if(adapter instanceof WebSocketDebugEventAdapter) {
			((WebSocketDebugEventAdapter)adapter).waitSession();
			Standalone.wireProcessDebugger(debugger, context);
		}
		return adapter;
	}

	public static void callServerAboutToStart(IServerConfiguration config, Context context) {
		final String serverAboutToStartMethod = config.getServerAboutToStartMethod();
		if(serverAboutToStartMethod!=null) try {
			logger.info(()->"Calling startUp method '" + serverAboutToStartMethod + "'");
			Interpreter.interpretMethod(context, new Identifier(serverAboutToStartMethod), Standalone.argsToArgValue(config.getArguments()));
		} catch(TerminatedError e) {
			// not an error
		} catch(Throwable t) {
			logger.error(()->"While calling startUp method " + serverAboutToStartMethod + "'", t);
		} finally {
			context.notifyCompleted();
		}
	}


	static void prepareWebHandlers(JettyServer jetty, HandlerList list) {
		try {
			list.addHandler(jetty.newWebApiHandler());
			list.addHandler(jetty.newWebSiteHandler());
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static int start(Runnable serverStopped) throws Throwable  {
		if(jettyServer.isStarted())
			throw new RuntimeException("Server is already started!");
		jettyServer.jettyStart(serverStopped);
		return jettyServer.getHttpPort();
	}
	
	public static void stop() throws Exception {
		if(jettyServer==null || !jettyServer.isStarted())
			throw new RuntimeException("Server is not started!");
		jettyServer.jettyStop();
	}

	public static boolean isStarted() {
		return jettyServer!=null  && jettyServer.isStarted();
	}
	
	
	public static DebugRequestServlet getDebugRequestServlet() {
		return jettyServer==null ? null : jettyServer.debugRequestServlet;
	}

	public static DebugEventServlet getDebugEventServlet() {
		return jettyServer==null ? null : jettyServer.debugEventServlet;
	}

	/* used by Server.pec */
	public static long getHttpPort() {
		return jettyServer!=null ? jettyServer.getHttpPort() : -1;
	}
	
	/* used by Server.pec */
	public static void installHandler(String path, IMethodDeclaration method) {
		// TODO check path (must start with '/') and method prototype
		logger.info(()->"Installing web service '" + method.getName() + "' at path '" + path + "'");
		// TODO move to WebApiContext
		WebSiteContext handler = jettyServer.getChildHandlerByClass(WebSiteContext.class);
		UserServlet servlet = new UserServlet(method);
		ServletHolder holder = new ServletHolder(servlet);
		servlet.setHolder(holder);
        handler.addServlet(holder, path);       
	}

	/* used by Server.pec */
	public static IAuthenticationSource getLoginFactory(String config) throws IOException {
		if(config==null)
			return IAuthenticationSource.instance.get();
		else try(InputStream input = new ByteArrayInputStream(config.getBytes())) {
			return getLoginFactory(new YamlConfigurationReader(input));
		} 
	}
	
	public static IAuthenticationSource getLoginFactory(IConfigurationReader reader) {
		return new ServerConfiguration(reader, Collections.emptyMap())
				.getHttpConfiguration()
				.getAuthenticationConfiguration()
				.getAuthenticationSourceConfiguration()
				.getAuthenticationSourceFactory()
				.newAuthenticationSource();
	}

	static ThreadLocal httpUser = new ThreadLocal<>();
	
	/* used by Server.pec */
	public static String getHttpUser() {
		return httpUser.get();
	}
	
	public static void setHttpUser(String user) {
		httpUser.set(user);
	}
	
	static ThreadLocal httpSession = new ThreadLocal<>();

	/* used by Server.pec */
	public static DocumentValue getHttpSession() {
		return httpSession.get();
	}
	
	public static void setHttpSession(DocumentValue session) {
		httpSession.set(session);
	}
	
	/* used by Server.pec */
	public static String getHttpQueryParameter(String name) {
		HttpServletRequest request = CleverServlet.CURRENT_REQUEST.get();
		if(request==null)
			throw new ReadWriteError("Not invoked during server request!");
		return request.getParameter(name);
	}


	/* used by Server.pec */
	public static void httpRedirect(String path) throws IOException {
		HttpServletResponse response = CleverServlet.CURRENT_RESPONSE.get();
		if(response==null)
			throw new ReadWriteError("Not invoked during server request!");
		response.sendRedirect(path);
	}


	/* used by Server.pec */
	public static void httpLogout(String path) throws IOException {
		HttpServletRequest request = CleverServlet.CURRENT_REQUEST.get();
		if(request==null)
			throw new ReadWriteError("Not invoked during server request!");
		request.getSession().invalidate();
		httpRedirect(path);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy