Is it possible for TestContainer to receive data from ServletContext as in the following case?
public class LinkResourceTest extends JerseyTest {
#Override
protected Application configure() {
ResourceConfig config = new ResourceConfig(LinkResource.class);
config.register(StatusResponseFilter.class);
config.register(JacksonFeature.class);
config.register(MultiPartFeature.class);
config.register(ExceptionMapperFeature.class);
config.register(JacksonContextResolver.class);
config.register(DatabaseFeature.class);
return config;
}
#Override
protected void configureClient(ClientConfig config) {
config.register(MultiPartFeature.class);
}
}
The config.register(DatabaseFeature.class); line makes trouble because DatabaseFeature needs a ServletContext in the constructor, which I have for production.
public class DatabaseFeature implements Feature {
private ServletContext servletContext;
public DatabaseFeature(#Context ServletContext servletContext) {
this.servletContext = servletContext;
}
#Override
public boolean configure(FeatureContext context) {
context.register(new DatabaseBinding(servletContext));
return true;
}
}
Related
I am building a REST API into an existing Spring Java application and I am not sure how to pass the Bean to the Rest Controller from the Main part of the app.
I would like to be able to have the Bean IDao created with its database instance passed into the UserController so it can be used as shown below.
As is, it is not able to autowire the Bean into the UserController. If I change the ComponentScan to include the main package it will autowire but not without ending up in and infinite Bean creation loop. What am I doing wrong?
package com.app.main;
public class App {
private static AnnotationConfigApplicationContext ctx;
public static void main(String[] args) throws Exception {
ctx = new AnnotationConfigApplicationContext(RestApiConfig.class);
}
}
package com.app.main;
#Configuration
public class RestApiConfig {
#Bean
public IDao<User> userDao(Database database) {
return new DatabaseDao<>(database, User.class);
}
#Bean
public Database database() {
return new Database();
}
#Bean
public RestApi restApi(IDao<User> userDao) {
return new RestApi(userDao);
}
package com.app.rest;
public class RestApi {
private final int PORT = 8080;
private final IDao<User> userDao;
public RestApi( IDao<User> userDao) {
this.userDao = userDao;
run();
}
public void run() {
String contextPath = "/api";
String webappDir = new File("src/main/webapp").getAbsolutePath();
Tomcat tomcat = new Tomcat(); // Tomcat 9.x.x
tomcat.setPort(PORT);
tomcat.getConnector(); // Trigger the creation of the default connector
Context context = tomcat.addWebapp(contextPath, webappDir);
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
tomcat.getServer().await();
}
}
package com.app.rest;
#Configuration
#EnableWebMvc
#ComponentScan({"com.app.rest"})
public class RestApiServletConfig {
}
package com.app.rest;
public class RestApiServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ RestApiServletConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[]{ "/" };
}
}
package com.app.rest;
#RestController
public class UserController {
private final IDao<User> repository;
UserController(IDao<User> repository) {
this.repository = repository;
}
#GetMapping("/users/{id}")
public User userById(#PathVariable Long id) {
return repository.get(id);
}
}
I have a request dumper filter that I want to activate/deactivate at runtime (using a custom actuator endpoint). However I cannot find a way to do so without restarting the app. My current solution does just that:
#Configuration
public class AppConfigs {
#Value("${request.dumper.active:false}")
private Boolean dumpActive;
#Bean
public FilterRegistrationBean requestDumperFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter requestDumperFilter = new RequestDumperFilter();
registration.setFilter(requestDumperFilter);
registration.addUrlPatterns("/*");
registration.setEnabled(dumpActive);
return registration;
}
Now I want to use something like that:
#Component
public class RequestdumperEndpoint implements Endpoint<Boolean > {
#Autowired
private RequestDumperFilter requestDumperFilter;
public String getId() {
return "requestdumper";
}
public Boolean invoke() {
return requestDumperFilter.isEnabled();
}
public Boolean setEnabled(Boolean enabled) {
return requestDumperFilter.setEnabled(enabled);
}
But obviously there are not isEnabled and setEnabled methods on a Filter.
Any ideas how I might be able to get what I need?
First add your filter using as a bean so you can hook into it:
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Value("${request.dumper.active:false}")
private Boolean dumpActive;
#Bean
private MyRequestDumperFilter myRequestDumperFilter() {
MyRequestDumperFilter filter = new MyRequestDumperFilter();
filter.setEnabled(dumpActive);
return filter;
}
#Override
protected String[] getServletMappings() {
//..
return new String[0];
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{myRequestDumperFilter()};
}
#Override
protected Class<?>[] getRootConfigClasses() {
//..
return new Class<?>[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
//..
return new Class<?>[0];
}
}
You filter will then look something like :
public class MyRequestDumperFilter extends RequestDumperFilter{
private Boolean enabled;
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Boolean getEnabled() {
return enabled;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (enabled) {
super.doFilter(request, response, chain);
}
else {
chain.doFilter(request,response);
}
}
}
So I have looked around and everywhere says that I need to check my configuration but what doesn't make sense to me is that my app will run on a different computer but the one I use for development. Just to provide some context, this app is purely restful with token authentication. Here's what my config looks like:
Security Init:
#Order(1)
public class SecurityWebappInitializer extends AbstractSecurityWebApplicationInitializer
{
}
App Init:
#Order(2)
public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
#Override
protected Class<?>[] getRootConfigClasses()
{
return new Class[]{RootConfiguration.class, SecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[]{WebConfiguration.class};
}
#Override
protected String[] getServletMappings()
{
return new String[]{"/", "/rest/*"};
}
#Override
protected Filter[] getServletFilters()
{
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[] {characterEncodingFilter};
}
}
SecurityConfig:
#EnableWebSecurity
#EnableGlobalMethodSecurity(jsr250Enabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private NoOpAuthProvider noOpAuthenticationProvider;
#Autowired
private TokenFilter tokenFilter;
public SecurityConfig()
{
super(true);
}
#Override
public void configure(WebSecurity web) throws Exception
{
web
.ignoring()
.antMatchers("/rest/authentication/login")
.antMatchers("/services/**")
.antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("**").hasRole("RUN").and()
.addFilterAfter(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().and()
.logout();
}
#Bean
public AuthenticationManager authenticationManager() throws Exception
{
List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>();
authenticationProviders.add(noOpAuthenticationProvider);
return new ProviderManager(authenticationProviders);
}
}
WebConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.example.tinker.web")
public class WebConfiguration extends WebMvcConfigurerAdapter
{
#Autowired
private PrincipalRetrievalService principalRetrievalService;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/resources/**").addResourceLocations("resources/").setCachePeriod(31556926);
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers)
{
argumentResolvers.add(new WebArgumentResolver(principalRetrievalService));
super.addArgumentResolvers(argumentResolvers);
}
}
Any idea what would be causing my problems?
There is no need to implement AbstractSecurityWebApplicationInitializer.
Security is initialized via ApplicationInitializer/RootConfiguration/#ComponentScan/SecurityConfig. Also there si no need to add SecurityConfig in getRootConfigClasses.
I'm using Apache Tomcat 7.0.54 and Spring MVC 4.0.1 and trying to configure DispatcherServlet with Java:
I've written the config class:
public class AppInitializer extends AbstractDispatcherServletInitializer{
#Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocation("/WEB-INF/her-servlet.xml");
return context;
}
#Override
protected String[] getServletMappings() {
return new String[] {"*.her"};
}
#Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
and it doesn't work. But if I write the follwoing:
public class AppInitializer implements WebApplicationInitializer{
#Override
public void onStartup(ServletContext sc) throws ServletException {
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocation("/WEB-INF/her-servlet.xml");
ServletRegistration.Dynamic registration = sc.addServlet("her", new DispatcherServlet(context));
registration.setLoadOnStartup(1);
registration.addMapping("*.her");
}
}
It'll work fine. I don't understand the problem. Could you help me to solve?
I cannot seem to get simple Spring application to work with JavaConfig.
public class WebApp extends AbstractAnnotationConfigDispatcherServletInitializer {
private static final Logger logger = Logger.getLogger(WebApp.class);
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ WebAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[]{ "/" };
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
logger.debug("onStartup");
super.onStartup(servletContext);//MUST HAVE
servletContext.setInitParameter("defaultHtmlEscape", "true");
}
#Configuration
#EnableWebMvc
#ComponentScan("com.doge.controller")
public static class WebAppConfig extends WebMvcConfigurerAdapter {
}
}
And controller:
package com.doge.controller;
#RestController
public class HelloController {
#RequestMapping("/")
public String sayHello() {
System.out.println("something");
return "index";
}
}
I always get 404 on "localhost:8080/Build" nor "localhost:8080".
Nothing is ever logged nor printed, just "INFO: Server startup in 538 ms".
There are few options of initialize Spring web application. The easiest is like below:
public class SpringAnnotationWebInitializer extends AbstractContextLoaderInitializer {
#Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext applicationContext =
new AnnotationConfigWebApplicationContext();
applicationContext.register(WebAppConfig.class);
return applicationContext;
}
}
Other options can be found here: http://www.kubrynski.com/2014/01/understanding-spring-web-initialization.html