How does a web container know that a particular servlet hasn't been initialized. Is there any particular flag which shows the status of the servlet or anything else managed by the servlet
Container initial servlet during start up ( or restart ) one by one as mentioned in web.xml. You can also find if a servelt is initiated or destroyed by override init and destroy methods.
public class PrecompressedResourceServlet extends HttpServlet {
private static final Logger LOG = LoggerFactory
.getLogger(PrecompressedResourceServlet.class);
#Override
public void init() throws ServletException {
LOG.info("The PrecompressedResourceServlet initialized...");
super.init();
}
}
Related
Currently I am trying to get my script to run on a tomcat server by using the basic web container guidelines for spring-batch-boot from the documentation https://docs.spring.io/spring-batch/reference/html/configureJob.html
The script was working correctly as a jar file before modifications to the main class but when I try converting it to a servlet I am having issues with my #PostConstruct starting only on server startup. This code sets application.properties to spring.batch.job.enabled=false and has a controller of
#Controller
public class JobLauncherController {
#Autowired
JobLauncher jobLauncher;
#Autowired
Job job;
#RequestMapping("/jobLauncher.html")
public void handle() throws Exception{
jobLauncher.run(job, new JobParameters());
}
With The main Application to start the servlet for tomcat as
#SpringBootApplication
#EnableBatchProcessing
public class BatchApplication extends SpringBootServletInitializer{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(BatchApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(BatchApplication.class, args);
}
The problem is that my job uses custom item readers and writers that initializes it before running it using #PostConstruct. It runs the #PostConstruct at server startup which is what helps initialize the beans for writing.
My item readers/writers look like this
public class CustomReader extends ItemStreamSupport implements ItemReader<Acct>, ResourceAwareItemReaderItemStream<Acct> {
//basic autowiring
private int nextAcctIndex;
private List<Acct> acctsList = new ArrayList();
#PostConstruct
private void initialize() throws IOException {
//logic to parse files
acctsList = Collections.unmodifiableList(acctsList);
nextAcctIndex = 0;
}
#Override
public Acct read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
// System.out.println("Start Read");
Acct nextAcct = null;
if (nextAcctIndex < acctsList.size()) {
nextAcct = acctsList.get(nextAcctIndex);
nextAcctIndex++;
//System.out.println(nextAcct);
}
The BatchConfiguration calls everything like most examples as
#Bean public
IteamReader<Acct> CustomReader(){ return new CustomReader();}
My question is am I going about this the wrong way or is there a way to make it so the #PostConstruct is able to be called only when the Controller request for it?
you need to use
#BeforeStep
public void beforeStep(StepExecution stepExecution) {
init();
}
#PostConstruct is used to initialize once after applicationContext is loaded.
In your case you want to run this initialization every time job is running (you don't want data to be leaked across different jobs, right?)
Environment:
WildFly 9.0.1/9.0.2
Java EE 7 Full profile
Weld CDI environment.
Because of the number of requests I am expecting, I want to implement async request on top of the FacesServlet, and did this:
public class AsyncFacesServlet extends HttpServlet {
private static final long serialVersionUID = 111966573758921845L;
private FacesServlet delegate;
#Inject
private BeanManager beanManager;
#Inject
private ServletContext servletContext;
#Override
public void init(final ServletConfig servletConfig) throws ServletException {
delegate = new FacesServlet();
delegate.init(servletConfig);
}
#Override
public void destroy() {
delegate.destroy();
}
#Override
public ServletConfig getServletConfig() {
return delegate.getServletConfig();
}
#Override
public String getServletInfo() {
return delegate.getServletInfo();
}
#Override
public void service(final ServletRequest request, final ServletResponse response) throws ServletException, IOException {
final AsyncContext asyncContext = request.isAsyncStarted()
? request.getAsyncContext() : request.startAsync(request, response);
final Runnable runnable = () -> {
try {
delegate.service(request, response);
} catch (final IOException | ServletException ex) {
throw Throwables.propagate(ex);
}
};
asyncContext.start(runnable);
}
}
And then updated my web.xml as:
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>com.mycompany.service.faces.AsyncFacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
When I deploy, I get the following exceptions, which indicates that Weld was not correctly initialized inside the asynccontext.
SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-38) Error Rendering View[/login.xhtml]: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:708)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:95)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.get(ContextualInstanceStrategy.java:178)
at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:761)
at org.jboss.weld.el.AbstractWeldELResolver.lookup(AbstractWeldELResolver.java:107)
at org.jboss.weld.el.AbstractWeldELResolver.getValue(AbstractWeldELResolver.java:90)
at org.jboss.as.jsf.injection.weld.ForwardingELResolver.getValue(ForwardingELResolver.java:46)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:188)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
at com.sun.el.parser.AstIdentifier.getValue(AstIdentifier.java:116)
at com.sun.el.parser.AstValue.getBase(AstValue.java:151)
at com.sun.el.parser.AstValue.getValue(AstValue.java:200)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
at javax.faces.component.UIOutput.getValue(UIOutput.java:174)
at javax.faces.component.UIInput.getValue(UIInput.java:291)
at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:205)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:355)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:164)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:920)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1863)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:176)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:890)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1856)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:458)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:134)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
at com.mycompany.service.faces.servlet.AsyncFacesServlet.lambda$service$17(AsyncFacesServlet.java:61)
Whats happening is that, Weld is not properly initialized or context is not propagated to the async context execution.
How can I be able to propagate or recreate the weld context upon async-request call?
I'll prefix my answer with a note that there is an open CDI spec issue to make async behavior more portable, Specify that web scoped (request, session, application) beans are injectable in async servlets
What you can do, in a Weld specific way, is start the context. Apache DeltaSpike has some utilities that will make this container in-specific as well, http://deltaspike.apache.org/documentation/container-control.html#ContextControlUsage
If your runnable is a managed bean, you can use BoundRequestContext in weld to start a request context for that thread. More here. The downside is that its a new context, not a bridged context.
I am trying to create an UI component that allow the user to customize the timeout of sessions. So I created a servlet as below:
public class SessionTimeoutServlet extends AbstractBaseServlet {
private static final long serialVersionUID = 2567293974465204729L;
public static final String REQUEST_TIMEOUT_PARAMETR_NAME = "timeout";
private static final String TIMEOUT_TYPE_INIT_PARAMETER_NAME = "timeoutType";
private static final String WEB_TYPE_TIMEOUT = "web";
private static final String WEBSERVICE_TYPE_TIMEOUT = "webService";
#EJB(mappedName = SessionSettingsRemote.BEAN_NAME)
private SessionSettingsRemote sessionSettingsBean;
#PostConstruct
public void initTimeout() {
try {
String timeoutType = getServletContext().getInitParameter(TIMEOUT_TYPE_INIT_PARAMETER_NAME);
if (WEBSERVICE_TYPE_TIMEOUT.equals(timeoutType)) {
setCustomTimeout(sessionSettingsBean.getSessionSettingsDTO().getWebServiceSessionTimeoutInterval());
} else if (WEB_TYPE_TIMEOUT.equals(timeoutType)) {
setCustomTimeout(sessionSettingsBean.getSessionSettingsDTO().getWebSessionTimeoutInterval());
} else {
setCustomTimeout(30);
}
} catch (ApplicationException e) {
setCustomTimeout(30);
}
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int timeout = Integer.parseInt(request.getParameter(REQUEST_TIMEOUT_PARAMETR_NAME));
setCustomTimeout(timeout);
}
public static void setCustomTimeout(int customTimeout) {
SessionManagerListener.setCustomTimeout(customTimeout);
}
}
However, when I deploy this on GlassFish, I get below exception.
Caused by: java.lang.IllegalStateException: ServletConfig has not been initialized
at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:199)
at com.accedian.ems.uiapplication.server.servlets.SessionTimeoutServlet.initTimeout(SessionTimeoutServlet.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl$3.run(InjectionManagerImpl.java:766)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.invokeLifecycleMethod(InjectionManagerImpl.java:760)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:531)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:141)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:127)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:347)
at com.sun.enterprise.web.WebContainer.createServletInstance(WebContainer.java:991)
at com.sun.enterprise.web.WebModule.createServletInstance(WebModule.java:2130)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1404)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1381)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5732)
I have used getServletConfig() before getServletContext() but it was null. So why is my config and context are not properly set ?
Servlets predate managed beans and annotations and all the fancy stuff you see since Java EE 6. Previously, you have to explicitly implement a predefined abstract/template method in order to perform a task at a certain moment in the lifecycle.
For servlets, in order to hook on its initialization the same way you'd use #PostConstruct on a "normal" managed bean, you have to override the predefined GenericServlet#init() method.
#Override
public void init() {
// ...
}
The getServletContext() will be available there.
If you pay attention to the GenericServlet javadoc, you'll notice that there's also an init(ServletConfig). It's however strongly recommended to not use that method, but use init() instead. The default implementation of init(ServletConfig) namely takes care that the ServletContext is properly set. You'd have to mind calling super.init(config) to not make the same mistake. As a historical note, see that the canonical name of a #PostConstruct method as you see on managed beans, "init", is inherited from exactly this Servlet API.
In case you wonders, the #PreDestroy equivalent is the GenericServlet#destroy() method.
#Override
public void destroy() {
// ...
}
I have a simple spring boot app and I'm trying to get it up and running. The config consists of an app context ( applicationContext.xml) XML with a bunch of beans in it. I have a Spring application class:
#SpringBootApplication
#Configuration
#ImportResource("classpath:applicationContext.xml")
public class WebCheckApplication {
private static final Logger logger = Logger.getLogger(WebCheckApplication.class);
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(WebCheckApplication.class, args);
if (logger.isDebugEnabled()) {
logger.debug("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
logger.debug(beanName);
}
}
}
}
And I have a #WebListener class that grabs a few beans from the WebContext from within the ServletContext:
#WebListener
public class SystemPropertiesContextInitializer extends SysPropsAlertsFetcher implements ServletContextListener {
private static final Logger logger = Logger.getLogger(SystemPropertiesContextInitializer.class);
#Override
public void contextDestroyed(ServletContextEvent sce) {
//remove the SystemProperties and alert types map object from context
sce.getServletContext().removeAttribute(BaseAuthenticatedController.SYSPROPS_KEY);
sce.getServletContext().removeAttribute(BaseAuthenticatedController.ALERT_TYPES_MAP_KEY);
}
#Override
public void contextInitialized(ServletContextEvent sce) {
SysPropsDataAccess = (SystemPropertiesDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("SystemPropertiesDataAccess");
AlertsDataAccess = (AlertDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("AlertsDataAccess");
fetchObjects(sce.getServletContext());
}
}
When I attempt to start the app, I get the following error:
SEVERE: Exception sending context initialized event to listener instance of class web.SystemPropertiesContextInitializer
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:83)
at .web.SystemPropertiesContextInitializer.contextInitialized(SystemPropertiesContextInitializer.java:31)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4994)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5492)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
and it occurs at this line:
SysPropsDataAccess = (SystemPropertiesDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("SystemPropertiesDataAccess");
It looks like Spring isn't creating a WebApplicationContext.
Greater than or equal 1.3.0.RC1 use #ServletComponentScan
#ServletComponentScan // <-- This scans for EJB #WebFilter, #WebListener and #WebServlet
#SpringBootApplication
#ImportResource("classpath:applicationContext.xml")
public class WebCheckApplication {
Less than or equal 1.2.x use #Component to scan for listener
#Component // <-- This allows the component to be found by #ComponentScan inside of #SpringBootApplication
#WebListener
public class MojoSystemPropertiesContextInitializer extends MojoSysPropsAlertsFetcher implements ServletContextListener {
War Deploy extend SpringBootServletInitializer
public class WebCheckApplication extends SpringBootServletInitializer {
In 1.3.0.RC1 #ServletComponentScan was added so simply annotating your main application config should allow these to be picked up. Otherwise adding #Component to your ServletContextListener should work
This link is a discussion on how they currently handle #WebFilter how they decided to handle #WebFilter and they also discuss SpringBootServletInitializer and how this would pick process each item twice if both were to be used. Also links to the commits that implement the new feature.
https://github.com/spring-projects/spring-boot/issues/2290
If you intend to deploy your application as a war file you may also have your main configuration extend SpringBootServletInitializer
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html
All that was needed was to make the Application class extend SpringBootServletInitializer
I'm using Spring-Security 3.2.4 and Spring Boot 1.1.0 (and it's related dependencies versions 4.X).
I'm writing a web application that will be run in an embedded tomcat.
I'm trying to add two additional filters(not related to Spring security) that one of them will be invoked before the Spring-Security-FilterChainProxy and the other one will be invoked after the Spring-Security-FilterChainProxy.
My Spring-Security configuration files:
#Configuration
#EnableWebMvcSecurity
public class SecurityCtxConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("pass").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.usernameParameter("user").passwordParameter("password");
}
}
And the Main class (Application.class):
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
#Bean
RequestFilter beforeSpringSecurityFilter(){
return new RequestFilter();
}
#Bean
RequestFilter afterSpringSecurityFilter(){
return new RequestFilter();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And the Filter implementation:
public class RequestFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
Is there a way to controll the invocation order when taking in account the FilterChainProxy (that is beeing created by the WebSecurityConfigurerAdapter ?
To be percise, the required order is:
request-filter-1
Spring-Security FilterChain
request-filter-2
Thanks
Agree with everything stated by Dave Syer ;) but wished to add a Java Config example of using the FilterRegistrationBean.
In my situation, I was finding that my custom security filter (using Spring Security) was being fired twice for every request. Adding the FilterRegistrationBean config fixed this.
#Bean(name = "myFilter")
public MyAuthenticationFilter myAuthenticationFilter(final MyAuthenticationEntryPoint entryPoint) {
final MyAuthenticationFilter filter = new MyAuthenticationFilter();
filter.setEntryPoint(entryPoint);
return filter;
}
/**
* We do this to ensure our Filter is only loaded once into Application Context
*
*/
#Bean(name = "authenticationFilterRegistration")
public FilterRegistrationBean myAuthenticationFilterRegistration(final MyAuthenticationFilter filter) {
final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
(Regarding my specific issue of filter being registered twice in Application Context - Rather than using a FilterRegistrationBean, I also found re-implementing the MyAuthenticationFilter to inherit from OncePerRequestFilter instead of GenericFilterBean also worked. However, OncePerRequestFilter support is from Servlet 3.x upwards and since I was writing a public library, support from Servlet 2.x may be needed)
The FilterChainProxy use by Spring Security is not Ordered (if it was you could order all your filters). But you should be able to register it in a FilterRegistrationBean which is Ordered and register your other filters the same way. In the case of the security filter you can inject it by name into the registration bean. The others you can probably inject by calling a #Bean method.
At some point spring boot exposed the security filter as a property. This is now pretty easy to do.
In you application.yml:
spring:
security:
filter:
order: 20
And some filter you want to invoke after Spring Security does it's thing:
#Bean
public FilterRegistrationBean<Filter> afterAuthFilterRegistrationBean() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
//a filter that extends OncePerRequestFilter
AfterAuthFilter afterAuthFilter = new AfterAuthFilter();
registrationBean.setFilter(afterAuthFilter);
//this needs to be a number greater than than spring.security.filter.order
registrationBean.setOrder(30);
return registrationBean;
}
For a filter that is executed before Spring security, set the order to a number less than 20.
If you are using web.xml approaches, you can follow this:
https://stackoverflow.com/a/11929129/1542363
If you using Java config approaches, you can do this in WebSecurityConfigurerAdapter
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(your-request-filter-1, ChannelProcessingFilter.class);
http.addFilterAfter(your-request-filter-2, SwitchUserFilter.class);
}
Always check the library version you are using, and refer to the specific document for the correct order of the filter chains:
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#ns-custom-filters
Or, if you using AbstractSecurityWebApplicationInitializer, you can use the insertFilters or appendFilters.
public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
}
More info You can refer this:
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf-multipart