What is the best way to make threadsafe HashMap in Tomcat ?I'm going to create ConcurrentHashMap on InitServlet once on load on my application.
(<load-on-startup>1</load-on-startup>)
Requests from different threads will read and write data to my ConcurrentHashMap.
I'm not good in mutlithreading, so not sure is it approach correct?
And where is the best place to put this HashMap should i make it static ?
Thank you
Don't make it static - put it in the ServletContext via ctx.setAttribute("mapAttrKey", map). Otherwise it's fine. However it is not very common to do things like this, so please share your use-case - there might be a more proper solution.
If the "initServlet" does nothing else than webapplication initialization, then you'd rather prefer a ServletContextListenrer. Here's a kickoff example:
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.
}
}
Register it in web.xml as follows:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
That's it. You could keep of the Map as an instance variable and/or store it in the ServletContext (the application scope).
Related questions:
Using init Servlet
Related
So I'm trying to do a simple web-app using the default stuff (Tomcat, no framework).
What I want is after I start server, I want my application to create a "Sample.txt" file in my server using a "SetUpDataService.class". Is there a way to do that?
Im thinking creating a "SetUpServlet" without mapping and just call the "SetUpDataService.class" in the init method, but it looks so dirty and feels wrong.
What is the best way for that using the default stuff?
And is there a library exists for that purpose? Currently im not using any 3rd party library to strengthen my core understanding of JavaEE.
PS. I dont know if this question exists.I just cant find the right keyword so I posted this question.
EDIT: How about creating initial data on database? Is the approach OK?
Just for knowledge if you wanted to do that, you can achieve that using ServletContextListener as shown below. contextInitialized() method will be called by the container during startup (i.e., when the servletcontext object is being created).
#WebListener
public class MyProjectListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
//add your file creation code here
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
//add code cleanup the resources
}
}
I think this is more a design specific question, than direct coding issue.
I want to implement a websocket service which serves an updated dataset from a foreign http:// resource to the clients.
but i want to have the data available before the first client connects, so #OnLoad notation won't do.
In HttpServlet world I would
#Override
public void init() throws...
I could not figure out a suitable way for doing so just using JSR-356.
I tried with custom ServerEndpointConfig.Configurator but that does not seem to give me access to method similar to init() from HttpServlet.
So my question is:
Letting the websocket Endpoint class extend HttpServlet gives me access to the init() method and I can place my initial logic there.
Is that a suitable way for solving my problem, or have i missed something in JSR-356 which does the job elegantly and without importing mostly unused servlet packages?
Thank you very much!
A class annotated with #ServerEndpoint("/myEndPoint") is instantiated each time a new connection is created via #OnOpen. It is not a static class nor a singleton (e.g. not behaves as Spring #Service).
I have a similar problem to yours, I need to make a web socket the observer of a Spring web service (don't ask, I'm with you that is a bad architecture the problem). In order to make it an observer, I have to add it to the observable class, but because of the lack of an initialization for the web socket I don't have a clear spot where to add the observer, adding it in the #OnOpen method would repeatedly add it on each new connection.
The only solution I found is a workaround. Usually a web socket class has a static Set of the peers connected to it, you need something similar for your initialization. Either use a static block or a static flag in the constructor. In my case I solved with:
private static boolean observerFlag = false;
private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
public MyWebSocket() {
if (!observerFlag) {
observable.addObserver(this);
observerFlag = true;
}
}
And to remove the observer:
#OnClose
public void onClose(Session peer) {
peers.remove(peer);
if (peers.isEmpty()) {
observable.deleteObserver(this);
observerFlag = false;
}
}
I repeat that this is a workaround, I think that there is a more elegant solution.
I have a 3-tier application I have to modify. I'm totally new to the entire webstuff of Java, so bear with me please.
Currently the application has a UI, Application and Database layer but I am attempting to decouple the SQL database from the database layer using dependency injection.
So at some point I'm not going to need SQL server credentials in my application because the database backend might be plain text.
The point is that the current SQL credentials are stored in the web.xml file as init-parameters. These are fetched in servlet code as follows:
String cfgfile = getInitParameter("config_file");
properties.load(new FileInputStream(cfgfile));
//Some code..
properties.getProperty("dbUser");
This happens in the front-end, is passed to the applicationlayer constructor, which passes it on to the database constructor.
So this works, but the credentials are just passed along to the data access layer to then create a SQLDatabase.
So I figured I'd just pull these credentials in inside the SQL specific class. However, I'm stuck on how to get them out of the web.xml file.
I tried using getServletContext() but that doesnt seem to work.
I can imagine that there is no notion of any servlet at the DAL level, so I'm stuck on how to fix this.
Register ServletContextListener to load Init parameters at server start-up.
Load properties and make it visible to other classes statically.
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));
//Some code..
properties.getProperty("dbUser");
}
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>
You are correct that the web.xml seems the wrong place to be defining database credentials.
It sounds like you really want to define the database credentials as properties and inject them directly into your data access layer.
As you are using Spring you might want to consider defining a DataSource within your context.xml and either defining the credentials directly in there or using a properties file. Have a look at the Spring documentation for more details.
You'll have to excuse me if I'm describing this incorrectly, but essentially I'm trying to get a service-like class to be instantiated just once at server start and to sort of "exist" in the background until it is killed off at server stop. At least from what I can tell, this is not exactly the same as a typical servlet (though I may be wrong about this). What's even more important is that I need to also be able to access this service/object later down the line.
As an example, in another project I've worked on, we used the Spring Framework to accomplish something similar. Essentially, we used the configuration XML file along with the built-in annotations to let Spring know to instantiate instances of some of our services. Later down the line, we used the annotation #Autowired to sort of "grab" the object reference of this pre-instantiated service/object.
So, though it may seem against some of the major concepts of Java itself, I'm just trying to figure out how to reinvent this wheel here. I guess sometimes I feel like these big app frameworks do too much "black-box magic" behind the scenes that I'd really like to be able to fine-tune.
Thanks for any help and/or suggestions!
Oh and I'm trying to run this all from JBoss 6
Here's one way to do it. Add a servlet context listener to your web.xml, e.g.:
<listener>
<listener-class>com.example.BackgroundServletContextListener</listener-class>
</listener>
Then create that class to manage your background service. In this example I use a single-threaded ScheduledExecutorService to schedule it to run every 5 minutes:
public class BackgroundServletContextListener implements ServletContextListener {
private ScheduledExecutorService executor;
private BackgroundService service;
public void contextInitialized(ServletContextEvent sce) {
service = new BackgroundService();
// setup single thread to run background service every 5 minutes
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(service, 0, 5, TimeUnit.MINUTES);
// make the background service available to the servlet context
sce.getServletContext().setAttribute("service", service);
}
public void contextDestroyed(ServletContextEvent sce) {
executor.shutdown();
}
}
public class BackgroundService implements Runnable {
public void run() {
// do your background processing here
}
}
If you need to access the BackgroundService from web requests, you can access it through the ServletContext. E.g.:
ServletContext context = request.getSession().getServletContext();
BackgroundService service = (BackgroundService) context.getAttribute("service");
Have you considered using an EJB 3.1 Session bean? These can be deployed in a war file, and can be annotated with #Singleton and #Startup.
A number of annotations available with EJB 3.1 are designed to bring Spring goodies into the Java EE framework. It may be the re-invention you're considering has been done for you.
If you must roll your own, you can create a servlet and configure it start up when the application does using load-on-startup. I built a system like that a few years ago. We then used the new(ish) java.util.concurrent stuff like ExecutorService to have it process work from other servlets.
More information about what you're trying to do, and why the existing ways of doing things is insufficient, would be helpful.
You can use messaging for that. Just send message to the queue, and let the message listener do the processing asynchronously in the background.
You can use JMS for the implementation, and ActiveMQ for the message broker.
Spring has JMSTemplate, JMSGateWaySupport API to make JMS Implementation simple
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jms.html
Here's what I'm trying to do:
public void init(ServletConfig config) {
// ...
URL url = new URL("http://myhost:port/path/to/otherservlet");
// ... do stuff with contents of url
}
This works fine, but myhost and port are hardcoded and I want to avoid that. I want
URL url = new URL("/path/to/otherservlet");
but that's not valid. I've also tried
config.getServletContext().getResource("/path/to/otherservlet");
but that only works on static files.
How can I use the result of getting one servlet to initialize another? I don't want to use RequestDispatcher's forward() or include() methods -- the results of otherservlet are intended for use in the init() method, not to be sent in the response.
If possible, I think the better approach is to refactor the code for the other servlet into a class somewhere that can be called directly for the output that you need.
I wouldn't be surprised to find that it can't be done. I think toby's answer (split the code out into a common class) is the best approach, but if that's really not possible, try encoding the host and port to be used for local requests as context parameters in the server's web.xml file:
<context-param>
<param-name>localhost</param-name>
<param-value>localhost</param-value>
</context-param>
<context-param>
<param-name>localport</param-name>
<param-value>8080</param-value>
</context-param>
and get the values with context.getInitParameter("localhost") etc. You could also try to determine the values dynamically, but you might have to wait for a request to come in so you can use something like HttpUtils.getRequestURL(req) - I don't know any other way to do it.
Maybe it'd work if you prepend that URL with the servlet context.
I agree that a refactoring sounds like a better idea. If it's an init operation, and both servlets are in the same context, perhaps the parameters can be externalized to a file or database in such a way that both can pick them up.
I wouldn't like an init to be too extensive.