Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

org.ocpsoft.rewrite.servlet.config.Resource.java is not resolving resources properly in a Spring-boot application #206

Open
MartinAhrer opened this issue Apr 8, 2015 · 7 comments

Comments

@MartinAhrer
Copy link

I have a working web application with the ocpsoft rewrite filter installed.

            addRule().
                when(isInbound().
                    and(Path.matches("/client/{path}")).
                    andNot(Path.matches(CLIENT_BASE_URL)).
                    andNot(Resource.exists(webJarPrefix + "/{path}"))
                ).
                perform(Log.message(INFO, "Forwarding to "+CLIENT_BASE_URL+" from {path}").
                    and(Forward.to(CLIENT_BASE_URL))
                ).
                where("path").matches(".*").

It is trying to detect the existence of an asset deployed with the application (as a webjar). For example the resource path (file name) might be /webjars/web-client/6.1.31.LOCAL/js/app.c0344c23.js.

However when executed within the same Spring-boot(-ified) application the rewrite filter is not able to load such resources and fails with rewriting. It is the org.ocpsoft.rewrite.servlet.config.Resource#evaluateHttp that fails with return (event.getServletContext().getResource(file) != null).
When executing new ClassPathResource("META-INF/resources/webjars/web-client/6.1.31.LOCAL/js/app.c0344c23.js").getInputStream() at the same location, Spring's ClassPathResource is able to load the resource - so it is there at the right location. It just can't be loaded using the servlet context object used by the rewrite Resource class.

The Spring-boot setup for the filter is

@Bean
@Qualifier("client")
public ServletRegistrationBean clientServletRegistrationBean() {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();

    AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
    applicationContext.register(ClientViewerConfiguration.class);
    dispatcherServlet.setApplicationContext(applicationContext);

    ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/client/*");
    servletRegistrationBean.setName("client");

    return servletRegistrationBean;
}

@Bean
public FilterRegistrationBean rewriteFilterRegistrationBean(@Qualifier("client") ServletRegistrationBean clientServletRegistrationBean) {
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new RewriteFilter(), clientServletRegistrationBean);
    filterRegistrationBean.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE, DispatcherType.ERROR));

    return filterRegistrationBean;
}

The rewrite configuration provider is registered through a /META-INF/services/org.ocpsoft.rewrite.config.ConfigurationProvider file located in the classpath.

@chkal
Copy link
Member

chkal commented Apr 8, 2015

Thanks for reporting this. Could you perhaps use your debugger to check if the file value created in this line is correct?

String file = builder.build(event, context, Transpositions.encodePath());

And could you post the value of the file variable? I remember there are rules in regard to leading slashes for ServletContext.getResource().

@MartinAhrer
Copy link
Author

The value is /webjars/web-client/6.1.31.LOCAL/css/main-blue.ee89bcc6.css for example. So it has a leading /. I believe it must have that leading slash, otherwise getResource will throw an exception.

@chkal
Copy link
Member

chkal commented Apr 8, 2015

Yeah, your are correct. I just checked the javadocs:

http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContext.html#getResource(java.lang.String)

However, from my understanding getResource() should work fine here. Could you perhaps try to call ServletContext.getResource() from your application code just to check if it works or not. If not, this looks like a Spring Boot issue. The docs clearly state that META-INF/resources is supported.

@MartinAhrer
Copy link
Author

I have cross-posted that to stackoverflow http://stackoverflow.com/questions/29512824/ocpsoft-rewrite-is-not-able-to-detect-a-class-path-resource-in-a-spring-boot-app.

For now I have found a workaround:

class Resource extends HttpCondition implements Parameterized {

    private final ParameterizedPatternParser resource;

    public Resource(final String resource) {
        this.resource = new RegexParameterizedPatternParser(resource);
    }

    @Override
    public boolean evaluateHttp(HttpServletRewrite event, EvaluationContext context) {
        if (resource != null) {
            ParameterizedPatternBuilder builder = resource.getBuilder();
            if (builder.isParameterComplete(event, context)) {
                String file = builder.build(event, context, Transpositions.encodePath());
                try {
                    return new ClassPathResource("META-INF/resources" + file).exists();
                } catch (Exception e) {
                    log.debug("Invalid file format [{}]", file);
                }
            }
            // the default implementation does handle the !builder.isParameterComplete(event, context) here
        }
        return false;
    }

    @Override
    public Set<String> getRequiredParameterNames() {
        return resource.getRequiredParameterNames();
    }

    @Override
    public void setParameterStore(ParameterStore store) {
        resource.setParameterStore(store);
    }
}

@chkal
Copy link
Member

chkal commented Apr 8, 2015

Sure. Of cause you can create your own condition and implement it like this. That's fine.

However, I really think the default Resource class should work fine. Perhaps a Spring Boot / Jetty issue?

@MartinAhrer
Copy link
Author

I know for sure that my classic WAR deployment works with that Resource class. It was only required within the Spring Boot environment-

@chkal
Copy link
Member

chkal commented Apr 8, 2015

So a Spring Boot issue...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants