Jetty embedding revisited

This commit is contained in:
Claude Brisson
2023-05-12 14:21:41 +02:00
parent adca33ee26
commit a28f623eee
45 changed files with 911 additions and 470 deletions

31
bootstrap/pom.xml Normal file
View File

@@ -0,0 +1,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jeudego.pairgoth</groupId>
<artifactId>engine-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>bootstrap</artifactId>
<packaging>jar</packaging>
<description>Simple Bootstrap for the Server UberJar (when packaged in a WAR)</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<mainClass>jetty.bootstrap.JettyBootstrap</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,55 @@
//
// ========================================================================
// Copyright (c) Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package jetty.bootstrap;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
public class JettyBootstrap
{
public static void main(String[] args)
{
try
{
URL warLocation = JettyBootstrap.class.getProtectionDomain().getCodeSource().getLocation();
if (warLocation == null)
{
throw new IOException("JettyBootstrap not discoverable");
}
LiveWarClassLoader clWar = new LiveWarClassLoader(warLocation);
System.err.println("Using ClassLoader: " + clWar);
Thread.currentThread().setContextClassLoader(clWar);
File warFile = new File(warLocation.toURI());
System.setProperty("org.eclipse.jetty.livewar.LOCATION",warFile.toPath().toRealPath().toString());
Class<?> mainClass = Class.forName("org.jeudego.pairgoth.container.ServerMain",false,clWar);
Method mainMethod = mainClass.getMethod("main",args.getClass());
mainMethod.invoke(mainClass,new Object[] { args });
}
catch (Throwable t)
{
t.printStackTrace(System.err);
System.exit(-1);
}
}
}

View File

@@ -0,0 +1,171 @@
//
// ========================================================================
// Copyright (c) Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package jetty.bootstrap;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
public class LiveWarClassLoader extends ClassLoader implements Closeable
{
private static final String ID = LiveWarClassLoader.class.getSimpleName();
private static final boolean DEBUG = Boolean.getBoolean("jetty.bootstrap.debug");
private static final String CLASSES_BASE = "WEB-INF/jetty-server/";
private final URI warFileUri;
private JarFile warFile;
public LiveWarClassLoader(URL warFileUrl) throws URISyntaxException, IOException
{
this.warFileUri = warFileUrl.toURI();
this.warFile = new JarFile(new File(warFileUri));
}
public void close() throws IOException
{
warFile.close();
}
private void debug(String format, Object... args)
{
if (DEBUG)
{
System.err.printf('[' + ID + "] " + format + "%n",args);
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
debug("findClass: %s",name);
String path = name.replace('.','/').concat(".class");
ZipEntry entry = findEntry(path);
if (entry != null)
{
try
{
return loadClass(name,entry);
}
catch (IOException e)
{
throw new ClassNotFoundException(name,e);
}
}
else
{
throw new ClassNotFoundException(name);
}
}
private ZipEntry findEntry(String name)
{
StringBuilder path = new StringBuilder();
path.append(CLASSES_BASE);
if (name.charAt(0) == '/')
{
path.append(name.substring(1));
}
else
{
path.append(name);
}
ZipEntry entry = warFile.getEntry(path.toString());
debug("findEntry(%s) %s => %s",name,path,entry);
return entry;
}
@Override
protected URL findResource(String name)
{
debug("findResource: %s",name);
ZipEntry entry = findEntry(name);
if (entry != null)
{
try
{
return URI.create("jar:" + this.warFileUri.toASCIIString() + "!/" + entry.getName()).toURL();
}
catch (MalformedURLException e)
{
e.printStackTrace(System.err);
return null;
}
}
return null;
}
@Override
protected Enumeration<URL> findResources(String name) throws IOException
{
debug("findResources: %s",name);
List<URL> urls = new ArrayList<>();
URL self = findResource(name);
if (self != null)
{
urls.add(self);
}
if (getParent() != null)
{
Enumeration<URL> parent = getParent().getResources(name);
while (parent.hasMoreElements())
{
urls.add(parent.nextElement());
}
}
return Collections.enumeration(urls);
}
private Class<?> loadClass(String name, ZipEntry entry) throws IOException
{
try (InputStream in = warFile.getInputStream(entry); ByteArrayOutputStream out = new ByteArrayOutputStream())
{
int len = 0;
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (true)
{
len = in.read(buffer,0,bufferSize);
if (len < 0)
break;
out.write(buffer,0,len);
}
byte[] classBytes = out.toByteArray();
return defineClass(name,classBytes,0,classBytes.length);
}
}
@Override
public String toString()
{
return String.format("%s[%s]",this.getClass().getName(),this.warFileUri);
}
}