Transfer ResultSet from class A to class B in Java - java

I am programming on a LoginForm with a MySQL database in Java. It all works well and now I wanted to add permissions. If someone logs in, the data from a specific user will be inserted in a Resultset. The problem is that I need to give the Resultset to the next class that I have the permissions in the other class and can say what the user is allowed to see. And the only clue I have is that if I call up the other class that I send it within it.
The Resultset
// That Code part is from Class A (In the Project LoginPage.java)
public void loginfunc() throws Exception {
String userID = userIDField.getText();
String password = String.valueOf((userPasswordField.getPassword()));
Connection con = getConnection();
try {
PreparedStatement statementuser = con.prepareStatement("SELECT * FROM uprtable WHERE username = '"+userID+"'");
//TODO transfer Resultset "result" to Class "WelcomePage"
ResultSet result = statementuser.executeQuery();
How I call up the other class
if (result.getString("username").equals(userID));
if (result.getString("password").equals(password)) {
frame.dispose();
String userresult = result.getString("username");
int rankresult = result.getInt("rank");
WelcomePage welcomePage = new WelcomePage(result);
}
The error I get is
'WelcomePage()' in 'com.company.WelcomePage' cannot be applied to
'(java.sql.ResultSet)'

From the error message it seems that WelcomePage class does not have a constructor that can accept a ResultSet.
You need to write a constructor in WelcomePage that can accept the ResultSet, the default constructor accepts no arguments.
For instance:
public class WelcomePage{
private ResultSet resultSet;
WelcomePage(ResultSet resultSet){
this.resultSet=resultSet;
}
}
PS: Τhis approach will work, but it would be better to parse the ResultSetinside the class that it was first referenced (Class A in this case), get all the required information release the database resources and then pass the needed data to the other class (Class B) in another way e.g. in a dedicated Java Bean.

Related

How to remove duplication from CallableStatement boiler plate code?

We have many stored procedures and functions that we call on our DB and the setup for each call in our data access layer is really verbose with setting the inputs and registering the output etc... Is there a better solution to maybe generating the CallableStatement dynamically for any stored procedure or function with any types/amounts of parameters and output type?
We have a home brew solution and it is ugly... full of if/else, fors and whiles... very hard to read and maintain. We have also tried to centralize common boilerplate code for like function calls. I.E. All of the ones that take a Long and return a boolean, all use the same centralized method with dynamic Long and stored procedure string.
The code is from memory please don't pay too much attention to syntax, this is a design question more than anything.
//Client usage in Controller class
certAwarded = PackageName.isCertAwardedFor(personIDToCheck);
//In class that mimics the interface of the database packages
//There would be a method per public function
public static boolean isCertAwardedFor(Long personID){
return PackageUtils.isMet(personID, "{? = call PACKAGE.is_met(?)}");
}
//In Package scoped Utility class
//Attempt to centralize all single input param and return of boolean
//type of procedure calls.
static boolean isMet(Long personID, String proc){
boolean met = false;
try(AutoCloseableStatement stmt = new AutoCloseableStatement(proc)){
CallableStatement callableStmt = stmt.createStatement();
callableStmt.registerOutParameter(1, OracleTypes.VARCHAR2);
callableStmt.setLong(2, personID);
callableStmt.execute();
met = convertYNtoBool(callableStmt.getString(1));
}catch(SQLException ex){
Logger.log(ex);
}
return met;
}
///////////////////////////////////OR///////////////////////////////
//Client usage in Controller class
certAwarded = PackageName.isCertAwardedFor(personIDToCheck, CertPackageEnum);
//In class that mimics the interface of the database packages
//There would be a method per public function
public static boolean isCertAwardedFor(Long personID, PackageProc procCall){
return PackageUtils.call(personID, procCall.IS_CERT_AWARDED);
}
//In Package scoped Utility class
//Attempt to centralize all single input param and return of boolean
//type of procedure calls.
static boolean isMet(Long personID, String proc){
try(AutoCloseableStatement stmt = new AutoCloseableStatement(proc)){
CallableStatement callableStmt = stmt.createStatement();
LOTS OF CONDITIONS TO CHECK AND SET ALL POSSIBLE INPUTS AND OUTPUTS
}catch(SQLException ex){
Logger.log(ex);
}
return ?????
}

Connector class from JDBC

I'm learning about JDBC and I have learned the steps: open connection, execute statement, get result, etc. I know about Connection, Statements and the other interfaces, but I just found a tutorial with another class, the Connector class. And I don't understand what exactly we can do with this Connector class. I have made some app without this class and I don't understand why do I need the Connector class? Any feedback will be apreciated!
Here is the code:
public Set getAllUsers() {
Connector connector = new Connector();
Connection connection = connector.getConnection();
try {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM user");
Set users = new HashSet();
while(rs.next())
{
User user = extractUserFromResultSet(rs);
users.add(user);
}
return users;
} catch (SQLException ex) {
ex.printStackTrace();
}
return null;
}
UPDATE:
This is the link where you can find the entire code: https://dzone.com/articles/building-simple-data-access-layer-using-jdbc
Your Connector is probably a class with a factory method:
the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.
Basically it is a utility class to create a Connection hiding the complexity of connection creation.

Jdbc template crud operations

So I have the first steps of a webapp, have class Doctor and I want to perform some operations like view all, insert, delete, etc. :
public class Doctor {
public String firstName;
public String lastName;
public int id;
public Doctor(){
}
public Doctor(int id, String first, String last){
setId(id);
setFirstName(first);
setLastName(last);
}
// getters and setters
Here is an implementation of one method from my interface Service. They are all pretty much the same with the appropriate sql queries. I tried following several different tutorials.
public class DAOImpl implements DAO{
public void insertUpdateDoctor(Doctor doctor){
String sql = "INSERT INTO doc_flight.docflight_doctors(id, first_name,last_name)" + "Values(?,?,?)";
jdbcTemplateObject.update(sql,new Object[]{doctor.getId(),doctor.getFirstName(),doctor.getLastName()});
Heres the part in main where I try to call it. The program doesn't even try to enter the method, it doesn't come up in debug and moves to the next method I try in main, view all, which works. Presumably, I'm not calling the method correctly and tried rewriting all parts several times. Help?!
Doctor test = new Doctor(17,"jack", "sparrow");
service.insertUpdateDoctor(test);
The issue itself it's not pretty clear for me.
If the problem is that when calling this:
Doctor test = new Doctor(17,"jack", "sparrow");
service.insertUpdateDoctor(test);
The runtime is not getting inside insertUpdateDoctor, just check how you are instantiating the object service
if the problem is that it's not executing correctly the sql statement, try by using a PreparedStatement (it's a good practice) by doing something like:
String connectionStr = StringUtils.format("INSERT INTO %s.docflight_doctors(id, first_name,last_name) Values(?,?,?)", this.databaseName);
try (Connection connection = this.dataSource.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(connectionStr)) {
preparedStatement.setInt(1, doctor.getId());
preparedStatement.setString(2, doctor.getFirstName());
preparedStatement.setString(3, doctor.getLastName());
preparedStatement.execute();
connection.commit();
} catch (Exception ex) {
this.logger.error(String.format("Error when inserting: %s", ex.toString()));
}
Hope it may help you.
For me I would not write this class from scratch, I would prefer to generate it in few clicks and save my time using The Cloud Wizard:
Go to https://codegen.cloud-wizard.com
Click on Java
From the technologies section press on Java SE
Select JDBC Class transformer.
In the metadata section enter a name for the JDBC Class e.g. (DoctorDao)
Add some fields e.g. first name and last name
Press on generate code and you will get your class ready and working as expected.

Java and MySQL: More than 'max_user_connections' exception

For university, it is my excercise to develop a multiplayer game with Java. The communication between the clients shall not be handled with sockets or the like, but with the help of a MySQL database where the clients are adding their steps in the game. Because it is a game of dice, not a lot of queries are needed. (approximiately 30 queries per gaming session are needed).
I never used MySQL in connection with Java before, so this maybe is a beginner's fault. But actually, I often get an exception during the execution of my java project.
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: User my_username already has more than 'max_user_connections' active connections
My queries are executed in a DatabaseHelper.java class. The results are returned and evaluated in another class of the project. Since I use an MVC pattern, I evaluate the results in a controller or model class.
This for example is one of my quers in the DatabaseHelper.java class. The other queries are similar:
private static Connection conn;
private Connection getConn() {
return conn;
}
public void db_connect() throws ClassNotFoundException, SQLException{
// JDBC Klassen laden
Class.forName(dbClassName);
// Verbindungsversuch auf 5 Sekunden setzen
DriverManager.setLoginTimeout(5);
this.setConn(DriverManager.getConnection(CONNECTION,p)); // p contains the username and the database
}
public void db_close(){
try {
this.getConn().close();
} catch (SQLException e) {
if(GLOBALVARS.DEBUG)
e.printStackTrace();
}
}
public String[] query_myHighscores(int gameid, PlayerModel p) throws SQLException{
List<String> rowValues = new ArrayList<String>();
PreparedStatement stmnt;
if(gameid == GLOBALVARS.DRAGRACE)
stmnt = this.getConn().prepareStatement("SELECT score FROM highscore WHERE gid = ? and pname = ? ORDER BY score ASC LIMIT 0,3");
else
stmnt = this.getConn().prepareStatement("SELECT score FROM highscore WHERE gid = ? and pname = ? ORDER BY score DESC LIMIT 0,3");
stmnt.setInt(1, gameid);
stmnt.setString(2, p.getUname());
ResultSet rs = stmnt.executeQuery();
rs.beforeFirst();
while(rs.next()){
rowValues.add(rs.getString(1));
}
stmnt.close();
rs.close();
return (String[])rowValues.toArray(new String[rowValues.size()]);
}
The CONNECTION string is a string which looks like jdbc:mysql://my_server/my_database
In the HighscoreGUI.java class, I request the data like this:
private void actualizeHighscores(){
DatabaseHelper db = new DatabaseHelper();
try{
db.db_connect();
String[] myScoreDragrace = db.query_myHighscores(GLOBALVARS.GAME1); // id of the game as parameter
// using the string
} finally {
db.db_close();
}
So I tried:
Closing the statement and the ResultSet after each query
Used db_close() to close the connection to the dabase in the finally-block
Never returning a ResultSet (found out this may become a performance leak)
The stacktrace leads in the DatabaseHelper.java class to the line
this.setConn(DriverManager.getConnection(CONNECTION,p));
But I cannot find my mistake why I still get this exception.
I cannot change every settings for the database since this is a shared host. So I'd prefer a solution on Java side.
The problem is that you exceed your allowed set of connections to that database. Most likely this limit is exactly or very close to "1". So as soon as you request your second connection your program crashes.
You can solve this by using a connection pooling system like commons-dbcp.
That is the recommended way of doing it and the other solution below is only if you may not use external resources.
If you are prohibited in the external code that you might use with your solution you can do this:
Create a "Database" class. This class and only this class ever connects to the DB and it does so only once per program run. You set it up, it connects to the database and then all the queries are created and run through this class, in Java we call this construct a "singleton". It usually has a private constructor and a public static method that returns the one and only instance of itself. You keep this connection up through the entire livetime of your program and only reactivate it if it gets stall. Basically you implement a "Connection Pool" for the specific case of the pool size "1".
public class Database {
private static final Database INSTANCE = new Database();
private Database() {}
public static Database getInstance() {
return INSTANCE;
}
// add your methods here.
}
When the program terminates, close the Connection (using a shutdown hook).

java connection class, passing string from servlet

I am developing a web application using JSP and Servlets.(Database: Oracle10, Container: Glassfish).
I have developed A Class for creating connection.
(Conn.java):
public class Conn
{
private Connection con = null;
public Connection getCon()
{
String home = System.getProperty("user.home");
home = home+"\\dbFile.properties";
//Read properties of Connection String from that file and Create Connection
return con;
}
}
Then I have a 4 other classes for SELECT, INSERT, UPDATE, DELETE transactions which are using above Conn.java class for getting connection:
(Select.java)
public class Select
{
private Conn connection = new Conn();
private Connection con = null;
private PreparedStatement pstmt = null;
private ResultSet rs=null;
public String[][] selectData(String query)
{
String[][] data=null;
if(con==null)
{
con = connection.getCon();
}
//execute query put data in two dimensional array and then return it
return data;
}
}
INSERT, UPDATE and DELETE are coded similar way as above Select.java is coded.
So in all servlets I am just using those 4(SELECT, INSERT, UPDATE, DELETE) classes, passing query to them and getting the result.
Sample Servlet
public class SampleServ extends HttpServlet
{
Select select = new Select();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String data[][];
data = select.selectData(QUERY_GOES_HERE);
//AND OTHER CODE
}
}
It works perfectly, but now our requirement is to change Database String after user is login. So I want to pass the User specific property file name to the Conn.java class. So for that I am storing the property file name in cookie.
I have think one way of doing this:
Get the cookie value in all servlets
Pass the cookie value to the selectData() method of Select.java class And from that class
pass the cookie value to the getConn() method of Conn.java class
So I want know if there is any better way to pass this Connection String file name to Conn.java class?
Thanks in advance.
HttpSession is where user info should be stored (with some concerns).
In your case, where you seem to have many different web applications, each of them will have a different session, and you will need to update all of them.
I prefer another approach (and this is a personal opinion, which can be discussed) which is based in the ThreadLocal class.
You can write a servlet filter, that will
read the cookie value
store it in a ThreadLocal
after the filter.doFilter method, you will have to clean it (This is extremely important, so you don't the have the chance of mixing sessions), just put the clean method in a finally block so it gets executed whatever happens.
The main advantage of this approach is that you may not have access to the HttpSession or HttpServletRequest, and you will still be able to get the value in the ThreadLocal.
An example of a ThreadLocal container you can use is this one :
public class ThreadLocalContainer {
private static ThreadLocal<String> userId=new ThreadLocal<String>();
public static String getUserId(){
return userId.get();
}
public static void setUserId(String uid){
userId.set(uid);
}
public static void resetUserId(){
userId.remove();
}
}
then you will be able to access the userId just by calling ThreadLocalContainer.getUserId() everywhere in your code, even if you don¡t have access to the http context.
Make sure you define the servlet filter in all your webapps, so the userId gets properly set.

Categories