Skip to content

Commit 472413f

Browse files
authored
Static content update (#6195)
- renamed support to service (as it is an HttpService) - added support for single file static content handler for file system (works on classpath)
1 parent 150c037 commit 472413f

17 files changed

Lines changed: 229 additions & 67 deletions

File tree

examples/nima/media/src/main/java/io/helidon/examples/nima/media/MediaMain.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
2020
import io.helidon.common.http.Http.Header;
2121
import io.helidon.nima.webserver.WebServer;
2222
import io.helidon.nima.webserver.http.HttpRules;
23-
import io.helidon.nima.webserver.staticcontent.StaticContentSupport;
23+
import io.helidon.nima.webserver.staticcontent.StaticContentService;
2424

2525
/**
2626
* This application provides a simple file upload service with a UI to exercise multipart.
@@ -56,7 +56,7 @@ static void routing(HttpRules rules) {
5656
res.header(UI_LOCATION);
5757
res.send();
5858
})
59-
.register("/ui", StaticContentSupport.builder("WEB")
59+
.register("/ui", StaticContentService.builder("WEB")
6060
.welcomeFileName("index.html")
6161
.build())
6262
.register("/api", new FileService());

examples/nima/static-content/src/main/java/io/helidon/examples/nima/staticcontent/StaticContentMain.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
1818

1919
import io.helidon.nima.webserver.WebServer;
2020
import io.helidon.nima.webserver.http.HttpRouting;
21-
import io.helidon.nima.webserver.staticcontent.StaticContentSupport;
21+
import io.helidon.nima.webserver.staticcontent.StaticContentService;
2222

2323
/**
2424
* Static content example.
@@ -45,7 +45,7 @@ public static void main(String[] args) {
4545
static void routing(HttpRouting.Builder routing) {
4646
// register static content on root path of the server
4747
// use classpath /web to look for resources
48-
routing.register("/", StaticContentSupport.builder("web"))
48+
routing.register("/", StaticContentService.builder("web"))
4949
.get("/api/greet", (req, res) -> res.send("Hello World!"));
5050
}
5151
}

microprofile/server/src/main/java/io/helidon/microprofile/server/ServerCdiExtension.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import io.helidon.nima.webserver.context.ContextFeature;
4444
import io.helidon.nima.webserver.http.HttpRouting;
4545
import io.helidon.nima.webserver.http.HttpService;
46-
import io.helidon.nima.webserver.staticcontent.StaticContentSupport;
46+
import io.helidon.nima.webserver.staticcontent.StaticContentService;
4747

4848
import jakarta.annotation.Priority;
4949
import jakarta.enterprise.context.ApplicationScoped;
@@ -421,14 +421,14 @@ private void registerStaticContent() {
421421

422422
private void registerPathStaticContent(Config config) {
423423
Config context = config.get("context");
424-
StaticContentSupport.FileSystemBuilder pBuilder = StaticContentSupport.builder(config.get("location")
424+
StaticContentService.FileSystemBuilder pBuilder = StaticContentService.builder(config.get("location")
425425
.as(Path.class)
426426
.get());
427427
pBuilder.welcomeFileName(config.get("welcome")
428428
.asString()
429429
.orElse("index.html"));
430430

431-
StaticContentSupport staticContent = pBuilder.build();
431+
StaticContentService staticContent = pBuilder.build();
432432

433433
if (context.exists()) {
434434
routingBuilder.register(context.asString().get(), staticContent);
@@ -441,7 +441,7 @@ private void registerPathStaticContent(Config config) {
441441
private void registerClasspathStaticContent(Config config) {
442442
Config context = config.get("context");
443443

444-
StaticContentSupport.ClassPathBuilder cpBuilder = StaticContentSupport.builder(config.get("location").asString().get());
444+
StaticContentService.ClassPathBuilder cpBuilder = StaticContentService.builder(config.get("location").asString().get());
445445
cpBuilder.welcomeFileName(config.get("welcome")
446446
.asString()
447447
.orElse("index.html"));
@@ -455,7 +455,7 @@ private void registerClasspathStaticContent(Config config) {
455455
.flatMap(List::stream)
456456
.forEach(cpBuilder::addCacheInMemory);
457457

458-
StaticContentSupport staticContent = cpBuilder.build();
458+
StaticContentService staticContent = cpBuilder.build();
459459

460460
if (context.exists()) {
461461
routingBuilder.register(context.asString().get(), staticContent);

nima/tests/integration/webserver/static-content/src/test/java/io/helidon/nima/tests/integration/server/staticcontent/StaticContentTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
2222
import io.helidon.nima.webclient.http1.Http1Client;
2323
import io.helidon.nima.webclient.http1.Http1ClientResponse;
2424
import io.helidon.nima.webserver.http.HttpRouting;
25-
import io.helidon.nima.webserver.staticcontent.StaticContentSupport;
25+
import io.helidon.nima.webserver.staticcontent.StaticContentService;
2626

2727
import org.junit.jupiter.api.Test;
2828

@@ -39,7 +39,7 @@ class StaticContentTest {
3939

4040
@SetUpRoute
4141
static void routing(HttpRouting.Builder routing) {
42-
routing.register("/files", StaticContentSupport.builder("static")
42+
routing.register("/files", StaticContentService.builder("static")
4343
.welcomeFileName("welcome.txt")
4444
.build())
4545
.get("/files/default", (req, res) -> res.send("Nexted"));

nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/ClassPathContentHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -61,7 +61,7 @@ class ClassPathContentHandler extends FileBasedContentHandler {
6161
// URL's hash code and equal are not suitable for map or set
6262
private final Map<String, ExtractedJarEntry> extracted = new ConcurrentHashMap<>();
6363

64-
ClassPathContentHandler(StaticContentSupport.ClassPathBuilder builder) {
64+
ClassPathContentHandler(StaticContentService.ClassPathBuilder builder) {
6565
super(builder);
6666

6767
this.classLoader = builder.classLoader();

nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileBasedContentHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2021, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
4343
abstract class FileBasedContentHandler extends StaticContentHandler {
4444
private final Map<String, MediaType> customMediaTypes;
4545

46-
FileBasedContentHandler(StaticContentSupport.FileBasedBuilder<?> builder) {
46+
FileBasedContentHandler(StaticContentService.FileBasedBuilder<?> builder) {
4747
super(builder);
4848

4949
this.customMediaTypes = builder.specificContentTypes();

nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/FileSystemContentHandler.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
1818

1919
import java.io.IOException;
2020
import java.lang.System.Logger.Level;
21-
import java.net.URISyntaxException;
2221
import java.nio.file.Files;
2322
import java.nio.file.Path;
2423
import java.util.HashSet;
@@ -41,7 +40,7 @@ class FileSystemContentHandler extends FileBasedContentHandler {
4140
private final Path root;
4241
private final Set<String> cacheInMemory;
4342

44-
FileSystemContentHandler(StaticContentSupport.FileSystemBuilder builder) {
43+
FileSystemContentHandler(StaticContentService.FileSystemBuilder builder) {
4544
super(builder);
4645

4746
this.root = builder.root().toAbsolutePath().normalize();
@@ -148,7 +147,7 @@ boolean doHandle(Http.Method method,
148147
return handler.handle(handlerCache(), method, req, res, requestedResource);
149148
}
150149

151-
private void addToInMemoryCache(String resource) throws IOException, URISyntaxException {
150+
private void addToInMemoryCache(String resource) throws IOException {
152151
/*
153152
we need to know:
154153
- content size
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (c) 2023 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.helidon.nima.webserver.staticcontent;
18+
19+
import java.io.IOException;
20+
import java.nio.file.Files;
21+
import java.nio.file.Path;
22+
import java.util.Optional;
23+
24+
import io.helidon.common.http.Http;
25+
import io.helidon.common.http.ServerResponseHeaders;
26+
import io.helidon.nima.webserver.http.ServerRequest;
27+
import io.helidon.nima.webserver.http.ServerResponse;
28+
29+
class SingleFileContentHandler extends FileBasedContentHandler {
30+
private static final System.Logger LOGGER = System.getLogger(SingleFileContentHandler.class.getName());
31+
32+
private final boolean cacheInMemory;
33+
private final Path path;
34+
35+
SingleFileContentHandler(FileSystemBuilder builder) {
36+
super(builder);
37+
38+
this.cacheInMemory = builder.cacheInMemory().contains(".") || builder.cacheInMemory().contains("/");
39+
this.path = builder.root().toAbsolutePath().normalize();
40+
}
41+
42+
@Override
43+
public void beforeStart() {
44+
try {
45+
if (cacheInMemory) {
46+
// directly cache in memory
47+
byte[] fileBytes = Files.readAllBytes(path);
48+
cacheInMemory(".", detectType(fileName(path)), fileBytes, lastModified(path));
49+
} else {
50+
// cache a handler that loads it from file system
51+
cacheFileHandler();
52+
}
53+
} catch (IOException e) {
54+
LOGGER.log(System.Logger.Level.WARNING, "Failed to add file to in-memory cache, path: " + path, e);
55+
}
56+
super.beforeStart();
57+
}
58+
59+
@Override
60+
boolean doHandle(Http.Method method, String requestedPath, ServerRequest req, ServerResponse res) throws IOException {
61+
if ("".equals(requestedPath) || "/".equals(requestedPath)) {
62+
Optional<CachedHandler> cachedHandler = cacheHandler(".");
63+
if (cachedHandler.isPresent()) {
64+
return cachedHandler.get().handle(handlerCache(), method, req, res, requestedPath);
65+
}
66+
return doHandle(method, req, res);
67+
}
68+
69+
if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) {
70+
LOGGER.log(System.Logger.Level.DEBUG, "Requested sub-path for a single file static content: " + requestedPath);
71+
}
72+
return false;
73+
}
74+
75+
private boolean doHandle(Http.Method method, ServerRequest req, ServerResponse res) throws IOException {
76+
return cacheFileHandler().handle(handlerCache(), method, req, res, ".");
77+
}
78+
79+
private CachedHandler cacheFileHandler() {
80+
CachedHandler handler = new CachedHandlerPath(path,
81+
detectType(fileName(path)),
82+
FileBasedContentHandler::lastModified,
83+
ServerResponseHeaders::lastModified);
84+
cacheHandler(".", handler);
85+
86+
return handler;
87+
}
88+
}

nima/webserver/static-content/src/main/java/io/helidon/nima/webserver/staticcontent/StaticContentHandler.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@
4848
/**
4949
* Base implementation of static content support.
5050
*/
51-
abstract class StaticContentHandler implements StaticContentSupport {
51+
abstract class StaticContentHandler implements StaticContentService {
5252
private static final System.Logger LOGGER = System.getLogger(StaticContentHandler.class.getName());
5353

5454
private final Map<String, CachedHandlerInMemory> inMemoryCache = new ConcurrentHashMap<>();
@@ -57,7 +57,7 @@ abstract class StaticContentHandler implements StaticContentSupport {
5757
private final Function<String, String> resolvePathFunction;
5858
private final AtomicInteger webServerCounter = new AtomicInteger();
5959

60-
StaticContentHandler(StaticContentSupport.Builder<?> builder) {
60+
StaticContentHandler(StaticContentService.Builder<?> builder) {
6161
this.welcomeFilename = builder.welcomeFileName();
6262
this.resolvePathFunction = builder.resolvePathFunction();
6363
this.handlerCache = builder.handlerCache();

0 commit comments

Comments
 (0)