Class ServerPagesBundle
- java.lang.Object
-
- ru.vyarus.dropwizard.guice.module.context.unique.item.UniqueGuiceyBundle
-
- ru.vyarus.guicey.gsp.ServerPagesBundle
-
- All Implemented Interfaces:
ru.vyarus.dropwizard.guice.module.installer.bundle.GuiceyBundle
public class ServerPagesBundle extends ru.vyarus.dropwizard.guice.module.context.unique.item.UniqueGuiceyBundleBundle unifies dropwizard-views and dropwizard-assets bundles in order to bring server templating simplicity like with jsp. The main goal is to make views rendering through rest endpoints hidden and make template calls by their files to simplify static resources references (css ,js, images etc.). Also, errors handling is unified (like in usual servlets, but individually for server pages application).First of all global server pages support bundle must be installed (
builder(), preferably directly in the application class). This will activates dropwizard-views support (ViewBundle). Do not registerViewBundlemanually!Each server pages application is also registered as separate bundle (using
app(String, String, String)oradminApp(String, String, String)).Views configuration could be mapped from yaml file in main bundle:
ServerPagesBundle.ViewsBuilder.viewsConfiguration(ViewConfigurable). In order to fine tune configuration useServerPagesAppBundle.AppBuilder.viewsConfigurationModifier(String, ViewRendererConfigurationModifier)which could be used by applications directly in order to apply required defaults. But pay attention that multiple apps could collide in configuration (configure the same property)! Do manual properties merge instead of direct value set where possible to maintain applications compatibility (e.g. you declare admin dashboard and main users app, which both use freemarker and require default templates).Renderers (pluggable template engines support) are loaded with service lookup mechanism (default for dropwizard-views) but additional renderers could be registered with
ServerPagesBundle.ViewsBuilder.addViewRenderers(ViewRenderer...). Most likely, server page apps will be bundled as 3rd party bundles and so they can't be sure what template engines are installed in target application. UseServerPagesAppBundle.AppBuilder.requireRenderers(String...)to declare required template engines for each application and fail fast if no required templates engine. Without required engines declaration template files will be served like static files when direct template requested and rendering will fail for rest-mapped template.Each application could be "extended" using
extendApp(String)bundle. This way extra classpath location is mapped into application root. Pages from extended context could reference resources from the main context (most likely common root template will be used). Also, extended mapping could override resources from the primary location (but note that in case of multiple extensions order is not granted). Obvious case for extensions feature is dashboards, when extensions add extra pages to common dashboard application, but all new pages still use common master template.Application work scheme: assets servlet is registered on the configured path in order to serve static assets (customized version of dropwizard
AssetServletused which could recognize both primary and extended locations). Special filter above servlet detects file calls (by extension, but checks if requested file is template (and that's why list of supported templates is required)). If request is not for file, it's redirected to rest endpoint in order to render view (note that direct template files will also be rendered). Redirection scheme use application name, defined during bundle creation: {rest prefix}/{app name}/{path from request}. For example,.bundles(SpaPageBundle.app("ui", "/com/assets/path/", "ui/").build())Register application in main context, mapped to "ui/" path, with static resources in "/com/assets/path/" classpath path. Internal application name is "ui". When browser request any file directly, e.g. "ui/styles.css" then file "/com/assets/path/styles.css" will be served. Any other path is redirected to rest endpoint: e.g. "ui/dashboard/" is redirected to "{rest mapping}/ui/dashboard.
Note that@Template("dashboard.ftl") @Path("ui/dahboard") @Produces(MediaType.TEXT_HTML) public class DashboardPage { @GET public DashboardView get() { return new DashboardView(); } }Templateannotation on resource is required. Without it, bundle will not be able to show path in console reporting. Also, configured template automatically applied into view (so you don't have to specify template path in all methods (note that custom template path could still be specified directly, when required). View class must extendTemplateView. In all other aspects, it's pure dropwizard views.Templateannotation is jerseyNameBindingmarker so you can apply request/response filters only (!) for template resources (seeTemplateAnnotationFilteras example).Note that all resources, started from application name prefix are considered to be used in application.
extendApp(String)mechanism is used only to declare additional static resources (or direct templates). But in order to add new pages, handled by rest resources you dont need to do anything - they just must start with correct prefix (you can see all application resources in console just after startup).In order to be able to render direct templates (without supporting rest endpoint) special rest endpoint is registered which handles everything on application path (e.g. "ui/{file:.*}" for example application above). Only POST and GET supported for direct templates.
Bundle unifies custom pages handling to be able to use default 404 or 500 pages (for both assets and resources). Use builder
ServerPagesAppBundle.AppBuilder.errorPage(int, String)method to map template (or pure html) to response code (to be shown instead).Bundle could also enable filter from
SpaBundlein order to support single page applications routing (for cases when root page must be template and not just html, which makes direct usage ofSpaBundleuseless).Information about configured application may be acquired through
GspInfoServiceguice bean. But it could be used only after complete gsp initialization (between dropwizard run and jersey start).- Since:
- 22.10.2018
- See Also:
- dropwizard views
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static classServerPagesBundle.ViewsBuilderGlobal server pages support bundle builder.
-
Field Summary
Fields Modifier and Type Field Description static java.lang.StringFILE_REQUEST_PATTERNDefault pattern for file request detection.
-
Constructor Summary
Constructors Constructor Description ServerPagesBundle(ServerPagesGlobalState config)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description static ServerPagesAppBundle.AppBuilderadminApp(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath)Register application in admin context.static ServerPagesAppBundle.AppBuilderadminApp(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath, java.lang.ClassLoader loader)Same asadminApp(String, String, String)but with custom classloader to use for assets loading.static ServerPagesAppBundle.AppBuilderapp(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath)Register application in main context.static ServerPagesAppBundle.AppBuilderapp(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath, java.lang.ClassLoader loader)Same asapp(String, String, String)but with custom classloader to use for assets loading.static ServerPagesBundle.ViewsBuilderbuilder()Creates global server pages support bundle which must be registered in the application.static ServerPagesAppExtensionBundle.AppExtensionBuilderextendApp(java.lang.String name)Extend registered application.static ServerPagesAppExtensionBundle.AppExtensionBuilderextendApp(java.lang.String name, java.lang.ClassLoader loader)Same asextendApp(String)but with custom classloader to use for assets loading.java.util.List<io.dropwizard.views.common.ViewRenderer>getRenderers()Method is available for custom template detection logic (similar that used inside server pages filter) or to validate state in tests.java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>getViewsConfig()Method is available for custom views configuration state analysis logic (after startup) or to validate state in tests.voidinitialize(ru.vyarus.dropwizard.guice.module.installer.bundle.GuiceyBootstrap bootstrap)voidrun(ru.vyarus.dropwizard.guice.module.installer.bundle.GuiceyEnvironment environment)
-
-
-
Constructor Detail
-
ServerPagesBundle
public ServerPagesBundle(ServerPagesGlobalState config)
-
-
Method Detail
-
builder
public static ServerPagesBundle.ViewsBuilder builder()
Creates global server pages support bundle which must be registered in the application. Bundle installs standard dropwizard views bundle (ViewBundle). If views bundle is manually declared in application, it must be removed (to avoid duplicates). View bundle owning is required for proper configuration and to know all used template engines (renderers).After global support is registered, server pages applications may be declared with
app(String, String, String)andadminApp(String, String, String).It is assumed that global bundles support is registered directly in the dropwizard application (and not transitively in some bundle) and server page applications themselves could be registered nearby (in dropwizard application) or in any bundle (for example, some dashboard bundle just registers dashboard application, assuming that global server pages support would be activated).
- Returns:
- global views bundle builder
-
app
public static ServerPagesAppBundle.AppBuilder app(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath)
Register application in main context. Application names must be unique (when you register multiple server pages applications).Application could be extended with
extendApp(String)in another bundle.NOTE global server pages support bundle must be installed with
builder()in dropwizard application.- Parameters:
name- application name (used as servlet name)assetsPath- path to application resources (classpath); may be in form of package (dot-separated)uriPath- mapping uri- Returns:
- builder instance for server pages application configuration
- See Also:
for server pages applications global support
-
app
public static ServerPagesAppBundle.AppBuilder app(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath, java.lang.ClassLoader loader)
Same asapp(String, String, String)but with custom classloader to use for assets loading. All additional registration through this builder (ServerPagesAppBundle.AppBuilder.attachAssets(String)) would also be registered with provided class loader.WARNING: custom class loader will be automatically supported for static resources, but template engine may not be able to resolve template. For example, freemarker use class loader of resource class serving view, so if resource class and view template are in the same class loader then it will work. For sure direct template rendering (without custom resource class) will not work. Freemarker may be configured to support all cases with custom template loader (see
ServerPagesBundle.ViewsBuilder.enableFreemarkerCustomClassLoadersSupport()) which must be configured manually. Mustache is impossible to configure properly (with current mustache views renderer).- Parameters:
name- application name (used as servlet name)assetsPath- path to application resources (classpath); may be in form of package (dot-separated)uriPath- mapping uriloader- class loader to use for assets loading- Returns:
- builder instance for server pages application configuration
- See Also:
for server pages applications global support
-
adminApp
public static ServerPagesAppBundle.AppBuilder adminApp(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath)
Register application in admin context. Application names must be unique (when you register multiple server pages applications).You can't register admin application on admin context root because there is already dropwizard admin servlet
AdminServlet.Application could be extended with
extendApp(String)in another bundle.NOTE: global server pages support bundle must be installed with
builder()in dropwizard application.- Parameters:
name- application name (used as servlet name)assetsPath- path to application resources (classpath)uriPath- mapping uri- Returns:
- builder instance for server pages application configuration
- See Also:
for server pages applications global support
-
adminApp
public static ServerPagesAppBundle.AppBuilder adminApp(java.lang.String name, java.lang.String assetsPath, java.lang.String uriPath, java.lang.ClassLoader loader)
Same asadminApp(String, String, String)but with custom classloader to use for assets loading. All additional registration through this builder (ServerPagesAppBundle.AppBuilder.attachAssets(String)) would also be registered with provided class loader.WARNING: custom class loader will be automatically supported for static resources, but template engine may not be able to resolve template. For example, freemarker use class loader of resource class serving view, so if resource class and view template are in the same class loader then it will work. For sure direct template rendering (without custom resource class) will not work. Freemarker may be configured to support all cases with custom template loader (see
ServerPagesBundle.ViewsBuilder.enableFreemarkerCustomClassLoadersSupport()) which must be configured manually. Mustache is impossible to configure properly (with current mustache views renderer).- Parameters:
name- application name (used as servlet name)assetsPath- path to application resources (classpath)uriPath- mapping uriloader- class loader to use for assets loading- Returns:
- builder instance for server pages application configuration
- See Also:
for server pages applications global support
-
extendApp
public static ServerPagesAppExtensionBundle.AppExtensionBuilder extendApp(java.lang.String name)
Extend registered application. The most common use case is adding or overriding static assets of target application (e.g. for visual customization). Extension may be called before or after application registration - it does not matter.For example, if we register application like this
ServerPagesBundle.app("ui", "/com/path/assets/", "/ui")it will server static resources only from "/com/path/assets/" package. Suppose we want to add another page (with direct template) into the app:ServerPagesBundle.extendApp("ui").attachAssets("/com/another/assets/"). Now assets will be searched in both packages and if we have "/com/another/assets/page.tpl" then calling url "/ui/page.tpl" will render template. Resource in extended location could override original app resource: e.g. if we have "/com/another/assets/style.css" (extended) and "/com/path/assets/style.css" (original app) then "/ui/style.css" will return extended resource file.For new views addition, you may simply register new rest resources with prefix, used by application and it will detect it automatically (in example above app name is "ui").
If extended application is not registered no error will be thrown. This behaviour support optional application extension support (extension will work if extended application registered and will not harm if not).
Unlimited number of extensions could be registered for the same application (all extensions will be applied).
- Parameters:
name- extended application name- Returns:
- application extension bundle
-
extendApp
public static ServerPagesAppExtensionBundle.AppExtensionBuilder extendApp(java.lang.String name, java.lang.ClassLoader loader)
Same asextendApp(String)but with custom classloader to use for assets loading. All additional registration through this builder (ServerPagesAppBundle.AppBuilder.attachAssets(String)) would also be registered with provided class loader.WARNING: custom class loader will be automatically supported for static resources, but template engine may not be able to resolve template. For example, freemarker use class loader of resource class serving view, so if resource class and view template are in the same class loader then it will work. For sure direct template rendering (without custom resource class) will not work. Freemarker may be configured to support all cases with custom template loader (see
ServerPagesBundle.ViewsBuilder.enableFreemarkerCustomClassLoadersSupport()) which must be configured manually. Mustache is impossible to configure properly (with current mustache views renderer).- Parameters:
name- extended application nameloader- class loader to use for assets loading- Returns:
- application extension bundle
-
getRenderers
public java.util.List<io.dropwizard.views.common.ViewRenderer> getRenderers()
Method is available for custom template detection logic (similar that used inside server pages filter) or to validate state in tests.- Returns:
- list of used renderers (supported template engines)
-
getViewsConfig
public java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>> getViewsConfig()
Method is available for custom views configuration state analysis logic (after startup) or to validate state in tests.- Returns:
- final views configuration object (unmodifiable)
- Throws:
java.lang.NullPointerException- if views configuration is not yet created (views ot initialized)
-
initialize
public void initialize(ru.vyarus.dropwizard.guice.module.installer.bundle.GuiceyBootstrap bootstrap)
-
run
public void run(ru.vyarus.dropwizard.guice.module.installer.bundle.GuiceyEnvironment environment)
-
-