summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorMichael Peter Christen <mc@yacy.net>2026-07-11 12:08:35 +0200
committerMichael Peter Christen <mc@yacy.net>2026-07-11 12:08:35 +0200
commitb32b659023fa65a4141e64bbcfb82183bb6994de (patch)
tree37cad21a1212d2cb4fbc1b572c8358c9ba3363d0 /source
parente42386b3fbed3f94f733433a66495c453bfe7a51 (diff)
Added a server interface which is now implemeted by jetty 9
This will enable a better transition once we migrate to jetty 10
Diffstat (limited to 'source')
-rw-r--r--source/net/yacy/http/Jetty9HttpServerImpl.java526
-rw-r--r--source/net/yacy/http/YaCyHttpServer.java494
-rw-r--r--source/net/yacy/yacy.java137
3 files changed, 618 insertions, 539 deletions
diff --git a/source/net/yacy/http/Jetty9HttpServerImpl.java b/source/net/yacy/http/Jetty9HttpServerImpl.java
new file mode 100644
index 000000000..fea7e30a8
--- /dev/null
+++ b/source/net/yacy/http/Jetty9HttpServerImpl.java
@@ -0,0 +1,526 @@
+//
+// Jetty9HttpServerImpl
+// Copyright 2011 by Florian Richter
+// First released 13.04.2011 at https://yacy.net
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program in the file lgpl21.txt
+// If not, see <http://www.gnu.org/licenses/>.
+//
+
+package net.yacy.http;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.security.KeyStore;
+import java.util.StringTokenizer;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Handler;
+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.HandlerList;
+import org.eclipse.jetty.server.handler.InetAccessHandler;
+import org.eclipse.jetty.server.handler.gzip.GzipHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+import net.yacy.cora.util.ConcurrentLog;
+import net.yacy.http.servlets.YaCyDefaultServlet;
+import net.yacy.search.Switchboard;
+import net.yacy.search.SwitchboardConstants;
+import net.yacy.utils.PKCS12Tool;
+
+/**
+ * class to embedded Jetty 9 http server into YaCy
+ */
+public class Jetty9HttpServerImpl implements YaCyHttpServer {
+
+ private final Server server;
+
+ /**
+ * @param port TCP Port to listen for http requests
+ * @param host The network interface this connector binds to as an IP address or a hostname.
+ */
+ public Jetty9HttpServerImpl(final int port, final String host) {
+ final Switchboard sb = Switchboard.getSwitchboard();
+
+ this.server = new Server();
+
+ final int cores = Runtime.getRuntime().availableProcessors();
+ final int acceptors = Math.max(1, Math.min(4, cores/2)); // original: Math.max(1, Math.min(4,cores/8));
+
+ final HttpConfiguration httpConfig = new HttpConfiguration();
+ httpConfig.setRequestHeaderSize(16384);
+ final HttpConnectionFactory hcf = new HttpConnectionFactory(httpConfig);
+ final ServerConnector connector = new ServerConnector(this.server, null, null, null, acceptors, -1, hcf);
+ connector.setPort(port);
+ connector.setHost(host);
+ connector.setName("httpd-" + host + ":" + Integer.toString(port));
+ connector.setIdleTimeout(9000); // timout in ms when no bytes send / received
+ connector.setAcceptQueueSize(128);
+
+
+ this.server.addConnector(connector);
+
+
+ // add ssl/https connector
+ final boolean useSSL = sb.getConfigBool("server.https", false);
+
+ if (useSSL) {
+ final SslContextFactory sslContextFactory = new SslContextFactory.Server();
+ final SSLContext sslContext = this.initSslContext(sb);
+ if (sslContext != null) {
+
+ final int sslport = sb.getConfigInt(SwitchboardConstants.SERVER_SSLPORT, 8443);
+ sslContextFactory.setSslContext(sslContext);
+
+ // SSL HTTP Configuration
+ final HttpConfiguration https_config = new HttpConfiguration();
+ https_config.addCustomizer(new SecureRequestCustomizer());
+
+ // SSL Connector
+ final ServerConnector sslConnector = new ServerConnector(this.server,
+ new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
+ new HttpConnectionFactory(https_config));
+ sslConnector.setPort(sslport);
+ sslConnector.setName("ssld:" + Integer.toString(sslport)); // name must start with ssl (for withSSL() to work correctly)
+ sslConnector.setIdleTimeout(9000); // timout in ms when no bytes send / received
+
+ this.server.addConnector(sslConnector);
+ ConcurrentLog.info("SERVER", "SSL support initialized successfully on port " + sslport);
+ }
+ }
+
+ final YacyDomainHandler domainHandler = new YacyDomainHandler();
+ domainHandler.setAlternativeResolver(sb.peers);
+
+ // configure root context
+ final WebAppContext htrootContext = new WebAppContext();
+ htrootContext.setContextPath("/");
+ final String htrootpath = sb.appPath + "/" + sb.getConfig(SwitchboardConstants.HTROOT_PATH, SwitchboardConstants.HTROOT_PATH_DEFAULT);
+ ConcurrentLog.info("Jetty9HttpServerImpl", "htrootpath = " + htrootpath);
+ htrootContext.setErrorHandler(new YaCyErrorHandler()); // handler for custom error page
+ try {
+ htrootContext.setBaseResource(Resource.newResource(htrootpath));
+
+ // set web.xml to use
+ // make use of Jetty feature to define web.xml other as default WEB-INF/web.xml
+ // and to use a DefaultsDescriptor merged with a individual web.xml
+ // use defaults/web.xml as default and look in DATA/SETTINGS for local addition/changes
+ htrootContext.setDefaultsDescriptor(sb.appPath + "/defaults/web.xml");
+ final Resource webxml = Resource.newResource(sb.dataPath + "/DATA/SETTINGS/web.xml");
+ if (webxml.exists()) {
+ htrootContext.setDescriptor(webxml.getName());
+ }
+
+ } catch (final IOException ex) {
+ if (htrootContext.getBaseResource() == null) {
+ ConcurrentLog.severe("SERVER", "could not find directory: htroot ");
+ } else {
+ ConcurrentLog.warn("SERVER", "could not find: defaults/web.xml or DATA/SETTINGS/web.xml");
+ }
+ }
+
+ // as fundamental component leave this hardcoded, other servlets may be defined in web.xml only
+ final ServletHolder sholder = new ServletHolder(YaCyDefaultServlet.class);
+ sholder.setInitParameter("resourceBase", htrootpath);
+ sholder.setAsyncSupported(true); // needed for YaCyQoSFilter
+ //sholder.setInitParameter("welcomeFile", "index.html"); // default is index.html, welcome.html
+ htrootContext.addServlet(sholder, "/*");
+
+ final GzipHandler gzipHandler = new GzipHandler();
+ /*
+ * Decompression of incoming requests body is required for index distribution
+ * APIs /yacy/transferRWI.html and /yacy/transferURL.html This was previously
+ * handled by a GZIPRequestWrapper in the YaCyDefaultServlet.
+ */
+ gzipHandler.setInflateBufferSize(4096);
+
+ if (!sb.getConfigBool(SwitchboardConstants.SERVER_RESPONSE_COMPRESS_GZIP,
+ SwitchboardConstants.SERVER_RESPONSE_COMPRESS_GZIP_DEFAULT)) {
+ /* Gzip compression of responses can be disabled by user configuration */
+ gzipHandler.setExcludedMethods(HttpMethod.GET.asString(), HttpMethod.POST.asString());
+ }
+ htrootContext.setGzipHandler(gzipHandler);
+
+ // -----------------------------------------------------------------------------
+ // here we set and map the mandatory servlets, needed for typical YaCy operation
+ // to make sure they are available even if removed in individual web.xml
+ // additional, optional or individual servlets or servlet mappings can be set in web.xml
+
+ // in Jetty 9 servlet should be set only once
+ // therefore only the settings in web.xml is used
+ //add SolrSelectServlet
+ //htrootContext.addServlet(SolrSelectServlet.class, "/solr/select"); // uses the default core, collection1
+ //htrootContext.addServlet(SolrSelectServlet.class, "/solr/collection1/select"); // the same servlet, identifies the collection1 core using the path
+ //htrootContext.addServlet(SolrSelectServlet.class, "/solr/webgraph/select"); // the same servlet, identifies the webgraph core using the path
+
+ //htrootContext.addServlet(SolrServlet.class, "/solr/collection1/admin/luke");
+ //htrootContext.addServlet(SolrServlet.class, "/solr/webgraph/admin/luke");
+
+ // add proxy?url= servlet
+ //htrootContext.addServlet(YaCyProxyServlet.class,"/proxy.html");
+
+ // add GSA servlet
+ //htrootContext.addServlet(GSAsearchServlet.class,"/gsa/search");
+ // --- eof default servlet mappings --------------------------------------------
+
+ // define list of YaCy specific general handlers
+ final HandlerList handlers = new HandlerList();
+ if (sb.getConfigBool(SwitchboardConstants.PROXY_TRANSPARENT_PROXY, false)) {
+ // Proxyhandlers are only needed if feature activated (save resources if not used)
+ ConcurrentLog.info("SERVER", "load Jetty handler for transparent proxy");
+ handlers.setHandlers(new Handler[]{new MonitorHandler(), domainHandler, new ProxyCacheHandler(), new ProxyHandler()});
+ } else {
+ handlers.setHandlers(new Handler[]{new MonitorHandler(), domainHandler});
+ }
+ // context handler for dispatcher and security (hint: dispatcher requires a context)
+ final ContextHandler context = new ContextHandler();
+ context.setServer(this.server);
+ context.setContextPath("/");
+ context.setHandler(handlers);
+ context.setMaxFormContentSize(-1);
+ final org.eclipse.jetty.util.log.Logger log = Log.getRootLogger();
+ context.setLogger(log);
+ // make YaCy handlers (in context) and servlet context handlers available (both contain root context "/")
+ // logic: 1. YaCy handlers are called if request not handled (e.g. proxy) then servlets handle it
+ final ContextHandlerCollection allrequesthandlers = new ContextHandlerCollection();
+ allrequesthandlers.setServer(this.server);
+ allrequesthandlers.addHandler(context);
+ allrequesthandlers.addHandler(htrootContext);
+ allrequesthandlers.addHandler(new DefaultHandler()); // if not handled by other handler
+
+ final YaCyLoginService loginService = new YaCyLoginService();
+ // This is part of the built-in administrator's DIGEST password hash.
+ // Changing it invalidates the configured administrator password hash.
+ loginService.setName(sb.getConfig(SwitchboardConstants.ADMIN_REALM,"YaCy"));
+
+ final YaCySecurityHandler securityHandler = new YaCySecurityHandler();
+ securityHandler.setLoginService(loginService);
+
+ htrootContext.setSecurityHandler(securityHandler);
+
+ // wrap all handlers
+ final Handler crashHandler = new CrashProtectionHandler(this.server, allrequesthandlers);
+ // check server access restriction and add InetAccessHandler if restrictions are needed
+ // otherwise don't (to save performance)
+ final String white = sb.getConfig("serverClient", "*");
+ if (!white.equals("*")) { // full ip (allowed ranges 0-255 or prefix 10.0-255,0,0-100 or CIDR notation 192.168.1.0/24)
+ final StringTokenizer st = new StringTokenizer(white, ",");
+ final InetAccessHandler whiteListHandler;
+ if (white.contains("|")) {
+ /*
+ * At least one pattern includes a path definition : we must use the
+ * InetPathAccessHandler as InetAccessHandler doesn't support path patterns
+ */
+ whiteListHandler = new InetPathAccessHandler();
+ } else {
+ whiteListHandler = new InetAccessHandler();
+ }
+ int i = 0;
+ while (st.hasMoreTokens()) {
+ final String pattern = st.nextToken();
+ try {
+ whiteListHandler.include(pattern);
+ } catch (final IllegalArgumentException nex) { // catch format exception on wrong ip address pattern
+ ConcurrentLog.severe("SERVER", "Server Access Settings - IP filter: " + nex.getMessage());
+ continue;
+ }
+ i++;
+ }
+ if (i > 0) {
+ final String loopbackAddress = InetAddress.getLoopbackAddress().getHostAddress();
+ whiteListHandler.include(loopbackAddress);
+ whiteListHandler.setHandler(crashHandler);
+ this.server.setHandler(whiteListHandler);
+
+ ConcurrentLog.info("SERVER","activated IP access restriction to: [" + loopbackAddress + "," + white +"]");
+ } else {
+ this.server.setHandler(crashHandler); // InetAccessHandler not needed
+ }
+ } else {
+ this.server.setHandler(crashHandler); // InetAccessHandler not needed
+ }
+ }
+
+ /**
+ * start http server
+ */
+ public void startupServer() throws Exception {
+ // option to finish running requests on shutdown
+// server.setGracefulShutdown(3000);
+ this.server.setStopAtShutdown(true);
+ this.server.start();
+ }
+
+ /**
+ * stop http server and wait for it
+ */
+ public void stop() throws Exception {
+ this.server.stop();
+ this.server.join();
+ }
+
+ /**
+ * @return true if ssl/https connector is available
+ */
+ public boolean withSSL() {
+ final Connector[] clist = this.server.getConnectors();
+ for (final Connector c:clist) {
+ if (c.getName().startsWith("ssl")) return true;
+ }
+ return false;
+ }
+
+ /**
+ * The port of actual running ssl connector
+ * @return the ssl/https port or -1 if not active
+ */
+ public int getSslPort() {
+ final Connector[] clist = this.server.getConnectors();
+ for (final Connector c:clist) {
+ if (c.getName().startsWith("ssl")) {
+ final int port =((ServerConnector)c).getLocalPort();
+ return port;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * reconnect with new port settings (after waiting milsec) - routine returns
+ * immediately
+ * checks http and ssl connector for new port settings
+ * @param milsec wait time
+ */
+ public void reconnect(final int milsec) {
+
+ new Thread("Jetty8HttpServer.reconnect") {
+
+ @Override
+ public void run() {
+ if (milsec > 0) try {
+ Thread.sleep(milsec);
+ } catch (final Exception e) {
+ ConcurrentLog.logException(e);
+ }
+ try {
+ if (!Jetty9HttpServerImpl.this.server.isRunning() || Jetty9HttpServerImpl.this.server.isStopped()) {
+ Jetty9HttpServerImpl.this.server.start();
+ }
+
+ // reconnect with new settings (instead to stop/start server, just manipulate connectors
+ final Connector[] cons = Jetty9HttpServerImpl.this.server.getConnectors();
+ final int port = Switchboard.getSwitchboard().getLocalPort();
+ final int sslport = Switchboard.getSwitchboard().getConfigInt(SwitchboardConstants.SERVER_SSLPORT, 8443);
+ for (final Connector con : cons) {
+ // check http connector
+ if (con.getName().startsWith("httpd") && ((ServerConnector)con).getPort() != port) {
+ ((ServerConnector)con).close();
+ con.stop();
+ if (!con.isStopped()) {
+ ConcurrentLog.warn("SERVER", "Reconnect: Jetty Connector failed to stop");
+ }
+ ((ServerConnector)con).setPort(port);
+ con.start();
+ ConcurrentLog.info("SERVER", "set new port for Jetty connector " + con.getName());
+ continue;
+ }
+ // check https connector
+ if (con.getName().startsWith("ssl") && ((ServerConnector)con).getPort() != sslport) {
+ ((ServerConnector)con).close();
+ con.stop();
+ if (!con.isStopped()) {
+ ConcurrentLog.warn("SERVER", "Reconnect: Jetty Connector failed to stop");
+ }
+ ((ServerConnector)con).setPort(sslport);
+ con.start();
+ ConcurrentLog.info("SERVER", "set new port for Jetty connector " + con.getName());
+ }
+ }
+ } catch (final Exception ex) {
+ ConcurrentLog.logException(ex);
+ }
+ }
+ }.start();
+ }
+
+ /**
+ * Forces the login service to reload the built-in administrator credentials
+ * after they were changed in the configuration.
+ * @param username
+ */
+ public void resetUser(final String username) {
+ final YaCySecurityHandler hx = this.server.getChildHandlerByClass(YaCySecurityHandler.class);
+ if (hx != null) {
+ final YaCyLoginService loginservice = (YaCyLoginService) hx.getLoginService();
+ if (loginservice.removeUser(username)) { // remove old credential from cache
+ loginservice.loadUserInfo(username);
+ }
+ }
+ }
+
+ /**
+ * Removes the built-in administrator from the login service cache.
+ * @param username
+ */
+ public void removeUser(final String username) {
+ final YaCySecurityHandler hx = this.server.getChildHandlerByClass(YaCySecurityHandler.class);
+ if (hx != null) {
+ final YaCyLoginService loginservice = (YaCyLoginService) hx.getLoginService();
+ loginservice.removeUser(username);
+ }
+ }
+
+ /**
+ * get Jetty version
+ * @return version_string
+ */
+ public String getVersion() {
+ return "Jetty " + Server.getVersion();
+ }
+
+ /**
+ * Init SSL Context from config settings
+ * @param sb Switchboard
+ * @return default or sslcontext according to config
+ */
+ private SSLContext initSslContext(final Switchboard sb) {
+
+ // getting the keystore file name
+ String keyStoreFileName = sb.getConfig("keyStore", "").trim();
+
+ // getting the keystore pwd
+ String keyStorePwd = sb.getConfig("keyStorePassword", "").trim();
+
+ // take a look if we have something to import
+ final String pkcs12ImportFile = sb.getConfig("pkcs12ImportFile", "").trim();
+
+ // if no keyStore and no import is defined, then set the default key
+ if (keyStoreFileName.isEmpty() && keyStorePwd.isEmpty() && pkcs12ImportFile.isEmpty()) {
+ keyStoreFileName = "defaults/freeworldKeystore";
+ keyStorePwd = "freeworld";
+ sb.setConfig("keyStore", keyStoreFileName);
+ sb.setConfig("keyStorePassword", keyStorePwd);
+ }
+
+ if (pkcs12ImportFile.length() > 0) {
+ ConcurrentLog.info("SERVER", "Import certificates from import file '" + pkcs12ImportFile + "'.");
+
+ try {
+ // getting the password
+ final String pkcs12ImportPwd = sb.getConfig("pkcs12ImportPwd", "").trim();
+
+ // creating tool to import cert
+ final PKCS12Tool pkcsTool = new PKCS12Tool(pkcs12ImportFile,pkcs12ImportPwd);
+
+ // creating a new keystore file
+ if (keyStoreFileName.isEmpty()) {
+ // using the default keystore name
+ keyStoreFileName = "DATA/SETTINGS/myPeerKeystore";
+
+ // creating an empty java keystore
+ final KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null,keyStorePwd.toCharArray());
+ try (
+ /* Automatically closed by this try-with-resources statement */
+ final FileOutputStream ksOut = new FileOutputStream(keyStoreFileName);
+ ) {
+ ks.store(ksOut, keyStorePwd.toCharArray());
+ }
+
+ // storing path to keystore into config file
+ sb.setConfig("keyStore", keyStoreFileName);
+ }
+
+ // importing certificate
+ pkcsTool.importToJKS(keyStoreFileName, keyStorePwd);
+
+ // removing entries from config file
+ sb.setConfig("pkcs12ImportFile", "");
+ sb.setConfig("pkcs12ImportPwd", "");
+
+ // deleting original import file
+ // TODO: should we do this
+ } catch (final Exception e) {
+ ConcurrentLog.severe("SERVER", "Unable to import certificate from import file '" + pkcs12ImportFile + "'.",e);
+ }
+ } else if (keyStoreFileName.isEmpty()) return null;
+
+ // get the ssl context
+ try {
+ ConcurrentLog.info("SERVER","Initializing SSL support ...");
+
+ // creating a new keystore instance of type (java key store)
+ if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER", "Initializing keystore ...");
+ final KeyStore ks = KeyStore.getInstance("JKS");
+
+ // loading keystore data from file
+ if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER","Loading keystore file " + keyStoreFileName);
+ final FileInputStream stream = new FileInputStream(keyStoreFileName);
+ try {
+ ks.load(stream, keyStorePwd.toCharArray());
+ } finally {
+ try {
+ stream.close();
+ } catch(final IOException ioe) {
+ ConcurrentLog.warn("SERVER", "Could not close input stream on file " + keyStoreFileName);
+ }
+ }
+
+ // creating a keystore factory
+ if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER","Initializing key manager factory ...");
+ final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks,keyStorePwd.toCharArray());
+
+ // initializing the ssl context
+ if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER","Initializing SSL context ...");
+ final SSLContext sslcontext = SSLContext.getInstance("TLS");
+ sslcontext.init(kmf.getKeyManagers(), null, null);
+
+ return sslcontext;
+ } catch (final Exception e) {
+ final String errorMsg = "FATAL ERROR: Unable to initialize the SSL Socket factory. " + e.getMessage();
+ ConcurrentLog.severe("SERVER",errorMsg);
+ System.out.println(errorMsg);
+ return null;
+ }
+ }
+
+ public int getServerThreads() {
+ return this.server == null ? 0 : this.server.getThreadPool().getThreads() - this.server.getThreadPool().getIdleThreads();
+ }
+
+ @Override
+ public String toString() {
+ return this.server.dump() + "\n\n" + this.server.getState();
+ }
+}
diff --git a/source/net/yacy/http/YaCyHttpServer.java b/source/net/yacy/http/YaCyHttpServer.java
index b4844eb78..a4bff7bbd 100644
--- a/source/net/yacy/http/YaCyHttpServer.java
+++ b/source/net/yacy/http/YaCyHttpServer.java
@@ -20,507 +20,59 @@
package net.yacy.http;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.security.KeyStore;
-import java.util.StringTokenizer;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Handler;
-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.HandlerList;
-import org.eclipse.jetty.server.handler.InetAccessHandler;
-import org.eclipse.jetty.server.handler.gzip.GzipHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.webapp.WebAppContext;
-
-import net.yacy.cora.util.ConcurrentLog;
-import net.yacy.http.servlets.YaCyDefaultServlet;
-import net.yacy.search.Switchboard;
-import net.yacy.search.SwitchboardConstants;
-import net.yacy.utils.PKCS12Tool;
-
/**
- * class to embedded Jetty 9 http server into YaCy
+ * Servlet-container neutral interface to YaCy's embedded http server.
+ * This is the only view the rest of the code base has on the server;
+ * all container specific code (currently Jetty 9, see {@link Jetty9HttpServerImpl})
+ * stays behind this interface to ease migration to newer container versions.
*/
-public class YaCyHttpServer {
-
- private final Server server;
+public interface YaCyHttpServer {
/**
- * @param port TCP Port to listen for http requests
- * @param host The network interface this connector binds to as an IP address or a hostname.
+ * start the http server
*/
- public YaCyHttpServer(final int port, final String host) {
- final Switchboard sb = Switchboard.getSwitchboard();
-
- this.server = new Server();
-
- final int cores = Runtime.getRuntime().availableProcessors();
- final int acceptors = Math.max(1, Math.min(4, cores/2)); // original: Math.max(1, Math.min(4,cores/8));
-
- final HttpConfiguration httpConfig = new HttpConfiguration();
- httpConfig.setRequestHeaderSize(16384);
- final HttpConnectionFactory hcf = new HttpConnectionFactory(httpConfig);
- final ServerConnector connector = new ServerConnector(this.server, null, null, null, acceptors, -1, hcf);
- connector.setPort(port);
- connector.setHost(host);
- connector.setName("httpd-" + host + ":" + Integer.toString(port));
- connector.setIdleTimeout(9000); // timout in ms when no bytes send / received
- connector.setAcceptQueueSize(128);
-
-
- this.server.addConnector(connector);
-
-
- // add ssl/https connector
- final boolean useSSL = sb.getConfigBool("server.https", false);
-
- if (useSSL) {
- final SslContextFactory sslContextFactory = new SslContextFactory.Server();
- final SSLContext sslContext = this.initSslContext(sb);
- if (sslContext != null) {
-
- final int sslport = sb.getConfigInt(SwitchboardConstants.SERVER_SSLPORT, 8443);
- sslContextFactory.setSslContext(sslContext);
-
- // SSL HTTP Configuration
- final HttpConfiguration https_config = new HttpConfiguration();
- https_config.addCustomizer(new SecureRequestCustomizer());
-
- // SSL Connector
- final ServerConnector sslConnector = new ServerConnector(this.server,
- new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
- new HttpConnectionFactory(https_config));
- sslConnector.setPort(sslport);
- sslConnector.setName("ssld:" + Integer.toString(sslport)); // name must start with ssl (for withSSL() to work correctly)
- sslConnector.setIdleTimeout(9000); // timout in ms when no bytes send / received
-
- this.server.addConnector(sslConnector);
- ConcurrentLog.info("SERVER", "SSL support initialized successfully on port " + sslport);
- }
- }
-
- final YacyDomainHandler domainHandler = new YacyDomainHandler();
- domainHandler.setAlternativeResolver(sb.peers);
-
- // configure root context
- final WebAppContext htrootContext = new WebAppContext();
- htrootContext.setContextPath("/");
- final String htrootpath = sb.appPath + "/" + sb.getConfig(SwitchboardConstants.HTROOT_PATH, SwitchboardConstants.HTROOT_PATH_DEFAULT);
- ConcurrentLog.info("Jetty9HttpServerImpl", "htrootpath = " + htrootpath);
- htrootContext.setErrorHandler(new YaCyErrorHandler()); // handler for custom error page
- try {
- htrootContext.setBaseResource(Resource.newResource(htrootpath));
-
- // set web.xml to use
- // make use of Jetty feature to define web.xml other as default WEB-INF/web.xml
- // and to use a DefaultsDescriptor merged with a individual web.xml
- // use defaults/web.xml as default and look in DATA/SETTINGS for local addition/changes
- htrootContext.setDefaultsDescriptor(sb.appPath + "/defaults/web.xml");
- final Resource webxml = Resource.newResource(sb.dataPath + "/DATA/SETTINGS/web.xml");
- if (webxml.exists()) {
- htrootContext.setDescriptor(webxml.getName());
- }
-
- } catch (final IOException ex) {
- if (htrootContext.getBaseResource() == null) {
- ConcurrentLog.severe("SERVER", "could not find directory: htroot ");
- } else {
- ConcurrentLog.warn("SERVER", "could not find: defaults/web.xml or DATA/SETTINGS/web.xml");
- }
- }
-
- // as fundamental component leave this hardcoded, other servlets may be defined in web.xml only
- final ServletHolder sholder = new ServletHolder(YaCyDefaultServlet.class);
- sholder.setInitParameter("resourceBase", htrootpath);
- sholder.setAsyncSupported(true); // needed for YaCyQoSFilter
- //sholder.setInitParameter("welcomeFile", "index.html"); // default is index.html, welcome.html
- htrootContext.addServlet(sholder, "/*");
-
- final GzipHandler gzipHandler = new GzipHandler();
- /*
- * Decompression of incoming requests body is required for index distribution
- * APIs /yacy/transferRWI.html and /yacy/transferURL.html This was previously
- * handled by a GZIPRequestWrapper in the YaCyDefaultServlet.
- */
- gzipHandler.setInflateBufferSize(4096);
-
- if (!sb.getConfigBool(SwitchboardConstants.SERVER_RESPONSE_COMPRESS_GZIP,
- SwitchboardConstants.SERVER_RESPONSE_COMPRESS_GZIP_DEFAULT)) {
- /* Gzip compression of responses can be disabled by user configuration */
- gzipHandler.setExcludedMethods(HttpMethod.GET.asString(), HttpMethod.POST.asString());
- }
- htrootContext.setGzipHandler(gzipHandler);
-
- // -----------------------------------------------------------------------------
- // here we set and map the mandatory servlets, needed for typical YaCy operation
- // to make sure they are available even if removed in individual web.xml
- // additional, optional or individual servlets or servlet mappings can be set in web.xml
-
- // in Jetty 9 servlet should be set only once
- // therefore only the settings in web.xml is used
- //add SolrSelectServlet
- //htrootContext.addServlet(SolrSelectServlet.class, "/solr/select"); // uses the default core, collection1
- //htrootContext.addServlet(SolrSelectServlet.class, "/solr/collection1/select"); // the same servlet, identifies the collection1 core using the path
- //htrootContext.addServlet(SolrSelectServlet.class, "/solr/webgraph/select"); // the same servlet, identifies the webgraph core using the path
-
- //htrootContext.addServlet(SolrServlet.class, "/solr/collection1/admin/luke");
- //htrootContext.addServlet(SolrServlet.class, "/solr/webgraph/admin/luke");
-
- // add proxy?url= servlet
- //htrootContext.addServlet(YaCyProxyServlet.class,"/proxy.html");
-
- // add GSA servlet
- //htrootContext.addServlet(GSAsearchServlet.class,"/gsa/search");
- // --- eof default servlet mappings --------------------------------------------
-
- // define list of YaCy specific general handlers
- final HandlerList handlers = new HandlerList();
- if (sb.getConfigBool(SwitchboardConstants.PROXY_TRANSPARENT_PROXY, false)) {
- // Proxyhandlers are only needed if feature activated (save resources if not used)
- ConcurrentLog.info("SERVER", "load Jetty handler for transparent proxy");
- handlers.setHandlers(new Handler[]{new MonitorHandler(), domainHandler, new ProxyCacheHandler(), new ProxyHandler()});
- } else {
- handlers.setHandlers(new Handler[]{new MonitorHandler(), domainHandler});
- }
- // context handler for dispatcher and security (hint: dispatcher requires a context)
- final ContextHandler context = new ContextHandler();
- context.setServer(this.server);
- context.setContextPath("/");
- context.setHandler(handlers);
- context.setMaxFormContentSize(-1);
- final org.eclipse.jetty.util.log.Logger log = Log.getRootLogger();
- context.setLogger(log);
- // make YaCy handlers (in context) and servlet context handlers available (both contain root context "/")
- // logic: 1. YaCy handlers are called if request not handled (e.g. proxy) then servlets handle it
- final ContextHandlerCollection allrequesthandlers = new ContextHandlerCollection();
- allrequesthandlers.setServer(this.server);
- allrequesthandlers.addHandler(context);
- allrequesthandlers.addHandler(htrootContext);
- allrequesthandlers.addHandler(new DefaultHandler()); // if not handled by other handler
-
- final YaCyLoginService loginService = new YaCyLoginService();
- // This is part of the built-in administrator's DIGEST password hash.
- // Changing it invalidates the configured administrator password hash.
- loginService.setName(sb.getConfig(SwitchboardConstants.ADMIN_REALM,"YaCy"));
-
- final YaCySecurityHandler securityHandler = new YaCySecurityHandler();
- securityHandler.setLoginService(loginService);
-
- htrootContext.setSecurityHandler(securityHandler);
-
- // wrap all handlers
- final Handler crashHandler = new CrashProtectionHandler(this.server, allrequesthandlers);
- // check server access restriction and add InetAccessHandler if restrictions are needed
- // otherwise don't (to save performance)
- final String white = sb.getConfig("serverClient", "*");
- if (!white.equals("*")) { // full ip (allowed ranges 0-255 or prefix 10.0-255,0,0-100 or CIDR notation 192.168.1.0/24)
- final StringTokenizer st = new StringTokenizer(white, ",");
- final InetAccessHandler whiteListHandler;
- if (white.contains("|")) {
- /*
- * At least one pattern includes a path definition : we must use the
- * InetPathAccessHandler as InetAccessHandler doesn't support path patterns
- */
- whiteListHandler = new InetPathAccessHandler();
- } else {
- whiteListHandler = new InetAccessHandler();
- }
- int i = 0;
- while (st.hasMoreTokens()) {
- final String pattern = st.nextToken();
- try {
- whiteListHandler.include(pattern);
- } catch (final IllegalArgumentException nex) { // catch format exception on wrong ip address pattern
- ConcurrentLog.severe("SERVER", "Server Access Settings - IP filter: " + nex.getMessage());
- continue;
- }
- i++;
- }
- if (i > 0) {
- final String loopbackAddress = InetAddress.getLoopbackAddress().getHostAddress();
- whiteListHandler.include(loopbackAddress);
- whiteListHandler.setHandler(crashHandler);
- this.server.setHandler(whiteListHandler);
-
- ConcurrentLog.info("SERVER","activated IP access restriction to: [" + loopbackAddress + "," + white +"]");
- } else {
- this.server.setHandler(crashHandler); // InetAccessHandler not needed
- }
- } else {
- this.server.setHandler(crashHandler); // InetAccessHandler not needed
- }
- }
+ void startupServer() throws Exception;
/**
- * start http server
+ * stop the http server
*/
- public void startupServer() throws Exception {
- // option to finish running requests on shutdown
-// server.setGracefulShutdown(3000);
- this.server.setStopAtShutdown(true);
- this.server.start();
- }
+ void stop() throws Exception;
/**
- * stop http server and wait for it
+ * reconnect with new port settings (after waiting milsec) - routine returns immediately
+ * @param milsec wait time
*/
- public void stop() throws Exception {
- this.server.stop();
- this.server.join();
- }
+ void reconnect(int milsec);
/**
- * @return true if ssl/https connector is available
+ * @return true if the server runs a ssl/https connector
*/
- public boolean withSSL() {
- final Connector[] clist = this.server.getConnectors();
- for (final Connector c:clist) {
- if (c.getName().startsWith("ssl")) return true;
- }
- return false;
- }
+ boolean withSSL();
/**
- * The port of actual running ssl connector
* @return the ssl/https port or -1 if not active
*/
- public int getSslPort() {
- final Connector[] clist = this.server.getConnectors();
- for (final Connector c:clist) {
- if (c.getName().startsWith("ssl")) {
- final int port =((ServerConnector)c).getLocalPort();
- return port;
- }
- }
- return -1;
- }
-
- /**
- * reconnect with new port settings (after waiting milsec) - routine returns
- * immediately
- * checks http and ssl connector for new port settings
- * @param milsec wait time
- */
- public void reconnect(final int milsec) {
-
- new Thread("Jetty8HttpServer.reconnect") {
-
- @Override
- public void run() {
- if (milsec > 0) try {
- Thread.sleep(milsec);
- } catch (final Exception e) {
- ConcurrentLog.logException(e);
- }
- try {
- if (!YaCyHttpServer.this.server.isRunning() || YaCyHttpServer.this.server.isStopped()) {
- YaCyHttpServer.this.server.start();
- }
-
- // reconnect with new settings (instead to stop/start server, just manipulate connectors
- final Connector[] cons = YaCyHttpServer.this.server.getConnectors();
- final int port = Switchboard.getSwitchboard().getLocalPort();
- final int sslport = Switchboard.getSwitchboard().getConfigInt(SwitchboardConstants.SERVER_SSLPORT, 8443);
- for (final Connector con : cons) {
- // check http connector
- if (con.getName().startsWith("httpd") && ((ServerConnector)con).getPort() != port) {
- ((ServerConnector)con).close();
- con.stop();
- if (!con.isStopped()) {
- ConcurrentLog.warn("SERVER", "Reconnect: Jetty Connector failed to stop");
- }
- ((ServerConnector)con).setPort(port);
- con.start();
- ConcurrentLog.info("SERVER", "set new port for Jetty connector " + con.getName());
- continue;
- }
- // check https connector
- if (con.getName().startsWith("ssl") && ((ServerConnector)con).getPort() != sslport) {
- ((ServerConnector)con).close();
- con.stop();
- if (!con.isStopped()) {
- ConcurrentLog.warn("SERVER", "Reconnect: Jetty Connector failed to stop");
- }
- ((ServerConnector)con).setPort(sslport);
- con.start();
- ConcurrentLog.info("SERVER", "set new port for Jetty connector " + con.getName());
- }
- }
- } catch (final Exception ex) {
- ConcurrentLog.logException(ex);
- }
- }
- }.start();
- }
+ int getSslPort();
/**
- * Forces the login service to reload the built-in administrator credentials
- * after they were changed in the configuration.
+ * forces loginservice to reload user credentials
* @param username
*/
- public void resetUser(final String username) {
- final YaCySecurityHandler hx = this.server.getChildHandlerByClass(YaCySecurityHandler.class);
- if (hx != null) {
- final YaCyLoginService loginservice = (YaCyLoginService) hx.getLoginService();
- if (loginservice.removeUser(username)) { // remove old credential from cache
- loginservice.loadUserInfo(username);
- }
- }
- }
+ void resetUser(String username);
/**
- * Removes the built-in administrator from the login service cache.
+ * removes user from the loginservice
* @param username
*/
- public void removeUser(final String username) {
- final YaCySecurityHandler hx = this.server.getChildHandlerByClass(YaCySecurityHandler.class);
- if (hx != null) {
- final YaCyLoginService loginservice = (YaCyLoginService) hx.getLoginService();
- loginservice.removeUser(username);
- }
- }
+ void removeUser(String username);
/**
- * get Jetty version
- * @return version_string
+ * @return version string of the servlet container
*/
- public String getVersion() {
- return "Jetty " + Server.getVersion();
- }
+ String getVersion();
/**
- * Init SSL Context from config settings
- * @param sb Switchboard
- * @return default or sslcontext according to config
+ * @return the number of currently active (busy) server threads
*/
- private SSLContext initSslContext(final Switchboard sb) {
-
- // getting the keystore file name
- String keyStoreFileName = sb.getConfig("keyStore", "").trim();
-
- // getting the keystore pwd
- String keyStorePwd = sb.getConfig("keyStorePassword", "").trim();
-
- // take a look if we have something to import
- final String pkcs12ImportFile = sb.getConfig("pkcs12ImportFile", "").trim();
-
- // if no keyStore and no import is defined, then set the default key
- if (keyStoreFileName.isEmpty() && keyStorePwd.isEmpty() && pkcs12ImportFile.isEmpty()) {
- keyStoreFileName = "defaults/freeworldKeystore";
- keyStorePwd = "freeworld";
- sb.setConfig("keyStore", keyStoreFileName);
- sb.setConfig("keyStorePassword", keyStorePwd);
- }
-
- if (pkcs12ImportFile.length() > 0) {
- ConcurrentLog.info("SERVER", "Import certificates from import file '" + pkcs12ImportFile + "'.");
-
- try {
- // getting the password
- final String pkcs12ImportPwd = sb.getConfig("pkcs12ImportPwd", "").trim();
-
- // creating tool to import cert
- final PKCS12Tool pkcsTool = new PKCS12Tool(pkcs12ImportFile,pkcs12ImportPwd);
-
- // creating a new keystore file
- if (keyStoreFileName.isEmpty()) {
- // using the default keystore name
- keyStoreFileName = "DATA/SETTINGS/myPeerKeystore";
-
- // creating an empty java keystore
- final KeyStore ks = KeyStore.getInstance("JKS");
- ks.load(null,keyStorePwd.toCharArray());
- try (
- /* Automatically closed by this try-with-resources statement */
- final FileOutputStream ksOut = new FileOutputStream(keyStoreFileName);
- ) {
- ks.store(ksOut, keyStorePwd.toCharArray());
- }
-
- // storing path to keystore into config file
- sb.setConfig("keyStore", keyStoreFileName);
- }
-
- // importing certificate
- pkcsTool.importToJKS(keyStoreFileName, keyStorePwd);
-
- // removing entries from config file
- sb.setConfig("pkcs12ImportFile", "");
- sb.setConfig("pkcs12ImportPwd", "");
-
- // deleting original import file
- // TODO: should we do this
- } catch (final Exception e) {
- ConcurrentLog.severe("SERVER", "Unable to import certificate from import file '" + pkcs12ImportFile + "'.",e);
- }
- } else if (keyStoreFileName.isEmpty()) return null;
-
- // get the ssl context
- try {
- ConcurrentLog.info("SERVER","Initializing SSL support ...");
-
- // creating a new keystore instance of type (java key store)
- if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER", "Initializing keystore ...");
- final KeyStore ks = KeyStore.getInstance("JKS");
-
- // loading keystore data from file
- if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER","Loading keystore file " + keyStoreFileName);
- final FileInputStream stream = new FileInputStream(keyStoreFileName);
- try {
- ks.load(stream, keyStorePwd.toCharArray());
- } finally {
- try {
- stream.close();
- } catch(final IOException ioe) {
- ConcurrentLog.warn("SERVER", "Could not close input stream on file " + keyStoreFileName);
- }
- }
-
- // creating a keystore factory
- if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER","Initializing key manager factory ...");
- final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(ks,keyStorePwd.toCharArray());
-
- // initializing the ssl context
- if (ConcurrentLog.isFine("SERVER")) ConcurrentLog.fine("SERVER","Initializing SSL context ...");
- final SSLContext sslcontext = SSLContext.getInstance("TLS");
- sslcontext.init(kmf.getKeyManagers(), null, null);
-
- return sslcontext;
- } catch (final Exception e) {
- final String errorMsg = "FATAL ERROR: Unable to initialize the SSL Socket factory. " + e.getMessage();
- ConcurrentLog.severe("SERVER",errorMsg);
- System.out.println(errorMsg);
- return null;
- }
- }
-
- public int getServerThreads() {
- return this.server == null ? 0 : this.server.getThreadPool().getThreads() - this.server.getThreadPool().getIdleThreads();
- }
-
- @Override
- public String toString() {
- return this.server.dump() + "\n\n" + this.server.getState();
- }
+ int getServerThreads();
}
diff --git a/source/net/yacy/yacy.java b/source/net/yacy/yacy.java
index 1a5babbc4..251df47c5 100644
--- a/source/net/yacy/yacy.java
+++ b/source/net/yacy/yacy.java
@@ -42,10 +42,10 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
+import java.util.Properties;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import org.apache.http.Header;
import org.apache.http.HttpStatus;
@@ -61,13 +61,14 @@ import net.yacy.cora.protocol.ClientIdentification;
import net.yacy.cora.protocol.ConnectionInfo;
import net.yacy.cora.protocol.HeaderFramework;
import net.yacy.cora.protocol.TimeoutRequest;
-import net.yacy.cora.protocol.http.HTTPClient;
-import net.yacy.cora.util.ConcurrentLog;
-import net.yacy.ai.LogReportService;
-import net.yacy.data.TransactionManager;
+import net.yacy.cora.protocol.http.HTTPClient;
+import net.yacy.cora.util.ConcurrentLog;
+import net.yacy.ai.LogReportService;
+import net.yacy.data.TransactionManager;
import net.yacy.data.Translator;
import net.yacy.gui.YaCyApp;
import net.yacy.gui.framework.Browser;
+import net.yacy.http.Jetty9HttpServerImpl;
import net.yacy.http.YaCyHttpServer;
import net.yacy.kelondro.util.FileUtils;
import net.yacy.kelondro.util.Formatter;
@@ -292,14 +293,14 @@ public final class yacy {
final int deleteOldDownloadsAfterDays = (int) sb.getConfigLong("update.deleteOld", 30);
yacyRelease.deleteOldDownloads(sb.releasePath, deleteOldDownloadsAfterDays );
- // start main threads
- final int port = sb.getLocalPort();
- final String host = sb.getLocalHost();
- ScheduledExecutorService logReportScheduler = null;
- try {
- // start http server
- YaCyHttpServer httpServer;
- httpServer = new YaCyHttpServer(port, host);
+ // start main threads
+ final int port = sb.getLocalPort();
+ final String host = sb.getLocalHost();
+ ScheduledExecutorService logReportScheduler = null;
+ try {
+ // start http server
+ YaCyHttpServer httpServer;
+ httpServer = new Jetty9HttpServerImpl(port, host);
httpServer.startupServer();
sb.setHttpServer(httpServer);
// TODO: this has no effect on Jetty (but needed to reflect configured value and limit is still used)
@@ -375,13 +376,13 @@ public final class yacy {
}
}
// initialize number formatter with this locale
- if (!lang.equals("browser")) // "default" is handled by .setLocale()
- Formatter.setLocale(lang);
-
- logReportScheduler = LogReportService.startScheduler(sb);
-
- // registering shutdown hook
- ConcurrentLog.config("STARTUP", "Registering Shutdown Hook");
+ if (!lang.equals("browser")) // "default" is handled by .setLocale()
+ Formatter.setLocale(lang);
+
+ logReportScheduler = LogReportService.startScheduler(sb);
+
+ // registering shutdown hook
+ ConcurrentLog.config("STARTUP", "Registering Shutdown Hook");
final Runtime run = Runtime.getRuntime();
run.addShutdownHook(new shutdownHookThread(sb, shutdownSemaphore));
@@ -400,18 +401,18 @@ public final class yacy {
} catch (final Exception e) {
ConcurrentLog.severe("MAIN CONTROL LOOP", "PANIC: " + e.getMessage(),e);
}
- // shut down
- ConcurrentLog.config("SHUTDOWN", "caught termination signal");
- LogReportService.stopScheduler(logReportScheduler);
- httpServer.stop();
-
- ConcurrentLog.config("SHUTDOWN", "server has terminated");
- sb.close();
- } catch (final Exception e) {
- LogReportService.stopScheduler(logReportScheduler);
- ConcurrentLog.severe("STARTUP", "Unexpected Error: " + e.getClass().getName(),e);
- //System.exit(1);
- }
+ // shut down
+ ConcurrentLog.config("SHUTDOWN", "caught termination signal");
+ LogReportService.stopScheduler(logReportScheduler);
+ httpServer.stop();
+
+ ConcurrentLog.config("SHUTDOWN", "server has terminated");
+ sb.close();
+ } catch (final Exception e) {
+ LogReportService.stopScheduler(logReportScheduler);
+ ConcurrentLog.severe("STARTUP", "Unexpected Error: " + e.getClass().getName(),e);
+ //System.exit(1);
+ }
if (lock != null && lock.isValid()) lock.release();
if (channel != null && channel.isOpen()) channel.close();
} catch (final Exception ee) {
@@ -726,21 +727,21 @@ public final class yacy {
final StringBuilder s = new StringBuilder(); for (final String a: args) s.append(a).append(" ");
yacyRelease.startParameter = s.toString().trim();
- // case for the application path if started normally with a jre command
- File applicationRoot = new File(System.getProperty("user.dir").replace('\\', '/'));
- File dataRoot = applicationRoot;
- final String dataRootOverrideProp = System.getProperty("yacy.data");
- final String dataRootOverrideEnv = System.getenv("YACY_DATA");
- final String dataRootOverride = (dataRootOverrideProp != null && !dataRootOverrideProp.isEmpty())
- ? dataRootOverrideProp
- : dataRootOverrideEnv;
- if (dataRootOverride != null && !dataRootOverride.isEmpty()) {
- dataRoot = new File(dataRootOverride);
- if(!dataRoot.isAbsolute()) {
- /* data root folder provided as a path relative to the user home folder */
- dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), dataRootOverride);
- }
- }
+ // case for the application path if started normally with a jre command
+ File applicationRoot = new File(System.getProperty("user.dir").replace('\\', '/'));
+ File dataRoot = applicationRoot;
+ final String dataRootOverrideProp = System.getProperty("yacy.data");
+ final String dataRootOverrideEnv = System.getenv("YACY_DATA");
+ final String dataRootOverride = (dataRootOverrideProp != null && !dataRootOverrideProp.isEmpty())
+ ? dataRootOverrideProp
+ : dataRootOverrideEnv;
+ if (dataRootOverride != null && !dataRootOverride.isEmpty()) {
+ dataRoot = new File(dataRootOverride);
+ if(!dataRoot.isAbsolute()) {
+ /* data root folder provided as a path relative to the user home folder */
+ dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), dataRootOverride);
+ }
+ }
//System.out.println("args.length=" + args.length);
//System.out.print("args=["); for (int i = 0; i < args.length; i++) System.out.print(args[i] + ", "); System.out.println("]");
if ((args.length >= 1) && (args[0].toLowerCase(Locale.ROOT).equals("-startup") || args[0].equals("-start"))) {
@@ -765,24 +766,24 @@ public final class yacy {
}
preReadSavedConfigandInit(dataRoot);
startup(dataRoot, applicationRoot, startupMemFree, startupMemTotal, true);
- } else if ((args.length >= 1) && ((args[0].toLowerCase(Locale.ROOT).equals("-shutdown")) || (args[0].equals("-stop")))) {
- // normal shutdown of yacy
- if (args.length == 2) {
- dataRoot = new File(args[1]);
- if(!dataRoot.isAbsolute()) {
- dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
- }
- }
- shutdown(dataRoot);
- } else if ((args.length >= 1) && (args[0].toLowerCase(Locale.ROOT).equals("-update"))) {
- // aut-update yacy
- if (args.length == 2) {
- dataRoot = new File(args[1]);
- if(!dataRoot.isAbsolute()) {
- dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
- }
- }
- update(dataRoot);
+ } else if ((args.length >= 1) && ((args[0].toLowerCase(Locale.ROOT).equals("-shutdown")) || (args[0].equals("-stop")))) {
+ // normal shutdown of yacy
+ if (args.length == 2) {
+ dataRoot = new File(args[1]);
+ if(!dataRoot.isAbsolute()) {
+ dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
+ }
+ }
+ shutdown(dataRoot);
+ } else if ((args.length >= 1) && (args[0].toLowerCase(Locale.ROOT).equals("-update"))) {
+ // aut-update yacy
+ if (args.length == 2) {
+ dataRoot = new File(args[1]);
+ if(!dataRoot.isAbsolute()) {
+ dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
+ }
+ }
+ update(dataRoot);
} else if ((args.length >= 1) && (args[0].toLowerCase(Locale.ROOT).equals("-version"))) {
// show yacy version
System.out.println(copyright);