Skip to content

Commit

Permalink
Adding org.eclipse.jetty.server.handler.PathMappingsHandler example
Browse files Browse the repository at this point in the history
  • Loading branch information
joakime committed Feb 15, 2024
1 parent 04d79a1 commit c9eb125
Show file tree
Hide file tree
Showing 10 changed files with 404 additions and 0 deletions.
1 change: 1 addition & 0 deletions embedded/path-mapping-handler/extras/extra.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
table { font-family: sans-serif; }
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions embedded/path-mapping-handler/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.examples.embedded</groupId>
<artifactId>jetty-embedded-examples</artifactId>
<version>12.0.x</version>
</parent>
<artifactId>path-mapping-handler</artifactId>
<version>12.0.x</version>
<packaging>jar</packaging>
<name>Jetty Examples :: Jetty 12.0.x :: Embedded :: Path Mapping Handler</name>

<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<version>${jetty.version}</version>
</dependency>

<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.3.2</version>
</dependency>

<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<version>${jetty-test-helper.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package examples;//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

import java.nio.charset.StandardCharsets;

import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;

public class HelloHandler extends Handler.Abstract
{
private final String msg;

public HelloHandler(String msg)
{
this.msg = msg;
}

@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/plain; charset=utf-8");
response.write(true, BufferUtil.toBuffer(String.format("%s%n", msg), StandardCharsets.UTF_8), callback);
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package examples;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.pathmap.PathSpec;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.PathMappingsHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;

public class PathMappingServer
{
public static void main(String[] args) throws Exception
{
Server server = PathMappingServer.newServer(8080);
server.start();
server.join();
}

public static Server newServer(int port) throws IOException
{
Server server = new Server(port);

ResourceFactory resourceFactory = ResourceFactory.of(server);

PathMappingsHandler pathMappingsHandler = new PathMappingsHandler();

Resource rootResourceDir = resourceFactory.newClassLoaderResource("/static-root/");
if (!Resources.isReadableDirectory(rootResourceDir))
throw new FileNotFoundException("Unable to find /static-root/ classloader directory");

ResourceHandler rootResourceHandler = new ResourceHandler();
rootResourceHandler.setBaseResource(rootResourceDir);
rootResourceHandler.setDirAllowed(false);
rootResourceHandler.setWelcomeFiles("index.html");

Path extrasDir = Path.of("extras").toAbsolutePath();
if (!Files.isDirectory(extrasDir))
throw new FileNotFoundException("Unable to find /extras/ directory on disk: " + extrasDir);
if (!Files.isReadable(extrasDir))
throw new FileNotFoundException("Unable to read directory (permissions?): " + extrasDir);

Resource extraResourceDir = resourceFactory.newResource(extrasDir);

ResourceHandler extraResourceHandler = new ResourceHandler();
extraResourceHandler.setBaseResource(extraResourceDir);
extraResourceHandler.setDirAllowed(true);

Resource metaInfResource = findMetaInfResources(resourceFactory, PathMappingServer.class.getClassLoader());

ResourceHandler metaInfResourceHandler = new ResourceHandler();
metaInfResourceHandler.setBaseResource(metaInfResource);
metaInfResourceHandler.setDirAllowed(false);

// The context-path is the portion of the path that doesn't belong to the filename.
// Example:
// You have this setup.
// * You have files you want to serve in "/home/user/webroot/"
// * You have that directory mapped against the path-spec of "/content/*"
//
// Then a request arrives against the path "/content/foo.txt"
// The server will send that request to the mapped location of "/content/*"
// which is your ResourceHandler serving content from "/home/user/webroot/"
// The looked for file will be <base-dir> + "/" + <request-path>
// which turns out to be "/home/user/webroot/content/foo.txt"
//
// The PathNameWrapper below allows you to map the incoming request path
// to a simple path name that the ResourceHandler of your choice can use
// against it's base resource.

pathMappingsHandler.addMapping(PathSpec.from("/"), rootResourceHandler);
pathMappingsHandler.addMapping(PathSpec.from("/extras/*"),
new StripContextPath("/extras", extraResourceHandler));
pathMappingsHandler.addMapping(PathSpec.from("/jars/*"),
new StripContextPath("/jars", metaInfResourceHandler));
// Example of a mapping to an extension.
pathMappingsHandler.addMapping(PathSpec.from("*.png"),
new PathNameWrapper((path) ->
{
int idx = path.lastIndexOf("/");
if (idx >= 0)
return "/images" + path.substring(idx);
return "/images/" + path;
}, extraResourceHandler));
pathMappingsHandler.addMapping(PathSpec.from("/hello/*"), new HelloHandler("Mappings"));

server.setHandler(pathMappingsHandler);
return server;
}

private static Resource findMetaInfResources(ResourceFactory resourceFactory, ClassLoader classLoader) throws IOException
{
List<URL> hits = Collections.list(classLoader.getResources("META-INF/resources"));
List<Resource> resources = new ArrayList<>();
for (URL hit : hits)
{
Resource resource = resourceFactory.newResource(hit);
if (Resources.isReadableDirectory(resource))
resources.add(resource);
}

if (resources.isEmpty())
throw new FileNotFoundException("Classloader Configuration error: No META-INF/resources entries found");

return ResourceFactory.combine(resources);
}

private static class StripContextPath extends PathNameWrapper
{
public StripContextPath(String contextPath, Handler handler)
{
super((path) ->
{
if (path.startsWith(contextPath))
return path.substring(contextPath.length());
return path;
}, handler);
}
}

private static class PathNameWrapper extends Handler.Wrapper
{
private final Function<String, String> nameFunction;

public PathNameWrapper(Function<String, String> nameFunction, Handler handler)
{
super(handler);
this.nameFunction = nameFunction;
}

@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
String originalPath = request.getHttpURI().getPath();

String newPath = nameFunction.apply(originalPath);

HttpURI newURI = HttpURI.build(request.getHttpURI()).path(newPath);

Request wrappedRequest = new Request.Wrapper(request)
{
@Override
public HttpURI getHttpURI()
{
return newURI;
}
};

return super.handle(wrappedRequest, response, callback);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.eclipse.jetty.LEVEL=INFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<title>Hello from /static-root/</title>
</head>
<body>
<h4>Hello from <code>/static-root/</code></h4>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<title>Showing index.html from root</title>
</head>
<body>
<h4>This is the index.html from /static-root/</h4>
</body>
</html>
Loading

0 comments on commit c9eb125

Please sign in to comment.