Is it possible to use static variables in my project to store data for all Servlets (they are in one .war file) and different requests? (It's not data that belongs to a distinct session)
data for all Servlets
You can use ServletContext for this.
Defines a set of methods that a servlet uses to communicate with its servlet container, for example, to get the MIME type of a file, dispatch requests, or write to a log file.
There is one context per "web application" per Java Virtual Machine. (A "web application" is a collection of servlets and content installed under a specific subset of the server's URL namespace such as /catalog and possibly installed via a .war file.)
For example: in web.xml
<context-param>
<param-name>param</param-name>
<param-value>Myname is web xml</param-value>
</context-param>
In your servlet
public class ParameterServlet extends HttpServlet {
---
public void init(ServletConfig config) throws ServletException {
super.init(config);
ServletContext context = getServletContext();
name= context.getInitParameter("param");
}
A complete example here.
For Objects
setting
getServletContext().setAttribute("myObj", obj);
getting
MyObj attribute = (MyObj)getServletContext().getAttribute("myObj");
you can access those objects across servlets.
Yes you can do that.
However it is better to define these constants in your web.xml using the <context-param> tag.
Servlets can then retrieve constants defined using the <context-param> tag using the call:
context.getInitParameter()
Example of name-value pairs in web.xml:
<context-param>
<param-name>name</param-name>
<param-value>Joe</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>password</param-value>
</context-param>
in web.xml you can define
<context-param>
<description>My variable</description>
<param-name>variable.name</param-name>
<param-value>value</param-value>
</context-param>
And then access it from Servlet code:
String variable = getServletContext().getInitParameter("variable.name");
Yes you can, the static variable will be accessible for all the servlet threads. But about using the static variable, you should make a proper decision depending on the factors like the life time of the data you want to store and the amount of data you are going to store.
And since it is used in servlets context, make sure that its thread-safe.
Related
I'm trying to set a parameter that's not allocated to a specific servlet but rather available globally throughout the web application. My current code gets the following as null:
<context-param>
<param-name>example</param-name>
<param-value>This is an example parameter value</param-value>
</context-param>
and
getServletConfig().getInitParameter("example");
Figured it out. Just had to change:
getServletConfig().getInitParameter("example");
to:
getServletContext().getInitParameter("example");
I have a GWT Server which will connect o another server via RMI or CustomConnection. I would like to have a way of telling the GWT Server which connection type to use.
What I could think of :
Adding custom tag in web.xml
Create a normal file containing the value of the connection
Which one is better? And do you know any other optimal way?
If you know at startup time, I would go with a initialization parameter:
http://docs.oracle.com/cd/E11035_01/wls100/webapp/progservlet.html#wp159396
For example, the following entries in the Java EE standard Web Application deployment descriptor, web.xml, define two initialization parameters: greeting, which has a value of Welcome and person, which has a value of WebLogic Developer.
<servlet>
...
<init-param>>
<description>The salutation</description>
<param-name>greeting</param-name>
<param-value>Welcome</param-value>
</init-param>
<init-param>
<description>name</description>
<param-name>person</param-name>
<param-value>WebLogic Developer</param-value>
</init-param>
</servlet>
To retrieve initialization parameters, call the getInitParameter(String name) method from the parent javax.servlet.GenericServlet class. When passed the name of the parameter, this method returns the parameter’s value as a String.
Overriding the init() Method
You can have your servlet execute tasks at initialization time by overriding the init() method. The following code fragment reads the tags that define a greeting and a name in the J2EE standard Web Application deployment descriptor, web.xml:
String defaultGreeting;
String defaultName;
public void init(ServletConfig config)
throws ServletException {
if ((defaultGreeting = getInitParameter("greeting")) == null)
defaultGreeting = "Hello";
if ((defaultName = getInitParameter("person")) == null)
defaultName = "World";
}
I have a pretty standard Spring 3.0.7 web app
The structure is like this
WebContent/
resources/
myStaticConent/
WEB-INF/
views/
myProtectedContent/
I am using the <mvc:resources> configuration for the static content and my controllers get views using the InternalViewResolver from WEB-INF/views
Now I have a requirement to return non-JSP content ( JPGs,PNGs,HTML,etc ) from a protected directory in WEB-INF
So a user might enter a URL like http:myWebApp/myProtectedContent and hit my protected content controller.
#Controller
public class HelloWorldController {
#RequestMapping(value="/myProtectedContent")
public String index() {
return "myjpg.jpg";
}
}
Essentially I want to conditionally serve a file just like I would a view. Anyone know how this can be done ?
I looked at some of the other methods here, Streaming using Inputstream seems overkill for files that are essentially static. Can I register another "view" type ? I need this to appear l( from the web browser side ) like a standard http request response ( like the current view implementation).
I would really like to avoid inventing my own file handling methods unless there is some reason why using the file access methods are better then Springs "other" view resolvers like ResourceBundleResolver
So the requirement is
Conditionally respond to a http request with variable file type (jpg,png,html) from inside WEB-INF without wrapping in a jsp or having the file interpreted by the JSTL view. The names of the files are known and static. The controller will determine the file name based on its own business logic.
You can reproduce the behavior of the underlying implementation of <mvc:resources/> which is org.springframework.web.servlet.resource.ResourceHttpRequestHandler, which essentially streams out the content of the static files - You can like ResourceHttpRequestHandler, extend from org.springframework.web.servlet.support.WebContentGenerator which has extensive support for sending last-modified and caching related headers, and finally to stream the content also there is a utility that Spring provides:
org.springframework.util.FileCopyUtils.copy(resource.getInputStream(), response.getOutputStream());
Updated:
#Controller
public class HelloWorldController implements ApplicationContextAware {
ApplicatonContext ctx = ...;
#RequestMapping(value="/myProtectedContent")
public void index(HttpServletRequest req, HttpServletResponse res) {
Resource resource = ctx.getResource("classpath:staticpath/myjpg.jpg");
FileCopyUtils.copy(resource.getInputStream(), response.getOutputStream());
}
}
Something you can do is to map a new servlet to the path you want to be protected and handle the request the way you want.
For example, in web.xml:
<servlet>
<servlet-name>protServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/protServlet-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>protServlet</servlet-name>
<url-pattern>/myProtectedContent</url-pattern>
</servlet-mapping>
This way, you map a new servlet (DispatcherServlet) for URLs that are protected content.
The load-on-startup value equals 2 is due if you already have a DispatcherServlet with this field value equals 1.
I've a Java GAE app that should clear the memcache whenever I deploy a new version of the app. I'm using static initializer, i.e.
static {
MemcacheServiceFactory.getMemcacheService().clearAll();
}
However, that would clear the memcache as well whenever a new instance is started, which is not desired behavior.
What is the proper way to execute initialization code?
TIA
I create my memcache keys using a factory and they always get appended with the version number of my app so when i upload a new version, the keys are new I forget about the old cached values, which will go away on their own.
I also have a servlet defined in web.xml with a security constraint for admin only, then I browse to it's URL (/admin/example) manually after an upgrade - logging in as as admin. The servlet has my run once code in it to kick off any tasks for upgrading store data and purging the cache.
<security-constraint>
<web-resource-collection>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
One time initializations of applications can be done in the init() method of the Servlet. Here is an example
public class CatalogServlet extends HttpServlet {
private BookDB bookDB;
public void init() throws ServletException {
bookDB = (BookDB)getServletContext().
getAttribute("bookDB");
}
In the above example, the ServletContext attribute is, of course, just a variable that exists between servlet calls (the normal way to maintain state). This, of course, assumes that you somewhere else stored this variable in the ServletContext. The other way is to create the variable in the deployment descriptor.
To set initialization parameters within your deployment descriptor (web.xml), here is an example:
<servlet
<servlet-name...
<servlet-class ...
<init-param>
<param-name>param1</param-name>
<param-value>value1</param-value>
</init-param>
</servlet>
If this doesn't answer it, please clarify "whenever a new instance is started".
Is it possible to add a servlet mapping at runtime? either through a ContextListener or within a Servlet's init() method?
Within the application I am using, all requests are handled through a single Servlet and their mappings are defined in the web.xml file. The number of mappings are increasing and adding a new mapping requires a new release.
Mapping the servlet to /* would not work since requests dispatched to JSPs and static content would also be routed to this Servlet.
Using a filter might be an option nevertheless, it will add a requirement for the filter to know what path to prefix to the RequestDispatcher.
For example:
Dispatcher Servlet Mapping
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
Routing Filter Definition
<filter>
<filter-name>RoutingFilter</filter-name>
<filter-class>com.ssv.web.filter.RoutingFilter</filter-class>
<init-param>
<param-name>exclude</param-name>
<param-value>/static/**:/action/**:/**/*.jsp</param-value>
</init-param>
<init-param>
<param-name>dispatcher-prefix</param-name>
<param-value>/action/**</param-value>
</init-param>
</filter>
In the above example, I would like to skip creating the filter, the filter mapping, and the servlet mapping and instead dynamically define mappings in a ContextListener.
I'm using Tomcat.
In servlet 3.0 (tomcat 7) it is possible: ServletContext.addServlet(..)
But in your case it may be wiser not to do that. Spring's DispatcherServlet for example is mapped to /*. It forwards to JSPs internally, and handles requests in its own non-servlet components, so that it doesn't need to register them dynamically. Take a look at spring-mvc anyway, even if you don't end up using it.
To dynamically add your own servlet, you need a servletcontext Object. From the api docs, there exists a method to bind your Servlet to the servletContext.
Servletconfig.getServletContext().addServlet("YourServletname",yourServletname.class);