I want to get servletContext in a Java class to read a file from WEB-INF directory. I extended my class with HttpServlet and tried to get the context as in the below code, but the servlet config is returned as null. I don't use any jsp or controller. My intention is to read a file directly placed in the WEB-INF directory from a Java class. Please let me know how I can get not null servletConfig / servletContext in the class:
ServletConfig config = getServletConfig();
ServletContext context = config.getServletContext();
InputStream resourceContent = context.getResourceAsStream("/WEB-INF/samplefile");
Trap for young players. If you override the
public void init(ServletConfig config)
method, you must call
super.init(config);
inside the method. Otherwise the superclass sees the context as null. It's mentioned in the Javadoc:
When overriding this form of the method, call super.init(config).
NB You can get the context directly via getServletContext(). There's no need to go via getServletConfig().
I had this same issue and it turned out the web.xml file was created in the wrong place and was not being loaded by the container.
It needs to be created in the root of the WEB-INF folder. Ideally let Eclipse do this for you when you create the project.
Related
the difference between ContextLoader and ContextLoaderListenerI am not understanding the difference. I have tried to search on google but I am not able to search. Please help me on this.
Performs the actual initialization work for the root application context. Called by ContextLoaderListener and ContextLoaderServlet.
Regards a "contextClass" parameter at the web.xml context-param level, falling back to the default context class (XmlWebApplicationContext) if not found. With the default ContextLoader, a context class needs to implement ConfigurableWebApplicationContext.
Passes a "contextConfigLocation" context-param to the context instance, parsing it into potentially multiple file paths which can be separated by any number of commas and spaces, like "applicationContext1.xml, applicationContext2.xml". If not explicitly specified, the context implementation is supposed to use a default location (with XmlWebApplicationContext: `
Note: In case of multiple config locations, later bean definitions
will override ones defined in earlier loaded files, at least when
using one of Spring's default ApplicationContext implementations. This
can be leveraged to deliberately override certain bean definitions via
an extra XML file.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/context/ContextLoader.html
I am absolutely confused with application context in spring. If i use spring (simple spring) create a beans.xml and then invoke Application context from (for example) main() method.
ApplicationContext context = new FileSystemXmlApplicationContext
("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");
all works well. But I don't understand if i move file on directory above or in another directory(for example) it will be ok?
in spring-mvc there is context for each DispatcherServlet which i create and where i specify some beans, there is common context for all servlets, how to specify this? in web.xml?
in general, please explain me this moment (I read spring in action, i undesrstand almost all, but these tricky moment isn't shown there.
From FileSystemXmlApplicationContext java doc:
Standalone XML application context, taking the context definition files from the file system or from URLs, interpreting plain paths as relative file system locations (e.g. "mydir/myfile.txt"). Useful for test harnesses as well as for standalone environments.
The key words here are context definition files, so you can pass paths to as many xml-files, as you want. Besides that, you can create an application context and pass it to the new one as a parent:
FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent)
Thus you can easily create the needed hierarchy of contexts.
ApplicationContext parentContext = new FileSystemXmlApplicationContext
("C:/some/path/ParentBeans.xml");
ApplicationContext childContext = new FileSystemXmlApplicationContext
(new String[]{"C:/some/path/ChildBeans1.xml", "C:/some/path/ChildBeans2.xml"}, parentContext);
if i move file on directory above all in another directory(for example) it will be ok?
As long as your path to file is correct and reachable - it's Ok.
Not sure if this question was previously asked, but I cannot seem to find the answer.
Where does one store the properties when loaded in a webapp.
I have a web application which has settings to allow system administrators via a user interface to change settings in the app.
For example the app allows only selected user groups to be able to go a certain page.
I wanted to allow system admins to go in and set the user groups that can go to the above mentioned page, and then change it at a later date.
The issue I'm facing is that once loaded the properties file, where do I store the data rather than continuously loading the properties file each time a user goes into the page.
I'm probably not getting the full concept of how properties are used so any guidance would be greatly appreciated.
Just make sure I can read the user groups in, can change the user groups without reloading the class/app and allow it to be thread safe and quick without two different threads having two different properties because we are using a load balanced environment. With a content share which is where the properties files are stored and accessed (not having any issues with this so not looking for help with where to store the properties file).
Any help greatly appreciated.
EDIT 1
The application runs on a clustered environment which means that other application servers could potentially have different values due to multiple ServletContexts.
Register ServletContextListener to load Init parameters and properties at server start-up.
Load properties at single time and make it visible to other classes statically or you can store it in application context as well to access it from anywhere such as JSP and Servlet.
Note: Make the properties file location configurable in web.xml rather than hard-coding it in Java class. You can retrieve the properties file location as system environment variable as well.
Sample code:
public class AppServletContextListener implements ServletContextListener {
private static Properties properties;
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
String cfgfile = servletContextEvent.getServletContext().getInitParameter("config_file");
properties.load(new FileInputStream(cfgfile));
// store it in application scope as well
servletContextEvent.getServletContext().setAttribute("prop",properties);
}
public static Properties getProperties(){
return properties;
}
}
web.xml:
<listener>
<listener-class>com.x.y.z.AppServletContextListener</listener-class>
</listener>
<context-param>
<param-name>config_file</param-name>
<param-value>config_file_location</param-value>
</context-param>
Please have a look at my another post that is asked in the same context:
Retrieve Init parameters outside servlet
EDIT
If you are changing the properties at run-time then don't use Servlet context according to the ServletContext javadoc:
In the case of a web application marked "distributed" in its deployment descriptor, there will be one context instance for each virtual machine. In this situation, the context cannot be used as a location to share global information (because the information won't be truly global). Use an external resource like a database instead.
The Servlet specification also states in "SRV.4.4.1 Context Attributes in a Distributed Container":
Context attributes are local to the JVM in which they were created. This prevents ServletContext attributes from being a shared memory store in a distributed container. When information needs to be shared between servlets running in a distributed environment, the information should be placed into a session (See Chapter SRV.7, “Sessions”), stored in a database, or set in an Enterprise JavaBeansTM component.
In that case you can try with some third party cache that works in distributed environment as well as mentioned below:
EHCache
Infinispan
OR store all the properties in the database.
The Servlet container offers the concept of Contexts. I find it helpful to consider a Context as a useful box for storing things in, and operates like a Map.
There are a number of different Contexts available to a Java Webapp, and they differ in scope (that is, how long the data held in the context lasts for, and where it can be accessed from). There is the Page Context, the Session Context and the Servlet Context
The Page Context has the narrowest scope, and is only lasts as long as a single page takes to process.
The Session Context has a greater scope, and lasts as long as single user session, i.e. multiple requests from a browser. It is useful if your webapp requires authentication - information about the authenticated user will be stored in the Session Context.
The Servlet Context is effectively global and is always available to the whole application. This is where I would recommend storing configuration properties which effect the functioning of the application.
In a Servlet, you may access the Servlet Context like this:
ServletContext context = request.getSession().getServletContext();
You can store something in the context like this:
context.setAttribute("key", object);
Where key is a String - the name of the attribute.
You may retrieve it again like this:
object = context.getAttribute("key");
Which returns an Object. You may cast it to whatever type it really is. If you want to, you can store a Properties object in it:
Properties props = //... get the properties from file
context.setAttribute("props", props);
And then retrieve them:
Properties props = (Properties) context.getAttribute("props");
Or you can store the individual properties as separate attributes in the context.
All contexts are accessed the same way.
You could go with the classic singleton pattern, where you have a single ApplicationProperties class which holds globally valid values for your application backed by a property file so no part of your application has to care about how to store the properties. Pseudo code:
public class ApplicationProperties {
private static final String PATH = "app.properties";
private static final ApplicationProperties INSTANCE = new ApplicationProperties();
private String userGroup;
private ApplicationProperties() {
// Load properties from PATH and populate fields.
this.userGroup = ...
}
public static ApplicationProperties getInstance() {
return INSTANCE;
}
public String getUserGroup() {
return this.userGroup;
}
public String setUserGroup(String userGroup) {
// Save to property file to persist.
this.userGroup = userGroup;
}
}
You just have to synchronize access to the fields that no two threads overwrite properties and create race conditions.
I'm working on a Spring MVC/Webflow Application (version 3.2) and trying to get exception handling working where I can output a custom exception message to a logfile and error.jsp. The problem I'm having is that the Exception Handler is not getting fired. I've created the following class and annotated it "#ControllerAdvice" and put it into the same package as my controller that is throwing the exception:
#ControllerAdvice
public class MyCustomExceptionController {
#ExceptionHandler(MyCustomException.class)
public ModelAndView handleMyException(MyCustomException ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/error/error");
modelAndView.addObject("errorId", ex.getErrorId());
modelAndView.addObject("message", ex.getErrorMessage());
return modelAndView;
}
}
and added the following to the mvc-config File:
<mvc:annotation-driven/>
And included the following in my app-config File:
<context:component-scan base-package="package containing my controllers and MyCustomExceptionController">
<context:include-filter type="annotation"
expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>
Any ideas why this isn't working?
The <mvc:annotation-driven/> element implicitly registers a ExceptionHandlerExceptionResolver bean. This class has a initExceptionHandlerAdviceCache() method which scans beans in the context to find those whose class type is annotated with #ControllerAdvice.
It does this by first calling ControllerAdviceBean.findAnnotatedBeans(ApplicationContext). Internally, this method uses ApplicationContext#getBeanDefinitionNames(). The javadoc of this method states
Does not consider any hierarchy this factory may participate
To clarify what this means. When you declare a ContextLoaderListener in your deployment descriptor, it loads what we call a root or application ApplicationContext and makes it available in the ServletContext. When you then declare a DispatcherServlet, it creates its own servlet ApplicationContext and uses any ApplicationContext it finds in the ServletContext attributes loaded by the ContextLoaderListener as a parent to that context. The hierarchy looks like so
Root ApplicationContext // loaded by the ContextLoaderListener
|
Servlet ApplicationContext // loaded by the DispatcherServlet
Every ApplicationContext has access to beans in parent contexts, but not the other way around.
The method above chooses not to use the beans in parent contexts and so only has access to beans in the current ApplicationContext (BeanFactory really).
As such, if your
<context:component-scan .../>
is declared in a root ApplicationContext as I'll assume from the name app-config, but the
<mvc:annotation-driven />
is declared in the servlet ApplicationContext, again assuming from mvc-config, then the ExceptionHandlerExceptionResolver looking for #ControllerAdvice beans will not find any. It is looking for beans in the servlet context but they aren't there, they are in the root context.
In case anyone else runs into a problem like this - I found an error I had.
I only had one RequestMapping (http://localhost:8080/myapp/verify/verify)
In an InterceptorController, in the PreHandle method, I explicitly threw an exception -> throw new MyCustomException("error","error.jsp") to test my #ControllerAdvice Exception handling.
When I went to http://localhost:8080/myapp/ I would see the interceptor controller get called, my custom exception get thrown, but the #ControllerAdvice class with my #ExceptionHandler(MyCustomException.class) was never called.
I added a #RequestMapping(value="/") and it resolved my issues. Since I was attempting to go to a URI that had no #RequestMapping associated with it, i was getting a 'NoHandlerFoundException' which was shorting out my Exception from bubbling up.
In short, make sure the URI you're attempting to invoke has a #RequestMapping associated with it, or have a method in your ExceptionHandler class to deal with the NoHandlerFoundException.
Hope this helps.
Is it somehow possible to accesse a sesssion-scoped bean in a class extending the GenericFacesPortlet?
Is a portlet even aware of the FacesContext?
What do I want to achieve?
I want to serve a file through the serveResource() method. The file's content should be retrieved from a bean implementing the method getResourceContent().
But unfortunately, I'm getting null when calling FacesContext.getCurrentInstance().
For your information: I'm using the JBoss Portlet Bridge in Version 2.1.0.FINAL.
The FacesContext will always be null in the GenericFacesPortlet. The GenericFacesPortlet creates the bridge and initializes it. The Bridge is actually creating the FacesContext and executing the JSF life cycle. From your GenericFacesPortlet point of view the FacesContext is not yet created (null).
In order to achieve what you want, you can grab the bean from the session. In order to do that you must use:
YourBean yourBean = (YourBean) request.getPortletSession().getAttribute("yourBeanName");
where "yourBeanName" is the name you used in the faces-config.xml when you defined YourBean.
Cheers!