0

I am loading a .war file and add it as web app to the embedded Tomcat server.

@Bean
public EmbeddedServletContainerFactory servletContainerFactory() {

    LOGGER.info("Adding web app");

    return new TomcatEmbeddedServletContainerFactory() {

        @Override
        protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {

            String appHome = System.getProperty(Environment.APP_HOME);

            String targetFileName = "web-0.0.1-SNAPSHOT.war";
            InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(targetFileName);

            LOGGER.info(System.getProperty("user.name"));
            LOGGER.debug("Loading WAR from " + appHome);

            File target = new File(Paths.get(appHome, targetFileName).toString());

            try {

                LOGGER.info(String.format("Copy %s to %s", targetFileName, target.getAbsoluteFile().toPath()));
                java.nio.file.Files.copy(resourceAsStream, target.getAbsoluteFile().toPath(), StandardCopyOption.REPLACE_EXISTING);

                Context context = tomcat.addWebapp("/", target.getAbsolutePath());
                context.setParentClassLoader(getClass().getClassLoader());

            } catch (ServletException ex) {
                throw new IllegalStateException("Failed to add webapp.", ex);
            } catch (Exception e) {
                throw new IllegalStateException("Unknown error while trying to load webapp.", e);
            }

            return super.getTomcatEmbeddedServletContainer(tomcat);
        }
    };
}

This is working so far but if I access http://localhost:8080/web I am getting

2017-03-04 11:18:59.588  WARN 29234 --- [nio-8080-exec-2] o.s.web.servlet.PageNotFound             : Request method 'GET' not supported

and the response

Allow: POST
Content-Length: 0
Date: Sat, 04 Mar 2017 10:26:16 GMT

I am sure all I have to do is to allow the GET method on /web and hopefully the static web content provided from the loaded war file will be accessible via web browser.

How/where can I configure the endpoint such that it allows GET requests?

I tried to introduce a WebController as described in this tutorial.

@Controller
public class WebController {

   private final static Logger LOGGER = Logger.getLogger(WebController.class);

   @RequestMapping(value = "/web", method = RequestMethod.GET)
   public String index() {
       LOGGER.info("INDEX !");
       return "index";
   }
}

In the log output I can see that this is getting mapped correctly:

RequestMappingHandlerMapping : Mapped "{[/web],methods=[GET]}" onto public java.lang.String org.ema.server.spring.controller.dl4j.WebController.index()

but it does not change the fact that I cannot visit the website.

I've also configured a InternalResourceViewResolver:

@Configuration
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {

    private final static Logger LOGGER = Logger.getLogger(MvcConfiguration.class);

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        LOGGER.info("configureViewResolvers()");
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();

        resolver.setSuffix(".html");
        registry.viewResolver(resolver);
    }


    @Override
    public void configureDefaultServletHandling(
            DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }  

}

web.xml

Since I configure everything in pure Java, this file does not define a lot:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <display-name>Easy Model Access Server</display-name>

    <listener>
        <listener-class>org.ema.server.ServerEntryPoint</listener-class>
    </listener>

    <context-param>
        <param-name>log4j-config-location</param-name>
        <param-value>WEB-INF/classes/log4j.properties</param-value>
    </context-param>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/web/*.html</url-pattern>
    </servlet-mapping>

</web-app>

Reproduce

If you want to reproduce this you can simply checkout the entire code from github. All you need to do this:

mkdir ~/.ema
git clone https://github.com/silentsnooc/easy-model-access
cd easy-model-access/ema-server
mvn clean install
java -jar server/target/server-*.jar

This will clone, build and run the server.

The directory ~/.ema directory is required at the moment. It is where the WAR is being copied as the server starts.

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
  • 2
    as you add your webapp into context `/web` have you tried `http://localhost:8080/web/web`? And how is your viewResolver configured? Add a log statement into your RequestMapping-method to see if it is called – thopaw Mar 04 '17 at 11:10
  • @ThomasPawlitzki You were right about http://localhost:8080/web/web ! If I go there, I see the log output from `WebController`. However, I am still getting `Request method 'GET' not supported`. – Stefan Falk Mar 04 '17 at 11:23
  • Configure a [View Resolver](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/ViewResolver.html) or for testing change your method to `@RequestMapping(value = "/web", method = RequestMethod.GET) public @ResponseBody String index() { ...}` – thopaw Mar 04 '17 at 11:27
  • @ThomasPawlitzki Okay I've added `@ResponseBody` - now the `GET` request works but I don't get to see the `index.html` - just the text "*index*" that's being returned from the `index()` function. I'll take a look at this view resolver. – Stefan Falk Mar 04 '17 at 11:31
  • @ThomasPawlitzki I've added the bean for the `ViewResolver` but it does not have any effect. Do I have to consider something other because of how I add the web application? – Stefan Falk Mar 04 '17 at 11:44
  • Look at the spring docs for [View Resolver](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-viewresolver). With this bean your index.html is found when configured correctly – thopaw Mar 04 '17 at 12:02
  • @ThomasPawlitzki why don't you configure view layer in application.properties and instead of redirecting you can use a template view. – Fırat Küçük Mar 18 '17 at 21:54

2 Answers2

1

My guess is that your web.xml maps any path to the Spring DispatcherServlet, something like:

<servlet>
  <servlet-name>app</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

Because of <url-pattern>/</url-pattern> any request must be handled by a Spring controller, for this reason your static files are not served by Tomcat. Also a pattern like /*.html would have same effect.

If you have only a few pages you might add one or more mapping to the predefined default servlet for them, before the mapping of Spring (and also before Spring Security if you use it):

 <servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>index.html</url-pattern>
 </servlet-mapping>

You may also use <url-pattern>*.html</url-pattern> or, if your resources are under the web path and there are only static resources there: <url-pattern>/web/*</url-pattern>

Maybe all this is done instead in Java code in the org.ema.server.ServerEntryPoint that you have as a listener in web.xml

I think the mapping I wrote up in web.xml is done in your case in method getServletMappings of class org.ema.server.spring.config.AppInitializer, I changed it to use a more strict pattern /rest-api/* instead than /, not sure pattern is correct and everything else works, but now http://127.0.0.1:8080/index.html works

   @Override
protected String[] getServletMappings() {
    return new String[] { "/rest-api/*" };
}
Testo Testini
  • 2,200
  • 18
  • 29
  • Well, my web.xml is pretty much empty. You can take a look at it: http://pastebin.com/hPvTWzw4 But does you second suggestion still apply? Do I only need to add the servlet-mapping for the default mapping? Is this servlet defined even without specifying it explicitly? And shouldn't it be `/web/index.html` or something like that? – Stefan Falk Mar 19 '17 at 15:58
  • Hm, it's still not working. I've updated my question with the method where I am loading the `.war` file. Would you be so kind and check if you notice anything that's wrong? :/ – Stefan Falk Mar 20 '17 at 19:53
  • have you tried to remove the controller for `/web` ? If is mapped it will take any request under `/web`. Also viewresolver does not help in serving static files but won't harm. – Testo Testini Mar 21 '17 at 17:16
  • I've commented everything out from the controller but I still get the `Request method 'GET' not supported` message. :/ – Stefan Falk Mar 21 '17 at 17:49
  • I don't know if you're willing to do so but I added a "*Reprocude*" section to my question. With only a few lines you could clone the project from git and run the server if you want. – Stefan Falk Mar 21 '17 at 18:01
  • I built it, had to remove 2 tests referencing some files in user.home and got to edit win registry to fix this weird http://stackoverflow.com/questions/6362037/java-error-opening-registry-key now I see your get not allowed.. – Testo Testini Mar 21 '17 at 19:22
  • Oh, okay I never tried to make in run on Windows yet - so it's possible that some changes may fail at the moment. I know the project is currently a bit messy :D Let me know if I can help you finding something .. – Stefan Falk Mar 21 '17 at 19:34
  • I see your get not supported for `index.html`. The registered mappings are listed at begin, I tested `http://127.0.0.1:8080/dl4j/we/getWordVector` and raises a ModelNotAvailableException for `null` model not available, so GET is working there, still think there is some handler up that handles these requests. How are the requests for `/dl4j/*` mapped ? Ah `http://127.0.0.1:8080/dl4j/we/getAvailableModels` works, outputs json – Testo Testini Mar 21 '17 at 19:42
  • Yes, the other requests are working - I am actually already using this server for my machine learning stuff. However, I'd like the web client to work as well but it's simply does not want to work for me. ^^ – Stefan Falk Mar 21 '17 at 19:45
  • **You** are the man! I feel a bit stupid but I am so glad it finally works! Thanks man! – Stefan Falk Mar 21 '17 at 20:16
-1

as I see the url: http://localhost:8080/web is wrong. You can try: http://localhost:8080/[name-of-war-file]/web

dphung duy
  • 19
  • 5
  • Nope, the problem is that the said endpoint does not support the GET request as stated. This was already discussed in the comment section of the question. – Stefan Falk Mar 20 '17 at 08:44