Support Velocity toolbox configurations from jar
Create an EmbeddedVelocityToolboxView which supports loading toolbox.xml files from the application classpath as well as the ServletContext. The VelocityAutoConfiguration class has been updated to use the new view. This change allows the `spring.velocity.toolbox-config-location` property to work with embedded servlet containers. Fixes gh-2912pull/3885/head
parent
1cfc6f64f6
commit
cca0b76ac8
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.web.servlet.view.velocity;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.apache.velocity.VelocityContext;
|
||||||
|
import org.apache.velocity.context.Context;
|
||||||
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.web.servlet.view.velocity.VelocityToolboxView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extended version of {@link VelocityToolboxView} that can load toolbox locations from
|
||||||
|
* the classpath as well as the servlet context. This is useful when run an embedded web
|
||||||
|
* server.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @since 1.2.5
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public class EmbeddedVelocityToolboxView extends VelocityToolboxView {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Context createVelocityContext(Map<String, Object> model,
|
||||||
|
HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||||
|
org.apache.velocity.tools.view.context.ChainedContext context = new org.apache.velocity.tools.view.context.ChainedContext(
|
||||||
|
new VelocityContext(model), getVelocityEngine(), request, response,
|
||||||
|
getServletContext());
|
||||||
|
if (getToolboxConfigLocation() != null) {
|
||||||
|
setContextToolbox(context);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void setContextToolbox(
|
||||||
|
org.apache.velocity.tools.view.context.ChainedContext context) {
|
||||||
|
org.apache.velocity.tools.view.ToolboxManager toolboxManager = org.apache.velocity.tools.view.servlet.ServletToolboxManager
|
||||||
|
.getInstance(getToolboxConfigFileAwareServletContext(),
|
||||||
|
getToolboxConfigLocation());
|
||||||
|
Map<String, Object> toolboxContext = toolboxManager.getToolbox(context);
|
||||||
|
context.setToolbox(toolboxContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServletContext getToolboxConfigFileAwareServletContext() {
|
||||||
|
ProxyFactory factory = new ProxyFactory();
|
||||||
|
factory.setTarget(getServletContext());
|
||||||
|
factory.addAdvice(new GetResourceMethodInterceptor(getToolboxConfigLocation()));
|
||||||
|
return (ServletContext) factory.getProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link MethodInterceptor} to allow the calls to getResourceAsStream() to resolve
|
||||||
|
* the toolboxFile from the classpath.
|
||||||
|
*/
|
||||||
|
private static class GetResourceMethodInterceptor implements MethodInterceptor {
|
||||||
|
|
||||||
|
private final String toolboxFile;
|
||||||
|
|
||||||
|
public GetResourceMethodInterceptor(String toolboxFile) {
|
||||||
|
if (toolboxFile != null && !toolboxFile.startsWith("/")) {
|
||||||
|
toolboxFile = "/" + toolboxFile;
|
||||||
|
}
|
||||||
|
this.toolboxFile = toolboxFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||||
|
if (invocation.getMethod().getName().equals("getResourceAsStream")
|
||||||
|
&& invocation.getArguments()[0].equals(this.toolboxFile)) {
|
||||||
|
InputStream inputStream = (InputStream) invocation.proceed();
|
||||||
|
if (inputStream == null) {
|
||||||
|
try {
|
||||||
|
inputStream = new ClassPathResource(this.toolboxFile, Thread
|
||||||
|
.currentThread().getContextClassLoader())
|
||||||
|
.getInputStream();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inputStream;
|
||||||
|
}
|
||||||
|
return invocation.proceed();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.web.servlet.view.velocity;
|
||||||
|
|
||||||
|
import org.springframework.web.servlet.view.velocity.VelocityView;
|
||||||
|
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extended version of {@link VelocityViewResolver} that uses
|
||||||
|
* {@link EmbeddedVelocityToolboxView} when the {@link #setToolboxConfigLocation(String)
|
||||||
|
* toolboxConfigLocation} is set.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @since 1.2.5
|
||||||
|
*/
|
||||||
|
public class EmbeddedVelocityViewResolver extends VelocityViewResolver {
|
||||||
|
|
||||||
|
private String toolboxConfigLocation;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initApplicationContext() {
|
||||||
|
if (this.toolboxConfigLocation != null) {
|
||||||
|
if (VelocityView.class.equals(getViewClass())) {
|
||||||
|
this.logger.info("Using EmbeddedVelocityToolboxView instead of "
|
||||||
|
+ "default VelocityView due to specified toolboxConfigLocation");
|
||||||
|
setViewClass(EmbeddedVelocityToolboxView.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.initApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setToolboxConfigLocation(String toolboxConfigLocation) {
|
||||||
|
super.setToolboxConfigLocation(toolboxConfigLocation);
|
||||||
|
this.toolboxConfigLocation = toolboxConfigLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author pwebb
|
||||||
|
*/
|
||||||
|
package org.springframework.boot.web.servlet.view.velocity;
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.web.servlet.view.velocity;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.struts.mock.MockHttpServletRequest;
|
||||||
|
import org.apache.struts.mock.MockHttpServletResponse;
|
||||||
|
import org.apache.struts.mock.MockServletContext;
|
||||||
|
import org.apache.velocity.tools.ToolContext;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
|
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link EmbeddedVelocityToolboxView}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class EmbeddedVelocityToolboxViewTests {
|
||||||
|
|
||||||
|
private static final String PATH = EmbeddedVelocityToolboxViewTests.class
|
||||||
|
.getPackage().getName().replace(".", "/");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadsContextFromClassPath() throws Exception {
|
||||||
|
ToolContext context = getToolContext(PATH + "/toolbox.xml");
|
||||||
|
assertThat(context.getToolbox().keySet(), contains("math"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadsWithoutConfig() throws Exception {
|
||||||
|
ToolContext context = getToolContext(null);
|
||||||
|
assertThat(context, notNullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ToolContext getToolContext(String toolboxConfigLocation) throws Exception {
|
||||||
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||||
|
context.setServletContext(new MockServletContext());
|
||||||
|
context.register(Config.class);
|
||||||
|
context.refresh();
|
||||||
|
EmbeddedVelocityToolboxView view = context
|
||||||
|
.getBean(EmbeddedVelocityToolboxView.class);
|
||||||
|
view.setToolboxConfigLocation(toolboxConfigLocation);
|
||||||
|
Map<String, Object> model = new LinkedHashMap<String, Object>();
|
||||||
|
HttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
HttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
ToolContext toolContext = (ToolContext) view.createVelocityContext(model,
|
||||||
|
request, response);
|
||||||
|
context.close();
|
||||||
|
return toolContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddedVelocityToolboxView view() {
|
||||||
|
EmbeddedVelocityToolboxView view = new EmbeddedVelocityToolboxView();
|
||||||
|
view.setUrl("http://example.com");
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public VelocityConfigurer velocityConfigurer() {
|
||||||
|
return new VelocityConfigurer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.web.servlet.view.velocity;
|
||||||
|
|
||||||
|
import org.apache.struts.mock.MockServletContext;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
|
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
|
||||||
|
import org.springframework.web.servlet.view.velocity.VelocityView;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link EmbeddedVelocityViewResolver}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class EmbeddedVelocityViewResolverTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void standardViewWithoutToolboxConfig() throws Exception {
|
||||||
|
ApplicationContext context = loadContext(WithoutToolboxConfig.class);
|
||||||
|
EmbeddedVelocityViewResolver resolver = context
|
||||||
|
.getBean(EmbeddedVelocityViewResolver.class);
|
||||||
|
Object viewClass = ReflectionTestUtils.getField(resolver, "viewClass");
|
||||||
|
assertEquals(VelocityView.class, viewClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void embeddedViewWithToolboxConfig() throws Exception {
|
||||||
|
ApplicationContext context = loadContext(WithToolboxConfig.class);
|
||||||
|
EmbeddedVelocityViewResolver resolver = context
|
||||||
|
.getBean(EmbeddedVelocityViewResolver.class);
|
||||||
|
Object viewClass = ReflectionTestUtils.getField(resolver, "viewClass");
|
||||||
|
assertEquals(EmbeddedVelocityToolboxView.class, viewClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApplicationContext loadContext(Class<?> config) {
|
||||||
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||||
|
context.setServletContext(new MockServletContext());
|
||||||
|
context.register(config);
|
||||||
|
context.refresh();
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class WithoutToolboxConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddedVelocityViewResolver resolver() {
|
||||||
|
return new EmbeddedVelocityViewResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public VelocityConfigurer velocityConfigurer() {
|
||||||
|
return new VelocityConfigurer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class WithToolboxConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddedVelocityViewResolver resolver() {
|
||||||
|
EmbeddedVelocityViewResolver resolver = new EmbeddedVelocityViewResolver();
|
||||||
|
resolver.setToolboxConfigLocation("/toolbox.xml");
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public VelocityConfigurer velocityConfigurer() {
|
||||||
|
return new VelocityConfigurer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<toolbox>
|
||||||
|
<tool>
|
||||||
|
<key>math</key>
|
||||||
|
<scope>application</scope>
|
||||||
|
<class>org.apache.velocity.tools.generic.MathTool</class>
|
||||||
|
</tool>
|
||||||
|
</toolbox>
|
Loading…
Reference in New Issue