How to get ServletContext attribute from a java class (not servlet) - java

Good evening! I have a web app with login-logout, where you can buy or sell some products. My queries are stored in a java class, called DBManager, which has just static methods that are called from servlets (I can't use JSP because in this project we can't use them, the professor gives us this constraint).
So here's the problem: I used to manage connection with ServletContextListener. In contextInitialized I set up connection, and in contextDestroyed I shutdown it. The attribute "Connection" is stored using ServletContext.setAttribute(Connection).
How can i get this parameter through the java class (not servlet) DBManager? I must get the object using getServletContext() inside a servlet and than passing it as an attribute, or there's a shortcut to avoid that?

Opening a connection in the method contextInitialized and closing it in contextDestroyed is a bad solution. Imagine that your web site has two visitors at the same time. They would now share the same database connection. If you work with transactions, you would end up with unexpected results where one visitor commits an intermediate state of a transaction executed by the other visitor. And if the connection is ever lost (maybe because the DB server is restarted), your application will fail because it does not re-establish the connection (unless you have a very smart JDBC driver).
A very expensive but safe solution would be to open a new connection for every database operation, and close it again immediately after the operation.
For a perfect solution, you would use some kind of connection pool. Whenever you need to execute a database statement (or a sequence of statements), you would borrow a connection from the pool. Once you're finished, you would return the connection to the pool. Most pool implementations take care of things like validation (check whether the connection is still "alive"), and multiple threads (different HTTP requests send by different visitors at the same time) can execute statements in parallel.
If you want to go for this solution, maybe the Commons DbUtils library is something for you: http://commons.apache.org/dbutils/
Or you check out the documentation of your Java application server or servlet engine (Tomcat?) to see what built-in DB connection pooling features it provides.

Instead of arbitrary getting the connection, you could change your class to receive a connection. That allows you to pass any instance of connection (what happens if you need to get data from another database?).
Also, imagine that the code will be ported to desktop. With this approach you can reuse your DAO without any changes.
class DBManager {
private Connection connection;
public DBManager(Connection connection) {
this.connection = connection;
}
//methods that will use the connection
}

In your HttpServlet doPost or doGet methods you can call getServletContext().
ServletContext sc = getServletContext();
DataSource ds = (DataSource) sc.getAttribute("ds");
Connection conn = ds.getConnection();
A servlet can bind an object attribute into the context by name. Any attribute bound into a context is available to any other servlet that is part of the same Web application.
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, stored in a database, or set in an Enterprise JavaBeans component.

Related

how to get one JDBC Connection for one user in application, if I have 50 users

I am creating a jdbc connection in web application.suppose ,50 users will use the application. currently, my application taking more than 20 connection for single user. how to improve the performance?
public class AuditConnection
{
private static String URL =
"jdbc:postgresql://localhost:5432/MDM_Audit?
user=rajan&password=rajan";
private static String driverName = "org.postgresql.Driver";
private static Connection con;
public static Connection getConnection() {
try {
Class.forName(driverName);
try {
con = DriverManager.getConnection(URL);
} catch (SQLException ex) {
System.out.println("Failed to create the database connection.");
}
} catch (ClassNotFoundException ex) {
// log an exception. for example:
System.out.println("Driver not found.");
}
return con;
}
}
Session & Context
In a web app, you should not be thinking about one database connection per user. Defining “user” in a web app is a bit amorphous. A user could be using multiple browser tabs/windows, or even multiple browsers. The user could be starting and closing sessions, or sessions could be expiring, and the user reconnecting.
Instead, think in terms of:
SessionEach time a user accesses your web app in a browser tab/window, a session is launched. The Java Servlet environment is built to handle the technical details on your behalf, handing you a HttpSession object. The session is closed when the user closes the browser tab/window, or after a time-out of inactivity, or when you programmatically close it, or when the Servlet container determines a problem such as failed network connection.
Each session includes a key-value store of “attributes” where you can keep objects scoped for this session.
ContextThe word “context” is Servlet-speak for your entire web app at runtime. The context is established before the first user request is processed, and is closed after the last response is sent.
On the ServletContext object you will find a key-store of “attributes” similar to the session’s attributes store.
The Servlet spec defines hooks into the lifecycle of both the session and context.
The hook for the context lifecycle is to write a class that implements ServletContextListener. You implement a pair of methods, one called by the Servlet container before the first user connection is handled (your web app is launching), and the other called after the last response is sent out (your web app is shutting-down). Search Stack Overflow for much existing coverage of this topic.
DataSource
Rather than establishing connections as you show there, it is generally better to use a DataSource object.
The JDBC driver from jdbc.postgresql.org provides an implementation of DataSource. See this Question for details: Produce a DataSource object for Postgres JDBC, programmatically.
One benefit of using the DataSource interface is that if you ever change to using a different JDBC driver (such as the pgjdbc-ng driver for Postgres), you need not change any of your calls to getConnection littered throughout your codebase.
The context starting-up hook discussed above is an ideal place for you to load your driver, test a connection to the database, and configure a DataSource object. Store that DataSource object in the “attributes” key-value store on the ServletContext mentioned above.
When you need a connection, access the ServletContext object to retrieve the DataSource your stored there as an attribute. Call DataSource::getConnection to obtain a Connection for your database.
Be sure to close the Connection object when finished with it. Learn to use the try-with-resources feature to make this closing chore a bit more elegant and easy in your code.
Connection pooling
Many people will suggest using connection-pooling. The theory here is that obtaining a connection is relatively expensive, taking a significant amount of time and CPU cycles.
Without pooling, we get a fresh connection to the database, do a bit of limited work, and then close and discard that connection. The Connection object goes out of scope and becomes a candidate for garbage-collection. On the database side, the process that was established by the Postgres Postmaster to handle that connection is closed, and memory freed-up. When a new connection is requested, the Postmaster must go to the bother of setting up a new process and allocating memory in the host OS.
With pooling, a bunch of existing database connections are held open, waiting to be used. When your app needs database work done, a connection is retrieved from the pool, you do your work, and then when you think you are closing the connection, the pool actually intervenes to keep that connection open and at the ready for future use. So every interaction with the database no longer means creating and destroying a connection with the database server.
If you go this route, the work you did above to use DataSource pays off. You switch from using a fresh-connection-each-time implementation of the DataSource interface with a connection-pooling implementation of the interface. So none of your code using the database need change.
Personally, I no longer use database connection pooling. Experiments of mine showed the premise of expensive connections to be exaggerated. Another problem: you must worry about connections being left in proper connection. For example, no pending transactions left open. Yet another problem: Trying to decide on a connection pooling implementation. There have been several over the years, and all have had various issues and problems, thereby inspiring yet another implementation. The upshot: The risk-benefit ratio of pooling is not good enough in my judgement.
You can keep the Connection opened without closing
Use Connection Pooling
(or)
Or you can save the connection object in the session and retrieve it in the servlet and pass it to the function in your DAO class whenever needed.

HikariCP - Setting connected database dynamically on connection check-in and check-out from connection pool

I need to switch the database when a connection is checked-in and checked-out from pool. For instance, session X needs to receive a connection to database A and session Y needs to receive connection to database B.
I amd able to do it with C3P0 using a connection customizer. It calls the methods onCheckIn and onCheckOut of AbstractConnectionCustomizer, so I can do something like:
public class MyConnectionCustomizer extends AbstractConnectionCustomizer {
#Override
public void onCheckOut(Connection c, String parentDataSourceIdentityToken) throws Exception {
if (something) {
c.setCatalog("some database name");
}
}
#Override
public void onCheckIn(Connection c, String parentDataSourceIdentityToken) throws Exception {
c.setCatalog("some other database name");
}
}
I am trying to switch to HikariCP but it calls the customize method of the IConnectionCustomizer only once, when the connection gets created. So, how can I manage to implement such functionality?
One use case is multi-tenancy where there is single Database with multiple schemas. Based on the tenant logged into the application we need to switch the schema dynamically
I'm trying to understand the use-case for this? Why wouldn't you use separate pools, if session X really needs a connection to database A, and session Y needs a connection to database B?
HikariCP will likely never support such functionality (I can say that as one of the authors). A connection pool should provide a DataSource that is completely transparent to the application, such that if the pool was removed and the native DataSource was used instead the application would function identically (albeit less efficiently).
The very fact that you can do something like this in C3P0, but not in HikariCP, Vibur, or Apache DBCP should be a red-flag. Using such functionality locks you into a specific pool implementation, which is never a good thing.
Sorry, I can't provide a happy answer. If I were you I would consider writing an application level helper class to get/return connections that provides the semantics you are looking for.

Can Servlets have multi-step interactions?

Is there any way to start executing java Servlet code (specifically, in Websphere Application Server) (one session, one thread on the Servlet) and then pause to get more information from the calling client at various points? I require that the current session, and ongoing Servlet thread, not die until specified, and instead keep waiting (open) for information from the client.
Is this kind of ongoing conversation possible? Or can the Servlet call to "doPost" only be started - and then the Servlet ignores the client until it finishes?
As suggested, I would use an object stored in session to maintain the state needed. You can also modify the session on a servlet by servlet basis if you need certain actions to extend the session timeout beyond the webapp defaults using the following method in the HttpSession API:
public void setMaxInactiveInterval(int interval) Specifies the time, in seconds, between client requests before the servlet container will invalidate this session. A negative time indicates the session should never timeout.
You just need to establish your logic for your object setting/retrieval from session. Typically something like this:
HttpSession session = req.getSession();
MyBeanClass bean;
Object temp = null;
temp = session.getAttribute("myBean");
if(temp !=null) {
bean = (MyBeanClass) temp;
} else {
bean = new MyBeanClass();
}
// Logic
session.setAttribute("myBean", bean);
You can save/update your session state between requests and when the next request comes, you can restore and continue whatever you were doing.
I have not done this with directly, but the underlying support is somewhat related to Jetty's continuation model and Servlet 3.0 Suspend/Resume support.
Web frameworks that work like the post description (actually, they are resumed across different connections) are sometimes called Continuation-Based frameworks. I am unsure of any such frameworks in Java (as the Java language is not conducive to such models) but there are two rather well known examples of the general principle:
Seaside (for Smalltalk) and;
Lift (for Scala).
Hope this was somewhat useful.

JDBC/Connectorj: When to load drivers?

I was wondering what is the 'correct' way to load drivers for my Java servlet.
Currently, I have a InitializeDrivers() function that I call at the beginning of my application.
public static boolean InitializeDrivers()
{
try {
Class.forName("com.mysql.jdbc.Driver");
return true;
} catch (ClassNotFoundException ex) {
// log error
return false;
}
}
After that is done, I go on performing my various requests/inserts to the database depending on the HTTP request that was received. However, since my servlet can receive hundreds of requests per seconds, InitializeDrivers() will be called one time for each request.
Is it the correct way to do this, or is there a way to load the drivers only once?
When you're using a database in a servlet, then it is better to let the servlet container manage database connections through a connection pool instead of directly getting a database connection yourself in the servlet.
Opening a connection to a database server is a relatively slow operation. Also, the number of connections that a database can handle at the same time is limited. Your application will be slow and not very scalable when you open a database connection each time you need to access the database. Also, database connections are not thread-safe, so you cannot store a database connection in a static member variable of the servlet and use that every time.
A connection pool manages a number of open connections for you (so that you don't have to open the connection each time you need to access the database), and manages the number of connections that are open at the same time. In for example Apache Tomcat, you can configure this so that you lookup a javax.sql.DataSource object via JNDI, which you then use to get a Connection object from.
This page explains how to configure Tomcat and use a DataSource in your servlet:
JNDI Datasource HOW-TO
If you do not want to do this and you want to continue using database connections from your servlet (which I do not recommend), then you could load the driver in a static initializer block in your servlet:
public class MyServlet extends HttpServlet {
static {
Class.forName("com.mysql.jdbc.Driver");
}
// ...
}
Note that in JDBC 4.0, loading the driver explicitly is not necessary anymore; JDBC will automatically find drivers as long as they in the classpath.

Correct usage of Stateful Beans with Servlets

We currently have a Stateful bean that is injected into a Servlet. The problem is that sometimes we get a Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1] when executing a method on the stateful bean.
public class NewServlet extends HttpServlet {
#EJB
private ReportLocal reportBean;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
String[] parameters = fetchParameters(request);
out.write(reportBean.constructReport(parameters));
} finally {
out.close();
}
}
}
In the above code, constructReport will check if it needs to open a new connection to the database specified in the Report after which a Report in HTML is constructed from a query which is built from the parameters specified.
The reason why we chose to use a stateful bean over a stateless bean was because we need to open a database connection to an unknown database and perform queries on it. With a stateless bean it seems terribly inefficient to repeatedly open and close database connections with each injected instance of the bean.
A few more details regarding the ConcurrentAccessException: as per the EJB spec, access to SLSB is synchronized by the app. server. However, this is not the case with SFSB. The burden of making sure that the SFSB is not accessed concurrently is on the application developer's shoulders.
Why? Well, synchronization of SLSB is only necessary at the instance-level. That is, each particular instance of the SLSB is synchronized, but you may have multiple instances in a pool or on different node in a cluster, and concurrent requests on different instances is not a problem. This is unfortunately not so easy with SFSB because of passivation/activation of instances and replication across the cluster. This is why the spec doesn't enforce this. Have a look at this dicussion if you are interested in the topic.
This means that using SFSB from servlet is complicated. A user with multiple windows from the same session, or reloading page before the rendering finished can lead to concurrent access. Each access to the EJB that is done in a servlet needs theoretically to be synchronized on the bean itself. What I did was to to create an InvocationHandler to synchronize all invocations on the particular EJB instance:
public class SynchronizationHandler implements InvocationHandler {
private Object target; // the EJB
public SynchronizationHandler( Object bean )
{
target = bean;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
synchronized( target )
{
// invoke method to the target EJB
}
}
}
Then, right after you obtain the remote reference to the EJB, you wrap it with the SynchronizationHandler. This way you are sure that this particular instance will not be accessed concurrently from your app (as long as it runs in only one JVM). You can also write a regular wrapper class which synchronizes all the methods of the bean.
My conclusion is nevertheless: use SLSB whenever possible.
EDIT:
This answer reflects the EJB 3.0 specs (section 4.3.13):
Clients are not allowed to make concurrent calls to a stateful session
object. If a client-invoked business method is in progress on an
instance when another client-invoked call, from the same or different
client, arrives at the same instance of a stateful session bean class,
if the second client is a client of the bean’s business interface, the
concurrent invocation may result in the second client receiving the
javax.ejb.ConcurrentAccessException
Such restrictions have been removed in EJB 3.1 (section 4.3.13):
By default, clients are allowed to make concurrent calls to a stateful
session object and the container is required to serialize such
concurrent requests.
[...]
The Bean Developer may optionally specify that concurrent client
requests to a stateful session bean are prohibited. This is done using
the #AccessTimeout annotation or access-timeout deployment descriptor
element with a value of 0. In this case, if a client-invoked business
method is in progress on an instance when another client-invoked call,
from the same or different client, arrives at the same instance of a
stateful session bean, if the second client is a client of the bean’s
business interface or no-interface view, the concurrent invocation
must result in the second client receiving a
javax.ejb.ConcurrentAccessException
This is not what stateful session beans (SFSB) are intended to be used for. They are designed to hold conversation state, and are to be bound to the user's http session to hold that state, like a heavyweight alternative to storing state in the session directly.
If you want to hold things like database connections, then there are better ways to go about it.
Best option is to use a connection pool. You should always use a connection pool, and if you're running inside an application server (which, if you're using EJBs, then you are), then you can easily use your appserver's datasource configuration to create a connection pool, and use that inside your stateless session bean (SLSB).
Until you provide some code and the stacktrace, I'd suggest that you consider using a connection pool.
If by "unknown database" you mean a database whose parameters are supplied by the end user, and hence no preconfigured connection pool is possible, you can still use the connection pool concept, rather than opening a new connection each time.
Also, theck this thread.
Session beans cannot be used concurrently, like skaffman said they were meant to handle state corresponding to the client session and are typically stored in the session object per client.
Refactoring to use a database pool to handle concurrent requests to your resources is the way to go.
In the meantime, if all you need is this trivial use, you could synchronise the call to constructReport as in:
synchronised (reportBean) {
out.write(reportBean.constructReport(parameters));
}
Note that this is no solution if constructReport takes a significant amount of time relative to your number of clients.
you should never syncronize servlet or ejb access since this cause requests queue and if you have N concurrently users the last one will wait for a long time and often get a timeout response!!! Syncronize method is not intended for this reason!!!

Categories

Resources