5

I would like to add hawt.io as an embedded component to my spring boot 'fat jar' application which has an embedded tomcat server.

How can I do this? How could I deploy the hawt.io war file?

UPDATE: I added the dependencies:

  • hawtio-web
  • hawtio-core
  • hawtio-plugin-mbean
  • hawtio-springboot to my pom

When I start the application now and open the url localhost:8080/hatio/index.html I get the login page presented. Since I don't know username and password I the added hawtio.authenticationEnabled=false to my application.properties

But - now I get a warning ' WARN 3420 --- [nio-8080-exec-4] o.s.web.servlet.PageNotFound : Request method 'POST' not supported' followed by a a null pointer exception.

References: http://hawt.io/configuration/index.html

ABX
  • 1,173
  • 2
  • 22
  • 39

2 Answers2

6

I had exactly the same issue - and here is how I solved the problem.

I found out that spring-boot doesnt support legacy web.xml configuration which is what you get when the maven-war-plugin does the overlay of the hawtio-web project on top of your own war. The resulting war contains both your web code as well as the content of the hawtio-web archive.

See http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html

So I started the process of configuring the servlets and filters in spring.

First add the necesary dependencies to pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring-boot-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
        <version>${spring-boot-version}</version>
    </dependency>
    <dependency>
        <groupId>io.hawt</groupId>
        <artifactId>hawtio-springboot</artifactId>
        <version>${hawtio.version}</version>
    </dependency>
    <dependency>
        <groupId>io.hawt</groupId>
        <artifactId>hawtio-core</artifactId>
        <version>${hawtio.version}</version>
    </dependency>
</dependencies>

Im using these versions:

<hawtio.version>2.0.0</hawtio.version>
<spring-boot.version>1.2.3.RELEASE</spring-boot.version>

Add a Configuration class to configure the servlets and filters:

@Configuration
public class HawtioConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/hawtio/plugins/**").addResourceLocations("/app/", "classpath:/static/hawtio/app/");
        registry.addResourceHandler("/hawtio/**").addResourceLocations("/", "/app/", "classpath:/static/hawtio/",
                "classpath:/static/hawtio/app/");
    }

    @Override
    public void addViewControllers(final ViewControllerRegistry registry) {
        registry.addViewController("/hawtio/plugin").setViewName("forward:/plugin");
        registry.addViewController("/hawtio/").setViewName("redirect:/hawtio/index.html");
    }

    @Bean
    public ServletRegistrationBean userServlet() {
        return new ServletRegistrationBean(new UserServlet(), "/user/*", "/hawtio/user/*");
    }

    @Bean
    public ServletRegistrationBean jolokiaproxy() {
        return new ServletRegistrationBean(new ProxyServlet(), "/hawtio/proxy/*");
    }

    @Bean
    public ServletRegistrationBean kubeservice() {
        return new ServletRegistrationBean(new ServiceServlet(), "/hawtio/service/*");
    }

    @Bean
    public ServletRegistrationBean kubepod() {
        return new ServletRegistrationBean(new PodServlet(), "/hawtio/pod/*");
    }

    @Bean
    public ServletRegistrationBean fileupload() {
        return new ServletRegistrationBean(new UploadServlet(), "/hawtio/file-upload/*");
    }

    @Bean
    public ServletRegistrationBean loginservlet() {
        return new ServletRegistrationBean(new LoginServlet(), "/hawtio/auth/login/*");
    }

    @Bean
    public ServletRegistrationBean logoutservlet() {
        return new ServletRegistrationBean(new LogoutServlet(), "/hawtio/auth/logout/*");
    }

    @Bean
    public ServletRegistrationBean keycloakservlet() {
        return new ServletRegistrationBean(new KeycloakServlet(), "/hawtio/keycloak/*");
    }

    @Bean
    public ServletRegistrationBean exportcontextservlet() {
        return new ServletRegistrationBean(new ExportContextServlet(), "/hawtio/exportContext/*");
    }

    @Bean
    public ServletRegistrationBean mavenSource() {
        return new ServletRegistrationBean(new JavaDocServlet(), "/hawtio/javadoc/*");
    }

    @Bean
    public ServletRegistrationBean contextFormatter() {
        return new ServletRegistrationBean(new ContextFormatterServlet(), "/hawtio/contextFormatter/*");
    }

    @Bean
    public ServletRegistrationBean gitServlet() {
        return new ServletRegistrationBean(new GitServlet(), "/hawtio/git/*");
    }

    @Bean
    public ServletListenerRegistrationBean hawtioContextListener() {
        return new ServletListenerRegistrationBean<>(new HawtioContextListener());
    }

    @Bean
    public ServletListenerRegistrationBean fileCleanerCleanup() {
        return new ServletListenerRegistrationBean<>(new FileCleanerCleanup());
    }

    @Bean
    public FilterRegistrationBean redirectFilter() {
        final FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new RedirectFilter());
        filter.setUrlPatterns(Collections.singletonList("/hawtio/*"));
        return filter;
    }

    @Bean
    public FilterRegistrationBean sessionExpiryFilter() {
        final FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new SessionExpiryFilter());
        filter.setUrlPatterns(Collections.singletonList("/hawtio/*"));
        return filter;
    }

    @Bean
    public FilterRegistrationBean cacheFilter() {
        final FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new CacheHeadersFilter());
        filter.setUrlPatterns(Collections.singletonList("/hawtio/*"));
        return filter;
    }

    @Bean
    public FilterRegistrationBean CORSFilter() {
        final FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new CORSFilter());
        filter.setUrlPatterns(Collections.singletonList("/hawtio/*"));
        return filter;
    }

    @Bean
    public FilterRegistrationBean XFrameOptionsFilter() {
        final FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new XFrameOptionsFilter());
        filter.setUrlPatterns(Collections.singletonList("/hawtio/*"));
        return filter;
    }

    @Bean
    public FilterRegistrationBean AuthenticationFilter() {
        final FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new AuthenticationFilter());
        filter.setUrlPatterns(Arrays.asList("/hawtio/auth/*", "/jolokia/*", "/hawtio/upload/*", "/hawtio/javadoc/*"));
        return filter;
    }

}

I have tested this with both jetty and tomcat - and it works with both. I have also submitted this as a patch to hawtio, but it is not released as of yet. You could compile hawtio yourself and import the HawtioConfiguration: https://github.com/hawtio/hawtio/blob/master/hawtio-springboot/src/main/java/io/hawt/springboot/HawtioConfiguration.java

I have also updated the hawtio-sample to use the HawtioConfiguration: https://github.com/hawtio/hawtio/tree/master/hawtio-sample-springboot

Now i can access hawtio by visiting http://localhost:8080/hawtio/index.html

Hope this helps.

Good luck.

stalet
  • 1,345
  • 16
  • 24
  • Works fine for me, except that I commented the redirect for "/" because some of my camel services after navigating throught the hawt.io camel console. – 0x0me Jun 05 '15 at 21:14
  • I have improved this and added it as a feature in hawtio itself. https://github.com/hawtio/hawtio/pull/1969 Im not sure which release it will be in. – stalet Jun 09 '15 at 06:47
  • Updated the example so that it now works when refreshing the page, and without overlays. Added references to the patch i submitted into hawtio. – stalet Jun 19 '15 at 08:22
  • Any idea on auth with this setup? I've managed to get things working but cannot get past the login screen. I've tried adding ```hawtio.authenticationEnabled=false``` to the properties file. [Hawt.io docs](http://hawt.io/configuration/index.html) mention settings for TomCat, but this is embedded. Not sure if ```tomcat-users.xml``` applies. – Nathanial Woolls Jun 20 '15 at 05:23
  • Running with ```java -Dhawtio.authenticationEnabled=false``` does allow me to disable to login screen, but the dashboard has a broken image link in the upper-left and non-working nav. Chrome console shows a lot of 404s. – Nathanial Woolls Jun 20 '15 at 05:52
  • It looks like you are using this code in the sample to suppress the login (not sure why its required) but that still gets me to a non-functional site if I follow your steps with a fresh Spring Boot app: ```System.setProperty(AuthenticationFilter.HAWTIO_AUTHENTICATION_ENABLED, "false");``` – Nathanial Woolls Jun 20 '15 at 07:01
  • Here's an [example project](https://www.dropbox.com/s/sih2rkkmihiqajy/spring-boot-hawtio-broken.zip?dl=0) showing the issue. – Nathanial Woolls Jun 20 '15 at 07:33
  • Can confirm this does work (better) as long as you clone Hawtio repo and use that code (currently 1.5-SNAPSHOT). Not sure if it's doable with the stable releases. However, the images for the Camel route children are broken links. – Nathanial Woolls Jun 21 '15 at 04:03
  • To add to the ```HAWTIO_AUTHENTICATION_ENABLED``` weirdness, adding Spring Security to the project seems to re-enable the hawtio login screen (without the ability to login, even with a valid Spring Security session). – Nathanial Woolls Jun 21 '15 at 06:16
  • The example is without authentIcation. tried briefly to add auth the other day, but It was not straightfoward. I will add another answer If i get it to work. – stalet Jun 21 '15 at 09:04
  • To enable security you have to add a jaas context and loginmodule for the jaas context. I used the one in the jetty sourcecode and made some changes to it to fit my needs. See the io.hawt.web.AuthenticationFilter for details. I will ask the hawtio developers if they want a solution for this as well - when it is a bit more refined. – stalet Jun 24 '15 at 13:03
  • I've diagnosed and reported both the [issue with Spring Security](https://github.com/hawtio/hawtio/issues/1975) and the issue with the [broken image links in hawtio-springboot](https://github.com/hawtio/hawtio/issues/1985) with workarounds. – Nathanial Woolls Jul 08 '15 at 04:11
  • @NathanialWoolls is the images the only thing you had to fix? I can't get hawtio-sample-springboot to run with the hawtio 1.4.52 code. My browser hits /hawtio/perspective/** urls which don't exist. E.g. http://localhost:10000/hawtio/perspective/img/icons/java.svg but I can get the img by changing the url and removing /perspective/. I am also working on adding spring security - but first it must work without ;-) – Lasse L Jul 13 '15 at 13:02
  • No.. it must be something on my work PC. It works fine from my macbook at home. – Lasse L Jul 13 '15 at 17:14
  • @stalet When I change tomcat for jetty, I don't have a Jetty tab. Do you know why? – Marc Jun 16 '16 at 20:46
  • @Marc i dont think they have created a plugin for jetty yet. – stalet Jun 16 '16 at 21:11
  • All the links are now 404. – Namphibian Oct 05 '20 at 01:28
5

Here is what I have from following the latest tutorials (I'm guessing Hawtio improved this since this question was asked and answered originally): Using spring-boot-starter-parent 1.3.5.RELEASE, Hawtio version 1.4.64, include the following dependencies:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.hawt</groupId>
            <artifactId>hawtio-springboot</artifactId>
            <version>${hawtio.version}</version>
        </dependency>
        <dependency>
            <groupId>io.hawt</groupId>
            <artifactId>hawtio-core</artifactId>
            <version>${hawtio.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
    </dependencies>

Here is a sample application class that sets up Hawtio with disabled authentication:

@SpringBootApplication
@EnableHawtio
public class SampleApplication {
    @Autowired
    private ServletContext servletContext;

    public static void main(String[] args) {
        System.setProperty(AuthenticationFilter.HAWTIO_AUTHENTICATION_ENABLED, "false");
        SpringApplication.run(SampleApplication.class, args);
    }

    @PostConstruct
    public void init() {
        final ConfigManager configManager = new ConfigManager();
        configManager.init();
        servletContext.setAttribute("ConfigManager", configManager);
    }

    /**
     * Set things up to be in offline mode
     * @return
     * @throws Exception
     */
    @Bean
    public ConfigFacade configFacade() throws Exception {
        ConfigFacade config = new ConfigFacade() {
            public boolean isOffline() {
                return true;
            }
        };
        config.init();
        return config;
    }
}

You can find the full code here in a sample application that includes Apache Camel: https://github.com/bowdoincollege/spring-boot-camel-sample

Erik Pearson
  • 1,363
  • 1
  • 11
  • 20