diff --git a/.java-version b/.java-version index 98d9bcb7..3b5b5d8f 100644 --- a/.java-version +++ b/.java-version @@ -1 +1 @@ -17 +11.0 \ No newline at end of file diff --git a/README.md b/README.md index f6438677..f8155df0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## TL;DR -- Make sure you have Java 17 or higher installed +- Make sure you have Java 11 or higher installed - Download and unpack the [latest release](https://code.host.antville.org/antville/helma/releases) - Invoke `./bin/helma`, resp. `./bin/helma.bat`, depending on your platform - Direct your web browser to diff --git a/build.gradle b/build.gradle index cd60e214..25eef9d1 100644 --- a/build.gradle +++ b/build.gradle @@ -18,8 +18,8 @@ allprojects { apply plugin: 'java' java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } repositories { @@ -51,15 +51,14 @@ configurations { dependencies { implementation 'com.google.code.gson:gson:2.12.1' implementation 'commons-codec:commons-codec:1.18.0' - implementation 'org.apache.commons:commons-fileupload2-core:2.0.0-M2' - implementation 'org.apache.commons:commons-fileupload2-jakarta:2.0.0-M1' + implementation 'commons-fileupload:commons-fileupload:1.5' implementation 'commons-logging:commons-logging:1.3.5' implementation 'commons-net:commons-net:3.11.1' implementation 'com.sun.mail:javax.mail:1.6.2' - implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0' + implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' - implementation 'org.eclipse.jetty.ee9:jetty-ee9-servlet:12.0.19' - implementation 'org.eclipse.jetty:jetty-xml:12.0.19' + implementation 'org.eclipse.jetty:jetty-servlet:9.4.57.v20241219' + implementation 'org.eclipse.jetty:jetty-xml:9.4.57.v20241219' implementation 'org.mozilla:rhino-all:1.8.0' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' diff --git a/src/main/java/helma/framework/CookieTrans.java b/src/main/java/helma/framework/CookieTrans.java index 5293b843..fed45960 100644 --- a/src/main/java/helma/framework/CookieTrans.java +++ b/src/main/java/helma/framework/CookieTrans.java @@ -17,7 +17,7 @@ package helma.framework; import java.io.Serializable; -import jakarta.servlet.http.Cookie; +import javax.servlet.http.Cookie; /** * Cookie Transmitter. A simple, serializable representation diff --git a/src/main/java/helma/framework/RequestBean.java b/src/main/java/helma/framework/RequestBean.java index bf377a63..49091022 100644 --- a/src/main/java/helma/framework/RequestBean.java +++ b/src/main/java/helma/framework/RequestBean.java @@ -16,12 +16,12 @@ package helma.framework; -import jakarta.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequest; import java.io.Serializable; import java.util.Map; /** - * + * */ public class RequestBean implements Serializable { private static final long serialVersionUID = -6826881712426326687L; @@ -89,7 +89,7 @@ public class RequestBean implements Serializable { * @return the header value, or null */ public String getHeader(String name) { - return req.getHeader(name); + return req.getHeader(name); } /** diff --git a/src/main/java/helma/framework/RequestTrans.java b/src/main/java/helma/framework/RequestTrans.java index ec8218fe..83665ba8 100644 --- a/src/main/java/helma/framework/RequestTrans.java +++ b/src/main/java/helma/framework/RequestTrans.java @@ -19,9 +19,9 @@ package helma.framework; import helma.util.SystemMap; import helma.util.StringUtils; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.Cookie; import org.apache.commons.codec.binary.Base64; diff --git a/src/main/java/helma/framework/ResponseBean.java b/src/main/java/helma/framework/ResponseBean.java index 061ecb54..c2790a34 100644 --- a/src/main/java/helma/framework/ResponseBean.java +++ b/src/main/java/helma/framework/ResponseBean.java @@ -19,7 +19,7 @@ package helma.framework; import helma.objectmodel.db.Transactor; import helma.scripting.ScriptingException; -import jakarta.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponse; import java.io.Serializable; import java.io.StringWriter; import java.io.PrintWriter; diff --git a/src/main/java/helma/framework/ResponseTrans.java b/src/main/java/helma/framework/ResponseTrans.java index 239487d7..af65a4c1 100644 --- a/src/main/java/helma/framework/ResponseTrans.java +++ b/src/main/java/helma/framework/ResponseTrans.java @@ -21,7 +21,7 @@ import helma.framework.core.Application; import helma.util.*; import helma.scripting.ScriptingException; -import jakarta.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponse; import java.io.*; import java.security.*; import java.util.*; diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index e699a8d8..2deb88ee 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -19,13 +19,11 @@ import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.xmlrpc.XmlRpcHandler; - import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ResourceHandler; -import org.eclipse.jetty.ee9.servlet.ServletContextHandler; -import org.eclipse.jetty.ee9.servlet.ServletHolder; -import org.eclipse.jetty.util.resource.ResourceFactory; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; import helma.framework.core.Application; import helma.framework.repository.FileRepository; @@ -483,29 +481,23 @@ public class ApplicationManager implements XmlRpcHandler { // if there is a static direcory specified, mount it if (this.staticDir != null) { - String staticPath = getAbsoluteFile(this.staticDir).getCanonicalPath(); - getLogger().info("Serving static from " + staticPath); + File staticContent = getAbsoluteFile(this.staticDir); + + getLogger().info("Serving static from " + staticContent.getPath()); getLogger().info("Mounting static at " + staticMountpoint); ResourceHandler rhandler = new ResourceHandler(); - rhandler.setBaseResource(ResourceFactory.of(rhandler).newResource(staticPath)); + rhandler.setResourceBase(staticContent.getPath()); rhandler.setWelcomeFiles(staticHome); - ContextHandler staticContext = new ContextHandler(); - staticContext.setContextPath(staticMountpoint); + staticContext = ApplicationManager.this.context.addContext(staticMountpoint, ""); //$NON-NLS-1$ staticContext.setHandler(rhandler); - ApplicationManager.this.context.addHandler(staticContext); staticContext.start(); } - // I hope I am correct assuming Helma does not need Jetty’s session management, but using - // `ServletContextHandler.SESSIONS` causes an exception: Shared scheduler not started - appContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); - appContext.setContextPath(pathPattern); - context.addHandler(appContext); - + appContext = new ServletContextHandler(context, pathPattern, true, true); Class servletClass = servletClassName == null ? EmbeddedServletClient.class : Class.forName(servletClassName); ServletHolder holder = new ServletHolder(servletClass); @@ -537,9 +529,10 @@ public class ApplicationManager implements XmlRpcHandler { } if (protectedStaticDir != null) { - String protectedContent = getAbsoluteFile(protectedStaticDir).getCanonicalPath(); - appContext.setBaseResourceAsString(protectedContent); - getLogger().info("Serving protected static from " + protectedContent); + File protectedContent = getAbsoluteFile(protectedStaticDir); + appContext.setResourceBase(protectedContent.getPath()); + getLogger().info("Serving protected static from " + + protectedContent.getPath()); } // Remap the context paths and start @@ -563,9 +556,7 @@ public class ApplicationManager implements XmlRpcHandler { // unbind from Jetty HTTP server if (ApplicationManager.this.jetty != null) { if (this.appContext != null) { - // Adding appContext to the ContextHandlerCollection works (see above) but removing it causes an exception of - // incompatible types: ServletContextHandler cannot be converted to Handler - //ApplicationManager.this.context.removeHandler(this.appContext); + ApplicationManager.this.context.removeHandler(this.appContext); this.appContext.stop(); this.appContext.destroy(); this.appContext = null; diff --git a/src/main/java/helma/main/JettyServer.java b/src/main/java/helma/main/JettyServer.java index 83e09bcf..88ba8c10 100644 --- a/src/main/java/helma/main/JettyServer.java +++ b/src/main/java/helma/main/JettyServer.java @@ -16,12 +16,11 @@ package helma.main; + import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.util.resource.URLResourceFactory; import org.eclipse.jetty.xml.XmlConfiguration; import java.net.URL; @@ -37,20 +36,18 @@ public class JettyServer { public static JettyServer init(Server server, ServerConfig config) throws IOException { File configFile = config.getConfigFile(); if (configFile != null && configFile.exists()) { - URLResourceFactory resourceFactory = new URLResourceFactory(); - Resource resource = resourceFactory.newResource(configFile.toURI()); - return new JettyServer(resource); + return new JettyServer(configFile.toURI().toURL()); } else if (config.hasWebsrvPort()) { return new JettyServer(config.getWebsrvPort(), server); } return null; } - private JettyServer(Resource resource) throws IOException { + private JettyServer(URL url) throws IOException { http = new org.eclipse.jetty.server.Server(); try { - XmlConfiguration config = new XmlConfiguration(resource); + XmlConfiguration config = new XmlConfiguration(url); config.configure(http); } catch (IOException e) { @@ -62,7 +59,7 @@ public class JettyServer { private JettyServer(InetSocketAddress webPort, Server server) throws IOException { - + http = new org.eclipse.jetty.server.Server(); // start embedded web server if port is specified @@ -76,6 +73,7 @@ public class JettyServer { connector.setHost(webPort.getAddress().getHostAddress()); connector.setPort(webPort.getPort()); connector.setIdleTimeout(30000); + connector.setSoLingerTime(-1); connector.setAcceptorPriorityDelta(0); connector.setAcceptQueueSize(0); @@ -102,13 +100,12 @@ public class JettyServer { } private void openListeners() throws IOException { - // opening the listener here allows us to run on privileged port 80 under jsvc + // opening the listener here allows us to run on priviledged port 80 under jsvc // even as non-root user, because init() is called with root privileges // while start() will be called with the user we will actually run as - for (var connector : http.getConnectors()) { - if (connector instanceof ServerConnector) { - ((ServerConnector) connector).open(); - } + Connector[] connectors = http.getConnectors(); + for (int i = 0; i < connectors.length; i++) { + ((ServerConnector) connectors[i]).open(); } } } diff --git a/src/main/java/helma/main/Server.java b/src/main/java/helma/main/Server.java index d951adae..88d70db7 100644 --- a/src/main/java/helma/main/Server.java +++ b/src/main/java/helma/main/Server.java @@ -21,7 +21,6 @@ import helma.framework.repository.FileResource; import helma.framework.core.*; import helma.objectmodel.db.DbSource; import helma.util.*; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xmlrpc.*; @@ -153,8 +152,8 @@ public class Server implements Runnable { String javaVersion = System.getProperty("java.version", "0"); int majorVersion = Integer.parseInt(javaVersion.split("\\.")[0]); - if (majorVersion < 17) { - System.err.println("This version of Helma requires Java 17 or greater."); + if (majorVersion < 11) { + System.err.println("This version of Helma requires Java 11 or greater."); if (majorVersion == 0) { // don't think this will ever happen, but you never know System.err.println("Your Java Runtime did not provide a version number. Please update to a more recent version."); diff --git a/src/main/java/helma/servlet/AbstractServletClient.java b/src/main/java/helma/servlet/AbstractServletClient.java index 546a0698..3e3b3f59 100644 --- a/src/main/java/helma/servlet/AbstractServletClient.java +++ b/src/main/java/helma/servlet/AbstractServletClient.java @@ -22,29 +22,18 @@ package helma.servlet; import helma.framework.*; import helma.framework.core.Application; import helma.util.*; - import java.io.*; -import java.nio.charset.Charset; -import java.nio.charset.UnsupportedCharsetException; - +import java.util.*; import java.security.SecureRandom; import java.security.NoSuchAlgorithmException; -import java.util.*; - -import jakarta.servlet.*; -import jakarta.servlet.http.*; +import javax.servlet.*; +import javax.servlet.http.*; import org.apache.commons.codec.binary.Base64; - -import org.apache.commons.fileupload2.core.DiskFileItemFactory; -import org.apache.commons.fileupload2.core.FileItem; -import org.apache.commons.fileupload2.core.FileUploadException; -import org.apache.commons.fileupload2.core.FileUploadSizeException; -import org.apache.commons.fileupload2.core.ProgressListener; - -import org.apache.commons.fileupload2.jakarta.JakartaServletDiskFileUpload; -import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload; -import org.apache.commons.fileupload2.jakarta.JakartaServletRequestContext; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.*; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload.servlet.ServletRequestContext; /** * This is an abstract Hop servlet adapter. This class communicates with hop applications @@ -229,9 +218,9 @@ public abstract class AbstractServletClient extends HttpServlet { // read file uploads List uploads = null; - JakartaServletRequestContext reqcx = new JakartaServletRequestContext(request); + ServletRequestContext reqcx = new ServletRequestContext(request); - if (JakartaServletFileUpload.isMultipartContent(reqcx)) { + if (ServletFileUpload.isMultipartContent(reqcx)) { // get session for upload progress monitoring UploadStatus uploadStatus = getApplication().getUploadStatus(reqtrans); try { @@ -239,7 +228,7 @@ public abstract class AbstractServletClient extends HttpServlet { } catch (Exception upx) { log("Error in file upload", upx); String message; - boolean tooLarge = (upx instanceof FileUploadSizeException); + boolean tooLarge = (upx instanceof FileUploadBase.SizeLimitExceededException); if (tooLarge) { message = "File upload size exceeds limit of " + uploadLimit + " kB"; } else { @@ -664,12 +653,12 @@ public abstract class AbstractServletClient extends HttpServlet { map.put(name, newValues); } - protected List parseUploads(JakartaServletRequestContext reqcx, RequestTrans reqtrans, + protected List parseUploads(ServletRequestContext reqcx, RequestTrans reqtrans, final UploadStatus uploadStatus, String encoding) - throws FileUploadException, UnsupportedCharsetException, IOException { + throws FileUploadException, UnsupportedEncodingException { // handle file upload - DiskFileItemFactory factory = DiskFileItemFactory.builder().get(); - JakartaServletFileUpload upload = new JakartaServletFileUpload(factory); + DiskFileItemFactory factory = new DiskFileItemFactory(); + FileUpload upload = new FileUpload(factory); // use upload limit for individual file size, but also set a limit on overall size upload.setFileSizeMax(uploadLimit * 1024); upload.setSizeMax(totalUploadLimit * 1024); @@ -692,7 +681,7 @@ public abstract class AbstractServletClient extends HttpServlet { Object value; // check if this is an ordinary HTML form element or a file upload if (item.isFormField()) { - value = item.getString(Charset.forName(encoding)); + value = item.getString(encoding); } else { value = new MimePart(item); } diff --git a/src/main/java/helma/servlet/EmbeddedServletClient.java b/src/main/java/helma/servlet/EmbeddedServletClient.java index 9f9a37cc..80b3cd6e 100644 --- a/src/main/java/helma/servlet/EmbeddedServletClient.java +++ b/src/main/java/helma/servlet/EmbeddedServletClient.java @@ -19,7 +19,7 @@ package helma.servlet; import helma.framework.*; import helma.framework.core.Application; import helma.main.*; -import jakarta.servlet.*; +import javax.servlet.*; /** * Servlet client that runs a Helma application for the embedded diff --git a/src/main/java/helma/servlet/StandaloneServletClient.java b/src/main/java/helma/servlet/StandaloneServletClient.java index bdfeeeae..5e1af952 100644 --- a/src/main/java/helma/servlet/StandaloneServletClient.java +++ b/src/main/java/helma/servlet/StandaloneServletClient.java @@ -23,7 +23,7 @@ import helma.main.ServerConfig; import helma.main.Server; import java.io.*; -import jakarta.servlet.*; +import javax.servlet.*; import java.util.*; /** @@ -98,7 +98,7 @@ public final class StandaloneServletClient extends AbstractServletClient { repositoryImpl = "helma.framework.repository.FileRepository"; } } - + try { Repository newRepository = (Repository) Class.forName(repositoryImpl) .getConstructor(parameters) @@ -116,7 +116,7 @@ public final class StandaloneServletClient extends AbstractServletClient { } } } - + // add app dir FileRepository appRep = new FileRepository(appDir); log("adding repository: " + appDir); diff --git a/src/main/java/helma/util/MimePart.java b/src/main/java/helma/util/MimePart.java index e4ed29d8..f69f1d61 100644 --- a/src/main/java/helma/util/MimePart.java +++ b/src/main/java/helma/util/MimePart.java @@ -16,7 +16,7 @@ package helma.util; -import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload.FileItem; import java.io.*; import java.util.Date; @@ -238,7 +238,7 @@ public class MimePart implements Serializable { file = new File(base, filename); if (fileItem != null) { - fileItem.write(file.toPath()); + fileItem.write(file); // null out fileItem, since calling write() may have moved the temp file fileItem = null; } else { @@ -249,7 +249,7 @@ public class MimePart implements Serializable { // return file name return filename; } catch (Exception x) { - System.err.println("Error in MimePart.writeToFile(): " + x); + System.err.println("Error in MimePart.writeToFile(): " + x); return null; } }