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)
Related
So the problem is, that whenever I run my local tomcat server it runs the welcome servlet 3 times. It doesn't matter what is inside the doGet method, it might be only System.out.println("something"); and it will print 3 times: "something".
When the server is running and I'm calling the same servlet via web browser it works OK. I believe something is wrong with initialization, but I have no idea what and I couldn't find any solution so far. I have tried to build a completely new project, copy all classes and .xml files, but the result is exactly the same.
Edit: I'm using Itnellij UE.
Edit2: When I stop local server I'm getting this warning:
> 18-Dec-2018 21:41:23.388 WARNING [main]
> org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads
> The web application [ROOT] appears to have started a thread named
> [Abandoned connection cleanup thread] but has failed to stop it. This
> is very likely to create a memory leak. Stack trace of thread:
> java.lang.Object.wait(Native Method)
> java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
> com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:70)
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
> java.lang.Thread.run(Thread.java:748)
These are my classes and xmls:
Servlet:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
#WebServlet(name = "Servlet1", urlPatterns = {"/servlet1"})
public class Servlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String numberOfSolutions = getServletContext().getInitParameter("number-solutions");
int numberOfRows = Integer.parseInt(numberOfSolutions);
List<Solution> allSolutions;
Solution solution = new Solution();
Solution solution1 = new Solution("newServlet", 2, 3);
System.out.println();
try {
solution1.saveSolutionToDb();
allSolutions = solution.getAllSolutions(numberOfRows);
request.setAttribute("solutionsList", allSolutions);
getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Solution:
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
public class Solution {
private int id;
private Timestamp created;
private Timestamp updated;
private String description;
private int exerciseId;
private long usersId;
public Solution() {
}
public Solution(String description, int exerciseId, long usersId) {
this.description = description;
this.exerciseId = exerciseId;
this.usersId = usersId;
}
public void saveSolutionToDb() throws SQLException {
String query = "INSERT INTO solution(created,description,exercise_id,users_id) VALUES(NOW(),?,?,?);";
PreparedStatement preparedStatement = DbUtil.getConnection().prepareStatement(sql);
preparedStatement.setString(1, this.description);
preparedStatement.setInt(2, this.exerciseId);
preparedStatement.setLong(3, this.usersId);
preparedStatement.executeUpdate();
DbUtil.getConnection().close();
}
public ArrayList<Solution> getAllSolutions(int rows) throws SQLException {
ArrayList<Solution> listOfLoadedSolutions;
String query = "SELECT * FROM solution ORDER BY id DESC LIMIT " + rows + ";";
PreparedStatement preparedStatement = DbUtil.getConnection().prepareStatement(query);
listOfLoadedSolutions = getSolutions(preparedStatement);
DbUtil.getConnection().close();
return listOfLoadedSolutions;
}
private ArrayList<Solution> getSolutions(PreparedStatement preparedStatement) throws SQLException {
ArrayList<Solution> allLoadedSolutions = new ArrayList<>();
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Solution loadedSolution = new Solution();
loadedSolution.id = resultSet.getInt("id");
loadedSolution.created = resultSet.getTimestamp("created");
loadedSolution.updated = resultSet.getTimestamp("updated");
loadedSolution.description = resultSet.getString("description");
loadedSolution.exerciseId = resultSet.getInt("exercise_id");
loadedSolution.usersId = resultSet.getLong("users_id");
allLoadedSolutions.add(loadedSolution);
}
return allLoadedSolutions;
}
}
Connection:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class DbUtil {
private static DataSource ds;
public static Connection getConnection() throws SQLException {
return getInstance().getConnection();
}
private static DataSource getInstance() {
if (ds == null) {
try {
Context ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/szkola_programowania");
} catch (NamingException e) {
e.printStackTrace();
}
}
return ds;
}
}
context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/szkola_programowania"
auth="Container"
type="javax.sql.DataSource"
username="user"
password="pass"
driverClassName="com.mysql.cj.jdbc.Driver"
connectionProperties="useUnicode=yes;characterEncoding=utf8;"
url="jdbc:mysql://localhost:3306/szkola_programowania"
maxTotal="100"
maxIdle="30"
maxWaitMillis="10000" />
</Context>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<welcome-file-list>
<welcome-file>servlet1</welcome-file>
<welcome-file>default.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>number-solutions</param-name>
<param-value>5</param-value>
</context-param>
</web-app>
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pl.coderslab</groupId>
<artifactId>webExample</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
</dependencies>
</project>
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
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>
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>
I'm trying to run a simple servlet/mysql webapp using tomcat server in my eclipse.
when I try to connect to the database from a servlet, I get the following error:
org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create
PoolableConnectionFactory (Access denied for user ''#'localhost' (using password: YES))
below is the script that I executed:
The servlet:
import java.io.IOException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
public class EmployeeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Resource(name = "jdbc/testDB")
DataSource ds;
public EmployeeServlet() {
super();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Connection con = ds.getConnection();
Statement stmt = con.createStatement();
String query = "select * from Employee";
ResultSet rs = stmt.executeQuery(query);
PrintWriter out = response.getWriter();
response.setContentType("text/html");
out.print("<center><h1>Employee Details</h1></center>");
out.print("<html><body>");
out.print("<table border=\"1\" cellspacing=10 cellpadding=5>");
out.print("<tr><th>Employee ID</th>");
out.print("<th>Employee Name</th>");
out.print("<th>Salary</th>");
out.print("<th>Department</th></tr>");
while (rs.next()) {
out.print("<tr>");
out.print("<td>" + rs.getInt("emp_id") + "</td>");
out.print("<td>" + rs.getString("emp_name") + "</td>");
out.print("<td>" + rs.getDouble("salary") + "</td>");
out.print("<td>" + rs.getString("dept_name") + "</td>");
out.print("</tr>");
}
out.print("</table></body></html>");
} catch (SQLException e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}
content of context.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Context crossContext="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource name="jdbc/testDB" auth="Container"
type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/mysql">
</Context>
try connecting to mysql from any other tool / from command prompt with all the information you used in your code to connect to the same. Try including the port also in the connection url. Default port is 3306
Use mysql's GRANT query to give you permissions to access the database if you are accessing db from remote client.
seems port number missing in the url:
jdbc:mysql://localhost:<port>/mysql