com.novartis.opensource.yada.server.YADAServer Maven / Gradle / Ivy
The newest version!
/**
*
*/
package com.novartis.opensource.yada.server;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
import org.eclipse.jetty.rewrite.handler.RewriteRegexRule;
import org.eclipse.jetty.server.AbstractNetworkConnector;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.SecuredRedirectHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import com.novartis.opensource.yada.Finder;
import com.novartis.opensource.yada.YADARequest;
/**
* @author dvaron
* @since 10.0.0
*/
public class YADAServer {
/**
* Local logger handle
*/
static Logger l = Logger.getLogger(YADAServer.class);
/**
* Container of configuration data which shouldn't be hardcoded.
*/
private static Properties YADA_PROPERTIES = loadYADAProperties();
/**
* Constant equal to {@value}. Used for retrieving config for specific YADA
* index.
*
* (moved from {@link Finder})
*/
private final static String YADA_PROPERTIES_PATH = "YADA.properties.path";
/**
* Constant equal to {@value}. Used for setting non-ssl port
*/
private final static String YADA_SERVER_HTTP_PORT = "YADA.server.http.port";
/**
* Constant equal to {@value}. Used for setting ssl port
*/
private final static String YADA_SERVER_HTTPS_PORT = "YADA.server.https.port";
/**
* Constant equal to {@value}. Used for setting server context path
*/
public final static String YADA_SERVER_CONTEXT = "YADA.server.context";
/**
* Constant equal to {@value}. Used for setting keystore path
*/
public final static String YADA_SERVER_KEYSTORE_PATH = "YADA.server.keystore.path";
/**
* Constant equal to {@value}. Used for setting keystore path
*/
public final static String YADA_SERVER_KEYSTORE_SECRET = "YADA.server.keystore.secret";
/**
* Constant equal to {@value}. Used for setting keystore path
*/
public final static String YADA_REPOSITORY = "YADA.repository";
/**
*
*/
public YADAServer() {
}
/**
* @param args command line args
* @throws Exception catch all for any startup exceptions
*/
public static void main(String[] args) throws Exception {
System.out.println("Starting YADA Server...");
// Secure Handler (if needed)
SecuredRedirectHandler securedHandler = new SecuredRedirectHandler();
// Create and configure a ThreadPool.
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setDetailedDump(true);
threadPool.setName("yada");
// Create a Server instance.
org.eclipse.jetty.server.Server server = new Server(threadPool);
// The HTTP configuration object.
int connectorPort = Integer.valueOf((String)getProperties().get(YADA_SERVER_HTTP_PORT));
HttpConfiguration httpConfig = new HttpConfiguration();
// The ConnectionFactory for HTTP/1.1.
HttpConnectionFactory http11 = new HttpConnectionFactory(httpConfig);
// The ConnectionFactory for clear-text HTTP/2.
HTTP2CServerConnectionFactory h2c = new HTTP2CServerConnectionFactory(httpConfig);
// Create a ServerConnector to accept connections from clients.
Connector connector = new ServerConnector(server, http11, h2c);
((AbstractNetworkConnector) connector).setPort(connectorPort);
// Add the Connector to the YADAServer
server.addConnector(connector);
if(isSecured())
{
// Configure the SslContextFactory with the keyStore information.
int securePort = Integer.valueOf((String)getProperties().get(YADA_SERVER_HTTPS_PORT));
httpConfig.setSecurePort(securePort);
httpConfig.addCustomizer(new SecureRequestCustomizer());
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
String keystorePath = getProperties().getProperty(YADA_SERVER_KEYSTORE_PATH);
String keystoreSecret = getProperties().getProperty(YADA_SERVER_KEYSTORE_SECRET);
sslContextFactory.setKeyStorePath(keystorePath);
sslContextFactory.setKeyStorePassword(keystoreSecret);
// The ConnectionFactory for TLS.
SslConnectionFactory tls = new SslConnectionFactory(sslContextFactory, http11.getProtocol());
ServerConnector secureConnector = new ServerConnector(server, tls, http11);
secureConnector.setPort(securePort);
server.addConnector(secureConnector);
}
// Handlers
HandlerList handlerList = new HandlerList();
ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
// Set the Context
ContextHandler yadaPropContextHandler = new ContextHandler();
yadaPropContextHandler.setAllowNullPathInfo(true);
String ctx = getProperties().getProperty(YADA_SERVER_CONTEXT);
// context will be "/" if unset, or "/whatever" if set.
yadaPropContextHandler.setContextPath(ctx.startsWith("/") ? ctx : "/"+ctx);
String ctxPath = yadaPropContextHandler.getContextPath();
// Rewrites for path-style, converts /param/value/param/value
// into ?yp=param/value/param/value
String paramShortNames = String.join("|", YADARequest.fieldAliasMap.keySet());
String paramLongNames = String.join("|", new HashSet(YADARequest.fieldAliasMap.values()));
String allParams = "(?:" + paramShortNames + "|" + paramLongNames + ")";
String params = allParams.replaceAll("\\|q(?:name)?[|)]", "|");
String pathRx = "^(?:\\/)?((?:" + params + "\\/.+)*?[\\/{]?q(?:name)?[:\\/].+)$";
String pathFmt = ctxPath+"?yp=%s";
// This rule will change path-syntax into "/context?yp=uri" which is then handled by the Service class
RewriteRegexRule pathRule = new RewriteRegexRule(pathRx, String.format(pathFmt,"$1"));
pathRule.setTerminating(true);
// This rule will change requests for "yada.jsp?querystring" into "/context?querystring",
// i.e., strip off the jsp extension
String jspRx = "^\\/yada\\.jsp";
String jspFmt = ctxPath+"?$Q";
RewriteRegexRule jspRule = new RewriteRegexRule(jspRx, jspFmt);
// Add the rules to the handler
RewriteHandler rewriteHandler = new RewriteHandler();
rewriteHandler.addRule(pathRule);
rewriteHandler.addRule(jspRule);
// Set the YADARequest and Cors Handlers
YADARequestHandler yadaRequestHandler = new YADARequestHandler();
YADACorsHandler yadaCorsHandler = new YADACorsHandler();
// Set handlers hierarchy
HandlerList yadaHandlerList = new HandlerList();
yadaHandlerList.addHandler(yadaCorsHandler);
yadaHandlerList.addHandler(yadaRequestHandler);
rewriteHandler.setHandler(yadaHandlerList);
yadaPropContextHandler.setHandler(rewriteHandler);
contextHandlerCollection.addHandler(yadaPropContextHandler);
if(isSecured())
{
securedHandler.setHandler(contextHandlerCollection);
handlerList.addHandler(securedHandler);
}
else
{
handlerList.addHandler(contextHandlerCollection);
}
handlerList.addHandler(new DefaultHandler());
/*
* Handler Hierarchy:
*
* Server
* |
* +-- HandlerList
* | |
* | +-- SecuredHandler
* | | |
* | | +-- ContextHandlerCollection
* | | |
* | | +-- ContextHandler (/context)
* | | |
* | | +-- RewriteHandler (2 Rule)
* | | |
* | | +-- HandlerList (yadaHandlerList)
* | | |
* | | +-- YADACorsHandler
* | | |
* | | +-- YADARequestHandler
* | +-- DefaultHandler
* |
* +-- YADAErrorHandler
*/
// attach the handler to the server
server.setHandler(handlerList);
ErrorHandler errorHandler = new YADAErrorHandler();
server.setErrorHandler(errorHandler);
// Start the YADAServer so it starts accepting connections from clients.
server.start();
}
/**
* For loading properties
* @param props the props to set
*/
public void setProps(Properties props)
{
YADAServer.YADA_PROPERTIES = props;
}
/**
* @return the props
*/
public static Properties getProperties()
{
return YADA_PROPERTIES;
}
/**
* Sets {@code static} {@link #YADA_PROPERTIES} object. Moved from {@link Finder}
*
* @return {@link java.util.Properties}
*
*/
private final static Properties loadYADAProperties() {
Properties props = new Properties();
String path = System.getProperty(YADA_PROPERTIES_PATH);
try(InputStream is = new FileInputStream(new File(path)))
{
props.load(is);
l.info(String.format("Loaded %s", path));
}
catch (IOException e)
{
String msg = String.format("Cannot find or load YADA properties file %s", path);
l.fatal(msg);
System.exit(1);
}
return props;
}
/**
* Returns {@code true} if the {@link #YADA_SERVER_HTTPS_PORT} property is set, implying
* the other security-related props are set and valid
*
* @return {@code true} if the {@link #YADA_SERVER_HTTPS_PORT} property is set
*/
private static boolean isSecured() {
return getProperties().get(YADA_SERVER_HTTPS_PORT) != null
&& getProperties().get(YADA_SERVER_KEYSTORE_PATH) != null
&& getProperties().get(YADA_SERVER_KEYSTORE_SECRET) != null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy