Below is code that I have. I've been trying different ways to test, including stubbing, mocking and spying. When I tried mocking the DriverManager.getConnection(), I got a message that it's private. I'm trying to practice TDD, so I know that it's not the intention to test the connection itself but rather the behavior surrounding the connection.
public class Main {
public static void main(String[] args) {
Datasource datasource = new Datasource();
if(datasource.open() == false){
return;
}
datasource.close();
}
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Datasource {
public static final String DB_NAME = "DBNAME";
public static final String DB_USERNAME = "USERNAME";
public static final String DB_PASSWORD = "PASSWORD";
public static final String SUBPROTOCOL = "jdbc:oracle:thin:#";
public static final String SERVER_NAME = "SERVERNAME";
public static final String PORT_NUMBER = "1521";
public static final String CONNECTION_STRING = SUBPROTOCOL + SERVER_NAME + ":" + PORT_NUMBER + "/" + DB_NAME;
private Connection conn;
public boolean open(){
try {
conn = DriverManager.getConnection(CONNECTION_STRING, DB_USERNAME, DB_PASSWORD);
System.out.println("Connected to database successfully.");
return true;
} catch (SQLException e) {
System.out.println("Error connecting to database: " + e.getMessage());
return false;
}
}
/**
* Closes the connection to the HR database.
* #return void
*/
public void close() {
try {
if (conn != null) {
conn.close();
System.out.println("Closed database connection successfully.");
}
} catch (SQLException e) {
System.out.println("Error closing database connection: " + e.getMessage());
}
}
}
import static org.junit.jupiter.api.Assertions.*;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Spy;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class DatasourceTest {
#Test
void exceptionIsThrownIfHRDatabaseConnectionFails() throws SQLException {
//Datasource testDatasource = new Datasource();
//assertThrows(SQLException.class, () -> {testDatasource.open();});
//TODO come back to this to mock connection
Datasource testDatasource = mock(Datasource.class);
DriverManager testDriverManager = mock(DriverManager.class);
when(testDriverManager.getConnection(Datasource.CONNECTION_STRING, Datasource.DB_USERNAME, Datasource.DB_PASSWORD)).thenReturn(null);
assertThrows(SQLException.class, () -> {testDatasource.open();});
}
#Test
void exceptionIsThrownIfConnectionIsNullDuringClose() throws SQLException {
Datasource testDatasource = new Datasource();
DriverManager testDriverManager = mock(DriverManager.class);
when(testDriverManager.getConnection(Datasource.CONNECTION_STRING, Datasource.DB_USERNAME, Datasource.DB_PASSWORD)).thenReturn(null);
}
}
Many developers may argue this test does not make sense, but in some cases you may want to test that a connection was successfully closed after using it (eg: if you find that a bug was happening because your program was exceeding the max number of connections for a giving resource, TDD encourages you to adding a test for this bugfix). In order to do this
Design the method interface by adding a test and make it fail (class DatasetTest.java):
public void whenDatasetClosed_closedReturnsTrue() {
//Arrange
//create a new dataset instance of your Dataset Class
Dataset dataset = new Dataset();
//Act
dataset.close();
//Assert
assertTrue(dataset.isClosed());
}
make conn an attribute of Dataset class
Implement close() method in Dataset class
Add the isClosed() method to the Dataset class exposing the connection status (eg. dataset.isClosed(), class Dataset.java).
public boolean isClosed() {
return this.conn.isClosed();
}
Repeat for the case where the connection is not closed and should return false.
Related
I am running a test using the Java socket class, but somehow my socket.connect ALWAYS connects successfully to something, even if my url variable is null or incorrect. Does anyone know why?
package ping_run_send;
import java.util.*;
import java.lang.*;
import java.net.*;
import java.io.*
import java.security.cert.*;
import javax.net.ssl.*;
public class tcpping {
private String url, status;
private Date timestamp;
private long rtime;
tcpping(String input_url){
this.url = input_url;
}
void ping() {
try{
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my proxy", 80));
Socket socket = new Socket(proxy);
long tStart = System.currentTimeMillis();
socket.connect(new InetSocketAddress(url, 80),2000);
long tEnd = System.currentTimeMillis();
rtime = tEnd-tStart;
timestamp = new Date(tStart);
InputStream sIn = socket.getInputStream();
if (sIn != null) {
status = "normal";
socket.close();
}else {
status = "error";
}
} catch(final MalformedURLException e){
status = "error";
} catch(IOException e){
status = "error";
}
}
Long get_rtime() {
return rtime;
}
Date get_timestamp() {
return timestamp;
}
String get_status() {
return status;
}
}
I also tried changing the if statement from isConnected() to
InputStream sIn = socket.getInputStream();
if (sIn != null) {
status = "normal";
socket.close();
}else {
status = "error";
}
But nothing seems to be have changed on its ability to detect connection error.
my testing file:
package ping_run_send;
import java.lang.*;
import java.util.*;
import java.io.*;
import ping_run_send.httpping;
public class main {
public static void main(String[] args){
String url = "http://google.com";
//urls like "",http://gowegwgwoJOIJOI03OINEPJPogle.#(*%" all works somehow
tcpping testTcp = new tcpping(url);
testTcp.ping();
System.out.println("tcp ping:");
System.out.println(testTcp.get_rtime());
System.out.println(testTcp.get_timestamp());
System.out.println(testTcp.get_status());
}
}
It is connecting to the Proxy. When you specify a Proxy the connection is made to the Proxy and the Proxy itself handles the connections to the real endpoint.
I am using below setup for fetching data from oracle DB and connection pooling.
When I do getConnection on this setup, oracle data source always creates new connection and returns, until max limit is reached. Even if I finished executing the statement. how do I release connection?
I know I can use apache dpcp or oracle upc, but I want to fix below code and I can not use any other frameworks.
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import oracle.jdbc.pool.OracleConnectionCacheManager;
import oracle.jdbc.pool.OracleDataSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class DatabaseUtility {
private static final String CACHE_NAME = "DBCACHE";
private static OracleDataSource ods = null;
private static final Logger LOGGER = LogManager.getLogger(DatabaseUtility.class);
public static synchronized void init(Properties properties) throws SQLException {
if (ods == null) {
LOGGER.info("OracleDataSource Initialization");
ods = new OracleDataSource();
ods.setURL(PropertiesLoader.getValue(properties, "jdbc.datasource.url"));
ods.setUser(PropertiesLoader.getValue(properties, "jdbc.datasource.username"));
ods.setPassword(PropertiesLoader.getValue(properties, "jdbc.datasource.password"));
ods.setConnectionCachingEnabled(true);
ods.setConnectionCacheName(CACHE_NAME);
Properties cacheProps = new Properties();
cacheProps.setProperty(
"MinLimit", PropertiesLoader.getValue(properties, "jdbc.datasource.minlimit"));
cacheProps.setProperty(
"MaxLimit", PropertiesLoader.getValue(properties, "jdbc.datasource.maxlimit"));
cacheProps.setProperty(
"InitialLimit", PropertiesLoader.getValue(properties, "jdbc.datasource.minlimit"));
cacheProps.setProperty(
"ConnectionWaitTimeout", PropertiesLoader.getValue(properties, "jdbc.datasource.wait"));
cacheProps.setProperty(
"ValidateConnection",
PropertiesLoader.getValue(properties, "jdbc.datasource.validate"));
ods.setConnectionCacheProperties(cacheProps);
}
}
private DatabaseUtility() {
throw new AssertionError("Can not create object of DatabaseUtility!");
}
public static synchronized Connection getConnection(Properties properties) throws SQLException {
LOGGER.info("Request connection!");
if (ods == null) {
init(properties);
}
return ods.getConnection();
}
public static void closePooledConnections() throws SQLException {
if (ods != null) {
ods.close();
}
}
public static void listCacheInfos() throws SQLException {
OracleConnectionCacheManager occm =
OracleConnectionCacheManager.getConnectionCacheManagerInstance();
LOGGER.info(
occm.getNumberOfAvailableConnections(CACHE_NAME)
+ " connections are available in cache "
+ CACHE_NAME);
LOGGER.info(occm.getNumberOfActiveConnections(CACHE_NAME) + " connections are active");
}
}
So, how can I release a connection for reuse after I finished executing my query?
I'm writing a program (Java Application) for reading ePassport. For access I use the library org.jmrtd. What kind of object should I transfer in CardService.getInstance() ?
import net.sf.scuba.smartcards.CardService;
import net.sf.scuba.smartcards.CardServiceException;
import org.jmrtd.BACKeySpec;
import org.jmrtd.PassportService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestComponent {
private static final Logger log = LoggerFactory.getLogger(MainApp.class);
public static void main(String args[]) {
try {
CardService cs = CardService.getInstance(???????);
PassportService ps = new PassportService(cs);
ps.open();
ps.sendSelectApplet(false);
ps.sendSelectApplet(false);
BACKeySpec bacKey = new BACKeySpec() {
public String getDocumentNumber() {
return "xxxxxxxx";
}
public String getDateOfBirth() {
return "yyMMdd";
}
public String getDateOfExpiry() {
return "yyMMdd";
}
};
ps.doBAC(bacKey);
ps.close();
} catch (CardServiceException e) {
e.printStackTrace();
}
}
}
Answer found:
add in pom
net.sf.scuba
scuba-sc-j2se
0.0.13
import net.sf.scuba.smartcards.TerminalCardService;
CardTerminal terminal =TerminalFactory.getDefault().terminals().list().get(0);
CardService cs = CardService.getInstance(terminal);
PassportService ps = new PassportService(cs);
ps.open();
I've recently starting working on a java webapp (JSP / Servlet) that was developed by the internal developer of a company.
This app randomly doesn't return data, and inspecting the log I found some NullPointerExceptions related to the classes' member variable which holds the database connection. Following the stack trace it seems that a second thread closes the connection after it ended its task leaving the first thread without a connection.
By the needs of the company the app uses different databases, one which rules appdata, and others which contain data the app has to retrieve. So every class attached to the main servlet may connect to one or more databases depending on the task it has to accomplish.
I'm not familiar with JavaEE but giving a look at the database connection class, I see nothing which protect threads from conflicting each other.
Which is the correct way to handle such connections?
This is the code of the Database handler:
package it.metmi.mmasgis.utils;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class DBManager
{
private String szDatabase;
private String szUsername;
private String szPassword;
private String szError;
private Connection db;
private boolean bConnected;
private Logger logger;
public DBManager(String szDBName)
{
this(szDBName, "", "");
}
public DBManager(String szDBName, String szName, String szPass)
{
szDatabase = szDBName;
szUsername = szName;
szPassword = szPass;
bConnected = false;
szError = "";
logger = LogManager.getFormatterLogger(DBManager.class.getName());
}
public boolean connect()
{
logger.entry();
try {
Class.forName("com.mysql.jdbc.Driver");
if(!szDatabase.isEmpty())
{
String szCon = "jdbc:mysql://localhost/" + szDatabase;
if(!szUsername.isEmpty())
{
szCon += "?user=" + szUsername;
if(!szPassword.isEmpty())
szCon += "&password=" + szPassword;
}
db = DriverManager.getConnection(szCon);
bConnected = true;
} else {
logger.error("No database name!!");
System.exit(0);
}
} catch(SQLException | ClassNotFoundException e) {
szError = e.getMessage();
e.printStackTrace();
logger.error("Can't connect: %s", e);
}
return logger.exit(bConnected);
}
public void disconnect()
{
logger.entry();
try {
db.close();
bConnected = false;
} catch(SQLException e) {
e.printStackTrace();
logger.error("Can't disconnect: %s", e);
}
logger.exit();
}
public boolean isConnected()
{
return bConnected;
}
public String getError()
{
return szError;
}
public ArrayList<HashMap<String,String>> query(String szQuery)
{
logger.entry(szQuery);
ArrayList<HashMap<String,String>> aResults = new ArrayList<HashMap<String,String>>();
int iCols = 0;
try {
Statement stmt = db.createStatement();
logger.info("Query: %s", szQuery);
ResultSet rs = stmt.executeQuery(szQuery);
ResultSetMetaData rsmd = rs.getMetaData();
iCols = rsmd.getColumnCount();
while(rs.next())
{
HashMap<String,String> pv = new HashMap<String,String>();
for(int i = 0; i < iCols; i++)
{
String szCol = rsmd.getColumnLabel(i + 1);
String szVal = rs.getString(i + 1);
pv.put(szCol, szVal);
}
aResults.add(pv);
}
rs.close();
stmt.close();
} catch(SQLException e) {
e.printStackTrace();
szError = e.getMessage();
logger.error("Error executing query: %s", e);
}
return logger.exit(aResults);
}
public boolean update(String szQuery)
{
logger.entry(szQuery);
boolean bResult = false;
try {
Statement stmt = db.createStatement();
logger.info("Query: %s", szQuery);
stmt.executeUpdate(szQuery);
bResult = true;
stmt.close();
} catch(SQLException e) {
e.printStackTrace();
szError = e.getMessage();
bResult = false;
logger.error("Error executing query: %s", e);
}
return logger.exit(bResult);
}
}
The class Task which all the servlet classes are based on, is a simple abstract class:
package it.metmi.mmasgis.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class Task
{
public abstract void doTask(HttpServletRequest request, HttpServletResponse response);
}
The class which throws NullPointerExceptions it this one, during the invocation of db.disconnect(). This class is called rapidly via AJAX 4 or 5 times from the interface written in JS.
package it.metmi.mmasgis.servlet.params;
import it.metmi.mmasgis.servlet.Task;
import it.metmi.mmasgis.utils.Const;
import it.metmi.mmasgis.utils.DBManager;
import it.metmi.mmasgis.utils.Query;
import it.metmi.mmasgis.utils.Utility;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ClassType extends Task
{
private DBManager db = null;
private Logger logger = LogManager.getFormatterLogger(ClassType.class.getName());
#Override
public void doTask(HttpServletRequest request, HttpServletResponse response)
{
logger.entry(request, response);
String szCensimento = Utility.getParameter(request, "censimento");
String szCategoria = Utility.getParameter(request, "category");
ArrayList<HashMap<String,String>> aClasses = new ArrayList<HashMap<String,String>>();
PrintWriter out = null;
logger.debug("Census: %s", szCensimento);
logger.debug("Category: %s", szCategoria);
db = new DBManager(szCensimento, Const.DB_USER, Const.DB_PASS);
if(db.connect())
{
String szQuery = String.format(Query.classes, szCategoria, szCategoria);
aClasses = db.query(szQuery);
db.disconnect();
}
try {
out = response.getWriter();
jsonEncode(aClasses, out);
} catch(IOException e) {
e.printStackTrace();
logger.error("Failed to encode JSON: %s", e);
}
logger.exit();
}
private void jsonEncode(ArrayList<HashMap<String,String>> aData, PrintWriter out)
{
HashMap<String,Object> result = new HashMap<String,Object>();
result.put("results", aData);
result.put("success", true);
Gson gson = new GsonBuilder().create();
gson.toJson(result, out);
}
}
If the webapp would use only one database, it could be rewritten as a Singleton, but in this way I have no idea on how to handle different connections for different databases.
How can avoid these exceptions?
The problem was that the connection object was declared as member.
Moving the variable inside the methods resolved.
I've been trying to make some sort of alpha key system for my game. I thought in order to prevent people from decompiling my jar and changing around some code to bypass the system and get straight into my game, I thought about making it so after some verification, the server would send a serialized copy of a ClassLoader object to the client, which the client can then use to load the required files off an external host to start running the game.
Turns out it's not working at all.. ClassLoader seems to be non-serializeable. Are there any suggestions on how I could make a simliar system, or some way to somehow be able to ram that ClassLoader object through?
Source code:
Server.java:
package org.arno;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.arno.Packet.ClassLoaderPacket;
public class InitServer {
private static ObjectOutputStream out;
private static ObjectInputStream in;
private static ServerSocket server;
private static Socket connection;
private static final float HANDSHAKE_UID = 9678;
public static void main(String[] args) {
startServer();
}
private static void startServer() {
try {
server = new ServerSocket(7799,100);
System.out.println("[LoginServer] Initiated");
while (true) {
waitForClientConnection();
setStreams();
waitForHandShake();
sendData();
closeClientConnection();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void closeClientConnection() throws Exception {
out.close();
in.close();
connection.close();
}
private static void waitForHandShake() throws Exception{
float handshake = (float) in.readObject();
System.out.println(handshake == HANDSHAKE_UID? "Handshakes match UID" : "Wrong handshake sent");
}
private static void sendData() throws Exception {
ClassLoaderPacket.writeObject(new ClassLoaderPacket(out));
System.out.println("DATA SEND");
}
private static void waitForClientConnection() throws Exception {
connection = server.accept();
System.out.println("[LoginServer] Connection made from IP ["
+ connection.getInetAddress().getHostAddress() + "]");
}
private static void setStreams() throws Exception {
out = new ObjectOutputStream(connection.getOutputStream());
out.flush();
in = new ObjectInputStream(connection.getInputStream());
}
}
ClassLoaderPacket.java:
package org.arno.Packet;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* #author arno
* File: ClassLoaderPacket.java
*/
public class ClassLoaderPacket implements Serializable {
static ObjectOutputStream out;
private transient ClassLoader cL;
private static final String GAME_URL = "https://dl.dropboxusercontent.com/u/9385659/Avalonpk718.jar";
public ClassLoaderPacket(ObjectOutputStream out) throws MalformedURLException {
this.out = out;
cL = new URLClassLoader(new URL[] { new URL(GAME_URL) });
}
public ClassLoader getClassLoaderContext() {
return cL;
}
public static void writeObject(ClassLoaderPacket packet) throws IOException {
out.writeObject(packet.getClassLoaderContext());
}
}
Client sided reading:
public void receiveData() throws Exception {
gameLoader = (ClassLoader) in.readObject();
}
I think there are too much of complex fields in the ClassLoader in order to serialize it. Additionally, it should implement Serializable interface and have serialVersionUID in the serializable class.
Would it be enough just to obfuscate the code? I think there are plenty of tools which may help you to conceal your code.
Here is the useful thread about java code obfuscation/protection: Best Java obfuscator?