I want to call the init method when the application starts.
<servlet>
<servlet-name>servletTest</servlet-name>
<servlet-class>com.gateway.Gateway</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
above is my code to do so. But strangely init method gets called twice.
Below is my servlet code. Any help would be appreciated.
#WebServlet("/Gateway")
public class Gateway extends HttpServlet {
private static final long serialVersionUID = 1L;
public Gateway() {
super();
}
public void init(ServletConfig config) throws ServletException {
System.out.println("Init called");
}
public void destroy() {
System.out.println("Destroy called");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Received a Request");
response.getWriter().append("Served at: ").append(request.getContextPath());
}
}
You are actually creating two instances (objects) of the Gateway Servlet class one through web.xml and one through #WebServlet, so init() is being invoked twice (one from each instance). By default, a servlet class should have a single instance (unless you wanted to run differently).
So to solve the issue, you have got two options:
(1) Remove the web.xml and add loadOnStartup=1 to your #WebServlet as show below: #WebServlet(urlPatterns="/Gateway", loadOnStartup=1)
(2) Remove #WebServlet(urlPatterns="/Gateway") in your Gateway class and configure the servlet in web.xml as shown below:
<servlet>
<servlet-name>Gateway</servlet-name>
<servlet-class>com.gateway.Gateway</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Gateway</servlet-name>
<url-pattern>/Gateway</url-pattern>
</servlet-mapping>
Related
I'm working on creating a security library that will be used by several RESTful clients. I'm using Java EE 5, Jersey 1.17 and Maven. The clients will use my library to call a third party app using a token. The third party app will then return all the information it has on that token, like expiration, scope and userId.
My idea is to make a filter that will check if there is an Authorization header, and if that's so, it calls the third party app. If the third party app validates the token and returns the token's info, I need to return that information, stored in a TokenInformation object, back to the resources. In a previous post, someone said that I could do this:
public class MyFilter implements Filter{
#Override
public void doFilter(final ServletRequest request,
final ServletResponse response,
final FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String header = req.getHeader("Authorization");
TokenInformation info = new TokenInformation();
info = buildInfo(info);
if (true) {
request.setAttribute("auth", info);
chain.doFilter(request, response);
} else {
handleError(response);
}
}
}
So, by sending the TokenInformation object to the request as an additional attribute, I would be able to retrieve it later in the resource classes. The thing is that I'm using Java EE 5, and I didn't realize that I couldn't use the #Context annotation to inject the ServletRequest object. How can I access the ServletRequest object again from a resource class, so that I can access the TokenInformation object in, for example, the DAO?
The way I'm using jersey is by doing this in my web.xml:
<servlet>
<servlet-name>Security API</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.ni.apps.engineering.securitylibrary.resources.SecurityResource</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Security API</servlet-name>
<url-pattern>/1/*</url-pattern>
</servlet-mapping>
The SecurityResource class has this:
public class SecurityResource extends Application{
public static final String SUPPORTED_REPRESENTATIONS = MediaType.APPLICATION_XML
+ "," + MediaType.APPLICATION_JSON;
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
set.add(Security.class);
return set;
}
}
The Security class has this:
#Path("")
public class Security implements ISecurity{
#Override
public Response get(String upId) {
String test = "";
try{
TokenInformation tI = (TokenInformation) HttpServletRequestWrapper.
test = "test1";
}catch(Exception e){
System.out.println(e.getMessage());
}
return null;
}
}
You don't have to access ServletRequest at Dao layer.
In Servlet you can get ServletRequest object and you can pass the value to Dao layer.
If you really want to access then pass ServletRequest object to Dao layer by reference.
<servlet-name>Security API</servlet-name>
<servlet-class>com.packagename.MyServlet</servlet-class>
public MyServlet extends com.sun.jersey.spi.container.servlet.ServletContainer{}
You can extend jersey servlet and you can initialize Servlet with Application Class by programatically.
In MyServlet you can reach the request object.
Servlet Information :
https://jersey.java.net/apidocs/1.17/jersey/com/sun/jersey/spi/container/servlet/ServletContainer.html
I have a properties file in the WEB-INF with some properties that need to be used by my servlet (properties like a database password,...). What's the best way to load this file? Should I Override the init method of the servlet so that I only load the file once?
Thanks
I am not saying that this way is correct or anything since I don't work with JEE but from what I remember you can use ServletContextListener methods for this. Just implement it like
class ContextListenerImpl implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent sce) {
//lets skip it for now
}
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
//read parameter from properties and add it to servlet context attributes
sc.setAttribute("yourParameterName", "value");
}
}
You should be able to use it in any servlet via for instance
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//...
getServletContext().getAttribute("yourParameterName");
//...
}
BTW value of attributes can hold also other objects, not only Strings.
Oh, and lets not forget to add this listener to your web application. Just add
<listener>
<listener-class>full.name.of.ContextListenerImpl</listener-class>
</listener>
to your web.xml file.
First, a bit of context:
web.xml:
I match all /app/* requests to my dispatcher:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
My question, why does calling /app/import/view work when returning String:
Controller:
public class ImportController extends MultiActionController {
public String view(HttpServletRequest request, HttpServletResponse response) throws Exception
return "importer.home";
}
but NOT when returning ModelAndView:
public class ImportController extends MultiActionController {
public ModelAndView view(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("importer.home");
mav.addObject(new ExlFile());
return mav;
}
Is there a different naming convention if we use ModelAndView?
You're using MultiActionController, which has very strict constraints on method naming conventions and signatures.
However, you shouldn't be using MultiActionController at all, it's obsolete and deprecated. Write controllers as described in the Spring manual, i.e. using #Controller and #RequestMapping, then you get much more flexible method signatures.
If you are using spring 3.0, then i will prefer to use annotation.
#Controller
#RequestMapping(value = "/app")
public class ImportController {
#RequestMapping(value="/importer/home")
public ModelAndView view(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("importer.home");
mav.addObject(new ExlFile());
return mav;
}
I'd like the ability to modify/configure filters in a different way than web.xml. Here is a static configuration of 2 filters. I'd like the ability to have one filter statically configured and allow that filter to load additional filters. I just wanted to know if anyone knows of lib that already has this.
Using Servlet API 2.5
<web-app>
...
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>com.me.MyFilter1</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
<filter>
<filter-name>MyFilter2</filter-name>
<filter-class>com.me.MyFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
I've seen this done in Guice with GuiceFilter where the Filters are configured at runtime.
Just do the same job as the container already does. I.e. reinvent the wheel of the chain of responsibility design pattern as is under the covers been used by servlet filters.
public class GodFilter implements Filter {
private Map<Pattern, Filter> filters = new LinkedHashMap<Pattern, Filter>();
#Override
public void init(FilterConfig config) throws ServletException {
Filter1 filter1 = new Filter1();
filter1.init(config);
filters.put(new Pattern("/foo/*"), filter1);
Filter2 filter2 = new Filter2();
filter2.init(config);
filters.put(new Pattern("*.bar"), filter2);
// ...
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest hsr = (HttpServletRequest) request;
String path = hsr.getRequestURI().substring(hsr.getContextPath().length());
GodFilterChain godChain = new GodFilterChain(chain);
for (Entry<Pattern, Filter> entry : filters.entrySet()) {
if (entry.getKey().matches(path)) {
godChain.addFilter(entry.getValue());
}
}
godChain.doFilter(request, response);
}
#Override
public void destroy() {
for (Filter filter : filters.values()) {
filter.destroy();
}
}
}
with those little helper classes (which can if necessary be made private static nested classes of the above GodFilter):
public class Pattern {
private int position;
private String url;
public Pattern(String url) {
this.position = url.startsWith("*") ? 1
: url.endsWith("*") ? -1
: 0;
this.url = url.replaceAll("/?\\*", "");
}
public boolean matches(String path) {
return (position == -1) ? path.startsWith(url)
: (position == 1) ? path.endsWith(url)
: path.equals(url);
}
}
and
public class GodFilterChain implements FilterChain {
private FilterChain chain;
private List<Filter> filters = new ArrayList<Filter>();
private Iterator<Filter> iterator;
public GodFilterChain(FilterChain chain) {
this.chain = chain;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (iterator == null) {
iterator = filters.iterator();
}
if (iterator.hasNext()) {
iterator.next().doFilter(request, response, this);
} else {
chain.doFilter(request, response);
}
}
public void addFilter(Filter filter) {
if (iterator != null) {
throw new IllegalStateException();
}
filters.add(filter);
}
}
You could if necessary also feed a XML config file with all possible filters so that you end up with easier configuration. You could use reflection to create filters in init() of your GodFilter.
Oh nevermind, that's what the web.xml and the container already is doing...
Servlet 3.0 has the #WebFilter annotation to define a filter. No need to declare it in web.xml anymore.
But loading a filter from a filter is not supported. You could implement it yourself: it's "just" the chain of responsibility pattern, but why would you?
It can be achieved in easy steps, even for pre-3.0 Servlet spec:
Add a filter containing a static & ordered collection of Classes (chain).
Map the filter to intercept every traffic.
Manipulate the order & existence of your helper classes (those will be called privately by your filter upon interception of traffic) in the chain.
Ref: Xstream uses same kind of pattern for Serializer, well not with Servlet/Filter though. :)
I personally like the #WebFilter annotation to register servlet filters.
But another solution is to add the filter at runtime using the ServletContext's addFilter function.
Implement ServletContextListener; something like:
public class MyContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent ce) {
ServletContext servletContext = ce.getServletContext();
// you can even conditionally add this
servletContext.addFilter("My filter 1", MyFilter1.class)
.addMappingForUrlPatterns(allOf(DispatcherType.class), false, "/*");
}
}
Register listener:
<listener>
<listener-class>com.me.MyContextListener</listener-class>
</listener>
And of course you need to implement a Filter. But in your question you already refer to an example filter 'MyFilter1'.
Can we write an argument constructor in a Servlet? If yes, how can you call?
Can we write an argument constructor in a Servlet?
Yes, you can but it is useless since the servlet container won't invoke it.
The proper way to do it is to use the init() method:
#Override
public void init() throws ServletException {
String foo = getInitParameter("foo");
String bar = getServletContext().getInitParameter("bar");
// ...
}
In this example, getInitParameter("foo") returns the value of the <init-param> of the specific <servlet> entry in web.xml, and getServletContext().getInitParameter("bar") returns the value of the independent <context-param> in web.xml.
The problem can be state more generically:
"According to the servlets (2.3)
specification, the servlets are
instantiated by the servlet engine by
invoking the no-arg constructor. How
can I initialize a servlet properly
given that correct initialization
depends on the
central/global/unique/application
configuration?"
Actually, you can use serlvets with constructor and/or initialize them as you like. However, it requires a little bit of plumbing.
Assuming you have a servlet with a constructor having arguments:
package org.gawi.example.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SampleServlet extends HttpServlet
{
private final String mMessage;
public SampleServlet(String message)
{
mMessage = message;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/plain");
response.getWriter().write(mMessage);
}
}
The first thing you need is a unique servlet whithin your application, let's call it InitializationServlet, to create all the required instances. Those instances must then be exported in the servlet context to be retrieve by another servlet (explained later). The InitializationServlet may look like this:
package org.gawi.example.servlets;
import javax.servlet.*;
import javax.servlet.http.*;
public class InitializationServlet extends HttpServlet
{
public void init() throws ServletException
{
SampleServlet servletA = new SampleServlet("this is servlet A");
SampleServlet servletB = new SampleServlet("this is servlet B");
SampleServlet servletC = new SampleServlet("this is servlet C");
getServletContext().setAttribute("servletA", servletA);
getServletContext().setAttribute("servletB", servletB);
getServletContext().setAttribute("servletC", servletC);
}
}
You see that only the init() method has been provided. This servlet is not servicing any HTTP request. Its only purpose is to store the servlet in the ServletContext. Note that you could have also use this servlet to load your application configuration. So this can act as the web-application entry point, like the main(String[] args) method of a program. This might remind you of the ContextLoaderServlet of SpringSource.
The last piece is the DelegateServlet that will effectively be instantiated by the servlet container, only this servlet will forward all the pertinent method calls to the wrapped servlet instance:
package org.gawi.example.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DelegateHttpServlet extends HttpServlet
{
private static final String SERVLET_CONTEXT_KEY_INIT_PARAMETER = "servletContextKey";
private HttpServlet mServlet;
public void init(ServletConfig servletConfig) throws ServletException
{
super.init(servletConfig);
locateServlet(servletConfig);
mServlet.init(servletConfig);
}
private void locateServlet(ServletConfig servletConfig) throws ServletException
{
String servletContextAttributeName = servletConfig.getInitParameter(SERVLET_CONTEXT_KEY_INIT_PARAMETER);
if (servletContextAttributeName == null)
{
throw new ServletException("Unable to find init parameter '" + SERVLET_CONTEXT_KEY_INIT_PARAMETER + "'");
}
Object object = servletConfig.getServletContext().getAttribute(servletContextAttributeName);
if (object == null)
{
throw new ServletException("Unable to find " + servletContextAttributeName + " in servlet context.");
}
if (!(object instanceof HttpServlet))
{
throw new ServletException("Object is not an instance of"
+ HttpServlet.class.getName()
+ ". Class is "
+ object.getClass().getName()
+ ".");
}
mServlet = (HttpServlet) object;
}
public void destroy()
{
mServlet.destroy();
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
{
mServlet.service(req, res);
}
}
During its initialization, the DelegateServlet will look-up the target servlet in the servlet context using the servletContextKey servlet initial argument.
The web.xml for such an application might look like that:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Example</display-name>
<description>Example web showing handling of servlets w/ constructors.</description>
<servlet>
<servlet-name>Initialization</servlet-name>
<servlet-class>org.gawi.example.servlets.InitializationServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>A</servlet-name>
<servlet-class>org.gawi.example.servlets.DelegateHttpServlet</servlet-class>
<init-param>
<param-name>servletContextKey</param-name>
<param-value>servletA</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>B</servlet-name>
<servlet-class>org.gawi.example.servlets.DelegateHttpServlet</servlet-class>
<init-param>
<param-name>servletContextKey</param-name>
<param-value>servletB</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet>
<servlet-name>C</servlet-name>
<servlet-class>org.gawi.example.servlets.DelegateHttpServlet</servlet-class>
<init-param>
<param-name>servletContextKey</param-name>
<param-value>servletC</param-value>
</init-param>
<load-on-startup>4</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>A</servlet-name>
<url-pattern>/servlet/a</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>B</servlet-name>
<url-pattern>/servlet/b</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>C</servlet-name>
<url-pattern>/servlet/c</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>5</session-timeout>
</session-config>
</web-app>
Be sure to load the InitializationServlet first, using a low <load-on-startup> value.
The benefit of this approach is that HttpServlet objects can be handled like any other regular Java object or bean. Hence, it provides a better control over initialization: no more tricky stuff to do in the init() method, nor messy servlet init-arg handling.
You can't. Servlet is instantiated reflectively by container. If servlet spec have allowed arguments in constructor, you would have to have some complicated deployment descriptor like,
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>MyServlet</servlet-class>
<servlet-argument id="1" type="string">Test<servlet-argument>
<servlet-argument id="2" type="int">10</servlet-argument>
<load-on-startup>1</load-on-startup>
</servlet>
I guess no one wants that.
Constructors are objects managed by the application server.
For initialization, see the init() method.
Update:
Can I use a constructor in my servlet?
A: A servlet is a normal Java class, so when there are no custom
constructors, there is an implicit
default constructor with no arguments.
Servlet containers typically use the
Class.newInstance() method to load
servlets, so you must be careful to
add an explicit default constructor if
you add non-default constructors.
source: http://www.codestyle.org/java/servlets/FAQ.shtml