Skip to content
This repository has been archived by the owner on Jun 7, 2021. It is now read-only.

Commit

Permalink
Delegate all static resource handling to Undertow itself
Browse files Browse the repository at this point in the history
For hot reloading of changes during development, we now write out a
WEB-INF/undertow-external-mounts.conf. A side-effect of this is that
static content is now always served out of the same context as your
application. If static content needs to be served at a different
context than your application then that static content needs to reside
in a subdirectory of src/main/resources or src/main/webapp.
  • Loading branch information
bbrowning committed Nov 18, 2015
1 parent a24dadc commit 700a809
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 665 deletions.
1 change: 0 additions & 1 deletion integration-tests/src/main/resources/faildex.html

This file was deleted.

Expand Up @@ -12,8 +12,6 @@ default void assertBasicStaticContentWorks(String context) throws Exception {
// Ensure index files are used
assertContains(context, "This is index.html.");
assertContains(context + "foo", "This is foo/index.html.");
// Ensure content under src/main/resources is NOT served up
assertNotFound(context + "faildex.html");
// Ensure we don't serve up Java class files
assertNotFound(context + "java/lang/Object.class");
// And doubly ensure we don't serve up application class files
Expand Down
Expand Up @@ -66,6 +66,21 @@ public void testStaticContentWithContext() throws Exception {
}
}

@Test
public void testStaticContentWithBase() throws Exception {
Container container = newContainer();
container.start();
try {
WARArchive deployment = ShrinkWrap.create(WARArchive.class);
deployment.staticContent("foo");
container.deploy(deployment);
assertContains("", "This is foo/index.html.");
assertContains("index.html", "This is foo/index.html.");
} finally {
container.stop();
}
}

private void assertFileChangesReflected(String context) throws Exception {
if (context.length() > 0 && !context.endsWith("/")) {
context = context + "/";
Expand Down
@@ -0,0 +1,57 @@
package org.wildfly.swarm.integration.staticcontent.war;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import org.wildfly.swarm.arquillian.adapter.ArtifactDependencies;
import org.wildfly.swarm.undertow.WARArchive;

import java.net.URL;
import java.util.Arrays;
import java.util.List;

import static org.fest.assertions.Assertions.assertThat;

@RunWith(Arquillian.class)
public class StaticContentWarSubdirTest {
@ArquillianResource
URL contextRoot;

@Drone
WebDriver browser;

@Deployment
public static Archive createDeployment() throws Exception {
WARArchive deployment = ShrinkWrap.create(WARArchive.class);
deployment.staticContent("foo");
// Make sure we're testing from contents inside the jar only
deployment.delete("WEB-INF/undertow-external-mounts.conf");
return deployment;
}

@ArtifactDependencies
public static List<String> appDependencies() {
return Arrays.asList(
"org.wildfly.swarm:wildfly-swarm-undertow"
);
}

@RunAsClient
@Test
public void testStaticContent() throws Exception {
assertContains("", "This is foo/index.html.");
assertContains("index.html", "This is foo/index.html.");
}

public void assertContains(String path, String content) throws Exception {
browser.navigate().to(contextRoot + path);
assertThat(browser.getPageSource()).contains(content);
}
}
Expand Up @@ -47,14 +47,17 @@ public String getType() {

@Override
public Archive create(Container container) throws Exception {
return archiveFromCurrentApp();
}

public static WARArchive archiveFromCurrentApp() throws Exception {
WARArchive archive = ShrinkWrap.create(WARArchive.class, determineName());
setup( archive );
setup(archive);
archive.addModule("org.wildfly.swarm.undertow", "runtime");
archive.addAsServiceProvider("io.undertow.server.handlers.builder.HandlerBuilder", "org.wildfly.swarm.undertow.runtime.StaticHandlerBuilder");
return archive;
}

protected String determineName() {
protected static String determineName() {
String prop = System.getProperty( "wildfly.swarm.app.path" );
if ( prop != null ) {
File file = new File( prop );
Expand All @@ -73,11 +76,11 @@ protected String determineName() {
return UUID.randomUUID().toString() + ".war";
}

protected void setup(DependenciesContainer<?> archive) throws Exception {
protected static void setup(DependenciesContainer<?> archive) throws Exception {
boolean result = setupUsingAppPath(archive) || setupUsingAppArtifact(archive) || setupUsingMaven(archive);
}

protected boolean setupUsingAppPath(DependenciesContainer<?> archive) throws IOException {
protected static boolean setupUsingAppPath(DependenciesContainer<?> archive) throws IOException {
String appPath = System.getProperty("wildfly.swarm.app.path");

if (appPath != null) {
Expand All @@ -101,7 +104,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
return false;
}

protected boolean setupUsingAppArtifact(DependenciesContainer<?> archive) throws IOException {
protected static boolean setupUsingAppArtifact(DependenciesContainer<?> archive) throws IOException {
String appArtifact = System.getProperty("wildfly.swarm.app.artifact");

if (appArtifact != null) {
Expand All @@ -115,7 +118,7 @@ protected boolean setupUsingAppArtifact(DependenciesContainer<?> archive) throws
return false;
}

protected boolean setupUsingMaven(DependenciesContainer<?> archive) throws Exception {
protected static boolean setupUsingMaven(DependenciesContainer<?> archive) throws Exception {
Path pwd = Paths.get(System.getProperty("user.dir"));

final Path classes = pwd.resolve("target").resolve("classes");
Expand Down Expand Up @@ -153,7 +156,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
return success;
}

protected String convertSeparators(Path path) {
protected static String convertSeparators(Path path) {
String convertedPath = path.toString();

if (convertedPath.contains(File.separator)) {
Expand Down
Expand Up @@ -16,50 +16,101 @@
package org.wildfly.swarm.undertow;

import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ArchivePath;
import org.jboss.shrinkwrap.api.Filter;
import org.jboss.shrinkwrap.api.Filters;
import org.jboss.shrinkwrap.api.Node;
import org.jboss.shrinkwrap.api.importer.ExplodedImporter;
import org.jboss.shrinkwrap.impl.base.Validate;
import org.jboss.shrinkwrap.impl.base.path.BasicPath;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* @author Bob McWhirter
*/
public interface StaticContentContainer<T extends Archive<T>> extends Archive<T> {

default T staticContent() {
return staticContent( "/", "." );
}
Logger log = Logger.getLogger(StaticContentContainer.class.getName());

default T staticContent(String context) {
return staticContent( context, "." );
default T staticContent() {
return staticContent("");
}

default T staticContent(String context, String base) {
default T staticContent(String base) {
as(WARArchive.class).addModule("org.wildfly.swarm.undertow", "runtime");
as(WARArchive.class).addAsServiceProvider("io.undertow.server.handlers.builder.HandlerBuilder", "org.wildfly.swarm.undertow.runtime.StaticHandlerBuilder");

Node node = as(WARArchive.class).get("WEB-INF/undertow-handlers.conf");
try {
// Add all the static content from the current app to the archive
Archive allResources = DefaultWarDeploymentFactory.archiveFromCurrentApp();
// Here we define static as basically anything that's not a
// Java class file or under WEB-INF or META-INF
mergeIgnoringDuplicates(allResources, base, Filters.exclude(".*\\.class$"));
} catch (Exception ex) {
log.log(Level.WARNING, "Error setting up static resources", ex);
}

UndertowHandlersAsset asset = null;
Node node = get("WEB-INF/undertow-external-mounts.conf");
UndertowExternalMountsAsset asset = null;
if ( node == null ) {
asset = new UndertowHandlersAsset();
as(WARArchive.class).add( asset, "WEB-INF/undertow-handlers.conf" );
asset = new UndertowExternalMountsAsset();
add(asset, "WEB-INF/undertow-external-mounts.conf");
} else {
asset = (UndertowHandlersAsset) node.getAsset();
asset = (UndertowExternalMountsAsset) node.getAsset();
}

asset.staticContent( context, base );

// Add external mounts for static content so changes are picked up
// immediately during development
Path webResources = Paths.get(System.getProperty("user.dir"), "src", "main", "webapp");
if (base != null ) {
webResources = webResources.resolve(base);
}
if (Files.exists(webResources)) {
as(ExplodedImporter.class).importDirectory(webResources.toFile());
asset.externalMount(webResources.toString());
}
webResources = Paths.get(System.getProperty("user.dir"), "src", "main", "resources");
if (base != null ) {
webResources = webResources.resolve(base);
}
if (Files.exists(webResources)) {
asset.externalMount(webResources.toString());
}

return (T) this;
}

default T mergeIgnoringDuplicates(Archive<?> source, String base, Filter<ArchivePath> filter) {
if (!base.startsWith("/")) {
base = "/" + base;
}
// Get existing contents from source archive
final Map<ArchivePath, Node> sourceContent = source.getContent();

// Add each asset from the source archive
for (final Map.Entry<ArchivePath, Node> contentEntry : sourceContent.entrySet()) {
final Node node = contentEntry.getValue();
ArchivePath nodePath = contentEntry.getKey();
if (!nodePath.get().startsWith(base)) {
continue;
}
if (!filter.include(nodePath)) {
continue;
}
if (contains(nodePath)) {
continue;
}
nodePath = new BasicPath(nodePath.get().replaceFirst(base, ""));
// Delegate
if (node.getAsset() == null) {
addAsDirectory(nodePath);
} else {
add(node.getAsset(), nodePath);
}
}
return (T) this;
}
}
@@ -0,0 +1,25 @@
package org.wildfly.swarm.undertow;

import org.jboss.shrinkwrap.api.asset.Asset;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class UndertowExternalMountsAsset implements Asset {
private List<String> externalMounts = new ArrayList<>();

public void externalMount(String path) {
externalMounts.add(path);
}

@Override
public InputStream openStream() {
StringBuilder conf = new StringBuilder();
for (String each : this.externalMounts) {
conf.append(each + "\n");
}
return new ByteArrayInputStream(conf.toString().getBytes());
}
}

This file was deleted.

0 comments on commit 700a809

Please sign in to comment.