add: support for importing code using require() method (commonjs)

This commit is contained in:
Tobi Schäfer 2020-03-21 14:10:12 +01:00
parent db8d239c32
commit 23fdb31348
6 changed files with 475 additions and 152 deletions

View file

@ -46,11 +46,12 @@ configurations {
} }
dependencies { dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.sun.activation:javax.activation:1.2.0'
implementation 'commons-codec:commons-codec:1.14' implementation 'commons-codec:commons-codec:1.14'
implementation 'commons-fileupload:commons-fileupload:1.4' implementation 'commons-fileupload:commons-fileupload:1.4'
implementation 'commons-logging:commons-logging:1.2' implementation 'commons-logging:commons-logging:1.2'
implementation 'commons-net:commons-net:3.6' implementation 'commons-net:commons-net:3.6'
implementation 'com.sun.activation:javax.activation:1.2.0'
implementation 'javax.mail:javax.mail-api:1.6.2' implementation 'javax.mail:javax.mail-api:1.6.2'
implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'javax.servlet:javax.servlet-api:4.0.1'
implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1'

View file

@ -7,31 +7,30 @@
* http://adele.helma.org/download/helma/license.txt * http://adele.helma.org/download/helma/license.txt
* *
* Copyright 1998-2003 Helma Software. All Rights Reserved. * Copyright 1998-2003 Helma Software. All Rights Reserved.
*
* $RCSfile$
* $Author$
* $Revision$
* $Date$
*/ */
package helma.main; package helma.main;
import helma.framework.core.*; import java.io.File;
import helma.framework.repository.Repository; import java.util.ArrayList;
import helma.framework.repository.FileRepository; import java.util.Enumeration;
import helma.util.StringUtils; import java.util.Hashtable;
import org.apache.xmlrpc.XmlRpcHandler; import java.util.Vector;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.xmlrpc.XmlRpcHandler;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import java.io.*; import helma.framework.core.Application;
import java.util.*; import helma.framework.repository.FileRepository;
import helma.util.ResourceProperties; import helma.framework.repository.Repository;
import helma.servlet.EmbeddedServletClient; import helma.servlet.EmbeddedServletClient;
import helma.util.ResourceProperties;
import helma.util.StringUtils;
/** /**
* This class is responsible for starting and stopping Helma applications. * This class is responsible for starting and stopping Helma applications.
@ -55,11 +54,11 @@ public class ApplicationManager implements XmlRpcHandler {
public ApplicationManager(ResourceProperties props, Server server) { public ApplicationManager(ResourceProperties props, Server server) {
this.props = props; this.props = props;
this.server = server; this.server = server;
descriptors = new Hashtable(); this.descriptors = new Hashtable();
applications = new Hashtable(); this.applications = new Hashtable();
xmlrpcHandlers = new Hashtable(); this.xmlrpcHandlers = new Hashtable();
lastModified = 0; this.lastModified = 0;
jetty = server.jetty; this.jetty = server.jetty;
} }
/** /**
@ -67,13 +66,13 @@ public class ApplicationManager implements XmlRpcHandler {
* to create and start new applications. * to create and start new applications.
*/ */
protected void checkForChanges() { protected void checkForChanges() {
if (props.lastModified() > lastModified && server.getApplicationsOption() == null) { if (this.props.lastModified() > this.lastModified && this.server.getApplicationsOption() == null) {
try { try {
for (Enumeration e = props.keys(); e.hasMoreElements();) { for (Enumeration e = this.props.keys(); e.hasMoreElements();) {
String appName = (String) e.nextElement(); String appName = (String) e.nextElement();
if ((appName.indexOf(".") == -1) && if ((appName.indexOf(".") == -1) && //$NON-NLS-1$
(applications.get(appName) == null)) { (this.applications.get(appName) == null)) {
AppDescriptor appDesc = new AppDescriptor(appName); AppDescriptor appDesc = new AppDescriptor(appName);
appDesc.start(); appDesc.start();
appDesc.bind(); appDesc.bind();
@ -81,27 +80,27 @@ public class ApplicationManager implements XmlRpcHandler {
} }
// then stop deleted ones // then stop deleted ones
for (Enumeration e = descriptors.elements(); e.hasMoreElements();) { for (Enumeration e = this.descriptors.elements(); e.hasMoreElements();) {
AppDescriptor appDesc = (AppDescriptor) e.nextElement(); AppDescriptor appDesc = (AppDescriptor) e.nextElement();
// check if application has been removed and should be stopped // check if application has been removed and should be stopped
if (!props.containsKey(appDesc.appName)) { if (!this.props.containsKey(appDesc.appName)) {
appDesc.stop(); appDesc.stop();
} else if (server.jetty != null) { } else if (this.server.jetty != null) {
// If application continues to run, remount // If application continues to run, remount
// as the mounting options may have changed. // as the mounting options may have changed.
AppDescriptor ndesc = new AppDescriptor(appDesc.appName); AppDescriptor ndesc = new AppDescriptor(appDesc.appName);
ndesc.app = appDesc.app; ndesc.app = appDesc.app;
appDesc.unbind(); appDesc.unbind();
ndesc.bind(); ndesc.bind();
descriptors.put(ndesc.appName, ndesc); this.descriptors.put(ndesc.appName, ndesc);
} }
} }
} catch (Exception mx) { } catch (Exception mx) {
getLogger().error("Error checking applications", mx); getLogger().error("Error checking applications", mx);
} }
lastModified = System.currentTimeMillis(); this.lastModified = System.currentTimeMillis();
} }
} }
@ -118,7 +117,7 @@ public class ApplicationManager implements XmlRpcHandler {
* Bind an application by name * Bind an application by name
*/ */
public void register(String appName) { public void register(String appName) {
AppDescriptor desc = (AppDescriptor) descriptors.get(appName); AppDescriptor desc = (AppDescriptor) this.descriptors.get(appName);
if (desc != null) { if (desc != null) {
desc.bind(); desc.bind();
} }
@ -128,7 +127,7 @@ public class ApplicationManager implements XmlRpcHandler {
* Stop an application by name * Stop an application by name
*/ */
public void stop(String appName) { public void stop(String appName) {
AppDescriptor desc = (AppDescriptor) descriptors.get(appName); AppDescriptor desc = (AppDescriptor) this.descriptors.get(appName);
if (desc != null) { if (desc != null) {
desc.stop(); desc.stop();
} }
@ -140,18 +139,18 @@ public class ApplicationManager implements XmlRpcHandler {
*/ */
public void startAll() { public void startAll() {
try { try {
String[] apps = server.getApplicationsOption(); String[] apps = this.server.getApplicationsOption();
if (apps != null) { if (apps != null) {
for (int i = 0; i < apps.length; i++) { for (int i = 0; i < apps.length; i++) {
AppDescriptor desc = new AppDescriptor(apps[i]); AppDescriptor desc = new AppDescriptor(apps[i]);
desc.start(); desc.start();
} }
} else { } else {
for (Enumeration e = props.keys(); e.hasMoreElements();) { for (Enumeration e = this.props.keys(); e.hasMoreElements();) {
String appName = (String) e.nextElement(); String appName = (String) e.nextElement();
if (appName.indexOf(".") == -1) { if (appName.indexOf(".") == -1) { //$NON-NLS-1$
String appValue = props.getProperty(appName); String appValue = this.props.getProperty(appName);
if (appValue != null && appValue.length() > 0) { if (appValue != null && appValue.length() > 0) {
appName = appValue; appName = appValue;
@ -163,12 +162,12 @@ public class ApplicationManager implements XmlRpcHandler {
} }
} }
for (Enumeration e = descriptors.elements(); e.hasMoreElements();) { for (Enumeration e = this.descriptors.elements(); e.hasMoreElements();) {
AppDescriptor appDesc = (AppDescriptor) e.nextElement(); AppDescriptor appDesc = (AppDescriptor) e.nextElement();
appDesc.bind(); appDesc.bind();
} }
lastModified = System.currentTimeMillis(); this.lastModified = System.currentTimeMillis();
} catch (Exception mx) { } catch (Exception mx) {
getLogger().error("Error starting applications", mx); getLogger().error("Error starting applications", mx);
mx.printStackTrace(); mx.printStackTrace();
@ -179,7 +178,7 @@ public class ApplicationManager implements XmlRpcHandler {
* Stop all running applications. * Stop all running applications.
*/ */
public void stopAll() { public void stopAll() {
for (Enumeration en = descriptors.elements(); en.hasMoreElements();) { for (Enumeration en = this.descriptors.elements(); en.hasMoreElements();) {
try { try {
AppDescriptor appDesc = (AppDescriptor) en.nextElement(); AppDescriptor appDesc = (AppDescriptor) en.nextElement();
@ -194,14 +193,14 @@ public class ApplicationManager implements XmlRpcHandler {
* Get an array containing all currently running applications. * Get an array containing all currently running applications.
*/ */
public Object[] getApplications() { public Object[] getApplications() {
return applications.values().toArray(); return this.applications.values().toArray();
} }
/** /**
* Get an application by name. * Get an application by name.
*/ */
public Application getApplication(String name) { public Application getApplication(String name) {
return (Application) applications.get(name); return (Application) this.applications.get(name);
} }
/** /**
@ -209,7 +208,7 @@ public class ApplicationManager implements XmlRpcHandler {
*/ */
public Object execute(String method, Vector params) public Object execute(String method, Vector params)
throws Exception { throws Exception {
int dot = method.indexOf("."); int dot = method.indexOf("."); //$NON-NLS-1$
if (dot == -1) { if (dot == -1) {
throw new Exception("Method name \"" + method + throw new Exception("Method name \"" + method +
@ -222,10 +221,10 @@ public class ApplicationManager implements XmlRpcHandler {
String handler = method.substring(0, dot); String handler = method.substring(0, dot);
String method2 = method.substring(dot + 1); String method2 = method.substring(dot + 1);
Application app = (Application) xmlrpcHandlers.get(handler); Application app = (Application) this.xmlrpcHandlers.get(handler);
if (app == null) { if (app == null) {
app = (Application) xmlrpcHandlers.get("*"); app = (Application) this.xmlrpcHandlers.get("*"); //$NON-NLS-1$
// use the original method name, the handler is resolved within the app. // use the original method name, the handler is resolved within the app.
method2 = method; method2 = method;
} }
@ -240,33 +239,32 @@ public class ApplicationManager implements XmlRpcHandler {
private String getMountpoint(String mountpoint) { private String getMountpoint(String mountpoint) {
mountpoint = mountpoint.trim(); mountpoint = mountpoint.trim();
if ("".equals(mountpoint)) { if ("".equals(mountpoint)) { //$NON-NLS-1$
return "/"; return "/"; //$NON-NLS-1$
} else if (!mountpoint.startsWith("/")) { } else if (!mountpoint.startsWith("/")) { //$NON-NLS-1$
return "/" + mountpoint; return "/" + mountpoint; //$NON-NLS-1$
} }
return mountpoint; return mountpoint;
} }
private String joinMountpoint(String prefix, String suffix) { private String joinMountpoint(String prefix, String suffix) {
if (prefix.endsWith("/") || suffix.startsWith("/")) { if (prefix.endsWith("/") || suffix.startsWith("/")) { //$NON-NLS-1$//$NON-NLS-2$
return prefix+suffix; return prefix+suffix;
} else {
return prefix+"/"+suffix;
} }
return prefix+"/"+suffix; //$NON-NLS-1$
} }
private String getPathPattern(String mountpoint) { private String getPathPattern(String mountpoint) {
if (!mountpoint.startsWith("/")) { if (!mountpoint.startsWith("/")) { //$NON-NLS-1$
mountpoint = "/"+mountpoint; mountpoint = "/"+mountpoint; //$NON-NLS-1$
} }
if ("/".equals(mountpoint)) { if ("/".equals(mountpoint)) { //$NON-NLS-1$
return "/"; return "/"; //$NON-NLS-1$
} }
if (mountpoint.endsWith("/")) { if (mountpoint.endsWith("/")) { //$NON-NLS-1$
return mountpoint.substring(0, mountpoint.length()-1); return mountpoint.substring(0, mountpoint.length()-1);
} }
@ -279,19 +277,18 @@ public class ApplicationManager implements XmlRpcHandler {
File file = new File(path); File file = new File(path);
if (file.isAbsolute()) { if (file.isAbsolute()) {
return file; return file;
} else {
return file.getAbsoluteFile();
} }
return file.getAbsoluteFile();
} }
private Log getLogger() { private Log getLogger() {
return server.getLogger(); return this.server.getLogger();
} }
private String findResource(String path) { private String findResource(String path) {
File file = new File(path); File file = new File(path);
if (!file.isAbsolute() && !file.exists()) { if (!file.isAbsolute() && !file.exists()) {
file = new File(server.getHopHome(), path); file = new File(this.server.getHopHome(), path);
} }
return file.getAbsolutePath(); return file.getAbsolutePath();
} }
@ -336,58 +333,58 @@ public class ApplicationManager implements XmlRpcHandler {
* @param name the application name * @param name the application name
*/ */
AppDescriptor(String name) { AppDescriptor(String name) {
ResourceProperties conf = props.getSubProperties(name + '.'); ResourceProperties conf = ApplicationManager.this.props.getSubProperties(name + '.');
appName = name; this.appName = name;
mountpoint = getMountpoint(conf.getProperty("mountpoint", appName)); this.mountpoint = getMountpoint(conf.getProperty("mountpoint", this.appName)); //$NON-NLS-1$
pathPattern = getPathPattern(mountpoint); this.pathPattern = getPathPattern(this.mountpoint);
staticDir = conf.getProperty("static"); this.staticDir = conf.getProperty("static"); //$NON-NLS-1$
staticMountpoint = getPathPattern(conf.getProperty("staticMountpoint", this.staticMountpoint = getPathPattern(conf.getProperty("staticMountpoint", //$NON-NLS-1$
joinMountpoint(mountpoint, "static"))); joinMountpoint(this.mountpoint, "static"))); //$NON-NLS-1$
staticIndex = "true".equalsIgnoreCase(conf.getProperty("staticIndex")); this.staticIndex = "true".equalsIgnoreCase(conf.getProperty("staticIndex")); //$NON-NLS-1$//$NON-NLS-2$
String home = conf.getProperty("staticHome"); String home = conf.getProperty("staticHome"); //$NON-NLS-1$
if (home == null) { if (home == null) {
staticHome = new String[] {"index.html", "index.htm"}; this.staticHome = new String[] {"index.html", "index.htm"}; //$NON-NLS-1$ //$NON-NLS-2$
} else { } else {
staticHome = StringUtils.split(home, ","); this.staticHome = StringUtils.split(home, ","); //$NON-NLS-1$
} }
protectedStaticDir = conf.getProperty("protectedStatic"); this.protectedStaticDir = conf.getProperty("protectedStatic"); //$NON-NLS-1$
cookieDomain = conf.getProperty("cookieDomain"); this.cookieDomain = conf.getProperty("cookieDomain"); //$NON-NLS-1$
sessionCookieName = conf.getProperty("sessionCookieName"); this.sessionCookieName = conf.getProperty("sessionCookieName"); //$NON-NLS-1$
protectedSessionCookie = conf.getProperty("protectedSessionCookie"); this.protectedSessionCookie = conf.getProperty("protectedSessionCookie"); //$NON-NLS-1$
uploadLimit = conf.getProperty("uploadLimit"); this.uploadLimit = conf.getProperty("uploadLimit"); //$NON-NLS-1$
uploadSoftfail = conf.getProperty("uploadSoftfail"); this.uploadSoftfail = conf.getProperty("uploadSoftfail"); //$NON-NLS-1$
debug = conf.getProperty("debug"); this.debug = conf.getProperty("debug"); //$NON-NLS-1$
String appDirName = conf.getProperty("appdir"); String appDirName = conf.getProperty("appdir"); //$NON-NLS-1$
appDir = (appDirName == null) ? null : getAbsoluteFile(appDirName); this.appDir = (appDirName == null) ? null : getAbsoluteFile(appDirName);
String dbDirName = conf.getProperty("dbdir"); String dbDirName = conf.getProperty("dbdir"); //$NON-NLS-1$
dbDir = (dbDirName == null) ? null : getAbsoluteFile(dbDirName); this.dbDir = (dbDirName == null) ? null : getAbsoluteFile(dbDirName);
servletClassName = conf.getProperty("servletClass"); this.servletClassName = conf.getProperty("servletClass"); //$NON-NLS-1$
// got ignore dirs // got ignore dirs
ignoreDirs = conf.getProperty("ignore"); this.ignoreDirs = conf.getProperty("ignore"); //$NON-NLS-1$
// read and configure app repositories // read and configure app repositories
ArrayList repositoryList = new ArrayList(); ArrayList repositoryList = new ArrayList();
Class[] parameters = { String.class }; Class[] parameters = { String.class };
for (int i = 0; true; i++) { for (int i = 0; true; i++) {
String repositoryArgs = conf.getProperty("repository." + i); String repositoryArgs = conf.getProperty("repository." + i); //$NON-NLS-1$
if (repositoryArgs != null) { if (repositoryArgs != null) {
// lookup repository implementation // lookup repository implementation
String repositoryImpl = conf.getProperty("repository." + i + String repositoryImpl = conf.getProperty("repository." + i + //$NON-NLS-1$
".implementation"); ".implementation"); //$NON-NLS-1$
if (repositoryImpl == null) { if (repositoryImpl == null) {
// implementation not set manually, have to guess it // implementation not set manually, have to guess it
if (repositoryArgs.endsWith(".zip")) { if (repositoryArgs.endsWith(".zip")) { //$NON-NLS-1$
repositoryArgs = findResource(repositoryArgs); repositoryArgs = findResource(repositoryArgs);
repositoryImpl = "helma.framework.repository.ZipRepository"; repositoryImpl = "helma.framework.repository.ZipRepository"; //$NON-NLS-1$
} else if (repositoryArgs.endsWith(".js")) { } else if (repositoryArgs.endsWith(".js")) { //$NON-NLS-1$
repositoryArgs = findResource(repositoryArgs); repositoryArgs = findResource(repositoryArgs);
repositoryImpl = "helma.framework.repository.SingleFileRepository"; repositoryImpl = "helma.framework.repository.SingleFileRepository"; //$NON-NLS-1$
} else { } else {
repositoryArgs = findResource(repositoryArgs); repositoryArgs = findResource(repositoryArgs);
repositoryImpl = "helma.framework.repository.FileRepository"; repositoryImpl = "helma.framework.repository.FileRepository"; //$NON-NLS-1$
} }
} }
@ -408,17 +405,17 @@ public class ApplicationManager implements XmlRpcHandler {
} }
} }
if (appDir != null) { if (this.appDir != null) {
FileRepository appRep = new FileRepository(appDir); FileRepository appRep = new FileRepository(this.appDir);
if (!repositoryList.contains(appRep)) { if (!repositoryList.contains(appRep)) {
repositoryList.add(appRep); repositoryList.add(appRep);
} }
} else if (repositoryList.isEmpty()) { } else if (repositoryList.isEmpty()) {
repositoryList.add(new FileRepository( repositoryList.add(new FileRepository(
new File(server.getAppsHome(), appName))); new File(ApplicationManager.this.server.getAppsHome(), this.appName)));
} }
this.repositories = (RepositoryInterface[]) repositoryList.toArray(new RepositoryInterface[repositoryList.size()]); this.repositories = (Repository[]) repositoryList.toArray(new Repository[repositoryList.size()]);
} }
@ -427,21 +424,21 @@ public class ApplicationManager implements XmlRpcHandler {
try { try {
// create the application instance // create the application instance
app = new Application(appName, server, repositories, appDir, dbDir); this.app = new Application(this.appName, ApplicationManager.this.server, this.repositories, this.appDir, this.dbDir);
// register ourselves // register ourselves
descriptors.put(appName, this); ApplicationManager.this.descriptors.put(this.appName, this);
applications.put(appName, app); ApplicationManager.this.applications.put(this.appName, this.app);
// the application is started later in the register method, when it's bound // the application is started later in the register method, when it's bound
app.init(ignoreDirs); this.app.init(this.ignoreDirs);
// set application URL prefix if it isn't set in app.properties // set application URL prefix if it isn't set in app.properties
if (!app.hasExplicitBaseURI()) { if (!this.app.hasExplicitBaseURI()) {
app.setBaseURI(mountpoint); this.app.setBaseURI(this.mountpoint);
} }
app.start(); this.app.start();
} catch (Exception x) { } catch (Exception x) {
getLogger().error("Error creating application " + appName, x); getLogger().error("Error creating application " + appName, x);
x.printStackTrace(); x.printStackTrace();
@ -462,8 +459,8 @@ public class ApplicationManager implements XmlRpcHandler {
getLogger().error("Couldn't stop app", x); getLogger().error("Couldn't stop app", x);
} }
descriptors.remove(appName); ApplicationManager.this.descriptors.remove(this.appName);
applications.remove(appName); ApplicationManager.this.applications.remove(this.appName);
} }
void bind() { void bind() {
@ -471,21 +468,21 @@ public class ApplicationManager implements XmlRpcHandler {
getLogger().info("Binding application " + appName + " :: " + app.hashCode() + " :: " + this.hashCode()); getLogger().info("Binding application " + appName + " :: " + app.hashCode() + " :: " + this.hashCode());
// set application URL prefix if it isn't set in app.properties // set application URL prefix if it isn't set in app.properties
if (!app.hasExplicitBaseURI()) { if (!this.app.hasExplicitBaseURI()) {
app.setBaseURI(mountpoint); this.app.setBaseURI(this.mountpoint);
} }
// bind to Jetty HTTP server // bind to Jetty HTTP server
if (jetty != null) { if (ApplicationManager.this.jetty != null) {
if (context == null) { if(ApplicationManager.this.context == null) {
context = new ContextHandlerCollection(); ApplicationManager.this.context = new ContextHandlerCollection();
jetty.getHttpServer().setHandler(context); ApplicationManager.this.jetty.getHttpServer().setHandler(ApplicationManager.this.context);
} }
// if there is a static direcory specified, mount it // if there is a static direcory specified, mount it
if (staticDir != null) { if (this.staticDir != null) {
File staticContent = getAbsoluteFile(staticDir); File staticContent = getAbsoluteFile(this.staticDir);
getLogger().info("Serving static from " + staticContent.getPath()); getLogger().info("Serving static from " + staticContent.getPath());
getLogger().info("Mounting static at " + staticMountpoint); getLogger().info("Mounting static at " + staticMountpoint);
@ -494,58 +491,60 @@ public class ApplicationManager implements XmlRpcHandler {
rhandler.setResourceBase(staticContent.getPath()); rhandler.setResourceBase(staticContent.getPath());
rhandler.setWelcomeFiles(staticHome); rhandler.setWelcomeFiles(staticHome);
staticContext = context.addContext(staticMountpoint, ""); staticContext = ApplicationManager.this.context.addContext(staticMountpoint, ""); //$NON-NLS-1$
staticContext.setHandler(rhandler); staticContext.setHandler(rhandler);
staticContext.start(); staticContext.start();
} }
appContext = new ServletContextHandler(context, pathPattern, true, true); appContext = new ServletContextHandler(context, pathPattern);
Class servletClass = servletClassName == null ? Class servletClass = servletClassName == null ?
EmbeddedServletClient.class : Class.forName(servletClassName); EmbeddedServletClient.class : Class.forName(servletClassName);
ServletHolder holder = new ServletHolder(servletClass); ServletHolder holder = new ServletHolder(servletClass);
holder.setInitParameter("application", appName); appContext.addServlet(holder, "/*"); //$NON-NLS-1$
appContext.addServlet(holder, "/*");
if (cookieDomain != null) { holder.setInitParameter("application", appName); //$NON-NLS-1$
holder.setInitParameter("cookieDomain", cookieDomain);
if (this.cookieDomain != null) {
holder.setInitParameter("cookieDomain", this.cookieDomain); //$NON-NLS-1$
} }
if (sessionCookieName != null) { if (this.sessionCookieName != null) {
holder.setInitParameter("sessionCookieName", sessionCookieName); holder.setInitParameter("sessionCookieName", this.sessionCookieName); //$NON-NLS-1$
} }
if (protectedSessionCookie != null) { if (this.protectedSessionCookie != null) {
holder.setInitParameter("protectedSessionCookie", protectedSessionCookie); holder.setInitParameter("protectedSessionCookie", this.protectedSessionCookie); //$NON-NLS-1$
} }
if (uploadLimit != null) { if (this.uploadLimit != null) {
holder.setInitParameter("uploadLimit", uploadLimit); holder.setInitParameter("uploadLimit", this.uploadLimit); //$NON-NLS-1$
} }
if (uploadSoftfail != null) { if (this.uploadSoftfail != null) {
holder.setInitParameter("uploadSoftfail", uploadSoftfail); holder.setInitParameter("uploadSoftfail", this.uploadSoftfail); //$NON-NLS-1$
} }
if (debug != null) { if (this.debug != null) {
holder.setInitParameter("debug", debug); holder.setInitParameter("debug", this.debug); //$NON-NLS-1$
} }
if (protectedStaticDir != null) { if (this.protectedStaticDir != null) {
File protectedContent = getAbsoluteFile(protectedStaticDir); File protectedContent = getAbsoluteFile(this.protectedStaticDir);
appContext.setResourceBase(protectedContent.getPath()); this.appContext.setResourceBase(protectedContent.getPath());
getLogger().info("Serving protected static from " + getLogger().info("Serving protected static from " +
protectedContent.getPath()); protectedContent.getPath());
} }
// Remap the context paths and start // Remap the context paths and start
context.mapContexts(); ApplicationManager.this.context.mapContexts();
appContext.start(); this.appContext.start();
} }
// register as XML-RPC handler // register as XML-RPC handler
xmlrpcHandlerName = app.getXmlRpcHandlerName(); this.xmlrpcHandlerName = this.app.getXmlRpcHandlerName();
xmlrpcHandlers.put(xmlrpcHandlerName, app); ApplicationManager.this.xmlrpcHandlers.put(this.xmlrpcHandlerName, this.app);
} catch (Exception x) { } catch (Exception x) {
getLogger().error("Couldn't bind app", x); getLogger().error("Couldn't bind app", x);
x.printStackTrace(); x.printStackTrace();
@ -557,26 +556,26 @@ public class ApplicationManager implements XmlRpcHandler {
try { try {
// unbind from Jetty HTTP server // unbind from Jetty HTTP server
if (jetty != null) { if (ApplicationManager.this.jetty != null) {
if (appContext != null) { if (this.appContext != null) {
context.removeHandler(appContext); ApplicationManager.this.context.removeHandler(this.appContext);
appContext.stop(); this.appContext.stop();
appContext.destroy(); this.appContext.destroy();
appContext = null; this.appContext = null;
} }
if (staticContext != null) { if (this.staticContext != null) {
context.removeHandler(staticContext); ApplicationManager.this.context.removeHandler(this.staticContext);
staticContext.stop(); this.staticContext.stop();
staticContext.destroy(); this.staticContext.destroy();
staticContext = null; this.staticContext = null;
} }
context.mapContexts(); ApplicationManager.this.context.mapContexts();
} }
// unregister as XML-RPC handler // unregister as XML-RPC handler
if (xmlrpcHandlerName != null) { if (this.xmlrpcHandlerName != null) {
xmlrpcHandlers.remove(xmlrpcHandlerName); ApplicationManager.this.xmlrpcHandlers.remove(this.xmlrpcHandlerName);
} }
} catch (Exception x) { } catch (Exception x) {
getLogger().error("Couldn't unbind app", x); getLogger().error("Couldn't unbind app", x);
@ -584,8 +583,9 @@ public class ApplicationManager implements XmlRpcHandler {
} }
@Override
public String toString() { public String toString() {
return "[AppDescriptor "+app+"]"; return "[AppDescriptor "+this.app+"]"; //$NON-NLS-1$ //$NON-NLS-2$
} }
} }
} }

View file

@ -0,0 +1,73 @@
/*
* Helma License Notice
*
* The contents of this file are subject to the Helma License
* Version 2.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://adele.helma.org/download/helma/license.txt
*
* Copyright 2017 Daniel Ruthardt. All rights reserved.
*/
package helma.scripting.rhino;
import java.net.URI;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.commonjs.module.ModuleScript;
import org.mozilla.javascript.commonjs.module.provider.ModuleSourceProvider;
import org.mozilla.javascript.commonjs.module.provider.StrongCachingModuleScriptProvider;
/**
* Provides module scripts without compiling, should compiling not be possible for whatever reason.
* The main reason being targeted though, is the "generated bytecode for method exceeds 64K limit" issue.
*/
public class CompiledOrInterpretedModuleScriptProvider extends StrongCachingModuleScriptProvider {
/**
* Define the serialization UID.
*/
private static final long serialVersionUID = 1170789670529274963L;
/**
* Delegates to the super constructor.
*/
public CompiledOrInterpretedModuleScriptProvider(ModuleSourceProvider moduleSourceProvider) {
// do what would have been done anyways
super(moduleSourceProvider);
}
@Override
public ModuleScript getModuleScript(Context cx, String moduleId, URI moduleUri, URI baseUri, Scriptable paths) throws Exception {
try {
// try to load the module script with whatever optimization level is set for the application
return super.getModuleScript(cx, moduleId, moduleUri, baseUri, paths);
} catch (EvaluatorException ignore) {
// unlikely, but possible exception during loading the module script without compilation
Exception exception;
// get the application's optimization level
int optimizationLevel = cx.getOptimizationLevel();
try {
// set the optimization level to not compile, but interpret
cx.setOptimizationLevel(-1);
// load the module script with the newly set optimization level
ModuleScript moduleScript = super.getModuleScript(cx, moduleId, moduleUri, baseUri, paths);
// return the module script
return moduleScript;
} catch (Exception e) {
// remember the exception
exception = e;
} finally {
// re-set the optimization
cx.setOptimizationLevel(optimizationLevel);
}
// re-throw the exception catched when trying to load the module script without compilation
throw exception;
}
}
}

View file

@ -0,0 +1,35 @@
package helma.scripting.rhino;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import org.apache.commons.io.IOUtils;
import org.mozilla.javascript.commonjs.module.provider.ModuleSource;
public class JSONModuleSource extends ModuleSource {
private static final long serialVersionUID = 4446798833357540398L;
public JSONModuleSource(Object securityDomain, URI uri, URI base, Object validator) {
super(null, securityDomain, uri, base, validator);
}
@Override
public Reader getReader() {
StringBuffer content = new StringBuffer();
content.append("module.exports = "); //$NON-NLS-1$
try {
content.append(IOUtils.toString(this.getUri().toURL().openStream()));
} catch (IOException e) {
content.append("null"); //$NON-NLS-1$
}
content.append(";"); //$NON-NLS-1$
return new StringReader(content.toString());
}
}

View file

@ -0,0 +1,212 @@
/*
* Helma License Notice
*
* The contents of this file are subject to the Helma License
* Version 2.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://adele.helma.org/download/helma/license.txt
*
* Copyright 2017 Daniel Ruthardt. All rights reserved.
*/
package helma.scripting.rhino;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import org.apache.commons.io.FilenameUtils;
import org.mozilla.javascript.commonjs.module.provider.ModuleSource;
import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
/**
* Bridges the gap between CommonJS-style module loading and Node.js-style module loading.
*/
public class NodeModulesProvider extends UrlModuleSourceProvider {
/**
* Define the serialization UID.
*/
private static final long serialVersionUID = 6858072487233136717L;
/**
* Delegates to the super constructor.
*/
public NodeModulesProvider(Iterable<URI> privilegedUris, Iterable<URI> fallbackUris) {
// do what would have been done anyways
super(privilegedUris, fallbackUris);
}
/**
* Do what Node.js's LOAD_AS_FILE(X) would do.
* Case 4 ("If X.node is a file, load X.node as binary addon. STOP") is currently not supported (for
* quite obvious reasons). We might want to load JAR files in the future.
*
* @see https://nodejs.org/dist/latest-v9.x/docs/api/modules.html#modules_file_modules
*
* @param uri
* The file to load. FILE, FILE.js and FILE.json will be tried in this order.
* @param base
* Not used, only forwarded to
* {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
* @param validator
* Not used, only forwarded to
* {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
* @return
* The module source or null, if the module was not found.
*
* @throws IOException
* See {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
* @throws URISyntaxException
* See {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
*/
private ModuleSource loadAsFile(URI uri, URI base, Object validator)
throws IOException, URISyntaxException {
// lets assume the module is a file
File file = new File(uri);
// check if the file exists and is a file
if (file.exists() && file.isFile()) {
// check if the file is a JSON file
if (file.getAbsolutePath().toLowerCase().endsWith(".json")) { //$NON-NLS-1$
// return a JSON module source
return new JSONModuleSource(null, file.toURI(), base, validator);
} else {
// do what would have been done anyways
return super.loadFromUri(uri, base, validator);
}
}
// lets assume the module is a JS file
file = new File(new File(uri).getPath() + ".js"); //$NON-NLS-1$
// check if a file.js exists and is a file
if (file.exists() && file.isFile()) {
// do what would have been done anyways
return super.loadFromUri(uri, base, validator);
}
// lets assume the module is a JSON file
file = new File(new File(uri).getPath() + ".json"); //$NON-NLS-1$
// check if a file.json exists and is a file
if (file.exists() && file.isFile()) {
// return a JSON module source
return new JSONModuleSource(null, file.toURI(), base, validator);
}
// module not found
return null;
}
/**
* Do what Node.js's LOAD_AS_DIRECTORY(X) would do.
*
* @see https://nodejs.org/dist/latest-v9.x/docs/api/modules.html#modules_file_modules
*
* @param uri
* The directory to load.
* @param base
* Not used, only forwarded to
* {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
* @param validator
* Not used, only forwarded to
* {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
* @return
* The module source or null, if the module was not found.
*
* @throws JsonSyntaxException
* Thrown for problems accessing the module's "package.json" file.
* @throws IOException
* See {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
* @throws URISyntaxException
* See {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}.
*/
private ModuleSource loadAsDirectory(URI uri, URI base, Object validator)
throws JsonSyntaxException, IOException, URISyntaxException {
// lets assume the module is a directory
File directory = new File(uri);
// check if the directory exists and is a directory
if (directory.exists() && directory.isDirectory()) {
// the module source
ModuleSource moduleSource;
// lets assume that there is a "package.json" file in the directory
File packageFile = new File(directory, "package.json"); //$NON-NLS-1$
// check if the there is a "package.json" file in the directory
if (packageFile.exists() && packageFile.isFile()) {
// parse the JSON file
JsonObject json = new JsonParser()
.parse(new String(Files.readAllBytes(packageFile.toPath()))).getAsJsonObject();
// check if the JSON file defines a main JS file
if (json.has("main")) { //$NON-NLS-1$
// get the main JS file, removing the filename extension
String main = FilenameUtils.removeExtension(json.get("main").getAsString()); //$NON-NLS-1$
// load as file
moduleSource = this.loadAsFile(new File(directory, main).toURI(), base, validator);
// check if something was loaded
if (moduleSource != null) {
// return the loaded module source
return moduleSource;
}
}
}
// load as index
moduleSource = this.loadAsFile(new File(directory, "index").toURI(), base, validator); //$NON-NLS-1$
// check if something was loaded
if (moduleSource != null) {
// return the loaded module source
return moduleSource;
}
}
// module not found
return null;
}
/**
* Do what Node.js's require(X) would do.
*
* Case 1 is not supported, you will have to use modules from npmjs.org, re-implementing the core
* core module's functionality. We might want to use Nodeschnaps in the future.
* Case 2 is not supported, paths are always treated as relative paths within the application's
* "commonjs" directory.
* Case 5 additionally tries {@link UrlModuleSourceProvider#loadSource(URI, URI, Object)}, even if it is
* very unlikely that something, which hasn't been tried yet, will be done. One could say we are just
* delegating throwing the error.
*
* @see https://nodejs.org/dist/latest-v9.x/docs/api/modules.html#modules_file_modules
* @see https://github.com/killmag10/nodeschnaps
*/
protected ModuleSource loadFromUri(URI uri, URI base, Object validator)
throws IOException, URISyntaxException {
// the module source
ModuleSource moduleSource;
// load as file
moduleSource = this.loadAsFile(uri, base, validator);
// check if something was loaded
if (moduleSource != null) {
// return the loaded module source
return moduleSource;
}
// load as directory
moduleSource = this.loadAsDirectory(uri, base, validator);
// check if something was loaded
if (moduleSource != null) {
// return the loaded module source
return moduleSource;
}
// do what would have been done anyways
return super.loadFromUri(uri, base, validator);
}
}

View file

@ -44,7 +44,7 @@ import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.WrapFactory; import org.mozilla.javascript.WrapFactory;
import org.mozilla.javascript.Wrapper; import org.mozilla.javascript.Wrapper;
import org.mozilla.javascript.commonjs.module.RequireBuilder; import org.mozilla.javascript.commonjs.module.RequireBuilder;
import org.mozilla.javascript.commonjs.module.provider.*; import org.mozilla.javascript.commonjs.module.provider.StrongCachingModuleScriptProvider;
import org.mozilla.javascript.tools.debugger.ScopeProvider; import org.mozilla.javascript.tools.debugger.ScopeProvider;
import java.io.*; import java.io.*;
@ -175,9 +175,11 @@ public final class RhinoCore implements ScopeProvider {
} }
} }
// install the global require() function using our custom modules provider, so that
// CommonJS-style as well as NodeJS-style modules can be required
new RequireBuilder() new RequireBuilder()
.setModuleScriptProvider(new StrongCachingModuleScriptProvider( .setModuleScriptProvider(new CompiledOrInterpretedModuleScriptProvider(
new UrlModuleSourceProvider(commonJsPaths, null))) new NodeModulesProvider(commonJsPaths, null)))
.setSandboxed(true) .setSandboxed(true)
.createRequire(context, global) .createRequire(context, global)
.install(global); .install(global);