/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ratpack.groovy;
import com.google.common.collect.ImmutableMap;
import groovy.lang.Closure;
import groovy.lang.DelegatesTo;
import groovy.lang.GroovySystem;
import groovy.xml.MarkupBuilder;
import io.netty.util.CharsetUtil;
import ratpack.api.Nullable;
import ratpack.file.FileSystemBinding;
import ratpack.func.Action;
import ratpack.func.Function;
import ratpack.groovy.handling.*;
import ratpack.groovy.handling.internal.ClosureBackedHandler;
import ratpack.groovy.handling.internal.DefaultGroovyByMethodSpec;
import ratpack.groovy.handling.internal.GroovyDslChainActionTransformer;
import ratpack.groovy.internal.ClosureInvoker;
import ratpack.groovy.internal.ClosureUtil;
import ratpack.groovy.internal.GroovyVersionCheck;
import ratpack.groovy.internal.ScriptBackedHandler;
import ratpack.groovy.internal.capture.*;
import ratpack.groovy.script.ScriptNotFoundException;
import ratpack.groovy.template.Markup;
import ratpack.groovy.template.MarkupTemplate;
import ratpack.groovy.template.TextTemplate;
import ratpack.guice.BindingsSpec;
import ratpack.guice.Guice;
import ratpack.handling.Chain;
import ratpack.handling.Handler;
import ratpack.handling.Handlers;
import ratpack.handling.internal.ChainBuilders;
import ratpack.http.internal.HttpHeaderConstants;
import ratpack.registry.Registry;
import ratpack.server.*;
import ratpack.server.internal.BaseDirFinder;
import ratpack.server.internal.FileBackedReloadInformant;
import ratpack.util.internal.Paths2;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import static ratpack.util.Exceptions.uncheck;
/**
* Static methods for specialized Groovy integration.
*/
public abstract class Groovy {
private Groovy() {
}
/**
* Starts a Ratpack app, defined by the given closure.
* <p>
* This method is used in Ratpack scripts as the entry point.
* <pre class="groovy-ratpack-dsl">
* import ratpack.session.SessionModule
* import static ratpack.groovy.Groovy.*
*
* ratpack {
* bindings {
* // example of registering a module
* add(new SessionModule())
* }
* handlers {
* // define the application handlers
* get("foo") {
* render "bar"
* }
* }
* }
* </pre>
* <h3>Standalone Scripts</h3>
* <p>
* This method can be used by standalone scripts to start a Ratpack application.
* That is, you could save the above content in a file named “{@code ratpack.groovy}” (the name is irrelevant),
* then start the application by running `{@code groovy ratpack.groovy}` on the command line.
* <h3>Full Applications</h3>
* <p>
* It's also possible to build Groovy Ratpack applications with a traditional class based entry point.
* The {@link ratpack.groovy.GroovyRatpackMain} class provides such an entry point.
* In such a mode, a script like above is still used to define the application, but the script is no longer the entry point.
* Ratpack will manage the compilation and execution of the script internally.
*
* @param closure The definition closure, delegating to {@link ratpack.groovy.Groovy.Ratpack}
*/
public static void ratpack(@DelegatesTo(value = Ratpack.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) {
try {
RatpackScriptBacking.execute(closure);
} catch (Exception e) {
throw uncheck(e);
}
}
/**
* The definition of a Groovy Ratpack application.
*
* @see ratpack.groovy.Groovy#ratpack(groovy.lang.Closure)
*/
public interface Ratpack {
/**
* Registers the closure used to configure the {@link ratpack.guice.BindingsSpec} that will back the application.
*
* @param configurer The configuration closure, delegating to {@link ratpack.guice.BindingsSpec}
*/
void bindings(@DelegatesTo(value = BindingsSpec.class, strategy = Closure.DELEGATE_FIRST) Closure<?> configurer);
/**
* Registers the closure used to build the handler chain of the application.
*
* @param configurer The configuration closure, delegating to {@link GroovyChain}
*/
void handlers(@DelegatesTo(value = GroovyChain.class, strategy = Closure.DELEGATE_FIRST) Closure<?> configurer);
/**
* Registers the closure used to build the configuration of the server.
*
* @param configurer The configuration closure, delegating to {@link ServerConfigBuilder}
*/
void serverConfig(@DelegatesTo(value = ServerConfigBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure<?> configurer);
/**
* Evaluates the provided path using the Ratpack DSL and applies the configuration to this server.
* <p>
* The configuration supplied by the included path are applied inline with the existing parent configuration.
* This allows the same semantics as specifying the configuration in a single file to be followed.
* For {@link Ratpack#bindings(Closure)}, the configuration is appended.
* For {@link Ratpack#handlers} and {@link Ratpack#serverConfig(Closure)}, the configuration is merged.
* Settings from the parent configuration that are applied after the {@code include}, will be applied after the child configurations.
* <p>
* If the {@code path} is a relative path, then it will be resolved against the location of the parent script file that is including it.
*
* @param path The absolute path to the external Groovy DSL to included into the server.
* @since 1.3
*/
void include(Path path);
/**
* Evaluates the path provided using the Ratpack DSL and applies the configuration to this server.
* <p>
* The provided string is evaluated using {@link java.nio.file.Paths#get(String, String...)}
*
* @param path The absolute path to the external Groovy DSL to included into the server.
* @see #include(Path)
* @since 1.3
*/
void include(String path);
}
/**
* Methods for working with Groovy scripts as application components.
*/
public static abstract class Script {
/**
* {@value}
*/
public static final String DEFAULT_HANDLERS_PATH = "handlers.groovy";
/**
* {@value}
*/
public static final String DEFAULT_BINDINGS_PATH = "bindings.groovy";
/**
* {@value}
*/
public static final String DEFAULT_APP_PATH = "ratpack.groovy";
private Script() {
}
/**
* Asserts that the version of Groovy on the classpath meets the minimum requirement for Ratpack.
*/
public static void checkGroovy() {
GroovyVersionCheck.ensureRequiredVersionUsed(GroovySystem.getVersion());
}
/**
* Creates an application defining action from a Groovy script named {@value #DEFAULT_APP_PATH}.
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @return an application definition action
*/
public static Action<? super RatpackServerSpec> app() {
return app(false);
}
/**
* Creates an application defining action from a Groovy script named {@value #DEFAULT_APP_PATH}.
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @return an application definition action
*/
public static Action<? super RatpackServerSpec> app(boolean compileStatic) {
return app(compileStatic, DEFAULT_APP_PATH, DEFAULT_APP_PATH.substring(0, 1).toUpperCase() + DEFAULT_APP_PATH.substring(1));
}
/**
* Creates an application defining action from a Groovy script.
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @param script the script
* @return an application definition action
*/
public static Action<? super RatpackServerSpec> app(Path script) {
return app(false, script);
}
/**
* Creates an application defining action from a Groovy script.
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param script the script
* @return an application definition action
*/
public static Action<? super RatpackServerSpec> app(boolean compileStatic, Path script) {
return b -> doApp(b, compileStatic, script.getParent(), script);
}
/**
* Creates an application defining action from a Groovy script.
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param scriptPaths the potential paths to the scripts (first existing is used)
* @return an application definition action
*/
public static Action<? super RatpackServerSpec> app(boolean compileStatic, String... scriptPaths) {
return appWithArgs(compileStatic, scriptPaths);
}
/**
* Creates an application defining action from a Groovy script named {@value #DEFAULT_APP_PATH}
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @param args args to make available to the script via the {@code args} variable
* @return an application definition action
* @since 1.1
*/
public static Action<? super RatpackServerSpec> appWithArgs(String... args) {
return appWithArgs(false, new String[]{DEFAULT_APP_PATH, DEFAULT_APP_PATH.substring(0, 1).toUpperCase() + DEFAULT_APP_PATH.substring(1)}, args);
}
/**
* Creates an application defining action from a Groovy script.
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param script the script
* @param args args to make available to the script via the {@code args} variable
* @return an application definition action
* @since 1.1
*/
public static Action<? super RatpackServerSpec> appWithArgs(boolean compileStatic, Path script, String... args) {
return b -> doApp(b, compileStatic, script.getParent(), script, args);
}
/**
* Creates an application defining action from a Groovy script.
* <p>
* This method returns an action that can be used with {@link RatpackServer#of(Action)} to create an application.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param scriptPaths the potential paths to the scripts (first existing is used)
* @param args args to make available to the script via the {@code args} variable
* @return an application definition action
* @since 1.1
*/
public static Action<? super RatpackServerSpec> appWithArgs(boolean compileStatic, String[] scriptPaths, String... args) {
return b -> {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
BaseDirFinder.Result baseDirResult = Arrays.stream(scriptPaths)
.map(scriptPath -> BaseDirFinder.find(classLoader, scriptPath))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseThrow(() -> new ScriptNotFoundException(scriptPaths));
Path baseDir = baseDirResult.getBaseDir();
Path scriptFile = baseDirResult.getResource();
doApp(b, compileStatic, baseDir, scriptFile, args);
};
}
private static void doApp(RatpackServerSpec definition, boolean compileStatic, Path baseDir, Path scriptFile, String... args) throws Exception {
String script = Paths2.readText(scriptFile, StandardCharsets.UTF_8);
RatpackDslClosures closures = new RatpackDslScriptCapture(compileStatic, args, RatpackDslBacking::new).apply(scriptFile, script);
definition.serverConfig(ClosureUtil.configureDelegateFirstAndReturn(loadPropsIfPresent(ServerConfig.builder().baseDir(baseDir), baseDir), closures.getServerConfig()));
definition.registry(r -> {
return Guice.registry(bindingsSpec -> {
bindingsSpec.bindInstance(new FileBackedReloadInformant(scriptFile));
ClosureUtil.configureDelegateFirst(bindingsSpec, closures.getBindings());
}).apply(r);
});
definition.handler(r -> {
return Groovy.chain(r, closures.getHandlers());
});
}
private static ServerConfigBuilder loadPropsIfPresent(ServerConfigBuilder serverConfigBuilder, Path baseDir) {
Path propsFile = baseDir.resolve(BaseDir.DEFAULT_BASE_DIR_MARKER_FILE_PATH);
if (Files.exists(propsFile)) {
serverConfigBuilder.props(propsFile);
}
return serverConfigBuilder;
}
/**
* Creates a handler defining function from a {@value #DEFAULT_HANDLERS_PATH} Groovy script.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#handler(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#handlers(Closure)} method.
*
* @return a handler definition function
*/
public static Function<Registry, Handler> handlers() {
return handlers(false);
}
/**
* Creates a handler defining function from a {@value #DEFAULT_HANDLERS_PATH} Groovy script.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#handler(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#handlers(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @return a handler definition function
*/
public static Function<Registry, Handler> handlers(boolean compileStatic) {
return handlers(compileStatic, DEFAULT_HANDLERS_PATH);
}
/**
* Creates a handler defining function from a Groovy script.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#handler(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#handlers(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param scriptPath the path to the script
* @return a handler definition function
*/
public static Function<Registry, Handler> handlers(boolean compileStatic, String scriptPath) {
return handlersWithArgs(compileStatic, scriptPath);
}
/**
* Creates a handler defining function from a Groovy script.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#handler(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#handlers(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param scriptPath the path to the script
* @param args args to make available to the script via the {@code args} variable
* @return a handler definition function
* @since 1.1
*/
public static Function<Registry, Handler> handlersWithArgs(boolean compileStatic, String scriptPath, String... args) {
checkGroovy();
return r -> {
Path scriptFile = r.get(FileSystemBinding.class).file(scriptPath);
boolean development = r.get(ServerConfig.class).isDevelopment();
return new ScriptBackedHandler(scriptFile, development,
new RatpackDslScriptCapture(compileStatic, args, HandlersOnly::new)
.andThen(RatpackDslClosures::getHandlers)
.andThen(c -> Groovy.chain(r, c))
);
};
}
/**
* Creates a registry building function from a Groovy script named {@value #DEFAULT_BINDINGS_PATH}.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#registry(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#bindings(Closure)} method.
*
* @return a registry definition function
*/
public static Function<Registry, Registry> bindings() {
return bindings(false);
}
/**
* Creates a registry building function from a Groovy script named {@value #DEFAULT_BINDINGS_PATH}.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#registry(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#bindings(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @return a registry definition function
*/
public static Function<Registry, Registry> bindings(boolean compileStatic) {
return bindings(compileStatic, DEFAULT_BINDINGS_PATH);
}
/**
* Creates a registry building function from a Groovy script.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#registry(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#bindings(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param scriptPath the path to the script
* @return a registry definition function
*/
public static Function<Registry, Registry> bindings(boolean compileStatic, String scriptPath) {
return bindingsWithArgs(compileStatic, scriptPath);
}
/**
* Creates a registry building function from a Groovy script.
* <p>
* This method returns a function that can be used with {@link RatpackServerSpec#registry(Function)} when bootstrapping.
* <p>
* The script should call the {@link Script#ratpack(Closure)} method, and <b>only</b> invoke the {@link Ratpack#bindings(Closure)} method.
*
* @param compileStatic whether to statically compile the script
* @param scriptPath the path to the script
* @param args args to make available to the script via the {@code args} variable
* @return a registry definition function
* @since 1.1
*/
public static Function<Registry, Registry> bindingsWithArgs(boolean compileStatic, String scriptPath, String... args) {
checkGroovy();
return r -> {
Path scriptFile = r.get(FileSystemBinding.class).file(scriptPath);
String script = Paths2.readText(scriptFile, StandardCharsets.UTF_8);
Closure<?> bindingsClosure = new RatpackDslScriptCapture(compileStatic, args, BindingsOnly::new).andThen(RatpackDslClosures::getBindings).apply(scriptFile, script);
return Guice.registry(bindingsSpec -> {
bindingsSpec.bindInstance(new FileBackedReloadInformant(scriptFile));
ClosureUtil.configureDelegateFirst(bindingsSpec, bindingsClosure);
}).apply(r);
};
}
}
/**
* Builds a handler chain, with no backing registry.
*
* @param serverConfig The application server config
* @param closure The chain definition
* @return A handler
* @throws Exception any exception thrown by the given closure
*/
public static Handler chain(ServerConfig serverConfig, @DelegatesTo(value = GroovyChain.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) throws Exception {
return chain(serverConfig, null, closure);
}
/**
* Builds a chain, backed by the given registry.
*
* @param serverConfig The application server config
* @param registry The registry.
* @param closure The chain building closure.
* @return A handler
* @throws Exception any exception thrown by the given closure
*/
public static Handler chain(@Nullable ServerConfig serverConfig, @Nullable Registry registry, @DelegatesTo(value = GroovyChain.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) throws Exception {
return ChainBuilders.build(
new GroovyDslChainActionTransformer(serverConfig, registry),
new ClosureInvoker<Object, GroovyChain>(closure).toAction(registry, Closure.DELEGATE_FIRST)
);
}
/**
* Builds a chain, backed by the given registry.
*
* @param registry The registry.
* @param closure The chain building closure.
* @return A handler
* @throws Exception any exception thrown by the given closure
*/
public static Handler chain(Registry registry, @DelegatesTo(value = GroovyChain.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) throws Exception {
return chain(registry.get(ServerConfig.class), registry, closure);
}
/**
* Creates a chain action based on the given closure.
*
* @param closure The chain building closure.
* @return A chain action
*/
public static Action<Chain> chainAction(@DelegatesTo(value = GroovyChain.class, strategy = Closure.DELEGATE_FIRST) final Closure<?> closure) {
return chain -> ClosureUtil.configureDelegateFirst(GroovyChain.from(chain), closure);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based template, using no model and the default content type.
*
* @param id The id/name of the template
* @return a template
*/
public static TextTemplate groovyTemplate(String id) {
return groovyTemplate(id, null);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based markup template, using no model and the default content type.
*
* @param id The id/name of the template
* @return a template
*/
public static MarkupTemplate groovyMarkupTemplate(String id) {
return groovyMarkupTemplate(id, (String) null);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based template, using no model.
*
* @param id The id/name of the template
* @param type The content type of template
* @return a template
*/
public static TextTemplate groovyTemplate(String id, String type) {
return groovyTemplate(ImmutableMap.<String, Object>of(), id, type);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based markup template, using no model.
*
* @param id The id/name of the template
* @param type The content type of template
* @return a template
*/
public static MarkupTemplate groovyMarkupTemplate(String id, String type) {
return groovyMarkupTemplate(ImmutableMap.<String, Object>of(), id, type);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based template, using the default content type.
*
* @param model The template model
* @param id The id/name of the template
* @return a template
*/
public static TextTemplate groovyTemplate(Map<String, ?> model, String id) {
return groovyTemplate(model, id, null);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based markup template, using the default content type.
*
* @param model The template model
* @param id The id/name of the template
* @return a template
*/
public static MarkupTemplate groovyMarkupTemplate(Map<String, ?> model, String id) {
return groovyMarkupTemplate(model, id, null);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based markup template, using the default content type.
*
* @param id the id/name of the template
* @param modelBuilder an action the builds a model map
* @return a template
*/
public static MarkupTemplate groovyMarkupTemplate(String id, Action<? super ImmutableMap.Builder<String, Object>> modelBuilder) {
return groovyMarkupTemplate(id, null, modelBuilder);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based markup template.
*
* @param id the id/name of the template
* @param type The content type of template
* @param modelBuilder an action the builds a model map
* @return a template
*/
public static MarkupTemplate groovyMarkupTemplate(String id, String type, Action<? super ImmutableMap.Builder<String, Object>> modelBuilder) {
ImmutableMap<String, Object> model = uncheck(() -> Action.with(ImmutableMap.<String, Object>builder(), Action.noopIfNull(modelBuilder)).build());
return groovyMarkupTemplate(model, id, type);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based template.
*
* @param model The template model
* @param id The id/name of the template
* @param type The content type of template
* @return a template
*/
public static TextTemplate groovyTemplate(Map<String, ?> model, String id, String type) {
return new TextTemplate(model, id, type);
}
/**
* Creates a {@link ratpack.handling.Context#render(Object) renderable} Groovy based template.
*
* @param model The template model
* @param id The id/name of the template
* @param type The content type of template
* @return a template
*/
public static MarkupTemplate groovyMarkupTemplate(Map<String, ?> model, String id, String type) {
return new MarkupTemplate(id, type, model);
}
/**
* Creates a handler instance from a closure.
*
* @param closure The closure to convert to a handler
* @return The created handler
*/
public static Handler groovyHandler(@DelegatesTo(value = GroovyContext.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) {
return new ClosureBackedHandler(closure);
}
/**
* Immediately executes the given {@code closure} against the given {@code chain}, as a {@link GroovyChain}.
*
* @param chain the chain to add handlers to
* @param closure the definition of handlers to add
* @throws Exception any exception thrown by {@code closure}
*/
public static void chain(Chain chain, @DelegatesTo(value = GroovyChain.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) throws Exception {
new ClosureInvoker<Object, GroovyChain>(closure).invoke(chain.getRegistry(), GroovyChain.from(chain), Closure.DELEGATE_FIRST);
}
/**
* Creates a chain action implementation from the given closure.
*
* @param closure the definition of handlers to add
* @throws Exception any exception thrown by {@code closure}
* @return The created action
*/
public static Action<Chain> chain(@DelegatesTo(value = GroovyChain.class, strategy = Closure.DELEGATE_FIRST) final Closure<?> closure) throws Exception {
return (c) -> Groovy.chain(c, closure);
}
/**
* Shorthand for {@link #markupBuilder(CharSequence, Charset, Closure)} with a content type of {@code "text/html"} and {@code "UTF-8"} encoding.
*
* @param closure The html definition
* @return A renderable object (i.e. to be used with the {@link ratpack.handling.Context#render(Object)} method
*/
public static Markup htmlBuilder(@DelegatesTo(value = MarkupBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) {
return markupBuilder(HttpHeaderConstants.HTML_UTF_8, CharsetUtil.UTF_8, closure);
}
/**
* Renderable object for markup built using Groovy's {@link MarkupBuilder}.
*
* <pre class="groovy-chain-dsl">
* import static ratpack.groovy.Groovy.markupBuilder
*
* get("some/path") {
* render markupBuilder("text/html", "UTF-8") {
* // MarkupBuilder DSL in here
* }
* }
* </pre>
*
* @param contentType The content type of the markup
* @param encoding The character encoding of the markup
* @param closure The definition of the markup
* @return A renderable object (i.e. to be used with the {@link ratpack.handling.Context#render(Object)} method
*/
public static Markup markupBuilder(CharSequence contentType, CharSequence encoding, @DelegatesTo(value = MarkupBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) {
return new Markup(contentType, Charset.forName(encoding.toString()), closure);
}
public static Markup markupBuilder(CharSequence contentType, Charset encoding, @DelegatesTo(value = MarkupBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) {
return new Markup(contentType, encoding, closure);
}
/**
* Builds a content negotiating handler.
*
* @param registry the registry to obtain handlers from for by-class lookups
* @param closure the spec action
* @return a content negotiating handler
* @throws Exception any thrown by {@code action}
* @since 1.5
*/
public static Handler byContent(Registry registry, @DelegatesTo(value = GroovyByMethodSpec.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) throws Exception {
return Handlers.byContent(registry, s -> ClosureUtil.configureDelegateFirst(new DefaultGroovyByContentSpec(s), closure));
}
/**
* Builds a multi method handler.
*
* @param registry the registry to obtain handlers from for by-class lookups
* @param closure the spec action
* @return a multi method handler
* @throws Exception any thrown by {@code action}
* @since 1.5
*/
public static Handler byMethod(Registry registry, @DelegatesTo(value = GroovyByContentSpec.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) throws Exception {
return Handlers.byMethod(registry, s -> ClosureUtil.configureDelegateFirst(new DefaultGroovyByMethodSpec(s), closure));
}
}