Jetty setInitParameter is NOT initializing any parameter - java

I've embedded Jetty, and I'm trying to set an initialization parameter.
The main class Main creates a servlet of Cgi which extends CGI.
Within Main, I have the following code:
ServletContextHandler context2 = new ServletContextHandler(ServletContextHandler.SESSIONS);
context2.setContextPath("/cgi");
context2.setResourceBase("./cgi-bin");
context2.setInitParameter("commandPrefix", "perl");
context2.addServlet(new ServletHolder(new Cgi()), "/");
server.setHandler(context2);
Within Cgi, I check to see the parameter:
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println(servletConfig.getInitParameter("commandPrefix"));
super.init(servletConfig);
}
Each time, it prints out null for the getInitParameter call. Then when the Cgi does indeed NEED to use this, it doesn't, because it's not set. Why could this be happening?

You're setting the InitParameter on the ServletContextHandler, but you should be setting it on the ServletHolder.
(It's somewhat confusing, I know)

You've set a context init parameter, not a servlet init parameter. So you need to retrieve it as a context init parameter instead of as a servlet init parameter.
System.out.println(servletConfig.getServletContext().getInitParameter("commandPrefix"));
Alternatively, you can of course also set it as a servlet init parameter instead, but this way the parameter will only be available to the associated servlet only, not to all other servlets running in the same context. This may or may not be what you want, depending on the concrete functional requirement.

Related

Why do we need Init() method in servlets when servlets has it Construtor?

in java Constructor is used for initialization why we need init() for initialization.... This question was asked in an Interview
The constructor is for normal Java initialization of an object (though typically a Servlet implementation is expected to have a no-arg constructor).
The init() method is a method provided by the Servlet interface which a Servlet container will run to configure the Servlet. The Servlet container will provide a ServletConfig object which gives the Servlet instance access to the ServletContext and other configuration elements from the deployment descriptor.
the init() method is a part of Servlet and ServletConfig protocol. you can do what is related to the web-context in init() and what is private to Servlet class in constructor.
1) Constructors are used by "Web Container(e.g of Tomcat, WebSphere etc.) to instantiate GenericServlet/HttpServlet.
2) Role of "Servlet.init()" method is to inject defined in web.xml. Yes, you can define servlet level parameters in constructor as well, but then, as a developer you shall unnecessarily invest time in doing the same stuff which can be done implicitly for you by (Container+Servlet API).
3) Moreover, "Servlet.init()" is also used by web container to inject "ServletContext" object where you can't use constructor for that purpose.
Init() method is called by the servlet container to indicate to a servlet that the servlet is being placed into service.
The servlet container calls the init method exactly once after instantiating the servlet. The init method must complete successfully before the servlet can receive any requests. This is the reason we need init() method.
Refer these links:
http://www.tutorialspoint.com/servlets/servlets-life-cycle.htm
http://docs.oracle.com/javaee/5/api/javax/servlet/Servlet.html
The constructor is not part of the servlet lifecycle.
As per the javadocs
init and destroy, to manage resources that are held for the life of the servlet
and
The ServletConfig object can still be retrieved via getServletConfig().
In JDK 1.0 (for which servlets were originally written), constructors for dynamically loaded Java classes (such as servlets) couldn't accept arguments. So, in order to provide a new servlet any information about itself and its environment, a server had to call a servlet's init() method and pass along an object that implements the ServletConfig interface.
Also, Java doesn't allow interfaces to declare constructors. This means that the javax.servlet.Servlet interface cannot declare a constructor that accepts a ServletConfig parameter. It has to declare another method, like init().
It's still possible, of course, for you to define constructors for your servlets, but in the constructor you don't have access to the ServletConfig object or the ability to throw a ServletException.
I used init method to prepare my PreparedStatement once, so that the next time my servlet is called, the prepared statement already created. Please note that when a servlet first loaded in the app server, the init method will be executed. The subsequent called to the servlet, the init method will be ignored. It's only called once for the lifecycle of the servlet

How to get request parameters from a servlet init method

I am writing a Servlet that retrieves request parameters but needs to use them in the init method. Since the init method would be called before the doGet method and since the init method does not have a HttpServletRequest object as an argument, I don't know how to get the request parameters.
public class OpenIdServlet extends HttpServlet
{
...
...
private OpenIdManager manager;
#Override
public void init() throws ServletException
{
super.init();
manager = new OpenIdManager();
manager.setRealm("http://localhost:8080/OpenIDSample");
manager.setReturnTo("http://localhost:8080/OpenIDSample/openid"); //I need to append the value of a request parameter here...
}
...
...
}
So the question is: is there any way I can get HttpServletRequest parameters in the init() method of a servlet? If no what other better approach can one use to solve this problem? Thanks.
The init is called once on startup. So you have to live with a partial returnTo, and on request handling (doGet/doPost) complete it with the request parameters.
In fact the manager seems to be request dependent and hence should be created in the request - never as field. As there might be several requests. Maybe persisting as session attribute.
Your question doesn't make sense. There is no request when the init() method is called. It is called during container initialisation.
Do you mean initial parameter? They are available via the ServletContext provided as an argument to init().

LoggingFilter is ignored in Jersey and embedded Jetty

I'm trying to configure LoggingFilter for Jersey in an embedded Jetty setup. The glue code that is used is as follows:
ServletContainer servletContainer = new ServletContainer(application);
ServletHolder servletHolder = new ServletHolder(servletContainer);
servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true");
servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters",
"com.sun.jersey.api.container.filter.LoggingFilter");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters",
"com.sun.jersey.api.container.filter.LoggingFilter");
But the logging filter is actually ignored and I see no relevant logs in the console. How can I do this? Tested both on Jersey 1.x and 2.x.
A relevant answer describes how to achieve this using web.xml.
I think this is a very subtle nuance of the documented behavior of ServletContainer if it isn't an outright bug. The ServletContainer docs on the subject of init params read as:
All initialization parameters are added as properties of the created ResourceConfig.
The answer is hidden in there. Specifically, if the ResourceConfig instance isn't created by the ServletContainer, then the servlet init parameters aren't added as properties and thus won't influence your app's configuration. When you provide your own Application instance, as you did with the new ServletContainer(application), initialization follows roughly this course:
Your code invokes the following ServletContainer constructor with your Application instance:
public ServletContainer(Application app) {
this.app = app;
}
The container initializes your ServletContainer as part of a typical Servlet lifecycle:
protected void init(WebConfig webConfig) throws ServletException {
webComponent = (app == null)
? new InternalWebComponent()
: new InternalWebComponent(app);
webComponent.init(webConfig);
}
There goes your Application instance into the InternalWebComponent constructor. An InternalWebComponent is just a slight customization of WebComponent, so:
InternalWebComponent(Application app) {
super(app);
}
calls:
public WebComponent(Application app) {
if (app == null)
throw new IllegalArgumentException();
if (app instanceof ResourceConfig) {
resourceConfig = (ResourceConfig) app;
} else {
resourceConfig = new ApplicationAdapter(app);
}
}
This is where, since you provided an Application instance directly, a ResourceConfig is built for you in one of the branches of that second if. Immediately after construction, WebComponent.init() is called on the new component (refer back to the ServletContainer.init() call above, where we came from). Inside this init() call is where the "created ResourceConfig" referred to by the docs would be created, but in your case, one already exists, as shown by the trail we followed to get here. I.e., the resourceConfig isn't null, so the important line below doesn't execute:
public void init(WebConfig webConfig) throws ServletException {
...
if (resourceConfig == null)
resourceConfig = createResourceConfig(config);
...
}
That createResourceConfig() method (still in WebComponent) reads as:
private ResourceConfig createResourceConfig(WebConfig webConfig)
throws ServletException {
final Map<String, Object> props = getInitParams(webConfig);
final ResourceConfig rc = createResourceConfig(webConfig, props);
rc.setPropertiesAndFeatures(props);
return rc;
}
You can see in that call that setPropertiesAndFeatures() is used to copy the servlet's init params into the ResourceConfig instance. Unfortunately, this is the only place where that call is made, and in your case, execution never makes it here, basically because of your use of one of the non-default ServletContainer constructors.
I expect that the original authors wrote ServletContainer with just one, no-arg constructor and the other two were added later on for ease of use with Servlet 3.0 containers without realizing that this behavior was being introduced. Otherwise, I'd expect to see some mention of it in the docs.
So, long story short: either use the default ServletContainer constructor or find a way to take care of this part yourself:
Map<String, Object> props = getInitParams(webConfig);
rc.setPropertiesAndFeatures(props);
The first way is probably the simplest. For instance, you could specify your Application class as an init parameter, too, as long as there's nothing requiring you to instantiate it ahead of time, such as:
servletHolder.setInitParameter("javax.ws.rs.Application", "org.foo.MyApplication");
That way, the "normal" initialization path will be taken, meaning the WebComponent will create the ResourceConfig for you and apply the init params correctly.
I think you might be doing it wrong.
// Creating an instance of Jersey servlet, right?
ServletContainer servletContainer = new ServletContainer(application);
// Putting it in a container by reference.
ServletHolder servletHolder = new ServletHolder(servletContainer);
This page doesn't create the servlet like you do:
ServletHolder sh = new ServletHolder(WicketServlet.class);
This way Jetty creates an instance, and calls servlet's init().
In your case you might need to call init() but I am not sure where will you get the ServletConfiguration instance.
UPDATE:
You should try it this way:
ServletHolder servletHolder = new ServletHolder(ServletContainer.class);
servletHolder.setInitParameter("javax.ws.rs.Application", "MyRESTApplication");
servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true");
servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters",
"com.sun.jersey.api.container.filter.LoggingFilter");
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters",
"com.sun.jersey.api.container.filter.LoggingFilter");
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.addServlet(servletHolder, "/services/*");
server.setHandler(contextHandler);

Difference between session.getServletContext() and session.getServletContext().getContext("/SampleProject")

I have a Tomcat 6 instance running on my local machine.
I have made the following changes in its configuration:
In /conf/context.xml – changed the tag as follows
<Context crossContext="true">
In /conf/server.xml – changed the tag as follows
<Connector port="8080" protocol="HTTP/1.1" emptySessionPath="true"
connectionTimeout="20000"
redirectPort="8443" />
Suppose I have a WAR file named SampleProject.war deployed here which extract to folder SampleProject.
In some servlet in this WAR, say SampleServlet, I write two blocks of code as follows :
ServletContext context1 = session.getServletContext();
and
ServletContext context2 = session.getServletContext().getContext("/SampleProject");
What is the difference between context1 and context2? I thought that both refer to the application context. But if I set some attribute in context1 and access in context2, I don't get the value in context2.
Any help would be appreciated.
I feel your question was slightly misunderstood and that you already had the basic understanding of the API i.e. once a web-app sets its crossContext="true" it could use getContext() to get access to a context that corresponds to some other web-app deployed on the server.
getServletContext().getContext() equals NULL unless <Context crossContext="true">
From what I've understood, your question actually is that in /SameWebApp why
ServletContext context1 = session.getServletContext();
context1.setAttribute("contextAttribute", new Object());
ServletContext context2 = session.getServletContext().getContext("/SameWebApp");
System.out.println(context1.equals(context2)); // prints false, or
System.out.println(context2.getAttribute("contextAttribute")); // prints null (at least they could have been clones)
In just one word, the answer is "Security". Imagine if you couldn't guarantee that an "adminEmail" context attribute has not been tampered with by an evil web-app having its crossContext=true. Your app could potentially help compromise itself as soon as that "Forgot Password" request comes! :)
A Dive into Tomcat internals
Tomcat 7 provides a class ApplicationContext implements ServletContext that returns from getContext("/context-root") as
if (context.getCrossContext()) {
// If crossContext is enabled, can always return the context
return child.getServletContext();
} else if (child == context) {
// Can still return the current context
return context.getServletContext();
} else {
// Nothing to return
return (null);
}
Here context belongs to current web-app and child represents the other web-app. But, hold on, what makes Tomcat call it a child?
These two actually aren't ApplicationContext but instances of StandardContext a class that implements Context but instead of servlet specific things holds Tomcat specific config settings for a web-app like crossContext, hostname, mimeMappings etc. StandardContext.getParent() gives you the Container and hence it has been referred to as a child above.
Anyways, we're interested in the case when child == context is true i.e. getContext() was called on the "/SameWebApp". The call is being delegated to StandardContext.getServletContext() which has been implemented to return a different instance of ApplicationContext.
This is why the attributes you set in context1 are not found in context2.
But wait, there's some more to it. Why does StandardContext.getServletContext() return like
return (context.getFacade());
A Tomcat instance is basically executing two types of Java code:
container provided, and
user deployed
The container code is "Trusted" and may need to run with elevated privileges sometimes. The user code, on the other hand, is not trusted and needs to be restricted from compromising Tomcat internals.
One of the things that Tomcat does to achieve this is always wrap an ApplicationContextFacade around the ApplicationContext (and hence the StandardContext as well). So just to recap, what appears to be a simple ServletContext implementation is actually a StandardContext mapped to an ApplicationContext which is then wrapped within an ApplicationContextFacade.
For further information on how the ApplicationContextFacade works using Reflection in tandem with Globals.IS_SECURITY_ENABLED and SecurityUtil.isPackageProtectionEnabled() settings please take a look at Why do Servlets access Tomcat ApplicationContext through a Facade on SO.
References:
Tomcat 7 Source Code (Download Link)
Absolutely those two context objects are different from another..
Context1 object gives current web application servlet context obj.
( ServletContext context1 = session.getServletContext();)
and
context2 object gives the servletcontext obj of specified web application
(ServletContext context2 = session.getServletContext().getContext("/SampleProject");)
you are setting object in one context and trying to retrieve using another context, so it is not possible to get attribute from another web application context by putting it in current application context. But you can get attribute resides in another web application context by using second method.
Think OO & java EE platform standards + security.
The first call returns the definitive servlet context for the current app, with all operations supported.
The second call returns a copy of the servlet context that could be for any app. As stated (rather vaguely!) in the javadoc, it's purpose is to allow you to obtain a RequestDispatcher, so you can dispatch to pages of other apps. It's other major but implicit requirement is to do this securely and to respect the Java EE specs, which do not allow sharing of session state or servlet context between apps. Imagine the terrible damage "rogue App B" could do to "good App A" if it could just change (or read) Servlet Context data by brute force. That's why it's a copy.
Hence, setting attributes on the copy, does not result in changes to the original. You could argue that the copy should throw some "Operation Not Supported Exception". Alternatively, you could argue that getRequestDispatcher should be refactored either to another class, or to allow an App Context URL to be passed in. ... But, unfortunately, neither of these things are true. B^)

Init method invocation in filter

Could anyone please tell me why the following line about filter init method invocation is incorrect:
The init method on a filter is called
the first time a servlet mapped to
that filter is invoked.
Because it's called when filter is loaded and initialized by servlet container, which happens during web application startup. Filter's init() method will be called even if it will never intercept a single request.
From the API documentation:
void init(FilterConfig filterConfig) throws ServletException
Called by the web container to indicate to a filter that it is being placed into service. The servlet container calls the init method exactly once after instantiating the filter. The init method must complete successfully before the filter is asked to do any filtering work.

Categories