I want to restart a servlet (declared in web.xml, when JBoss is running) simply because its init-param points to a file which content has changed (i.e. providers.fac below has been modified).
If there is a way to reload the init-param without restarting the servlet, it will be good too.
I suppose I can modify the servlet to add a request param and function to restart itself ?
Is there any other option?
<servlet>
<servlet-name>coverage</servlet-name>
<servlet-class>coverageServlet</servlet-class>
<init-param>
<param-name>ConfigUrl</param-name>
<param-value>file:///C:/coverage/providers.fac</param-value>
</init-param>
<init-param>
<param-name>CacheDir</param-name>
<param-value>coverage</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Environment:
Servlet Api 2.4
JBoss 4.2
Spring Framework 2.5
If you are in jboss you can simply restart a servlet by altering the web.xml file if your servlet is exploded. On linux a touch would do.
Not sure what format your config file is but if you are trying to reload automatically a property configuration file I would have a look at the commons configuration lib that supports this out of the box(FileChangedReloadingStrategy)
If you are planning to restart your servlet automatically and many many times in a day/week you should make sure your permgen is good enough to handle the servlet reloads. There were instances where I had done this in production and burnt myself down with a lot of PermGen errors.
2 options:
Add an extra check on doGet() or doPost() which reloads the file when a certain request parameter is been set while an admin user is logged in and provide an admin screen which invokes that request.
Rewrite the servlet (or refactor the part to ServletContextListener) to store it in ServletContext instead of as an instance variable of the servlet and have some admin screen which reloads the file in ServletContext.
I would separate these concerns by pulling the file management out of the servlet and putting it into a JBoss JMX ServiceMBean. The MBean can take care of watching the file for changes and reloading when necessary, and can also expose the required operations [to the calling servlet]. This will allow you not to have to reload and re-init the servlet (or the WAR) which are fairly heavyweight operations.
I will invent a couple of operations for the FileManager:
public interface FileManagerMBean extends org.jboss.system.ServiceMBean {
public void setFileName(String fileName);
public void setCheckFrequency(long freq);
public String getCoverageData(......);
public String getProviderData(......);
}
The implementation might be (in the same package please :) )
public class FileManager extends org.jboss.system.ServiceMBeanSupport implements FileManagerMBean {
public void setFileName(String fileName) { .... }
public void setCheckFrequency(long freq) { .... }
public String getCoverageData(......) { /* impl */ }
public String getProviderData(......) { /* impl */ }
public void startService() throws Exception {
/* Start a file watcher thread */
}
public void stopService() throws Exception {
/* Stop the file watcher thread */
}
}
Your servlet might look like this:
// A ref to the MBean
FileManagerMBean fileMgr = null;
// The JMX MBean's ObjectName
ObjectName fileMgrOn = org.jboss.mx.util.ObjectNameFactory.create("portoalet.com:service=FileManager");
public void init() {
// Get the JBoss MBeanServer
MBeanServer server = org.jboss.mx.util.MBeanServerLocator.locateJBoss();
// Create an MBeanInvoker for the service
fileMgr = (FileManagerMBean)javax.management.MBeanServerInvocationHandler.newProxyInstance(server, fileMgrOn,FileManagerMBean.class, false);
}
Now you can use the fileMgr instance to make calls to your FileManager MBean, which should be thread safe unless you synchronize access to fileMgr.
I realize this looks a bit over-engineered, but you really should separate the functions of the servlet from the functions of managing the file.
Related
In https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html 11.1 there is an example:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
...
Then in chapter 11.4 there is another example but without the ac.refresh();
What benefit could refreshing the context immediately after its creation possibly have?
After calling refresh() it would be possible to get all configured contents from the ApplicationContext (beans, listeners, resources, etc.).
For instance, without refreshing the context any call to ac.getBean("myBean") would throw
java.lang.IllegalStateException:
BeanFactory not initialized or already closed - call 'refresh'
before accessing beans via the ApplicationContext
Usually in WebApplicationInitializer there is no need to get beans or other configured items, because its purpose is configuration of servlets and filters for the web application. That's why calling refresh is not necessary here.
I need to get some configuration and connect to external resources/objects/systems somewhere and store it in application scope.
I can see two ways to setup my application:
Overriding the init() in the existing servlets and required code there and keeping all constructed objects inside that same servlet.
Having some kind of an initialisation servlet and using its init() to do the work. Then storing created objects in ServletContext to share it with my other servlets.
Which out of above is better approach? Is there any better way to share objects between servlets? Calling them directly from one another or so...?
None of both is the better approach. Servlets are intended to listen on HTTP events (HTTP requests), not on deployment events (startup/shutdown).
CDI/EJB unavailable? Use ServletContextListener
#WebListener
public class Config implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// Do stuff during webapp's startup.
}
public void contextDestroyed(ServletContextEvent event) {
// Do stuff during webapp's shutdown.
}
}
If you're not on Servlet 3.0 yet and can't upgrade (it would be about time because Servlet 3.0 was introduced more than a decade ago), and thus can't use #WebListener annotation, then you need to manually register it in /WEB-INF/web.xml like below:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
To store and obtain objects in the application scope (so that all servlets can access them), use ServletContext#setAttribute() and #getAttribute().
Here's an example which lets the listener store itself in the application scope:
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("config", this);
// ...
}
and then obtain it in a servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
Config config = (Config) getServletContext().getAttribute("config");
// ...
}
It's also available in JSP EL by ${config}. So you could make it a simple bean as well.
CDI available? Use #Observes on ApplicationScoped.class
import jakarta.enterprise.context.ApplicationScoped; // And thus NOT e.g. jakarta.faces.bean.ApplicationScoped
#ApplicationScoped
public class Config {
public void init(#Observes #Initialized(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's startup.
}
public void destroy(#Observes #Destroyed(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #Inject. Make it if necessary also #Named so it's available via #{config} in EL as well.
Noted should be that this is new since CDI 1.1. If you're still on CDI 1.0 and can't upgrade, then pick another approach.
In case you're curious how to install CDI on a non-JEE server such as Tomcat, head to: How to install and use CDI on Tomcat?
EJB available? Consider #Startup#Singleton
#Startup
#Singleton
public class Config {
#PostConstruct
public void init() {
// Do stuff during webapp's startup.
}
#PreDestroy
public void destroy() {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #EJB. The difference with other approaches is that it's by default transactional and in case of #Singleton also read/write locked. So if you would ever need to inject a random EJB (e.g. #Stateless) into a #WebListener or an #ApplicationScoped then you could basically as good merge both into a single #Startup #Singleton.
See also:
How to run a background task in a servlet based web application?
ServletContainerInitializer vs ServletContextListener
How do I force an application-scoped bean to instantiate at application startup?
I have an app built with Jersey.I need to do some initialization on startup of the webapp/war in the Tomcat 7 container by running an application specific login/code.
What is the best way to do this with Jersey ? I have used ContextListener with contextInitialized()before in a Servlet environment. I need to make sure the Jersey resources are loaded before I make this call.
Not sure what you mean by "Jersey resources are loaded before", but if you want to really plug in into Jersey init process.. Jersey has several "monitoring" plugin points (not widely advertised or documented) and what I'm going to describe is being called after initialization of AbstractResourceModel - so right after app startup.
Try this:
#Provider
public class Listener implements AbstractResourceModelListener {
#Override
public void onLoaded(AbstractResourceModelContext modelContext) {
System.out.println("##### resource model initiated");
}
}
It should happen only once per app lifecycle, I'm not very sure about reloading, but you don't need to bother by it if you are not using that feature (anyway, you should put some check there to avoid multiple invocation if could cause some issues).
For Jersey 2.x you can do the following:
#Provider
private static class MyFeature implements Feature {
#Override
public boolean configure(FeatureContext context) {
//code goes here
return true;
}
}
I am converting a 6 year old application to Seam 2.2.
The application is used to run in java 1.4 and weblogic 8.
It only uses jsp and servlet.
In one servlet I use:
public void doGet (HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException
{
//...
ServletOutputStream out = = res.getOutputStream();
// displaying a lot of messages
// after each println() I do a flush()
out.println("lots of messages.....");
out.flush();
out.close();
//...
}
When running the application the messages were immediately seen in the browser.
When I run this using Seam 2.2 in Weblogic 10 and Java 1.6 the messages are not immediately seen in the browser.
Only when the servlet is finished running.
Can I change something to fix this?
I do not want to change/convert the servlet into a Seam component. The servlet is running fine. The only thing is the flushing of messages to the browser window which only happens after the servlet has stopped running.
Could it be that the reason is that the servlet now goes through the Seam filter:
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The reason is probably that the request goes through the SeamFilter, as you supposed.
I think it's not the SeamFilter itself that buffer the data stream from your servlet but the Ajax4Jsf filter that is invoked in the filter chain.
If you have RichFaces in the classpath there is a seam component that registers the Ajax4jsf filter in the chain. Namely, the Seam component is org.jboss.seam.web.ajax4jsfFilter.
If you don't need RichFaces try removing it from the classpath. If you need it, I suggest that you override org.jboss.seam.web.ajax4jsfFilter in order to skip the Ajax4Jsf filter for requests directed to your servlet.
Another possible solution is converting your servlet in a filter as a Seam component (see #Filter annotation) and positioning it at the beginning of the chain with the around attribute. Something like:
#Name("FormerServlet")
#Scope(STATELESS)
#BypassInterceptors
#Filter(around = "org.jboss.seam.web.ajax4jsfFilterInstantiator")
public class FormerServletFilter implements Filter
{
protected void init(FilterConfig filterConfig) throws Exception
{
}
protected void doDestroy()
{
}
/**
* Performs the filtering for a request.
*/
protected void doFilter(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain chain) throws Exception
{
if (thisRequestShoudBeManagedByMyServlet(request) )
{
// do here what you previously did in the servlet
} else
{
// go ahead with the Seam lifecycle
chain.doFilter(request, response);
}
}
You're running a servlet - there's nothing to do with Seam here. I suspect you need to re-evaluate your design, as there's not really an exact translation from servlet to Seam structure.
I need to get some configuration and connect to external resources/objects/systems somewhere and store it in application scope.
I can see two ways to setup my application:
Overriding the init() in the existing servlets and required code there and keeping all constructed objects inside that same servlet.
Having some kind of an initialisation servlet and using its init() to do the work. Then storing created objects in ServletContext to share it with my other servlets.
Which out of above is better approach? Is there any better way to share objects between servlets? Calling them directly from one another or so...?
None of both is the better approach. Servlets are intended to listen on HTTP events (HTTP requests), not on deployment events (startup/shutdown).
CDI/EJB unavailable? Use ServletContextListener
#WebListener
public class Config implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// Do stuff during webapp's startup.
}
public void contextDestroyed(ServletContextEvent event) {
// Do stuff during webapp's shutdown.
}
}
If you're not on Servlet 3.0 yet and can't upgrade (it would be about time because Servlet 3.0 was introduced more than a decade ago), and thus can't use #WebListener annotation, then you need to manually register it in /WEB-INF/web.xml like below:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
To store and obtain objects in the application scope (so that all servlets can access them), use ServletContext#setAttribute() and #getAttribute().
Here's an example which lets the listener store itself in the application scope:
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("config", this);
// ...
}
and then obtain it in a servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
Config config = (Config) getServletContext().getAttribute("config");
// ...
}
It's also available in JSP EL by ${config}. So you could make it a simple bean as well.
CDI available? Use #Observes on ApplicationScoped.class
import jakarta.enterprise.context.ApplicationScoped; // And thus NOT e.g. jakarta.faces.bean.ApplicationScoped
#ApplicationScoped
public class Config {
public void init(#Observes #Initialized(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's startup.
}
public void destroy(#Observes #Destroyed(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #Inject. Make it if necessary also #Named so it's available via #{config} in EL as well.
Noted should be that this is new since CDI 1.1. If you're still on CDI 1.0 and can't upgrade, then pick another approach.
In case you're curious how to install CDI on a non-JEE server such as Tomcat, head to: How to install and use CDI on Tomcat?
EJB available? Consider #Startup#Singleton
#Startup
#Singleton
public class Config {
#PostConstruct
public void init() {
// Do stuff during webapp's startup.
}
#PreDestroy
public void destroy() {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #EJB. The difference with other approaches is that it's by default transactional and in case of #Singleton also read/write locked. So if you would ever need to inject a random EJB (e.g. #Stateless) into a #WebListener or an #ApplicationScoped then you could basically as good merge both into a single #Startup #Singleton.
See also:
How to run a background task in a servlet based web application?
ServletContainerInitializer vs ServletContextListener
How do I force an application-scoped bean to instantiate at application startup?