
io.muserver.handlers.ResourceHandlerBuilder Maven / Gradle / Ivy
Show all versions of mu-server Show documentation
package io.muserver.handlers;
import io.muserver.MuHandlerBuilder;
import io.muserver.rest.RestHandlerBuilder;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Scanner;
import static io.muserver.handlers.ResourceType.DEFAULT_EXTENSION_MAPPINGS;
/**
* Used to create a {@link ResourceHandler} for serving static files.
* In order to serve from the filesystem during development, and from classpath and deploy time, see
* {@link #fileOrClasspath(String, String)}
*/
public class ResourceHandlerBuilder implements MuHandlerBuilder {
private DateTimeFormatter directoryListingDateFormatter;
private Map extensionToResourceType = DEFAULT_EXTENSION_MAPPINGS;
private String defaultFile = "index.html";
private ResourceProviderFactory resourceProviderFactory;
private boolean directoryListingEnabled = false;
private String directoryListingCss = null;
private ResourceCustomizer resourceCustomizer = null;
private BareDirectoryRequestAction bareDirectoryRequestAction = BareDirectoryRequestAction.REDIRECT_WITH_TRAILING_SLASH;
/**
* Specify custom filename extension to mime-type mappings. By default {@link ResourceType#DEFAULT_EXTENSION_MAPPINGS}
* are used.
* @param extensionToResourceType The mappings to use.
* @return This builder
*/
public ResourceHandlerBuilder withExtensionToResourceType(Map extensionToResourceType) {
this.extensionToResourceType = extensionToResourceType;
return this;
}
/**
* Specifies the file to use when a request such as /web/
is made. Defaults to index.html
* @param defaultFile The default file to use when a directory is requested, or null
for no default.
* @return This builder
*/
public ResourceHandlerBuilder withDefaultFile(String defaultFile) {
this.defaultFile = defaultFile;
return this;
}
ResourceHandlerBuilder withResourceProviderFactory(ResourceProviderFactory resourceProviderFactory) {
this.resourceProviderFactory = resourceProviderFactory;
return this;
}
/**
* Specifies whether or not to allow directory listing. This is disabled by default.
* Note that directory listings will not show if there is a file in the directory
* that matches the {@link #withDefaultFile(String)} setting. Set that to null
* if you do not want the default file (e.g. index.html
) to display.
* @param enabled true
to turn it on; false
to disable it.
* @return This builder
*/
public ResourceHandlerBuilder withDirectoryListing(boolean enabled) {
this.directoryListingEnabled = enabled;
return this;
}
/**
* Specifies a custom date format for the "Last modified" column when directory listing is enabled.
* @param dateTimeFormatter A format object, or null to use the default
* @return This builder
*/
public ResourceHandlerBuilder withDirectoryListingDateFormatter(DateTimeFormatter dateTimeFormatter) {
this.directoryListingDateFormatter = dateTimeFormatter;
return this;
}
/**
* Specifies CSS to use for the HTML directory listing page, if directory listing is enabled.
* @param css CSS styles to use, or null for the default
* @return This builder
*/
public ResourceHandlerBuilder withDirectoryListingCSS(String css) {
this.directoryListingCss = css;
return this;
}
/**
* Registers a hook to intercept responses, allowing things such as response header customization based on the request.
* @param resourceCustomizer A class to intercept responses
* @return This builder
*/
public ResourceHandlerBuilder withResourceCustomizer(ResourceCustomizer resourceCustomizer) {
this.resourceCustomizer = resourceCustomizer;
return this;
}
/**
* @return The current value of this property
*/
public DateTimeFormatter directoryListingDateFormatter() {
return directoryListingDateFormatter;
}
/**
* @return The current value of this property
*/
public Map extensionToResourceType() {
return Collections.unmodifiableMap(extensionToResourceType);
}
/**
* @return The current value of this property
*/
public String defaultFile() {
return defaultFile;
}
/**
* @return The current value of this property
*/
public boolean directoryListingEnabled() {
return directoryListingEnabled;
}
/**
* @return The current value of this property
*/
public String directoryListingCss() {
return directoryListingCss;
}
/**
* @return The current value of this property
*/
public ResourceCustomizer resourceCustomizer() {
return resourceCustomizer;
}
/**
* @return The action to take when a directory is requested without a trailing slash
*/
public BareDirectoryRequestAction bareDirectoryRequestAction() {
return bareDirectoryRequestAction;
}
/**
* Specifies the action to take when a directory is requested without a trailing slash.
*
* The default is {@link BareDirectoryRequestAction#REDIRECT_WITH_TRAILING_SLASH} which means a request
* to /{dirname}
will be redirected to /{dirname}/
* @param action The action to take
* @return this builder
*/
public ResourceHandlerBuilder withBareDirectoryRequestAction(BareDirectoryRequestAction action) {
if (action == null) {
throw new IllegalArgumentException("BareDirectoryRequestAction cannot be null");
}
this.bareDirectoryRequestAction = action;
return this;
}
/**
* Creates the handler
* @return The built handler
*/
public ResourceHandler build() {
if (resourceProviderFactory == null) {
throw new IllegalStateException("No resourceProviderFactory has been set");
}
String css = this.directoryListingCss;
if (directoryListingEnabled && css == null) {
InputStream cssStream = RestHandlerBuilder.class.getResourceAsStream("/io/muserver/resources/api.css");
Scanner scanner = new Scanner(cssStream, "UTF-8").useDelimiter("\\A");
css = scanner.next();
scanner.close();
}
DateTimeFormatter formatterToUse = this.directoryListingDateFormatter;
if (directoryListingEnabled && formatterToUse == null) {
formatterToUse = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss")
.withLocale(Locale.US)
.withZone(ZoneId.systemDefault());
}
return new ResourceHandler(resourceProviderFactory, defaultFile, extensionToResourceType, directoryListingEnabled, css, formatterToUse, this.resourceCustomizer, this.bareDirectoryRequestAction);
}
/**
* Creates a handler that serves files from the given directory.
* @param directoryPath The directory.
* @return A new builder.
*/
public static ResourceHandlerBuilder fileHandler(String directoryPath) {
return fileHandler(Paths.get(directoryPath));
}
/**
* Creates a handler that serves files from the given directory.
* @param baseDirectory The directory.
* @return A new builder.
*/
public static ResourceHandlerBuilder fileHandler(File baseDirectory) {
return fileHandler(baseDirectory.toPath());
}
/**
* Creates a handler that serves files from the given directory.
* @param path The directory.
* @return A new builder.
*/
public static ResourceHandlerBuilder fileHandler(Path path) {
return new ResourceHandlerBuilder().withResourceProviderFactory(ResourceProviderFactory.fileBased(path));
}
/**
* Creates a handler that serves files from the classpath..
* @param classpathRoot A classpath directory, such as /web
* @return A new builder.
*/
public static ResourceHandlerBuilder classpathHandler(String classpathRoot) {
return new ResourceHandlerBuilder().withResourceProviderFactory(ResourceProviderFactory.classpathBased(classpathRoot));
}
/**
* Creates a resource handler that serves from the file system if the directory exists; otherwise from the class path.
*
* A common use case is for when you want to serve from the file path at development time (so you can update
* files without restarting) but at deploy time resources are packaged in an uber jar.
* @param fileRootIfExists A path to a directory holding static content, which may not exist, e.g. src/main/resources/web
* @param classpathRoot A classpath path to a directory holding static content, e.g. /web
* @return Returns a file-based resource handler builder or a classpath-based one.
*/
public static ResourceHandlerBuilder fileOrClasspath(String fileRootIfExists, String classpathRoot) {
Path path = Paths.get(fileRootIfExists);
if (Files.isDirectory(path)) {
return fileHandler(path);
} else {
return classpathHandler(classpathRoot);
}
}
}