I'm working on a small JSF Project where I use a DB.
I'm working with DAO's. I'm not sure if I did it right because I never used JSF before.
My DAO's are Managedbeans with the Annotation #RequestScoped
My DB connector is a POJO.
My Question is, can my DB connector be a POJO or does it Need to be a Managedbean?
You could have a connection service class like follows: (this example assumes you already have a datasource setup in your application server)
public class ConnectionDB {
private Context initContext;
private static Context webContext;
private static DataSource dataSource = null;
private ConnectionDB() {
try {
initContext = new InitialContext();
webContext = (Context) initContext.lookup("java:/comp/env");
dataSource = (DataSource) webContext.lookup("name_ds");
} catch (NamingException e) {
e.printStackTrace();
}
}
public static DataSource getDS() {
if (dataSource == null) {
new ConnectionDB();
}
return dataSource;
}
}
In your web.xml you would need to add the following:
<resource-ref>
<res-ref-name>name_ds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Notice that I don't have it as a #ManagedBean.
Then you can use that class to initiate your connection in your other service classes, like follows:
public class Test{
private Connection conn;
private PreparedStatement prstmt;
private ResultSet rs;
public void testMethod() {
try {
conn = ConnectionDB.getDS().getConnection();
//create your sql, result sets and prepare statements
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
Related
I try to create a as-simple-as-possible connection manager för a small web-application that runs on a tomcat7 server. I have found many examples of how to implement this, but almost always those requires JNDI and JEE, or else there are no complete example.
I want my connection manager to deliver a connection from a connection-pool when I call getConnection(), and that it is thread-safe so that no other uses my connection until I close it.
In my application I call ConnectionManager.getConnection() from a REST-service and then use that connection for all database-calls throughout the request, and close it in a finally-clause.
Could someone please look at my code and see if it is good enough to fullfill my needs...? Is it any risk that two REST-calls could get the same connection or does the tomcat DataSource handle that for me?
Would it be more proper to make my class a DataSourceManager with a getDataSource() method that deliver the data source, and in my REST-service get a connection with DataSourceManager.getDataSource().getConnection()? Would it make any difference, technically?
Or do I have to do this in an other way to make it work properly...?
import java.sql.Connection;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import se.esvenska.util.Property;
public class ConnectionManager {
private static DataSource dataSource;
private static void initDataSource() throws DatabaseException {
try {
PoolProperties p = new PoolProperties();
p.setUrl("...url...");
p.setDriverClassName("org.postgresql.Driver");
p.setUsername("...user...");
p.setPassword("...password...");
p.setDefaultAutoCommit(false);
dataSource = new DataSource();
dataSource.setPoolProperties(p);
} catch (Exception e) {
e.printStackTrace();
throw new DatabaseException(e);
}
}
public static Connection getConnection() throws Exception {
if (dataSource == null) {
initDataSource();
}
return dataSource.getConnection();
}
}
It depends on what you mean by thread-safe. I don't think it'll blow up, but there's definitely the chance that you'll call initDataSource more than once.
public static Connection getConnection() throws Exception {
if (dataSource == null) { // Another thread can come in after this
initDataSource(); // and before this
}
return dataSource.getConnection();
}
You'll need to synchronize that method:
public static synchronized Connection getConnection() throws Exception {
// -----------^
if (dataSource == null) { // Now this region is
initDataSource(); // protected
}
return dataSource.getConnection();
}
I would recommend couple of changes:
Make constructor private
getConnection should be thread safe using double locking, detail here
package com.test;
import java.sql.Connection;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import se.esvenska.util.Property;
public class ConnectionManager {
private ConnectionManager() {
}
private static DataSource dataSource;
private static void initDataSource() throws DatabaseException {
try {
PoolProperties p = new PoolProperties();
p.setUrl("...url...");
p.setDriverClassName("org.postgresql.Driver");
p.setUsername("...user...");
p.setPassword("...password...");
p.setDefaultAutoCommit(false);
dataSource = new DataSource();
dataSource.setPoolProperties(p);
} catch (Exception e) {
e.printStackTrace();
throw new DatabaseException(e);
}
}
public static Connection getConnection() throws Exception {
if (dataSource == null) {
synchronized(ConnectionManager. class) {
if (dataSource == null) {
initDataSource();
}
}
}
return dataSource.getConnection();
}
}
I have created connection pool using ContextListener and host this project to tomcat.my config part as below.
in tomcat confg context.xml i have defined resource as below.
<Resource name="jdbc/TEST_DS"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:#server:1521/db"
username="uname"
password="pwd"
maxPoolSize="50"
removeAbandoned="true"
removeAbandonedTimeout="1000"
logAbandoned="true"
/>
now use this resource in ContextListener as below.
public class ConnectionListener implements ServletContextListener {
private DataSource dataSourceOracle = null;
private Connection connectionOracle = null;
private static final String ATTRIBUTE_NAME = "config";
public void contextDestroyed(ServletContextEvent sce) {
try {
if(connectionOracle!=null && !connectionOracle.isClosed() ){
this.connectionOracle.close();
this.connectionOracle = null;
}
ApplicationUtil.setServletContext(sce.getServletContext());
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public void contextInitialized(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
try {
String oracleDsName = servletContext.getInitParameter("oracle.ds.name");
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");
dataSourceOracle = (DataSource) envContext.lookup (oracleDsName);
connectionOracle = dataSourceOracle.getConnection();
System.out.println("testing Oracle connection >> "+connectionOracle);
ApplicationUtil.setServletContext(event.getServletContext());
} catch (SQLException e) {
e.printStackTrace();
}
catch (NamingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
servletContext.setAttribute(ATTRIBUTE_NAME, this);
}
public Connection getOracleConnection() throws SQLException, ClassNotFoundException {
return this.connectionOracle;
}
public static ConnectionListener getInstance(ServletContext servletContext) {
return (ConnectionListener) servletContext.getAttribute(ATTRIBUTE_NAME);
}
}
now call this connection using method:
public class ApplicationUtil {
private static ServletContext context;
/* Called by Listener */
public static void setServletContext(ServletContext context){
ApplicationUtil.context = context;
}
/* Use this method to access context from any location */
public static ServletContext getServletContext(){
return ApplicationUtil.context;
}
}
public class DBAccess {
ServletContext context = null;
public DBAccess(ServletContext cnt) {
context = cnt;
}
public Connection getOracleConnection() throws SQLException, ClassNotFoundException {
return ConnectionListener.getInstance(context).getOracleConnection();
}
public List getLanguageList() {
Connection cn = getOracleConnection();
...
}
}
these all are what i have created to make connection pool. now the issue is when the server is down connection will be closed . and i need to restart tomcat every time to make connection pool again.
Is there any permanent solution to resolve this ??
Any suggestions will be appreciate.
Thanks in adv.
A db connection cannot survive the db. When the DB shuts down, the connection is lost.
Don't get and store the connection object in the context initializing.
Ask the pool for a connection every time you need it and after working on it, release it.
If sometimes the db is not startet, you get errors, that you must handle, but if the db restarts, you are able to get connections without restarting your tomat.
I am new to javaEE and trying to make database connection. I can do it but i think my way of doing it is inefficient. Here is what i do:
static String dbUrl="jdbc:mysql://localhost:3306/Bank";
static String username="root";
static String password="";
static Connection con=null;
public static void connect ()
{
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
con=(Connection) DriverManager.getConnection(dbUrl,username,password);
System.out.println("Connected!");
}
catch (Exception e) {
e.printStackTrace();
System.out.println("not connected");
}
}
public void someFunctiontoConnectToDB{
try {
connect();
DO_THE_QUERY.....etc
}
}
Here is my problem, this method works fine, but i have to duplicate the same code whenever i try to connect to DB in another servlet or managed bean. I tried to create a class for connection and pass the Connection c as the parameter, but this time when it returns from the connection class, Connection object becomes null. Is there any other way i can make connection easier, and without code duplication?
Thanks
If it is possible try to get into JPA, it makes life much easier.
But if you are stuck with JDBC, here is a good approach for abstracting and encapsulating the Database Layer Core J2EE Patterns - Data Access Object
In a summary for your case I would do something like this:
The DAOFactory:
class MySqlDAOFactory {
static String dbUrl="jdbc:mysql://localhost:3306/Bank";
static String username="root";
static String password="";
static private Connection con;
public static void createConnection() {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
con=(Connection) DriverManager.getConnection(dbUrl,username,password);
System.out.println("Connected!");
}
catch (Exception e) {
e.printStackTrace();
System.out.println("not connected");
}
}
public static BankDAO getBankDAO() {
return new BankDAO(con);
}
}
And the BankDAO:
class BankDAO {
Connection con;
public BankDAO(Connection con) {
this.con = con;
}
public Account getAccountFor(String name) {
//JDBC Operations
return acc;
}
}
In your Managed Bean or Servlet:
public void someFunction() {
MySqlDAOFactory.createConnection();
BankDAO dao = MySqlDAOFactory.getBankDAO();
//get other DAOs
Account acc = dao.getAccountFor("bob");
}
You can create a class that will connect to database and make a method return the connection.
When you want to use connection in other classes, you simply call that method.
Or else what you can do is
Create a ServletContextListener
Add database connection code in the listener.
Add a method to return connection
Use it whenever required.
I have this simple CDI bean which displays content into JSF page:
#Named("ZonesController")
#ViewScoped
public class Zones implements Serializable
{
#Resource(name = "jdbc/Oracle")
private DataSource ds;
...........
public int countDBRowNum() throws Exception
{
String SqlStatement = null;
if (ds == null)
{
throw new SQLException();
}
Connection conn = ds.getConnection();
if (conn == null)
{
throw new SQLException();
}
PreparedStatement ps = null;
ResultSet resultSet = null;
int count = 0;
try
{
conn.setAutoCommit(false);
boolean committed = false;
try
{
SqlStatement = "SELECT COUNT(1) FROM component x, componentstats y WHERE x.componentstatsid = y.componentstatsid AND y.componenttypeid = 1100";
ps = conn.prepareStatement(SqlStatement);
resultSet = ps.executeQuery();
if (resultSet.next())
{
count = resultSet.getInt(1);
}
conn.commit();
committed = true;
}
finally
{
if (!committed)
{
conn.rollback();
}
}
}
finally
{
ps.close();
conn.close();
}
// Returns total rows in table.
return count;
}
.............
}
I created this JUnit test case which calls the Java method:
public class ZonesTest
{
#BeforeClass
public static void setUpClass() throws Exception
{
try
{
// Create initial context
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES,
"org.apache.naming");
InitialContext ic = new InitialContext();
ic.createSubcontext("java:");
ic.createSubcontext("java:/comp");
ic.createSubcontext("java:/comp/env");
ic.createSubcontext("java:/comp/env/jdbc");
// Construct DataSource
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
ds.setURL("jdbc:oracle:thin:#192.168.1.104:1521:oracle");
ds.setUser("admin");
ds.setPassword("qwerty");
ic.bind("java:/comp/env/jdbc/oracle", ds);
}
catch (NamingException ex)
{
//Logger.getLogger(MyDAOTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Test
public void testCountDBRowNum() throws Exception
{
Zones instance = new Zones();
int rows = instance.countDBRowNum();
System.out.println(rows);
}
}
I get error at these lines:
if (ds == null)
{
throw new SQLException();
}
How I can solve this problem? I want to use the datasource from the JUnit test during the testing. Can I somehow use the JUnit datasource?
You can make DataSource ds a JavaBean property and set its value on your JUnit test. This way you hide the complexity of the JNDI binding and focus your tests only on the business logic.
Your controller:
#Named("ZonesController")
#ViewScoped
public class Zones implements Serializable
{
#Resource(name = "jdbc/Oracle")
private DataSource ds;
public void setDs(DataSource ds){this.ds=ds;}
public DataSource getDs(){return ds;}
...
}
And you test class:
public class ZonesTest
{
private static OracleConnectionPoolDataSource ds;
#BeforeClass
public static void setUpClass() throws Exception
{
try
{
// Construct DataSource
ds = new OracleConnectionPoolDataSource();
ds.setURL("jdbc:oracle:thin:#192.168.1.104:1521:oracle");
ds.setUser("admin");
ds.setPassword("qwerty");
}
catch (NamingException ex)
{
//Logger.getLogger(MyDAOTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Test
public void testCountDBRowNum() throws Exception
{
Zones instance = new Zones();
instance.setDs(ds);
int rows = instance.countDBRowNum();
System.out.println(rows);
}
}
As a side note, following the MVC design pattern I would even decouple the controller business logic from the database connection, so no valid connection is needed to execute the unit tests and your focus is entirely on the behavior of your controller.
If you are using Spring and want to use all Spring beans within your JUnit class you can always use the #RunWith JUnit annotation.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class ZonesTest
{
#Autowire
Zones zones;
// your BeforeClass method here
#Test
public void testCountDBRowNum() throws Exception
{
int rows = zones.countDBRowNum();
System.out.println(rows);
}
}
I need a database connection in Java Web service implemented as a session bean, and I'm not sure if I do it right.
I created a class
public final class SQLUtils {
//.....
private static DataSource m_ds=null;
static
{
try
{
InitialContext ic = new InitialContext();
m_ds = (DataSource) ic.lookup(dbName); //Connection pool and jdbc resource previously created in Glassfish , dbName contains the proper JNDI resource name
}
catch (Exception e)
{
e.printStackTrace();
m_ds = null;
}
}
public static Connection getSQLConnection() throws SQLException
{
return m_ds.getConnection();
}
}
Whenever I need a connection I do
Connection cn = null;
try
{
cn = SQLUtils.getSQLConnection();
// use connection
}
finally
{
if (null != cn)
{
try
{
cn.close();
}
catch (SQLException e)
{
}
}
}
Is it ok to use it this way, or I DataSource must be a member of the bean ?
#Stateless
#WebService
public class TestBean {
private #Resource(name=dbName) DataSource m_ds;
}
I'm sorry if it is a nube question, but I'm pretty new to Java. Thanks in advance.
Apart from the C-style formatting, a few unnecessary lines and a bit poor exception handling, you can just do so.
Here's how I'd do it:
public final class SQLUtil {
private static DataSource dataSource;
// ..
static {
try {
dataSource = (DataSource) new InitialContext().lookup(name);
} catch (NamingException e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
I throw here ExceptionInInitializerError so that the application will immediately stop so that you don't need to face "unexplainable" NullPointerException when trying to obtain a connection.
In the ancient J2EE world, the traditional way to manage this was to use a ServiceLocator. Below, a sample implementation (non optimized, the DataSource could be cached):
public class ServiceLocator {
private Context initalContext;
private static ServiceLocator ourInstance = new ServiceLocator();
public static ServiceLocator getInstance() {
return ourInstance;
}
private ServiceLocator() {
try {
this.initalContext = new InitialContext();
} catch (NamingException ex) {
throw new ServiceLocatorException(...);
}
}
public DataSource getDataSource(String dataSourceName) {
DataSource datasource = null;
try {
Context ctx = (Context) initalContext.lookup("java:comp/env");
datasource = (DataSource) ctx.lookup(dataSourceName);
} catch (NamingException ex) {
throw new ServiceLocatorException(...);
}
return datasource;
}
}
To use it, simply call it like this:
DataSource ds = ServiceLocator.getInstance().getDataSource("jdbc/mydatabase");
But this was prior to the EJB3 and Dependency Injection era. Now, when using EJB3, if you have setup your DataSource in your EJB container, all you have to do to automatically inject the DataSource in your Stateless Bean is to write (where mydatabase is the name of the datasource):
#Resource
private DataSource mydatabase;
Use the name attribute if you want to explicitly, well, set the name:
#Resource(name="jdbc/mydatabase")
private DataSource dataSource;
EJB3 actually make the ServiceLocator pattern obsolete and you should really prefer injection when working with them.
Um, isn't this an example to a JDBC DataSource, not a Glassfish Connection Pool?