Using JUnit to test a class that connects to Database Java print this error:
Error:Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
Using the same class in a Main Class i have the same error.
Using the same class in a servlet, testing it from the browser, it works with no problems.
My database class to connect with DB (the error is on "ds.getConnection();"):
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class Database {
private static DataSource ds;
static {
try {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
ds = (DataSource) envCtx.lookup("jdbc/mua");
} catch (NamingException e) {
System.out.println("Error:" + e.getMessage());
}
}
public static Connection getConnessione() throws SQLException {
return ds.getConnection();
}
}
This is the context.xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Context>
<Resource name="jdbc/mua"
auth="Container"
driverClassName="com.mysql.jdbc.Driver"
type="javax.sql.DataSource"
username="root"
password="admin"
url="jdbc:mysql://localhost:3306/mua?useSSL=false"/>
</Context>
Related
I'm making a webapp using JSP and MYSQL.
I have set up a connection pool and used it in a Servlet, but I cannot access it.
I had to create manually the "lib" folder inside WEB-INF to put the database connector and the META-INF folder to put the context.xml file, because those folders were not there at the begining.
I'm following a tutorial from 2016 so I don't know how different it is now.
Thanks in advance for your help.
Src folder:
Main files:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
</web-app>
context.xml
<Context>
<Resource name="jdbc/wishes" auth="Container" type="javax.sql.DataSource" maxActive="15" maxIdle="3" maxWait="5000" username="root" password="" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/jee">
</Resource>
</Context>
Servlet
package com.gabit.dev.makeawish.controllers;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
#WebServlet(name = "ServletDatabase", value = "/ServletDatabase")
public class ServletDatabase extends HttpServlet {
private static final long serialVersionUID = 1L;
#Resource(name = "jdbc/wishes")
private DataSource myPool;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter output = response.getWriter();
response.setContentType("text/plain");
Connection myConnection = null;
Statement myStatement = null;
ResultSet myResult = null;
try {
myConnection = myPool.getConnection();
String query = "SELECT * FROM wishes";
myStatement = myConnection.createStatement();
myResult = myStatement.executeQuery(query);
while (myResult.next()) {
String title = myResult.getString(2);
output.println(title);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Error
java.lang.NullPointerException: Cannot invoke "javax.sql.DataSource.getConnection()" because "this.myPool" is null
at com.gabit.dev.makeawish.controllers.ServletDatabase.doGet(ServletDatabase.java:31)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:683)
...
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
Comment on the edit: I think I had already fixed my original issue (driver could not be found) and now I have the following problem:
EDIT 2: when I replace the url in context.xml with the full path (url=jdbc:sqlite:C:/Dev/workspace/jerseyrestdemo/resources/greetings.sqlite) it works. How can I now make that path relative??
EDIT 3: I followed the instructions inhow to configure JNDI datasource for db connection in tomcat: 1. Delete my project-specific context.xml and put the content into tomcat7/conf/context.xml. There I specified the namespace name=jdbc/greetings.sqlite
<Resource name="jdbc/greetings.sqlite"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
driverClassName="org.sqlite.JDBC"
url="jdbc:sqlite:resources/greetings.sqlite"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory">
</Resource>
In the DAO class I get the connection via
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource) envCtx.lookup("jdbc/greetings.sqlite");
conn = ds.getConnection();
But I still get the error org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (path to 'resources/greetings.sqlite': 'C:\Dev\eclipse\resources' does not exist)
EDIT 4: In the end, I go for storing the db file in the catalina home
/${catalina.home}/databases/greetings.sqlite as explained here. I guess you shouldn't store your db files in the web app project anyways
I have a SQLite db file in resources/greetings.sqlite under my project folder but when I run my webapp on tomcat it cannot find the db file:
java.sql.SQLException: path to 'resources/greetings.sqlite': 'C:\Dev\eclipse\resources' does not exist
at org.sqlite.core.CoreConnection.open(CoreConnection.java:192)
at org.sqlite.core.CoreConnection.<init>(CoreConnection.java:76)
at org.sqlite.jdbc3.JDBC3Connection.<init>(JDBC3Connection.java:25)
at org.sqlite.jdbc4.JDBC4Connection.<init>(JDBC4Connection.java:24)
at org.sqlite.SQLiteConnection.<init>(SQLiteConnection.java:45)
at org.sqlite.JDBC.createConnection(JDBC.java:114)
at org.sqlite.JDBC.connect(JDBC.java:88)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at demo.rest.jersey.spring.dao.JdbcGreetingDAO.getRowCount(JdbcGreetingDAO.java:29)
at demo.rest.jersey.spring.GreetingService.randomGreeting(GreetingService.java:29)
at demo.rest.jersey.spring.GreetingService.greet(GreetingService.java:18)
at demo.rest.jersey.spring.SpringRequestResource.getHello(SpringRequestResource.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
I have copied the jdbc jar into the tomcat/lib directory and added the code below in META-INF/context.xml and WEB-INF/web.xml.
This is what I put into my web.xml
<resource-ref>
<description>Greetings Database</description>
<res-ref-name>jdbc/greetings.sqlite</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
and I have created a file in WebContent/META-INF/context.xml. I assume the relative path in the url field of the Resource is not how it should be.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/greetings.sqlite"
auth="Container"
type="javax.sql.DataSource"
driverClassName="org.sqlite.JDBC"
url="jdbc:sqlite:resources/greetings.sqlite"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory">
</Resource>
</Context>
What I would like to avoid is putting the db file in a tomcat subdir but just make it part of the project, so others don't have to bother moving the file to their tomcat dir.
Here is the DAO class
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcGreetingDAO implements GreetingDAO
{
private Connection getConn() throws SQLException
{
Connection conn = null;
try
{
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/greetings.sqlite");
conn = ds.getConnection();
}
catch(NamingException ne)
{
System.out.println("Cannot get connection");
ne.printStackTrace();
}
return conn;
}
#Override
public void insert(String greeting) throws SQLException
{
Connection conn = getConn();
Statement st = conn.createStatement();
st.executeUpdate(String.format("INSERT INTO greetings (greeting) VALUES (%s)", greeting));
}
}
The DAO is used by a GreetingsService
public class GreetingService
{
#Autowired
private JdbcGreetingDAO dataSource;
public String addGreeting(String greeting) throws SQLException
{
dataSource.insert(greeting);
return greeting;
}
}
Thanks for the help
I've set up JNDI resources before, but I'm coming across an issue I'm not sure how to correct on my apache-tomcat-8.0.36 server.
My context.xml file contains the following:
<ResourceLink name="jdbc/FsEDBAdmin" global="jdbc/FsEDBAdmin" type="javax.sql.DataSource" />
<ResourceLink name="jdbc/FsEDBUser" global="jdbc/FsEDBUser" type="javax.sql.DataSource" />
<Resource name="jdbc/FsEDBAdmin" auth="Container"
type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://location"
username="user_admin" password="pass"
maxActive="20" maxIdle="10" maxWait="-1"/>
<Resource name="jdbc/FsEDBUser" auth="Container"
type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://location"
username="user_user" password="pass"
maxActive="20" maxIdle="10" maxWait="-1"/>
My web.xml :
<resource-ref>
<description>Admin Connection</description>
<res-ref-name>jdbc/FsEDBAdmin</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<description>User Connection</description>
<res-ref-name>jdbc/FsEDBUser</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
I'm also using these connections to define a Realm for authentication:
server.xml:
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Realm className="org.apache.catalina.realm.DataSourceRealm"
digest="digest_method" dataSourceName="jdbc/FsEDBAdmin" userTable="schema.table_name"
userNameCol="name_col" userCredCol="pass_col"
userRoleTable="schema.table_name" roleNameCol="rolename_col"
localDataSource="true"/>
</Realm>
But when I launch my application I'm getting the error mentioned in the title. I can give a full stack trace if requested.
I'd like to add on, that this was working at one point and the most recent change was the use of the Realm for authentication. Obviously I've made a mistake in defining these resources in one location or another, so another set of eyes to tell me where would be greatly appreciated. Thank you.
EDIT: This is how I'm calling the resource:
import path.to.CommonTools;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
/**
*
* #author Michael Potts
*/
public enum Resource {
INSTANCE;
private static BasicDataSource basicAdmin = null;
private static BasicDataSource basicUser = null;
private static final String JNDI_PREFIX = "java:/comp/env";
private static final String ADMIN_DB_NAME = "jdbc/FsEDBAdmin";
private static final String USER_DB_NAME = "jdbc/FsEDBUser";
/**
* Secure method that gives a connection from the pool for an Admin user
* #return java.sql.Connection
* #throws Exception Throws if Context isn't properly defined on Server
*/
public static Connection getAdminConnection() throws Exception {
try {
if(basicAdmin == null) { //1st time load
Context dbContext = (Context) new InitialContext().lookup(JNDI_PREFIX);
basicAdmin = (BasicDataSource) dbContext.lookup(ADMIN_DB_NAME);
}
return basicAdmin.getConnection();
} catch (NamingException | SQLException e) {
throw new RuntimeException("\nInvalid JNDI resource: " + ADMIN_DB_NAME + CommonTools.getStackTrace(e));
}
}
/**
* Secure method that gives a connection from the pool for a standard user
* #return java.sql.Connection
* #throws Exception Throws if Context isn't properly defined on Server
*/
public static Connection getUserConnection() throws Exception {
try {
if(basicUser == null) { //1st time load
Context dbContext = (Context) new InitialContext().lookup(JNDI_PREFIX);
basicUser = (BasicDataSource) dbContext.lookup(USER_DB_NAME);
}
return basicUser.getConnection();
} catch (NamingException | SQLException e) {
throw new RuntimeException("\nInvalid JNDI resource: " + USER_DB_NAME + CommonTools.getStackTrace(e));
}
}
}
So the solution for me was to remove ALL ENTRIES except the base Resource definitions in context.xml. This includes removing ResourceLink entries. So if you've tried everything and you're getting this error like I am just ignore all documentation and just define in Context.xml.
I've been trying to find a solution here but I cant...
I have the following code and i get this error.
Am I missing something? Thank you :)
Code
package src;
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Wrapper;
import java.util.Hashtable;
import java.util.Properties;
import java.io.*;
import javax.*;
import javax.activation.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import oracle.jdbc.pool.OracleDataSource;
public class TestServlet {
#SuppressWarnings("unused")
public static void main(String[] argv) throws SQLException, NamingException {
Context initialContext = new InitialContext();
if ( initialContext == null){System.out.println("initialContext null");}
else {System.out.println("initialContext");}
// Get DataSource
Context environmentContext = (Context)initialContext.lookup("java:/comp/env");
if ( environmentContext == null){System.out.println("envContext null.");}
else {System.out.println("envContext");}
DataSource ds = (DataSource)environmentContext.lookup("jdbc/testdb");
System.out.println("\n -------- Oracle JDBC Connection Testing ------");
try {
Connection jdbcConnection = ((Statement) ds).getConnection();
OracleDataSource ods = ((Wrapper) ds).unwrap(OracleDataSource.class);
jdbcConnection.close();
} catch (SQLException e) {
System.out.println("Connection Failed! Check output console");
e.printStackTrace();
return;
}
String message = "You are connected!";
System.out.println(message);
}
}
context.xml
<Context>
<Resource name="jdbc/testdb"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="dba01"
password="qvE-g7Cacontext.xml"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:oracle:thin:#10.0.1.6:1521:xe"/>
</Context>
Error
Exception in thread "main" javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.lookup(Unknown Source)
at src.TestServlet.main(TestServlet.java:34)
Please let me know if you need more information!
You need an initial context factory. For Tomcat it is org.apache.naming.java.javaURLContextFactory:
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.naming.java.javaURLContextFactory");
So is it the code deployed on the server? It seems you try to access the Context using standard java as you call static main (so I guess you are calling TeestServlet.main from your runtime). The context will be setup by the web server (Tomcat), so it is availble only after you deploy your web application to it.
Please note that driverClassName that you are using is incorrect.
It should be "oracle.jdbc.OracleDriver" if you are trying to connect to Oracle Database.
<Context>
<Resource name="jdbc/testdb"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="dba01"
password="qvE-g7Cacontext.xml"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:oracle:thin:#10.0.1.6:1521:xe"/>
</Context>
While running this sample code in eclipse (the issue is not related to JSF though) i get the error javax.naming.NamingException: Cannot create resource instance
Java file
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
#SessionScoped
public class CustomerBean implements Serializable{
//resource injection
#Resource(name="jdbc/SSHD")
private DataSource ds;
//if resource inject is not support, you still can get it manually.
public CustomerBean(){
try {
System.out.println("11111111111111");
Context ctx = new InitialContext();
System.out.println("222222222222222222");
ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SSHD");
} catch (NamingException e) {
System.out.println("3333333333333333333");
e.printStackTrace();
}
}
}
webapp/WEB-INF/web.xml
<resource-ref>
<description>SSHD Connection</description>
<res-ref-name>jdbc/SSHD</res-ref-name>
<res-type>oracle.jdbc.pool.OracleDataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
webapp/META-INF/context.xml
<Context>
<Resource name="jdbc/SSHD" auth="Container" type="oracle.jdbc.pool.OracleDataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="ABCD" password="XYZZ" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:#XX.XX.XX.XXXX:1521:SSHD"/>
</Context>
webapp/WEB-INF/lib
classes12.jar
error stack
11111111111111
javax.naming.NamingException: Cannot create resource instance
222222222222222222
3333333333333333333
at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:146)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321)
at org.apache.naming.NamingContext.lookup(NamingContext.java:843)
at org.apache.naming.NamingContext.lookup(NamingContext.java:154)
Please advise