Class ServerPagesBundle

  • All Implemented Interfaces:
    ru.vyarus.dropwizard.guice.module.installer.bundle.GuiceyBundle

    public class ServerPagesBundle
    extends ru.vyarus.dropwizard.guice.module.context.unique.item.UniqueGuiceyBundle
    Bundle 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 register ViewBundle manually!

    Each server pages application is also registered as separate bundle (using app(String, String, String) or adminApp(String, String, String)).

    Views configuration could be mapped from yaml file in main bundle: ServerPagesBundle.ViewsBuilder.viewsConfiguration(ViewConfigurable). In order to fine tune configuration use ServerPagesAppBundle.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. Use ServerPagesAppBundle.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 AssetServlet used 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.

     
      @Template("dashboard.ftl")
      @Path("ui/dahboard")
      @Produces(MediaType.TEXT_HTML)
      public class DashboardPage {
       @GET
       public DashboardView get() {
          return new DashboardView();
       }
      }
     
     
    Note that Template annotation 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 extend TemplateView. In all other aspects, it's pure dropwizard views. Template annotation is jersey NameBinding marker so you can apply request/response filters only (!) for template resources (see TemplateAnnotationFilter as 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 SpaBundle in order to support single page applications routing (for cases when root page must be template and not just html, which makes direct usage of SpaBundle useless).

    Information about configured application may be acquired through GspInfoService guice 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
    • Constructor Detail

      • ServerPagesBundle

        public ServerPagesBundle​(GlobalConfig 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) and adminApp(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 as app(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 uri
        loader - 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 as adminApp(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 uri
        loader - 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 as extendApp(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 name
        loader - class loader to use for assets loading
        Returns:
        application extension bundle
      • getRenderers

        public java.util.List<io.dropwizard.views.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)