Different Connections to Different Database by checking Map size - java

I have a HashMap that look something like this-
HashMap<String, TableConnectionInfo> tableList
which means it's value is a Class TableConnectionInfo which looks something like this-
public class TableConnectionInfo {
public String url;
public String user;
public String password;
public String driver;
public String suffix;
public String sql;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
}
So Suppose, If I have two values in the above HashMap. That means, I need to make two different connections to two different database. And suppose if that map has three values, then I need to make three different connections to three different database.
In the main thread, I am populating the above map by reading it from the properties file like this and after that this map won't get modified.
for (String arg : databaseNames) {
TableConnectionInfo ci = new TableConnectionInfo();
String url = prop.getProperty(arg + ".url");
String user = prop.getProperty(arg + ".user");
String password = prop.getProperty(arg + ".password");
String driver = prop.getProperty(arg + ".driver");
String suffix = prop.getProperty(arg + ".suffix");
String sql = prop.getProperty(arg + ".sql");
ci.setUrl(url);
ci.setDriver(driver);
ci.setPassword(password);
ci.setSql(sql);
ci.setSuffix(suffix);
ci.setUser(user);
tableList.put(arg, ci);
}
Now I am passing this tableList map to various threads like this and it won't be modified (by making set calls) by any thread. Each thread will be using get method to get the required method.
for (int i = 0; i< 1000; i++) {
service.submit(new Task(tableList));
}
So in the run method I need to make different conenctions basis on the tableList size. So if tableList size is two, that means I need to make two different connections, callableStatements and methods to two different database.
Question:-
So is there any better way as compared to way I am doing in my run method to create different connections to database basis on tableList size ?
Below is my Task class that impelements Runnable Interface
class Task implements Runnable {
private Connection[] dbConnection = null;
private CallableStatement[] callableStatement = null;
private ArrayList<Method> methods[] = null;
private final HashMap<String, TableConnectionInfo> tableLists;
public Task(HashMap<String, TableConnectionInfo> tableList) {
this.tableLists = tableList;
}
#Override
public void run() {
try {
int j = 0;
dbConnection = new Connection[tableLists.size()];
callableStatement = new CallableStatement[tableLists.size()];
methods = new ArrayList[tableLists.size()];
for (TableConnectionInfo ci : tableLists.values()) {
dbConnection[j] = getDBConnection(ci.getUrl(), ci.getUser(), ci.getPassword(), ci.getDriver());
callableStatement[j] = dbConnection[j].prepareCall(ci.getSql());
methods[j] = getRequiredMethods(ci.getSuffix());
j++;
}
}
}
}
Make a connection to that database-
private Connection getDBConnection(String url, String username, String password, String driver) {
Connection dbConnection = null;
try {
Class.forName(driver);
dbConnection = DriverManager.getConnection(url, username, password);
}
return dbConnection;
}
Just to add here getRequiredMethods will get all the methodNames of a particular table. So suppose if tableList size is 1 then we will be having only one connection to that database so getRequiredMethods will get all the methods for that table1 and store it in a ArrayList. But suppose if tableList size is 2 then we will be having two different connections to two different database so that is the reason I made methods as an array so that it can hold methods for table 1 and methods for table 2.

Ok, I'm still not sure how the Task is meant to use the data it's getting. But, I would move the getConnection, getCallableStatement and getMethods() functions to methods on the TableConnectionInfo. You can simply create a Collection of TableConnectionInfo (initialised as you already have, storing in an ArrayList). Then the Runnable simply iterates through the TableConnectionInfo.
public class TableConnectionInfo {
private String url;
private String user;
private String password;
private String driver;
private String suffix;
private String sql;
private Connection connection;
<snip... getters and setters for the properties>
public Connection getConnection() {
// TODO create and return a connection
if (connection == null) {
// create the connection
}
return connection;
}
public CallableStatement getCallableStatement() {
// get the callable statement
return null;
}
public Collection<Method> getMethods() {
// Get the Methods
return null;
}
}
public class TableTask implements Runnable {
private Collection<TableConnectionInfo> tables;
public TableTask(Collection<TableConnectionInfo> tables) {
this.tables = tables;
}
#Override
public void run() {
for (TableConnectionInfo table : tables) {
// do something with table.getConnection(), or table.getCallableStatement()
// and/or table.getMethods()
}
}
}

Related

Can't call a method from a separate class in Java

making a little mini blog application, just setting up the places to hold the data. I have 3 classes one for the post one for the user and one for the test, which I named Blog. when I try to call the getName(); method in the Blog class it won't run it keeps saying it needs a string, but I made an array of user objects, and input a string for the userName spot, and it still isn't working.
public class Blog
{
public static void main(String []args)
{
User[] userList = new User[3];
userList[0] = new User("what.com", "TheLegionCrab", "Jake Parham", "jparham#gmail.com");
userList[1] = new User("huh.com", "RaggleFraggle", "Brett Hawkins", "bhawkins#gmail.com");
userList[2] = new User("buh.com", "SeanBeast", "Sean Sweeney", "ssweeney#gmail.com");
for(int counter = 0; counter<userList.length; counter++)
{
User.getName();
}
}
}
public class User
{
private String url;
private String userName;
private String realName;
private String email;
public User(String url, String userName, String realName, String email)
{
this.url = url;
this.userName = userName;
this.realName = realName;
this.email = email;
}
public void getName(String userName)
{
System.out.println(userName);
}
}
public void getName(String userName)
{
System.out.println(userName);
}
Here your function require a String. That is why it need string to run. If you want to print the userName of the current User object in your loop then use this.
public void getName()
{
System.out.println(this.userName);
}
This refer to current User object in your loop.
Now back to your loop.
for(int counter = 0; counter<userList.length; counter++)
{
User.getName();
}
You use User class meanwhile you create variable as
User[] userList = new User[3];
To print from your var, you should use the var.
for(int counter = 0; counter<userList.length; counter++)
{
userList[counter].getName();
}
You need to access a User instance from your userList array (or get an instance some other way) to call the method on (and either assign it to a variable and use it or just print it). In Java, array access is performed with []. Something like
for (int counter = 0; counter < userList.length; counter++)
{
System.out.println(userList[counter].getName());
}
You could also you an enhanced for loop (for-each loop) like
for (User user : userList) {
System.out.println(user.getName());
}
Also, I don't think getName should be shadowing the class name field. You wanted something like,
public void getName()
{
System.out.println(this.userName);
}
or following the Java practice of returning the value in a getter (and to fix my examples above)
public String getName()
{
return this.userName;
}
That's because you specified that the getName method in the User class takes a String as the argument. You did that here:
public void getName(String userName)
{
System.out.println(userName);
}
So it's working exactly they way you have told it to.
But really, you want "setName()" to take a String arg, and "getName()" to take no arg. It should look like this:
public void setName(String new_userName)
{
username = new_userName;
}
public void getName()
{
System.out.println(userName);
}
But even then, I'd say that your method names are a bit ambiguous: should I use "getName" to get the username, or to get the realName?
(did you spot the error?)
It looks like what you want is to print the name of the user instance instead of the parameter to the getName method. Try this defining the method like this:
public void getName()
{
System.out.println(this.userName);
}
and in the main method:
User[] userList = new User[3];
userList[0] = new User("what.com", "TheLegionCrab", "Jake Parham", "jparham#gmail.com");
userList[1] = new User("huh.com", "RaggleFraggle", "Brett Hawkins", "bhawkins#gmail.com");
userList[2] = new User("buh.com", "SeanBeast", "Sean Sweeney", "ssweeney#gmail.com");
for(int counter = 0; counter<userList.length; counter++)
{
userList[counter].getName();
}
Issues:
a) Calling getName() without any object i.e as a static function. Instead use the objects created and call it as:
userList[counter].getName();
b)Creating User objects with the name (in constructor) and also calling getName with argument i.e userName. This is wrong/not needed. When you created the object, you have already informed the object about the userName. So have a clean getter without any argument.
getName()
The code:
public class Blog
{
public static void main(String []args)
{
User[] userList = new User[3];
userList[0] = new User("what.com", "TheLegionCrab", "Jake Parham", "jparham#gmail.com");
userList[1] = new User("huh.com", "RaggleFraggle", "Brett Hawkins", "bhawkins#gmail.com");
userList[2] = new User("buh.com", "SeanBeast", "Sean Sweeney", "ssweeney#gmail.com");
for(int counter = 0; counter<userList.length; counter++)
{
userList[counter].getName(); # Correct this to use the created objects.
}
}
}
public class User
{
private String url;
private String userName;
private String realName;
private String email;
public User(String url, String userName, String realName, String email)
{
this.url = url;
this.userName = userName;
this.realName = realName;
this.email = email;
}
public void getName() #Remove the argument.
{
System.out.println(this.userName);
}
}
You have to make the object of the User class before calling else your User class should be static to call it direct.
for(int counter = 0; counter<userList.length; counter++)
{ User obj = new User();
obj.getName();
}
else
public static User
{
public User(String url, String userName, String realName, String email)
{
this.url = url;
this.userName = userName;
this.realName = realName;
this.email = email;
}
public void getName(String userName)
{
System.out.println(userName);
}
}

How to Insert ArrayList data to the DataBase

Im try to insert data into Database using ArrayList.there is a Erro msg.
That is my Custmer.class method. this is what i got from when i going to pass ArrayList into another class.
incompatible types: ArrayList<String> cannot be converted to ArrayList<Inquiries>
I want to know how to do this using correct Using OOP concept
public void passingMsg(ArrayList<Inquiries> arrlist){
try {
System.out.println("Method "+arrlist);
String sq = "INSERT INTO Inquiries (name,mail,tp,msg)VALUES(?,?,?)";
PreparedStatement pr = con.prepareStatement(sq);
for(int i=0;i<arrlist.size();i++){
pr.setString(1,arrlist.get(i).getName());
pr.setString(2,arrlist.get(i).getMail());
pr.setString(3,arrlist.get(i).getTp());
pr.setString(4,arrlist.get(i).getMsg());
}
pr.executeQuery();//executeBatch();
} catch (SQLException ex) {
}
}
and this is how i get values from user
String name = txtName.getText();
String mail = txtEmail.getText();
String tp = txtTp.getText();
String msg = txtMsg.getText();
ArrayList<String> arrInq = new ArrayList<String>();
arrInq.add(name);
arrInq.add(mail);
arrInq.add(tp);
arrInq.add(msg);
Custmer c =new Custmer();
if( c.passingMsg(arrInq)){
try {
JOptionPane.showMessageDialog(this, "Successs!!");
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Unsuccesss!!");
e.printStackTrace();
}
}
and this is my Inquiries.class :
public class Inquiries {
private String name;
private String mail;
private String tp;
private String msg;
public Inquiries(String name,String mail,String tp,String msg){
this.name = name;
this.mail = mail;
this.tp = tp;
this.msg = msg;
}
//
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getTp() {
return tp;
}
public void setTp(String tp) {
this.tp = tp;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
Can Some one please explain whats wrong with this. please ?
Reason For Error
This was simply telling you that your types were incompatible for the operation you were trying to perform. In your passingMsg() method, you have its header as: public void passingMsg(ArrayList<Inquiries> arrlist). However, inside your "how i get values from user" area, which I will now refer to as "2nd Snippet", you have your method call declared as: if( c.passingMsg(arrInq)). This means that you are implying that your parameter being passed, arrInq in this case, is of the type ArrayList<Inquiries>, but it's not. It's being initialized in your 2nd Snippet as: ArrayList<String> arrInq = new ArrayList<String>();
Simple Fix
I take no responsibility for this code; use at your own risk. To fix this, you would want to change that entire 2nd Snippet to something similar to the following:
String name = txtName.getText();
String mail = txtEmail.getText();
String tp = txtTp.getText();
String msg = txtMsg.getText();
ArrayList<Inquiries> arrInq = new ArrayList<Inquiries>();
arrInq.add(new Inquiries(name, mail, tp, msg));
Custmer c = new Custmer();
try {
c.passingMsg(arrInq);
JOptionPane.showMessageDialog(this, "Successs!!");
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Unsuccesss!!");
e.printStackTrace();
}
You would also want to change the method header to either return a boolean, or fix it up a little bit to actually throw the exception. Such as:
public void passingMsg(ArrayList<Inquiries> arrlist) {
System.out.println("Method " + arrlist);
String sq = "INSERT INTO Inquiries(name,mail,tp,msg) VALUES(?,?,?)";
PreparedStatement pr = con.prepareStatement(sq);
for (Inquiries inquiries : arrlist) {
pr.setString(1, inquiries.getName());
pr.setString(2, inquiries.getMail());
pr.setString(3, inquiries.getTp());
pr.setString(4, inquiries.getMsg());
}
pr.executeQuery();//executeBatch();
}
Let's talk in O-O-P way.
Here Inquiries is your model, model is nothing but simple class that has instance members and public methods to get and set value of model's instance variable.
Generally we put all database related operations code in their respective models.
e.g. I have model "Model" which typically maps to database table say it as "TableModel" ,I would do something like this:
public class Model{
private int id;
private String attr;
//other properties of the model
public int getId(){
return id;
}
public void setId(int id){
this.id=id;
}
//other getters and setters
//here we write methods to performs database operations
public void save(){
//use "this" to get properties of object
//logic to save to this object in database table TableModel as record
}
public void delete(int id){
//logic to delete this object i.e. from database table TableModel
}
public Model get(int id){
//retrieve record from table TableModel with this id
}
//other methods to get data from database.
}
Now question is how I can use this in some another class. Let's say I have list of Model objects and I wish to insert them in to database.I will do it something like this:
public class AnotherClass{
public void someMethod(){
//create list of models objects e.g. get them from user interface
ArrayList<Model> models=new ArrayList<>();
for(int i=0;i<3;i++){
Model model=new Model();
model.setId(i);
model.setAttr("attr"+i);
models.add(model);
}
SomeOtherClass obj=new SomeOtherClass();
obj.insert(models);
}
}
public class SomeOtherClass{
//other code above.....
//my method that inserts each Model object in database
//Note: this is sample method , you should do it in optimized way
// e.g. batch insert
public void insert(ArrayList<Model> models){
for(Model myModel:models){
myModel.save();
}
}
//other code below.....
}
You are using the wrong type parameter for the ArrayList. Instead of ArrayList<String> you need ArrayList<Inquiries>. To fix the problem, you should remove this code ...
ArrayList<String> arrInq = new ArrayList<String>();
arrInq.add(name);
arrInq.add(mail);
arrInq.add(tp);
arrInq.add(msg);
... and replace it with this code:
ArrayList<Inquiries> arrInq = new ArrayList<Inquiries>();
arrInq.add(new Inquiries(name, mail, tp, msg));

Variable empty after assigning value from database to it

I am running a query to return the Course_Idthat is associated with the Course_Name that is selected using a JComboBox (slcCourse) in a form. The query seems to be correct, at least I think so, and the JComboBox returns the correct Course_Name from the table. When I try to assign the value returned, which should be the Course_Id from the database table, in a global or local variable and output it using JOptionPane that variable, it is empty. I am not sure why it is not being assigned to the variable and any help would be much appreciated.
The connection to the database works fine because I have already inserted records in the same class using the connection details. So the problem does not lie there.
Here is the code:
public void courseIdentifier()
{
Connection conDBase = null;
Statement stmt = null;
ResultSet r = null;
try
{
conDBase = getConnection();
stmt = conDBase.createStatement();
String courseSql = "SELECT Course_Id FROM a_courses WHERE Course_Name = '"
+ slcCourse.getSelectedItem() + "';";
r = stmt.executeQuery(courseSql);
String s = r.getString("Course_Id");
JOptionPane.showMessageDialog(null, s);
conDBase.close();
}
catch(SQLException ex)
{
ex.printStackTrace();
}
}
In case you wanted to see the connection details, here it is:
public class ConnectionDetails
{
private static final String username = "root";
private static final String password = "root";
private static final String driver = "com.mysql.jdbc.Driver";
private static final String url = "jdbc:mysql://localhost:3306/assignment?autoReconnect=true";
public static String getUsername()
{
return username;
}
public static String getPassword()
{
return password;
}
public static String getDriver()
{
return driver;
}
public static String getUrl()
{
return url;
}
}
You should call next() on the ResultSet before getting values from it :
if (r.next()) {
String s = r.getString("Course_Id");
}
Also, you might want to do something with the String you read from the ResultSet. Perhaps return it to the caller of the method.

create database connection once only

public class Database {
private String ric;
private String volume;
private String _url;
private String _userId;
private String _password;
private String _dbLib;
private String _dbFile;
private Connection _conn;
private PreparedStatement _statement;
public Database(LSE item) {
ric = item.get_ric();
volume = item.get_volume();
}
public void writeToDb() throws SQLException{
//setString
}
}
I have a ItemDispatcher class:
public class ItemDispatcher implements Runnable {
private LSE lse;
public ItemDispatcher(LSE lseItem) {
this.lse= lseItem;
}
#Override
public void run() {
try {
new Database(lse).writeToFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
run() method in ItemDispatcher runs repeatedly. I want to create database connection and prepareStatement in Database class, but doing this on Database class constuctor would create connection many times over. How can I change my design to create connection just once and not over and over again on every execution of run(). I am trying to not do this in any other class and just Database class
Within the scope of ItemDispatcher, declare private variable X of type Database. You might initialize it in a separate method (best) or in the constructor (might be ok). Use the private variable X instead of creating a new instance in method run
Do it in a static block in class Database
static {
}
But this implies that Connections and Statement will be static and then shared by all instances of Database.
Just as an example from another SO post:
public static final Map<String, String> initials = new HashMap<String, String>();
static {
initials.put("AEN", "Alfred E. Newman");
// etc.
}
Use the Singleton pattern . This will allow you to have only one instace of the Database connection.
Taking your code as an example, it would be like this :
public class Database {
private String ric;
private String volume;
private String _url;
private String _userId;
private String _password;
private String _dbLib;
private String _dbFile;
private Connection _conn;
private PreparedStatement _statement;
private static final Database INSTANCE;
private Database(LSE item) {
ric = item.get_ric();
volume = item.get_volume();
}
public static final Database getInstance(LSE item) {
if (INSTANCE == null) {
INSTANCE = new Database(LSE item);
}
return INSTANCE;
}
public void writeToDb() throws SQLException{
//setString
}
}
If your application will be using Threads (Concurrency), I suggest you also to prepare your singleton for those situations , see this question

Declaring object type via String

Here is my function:
private boolean CheckPassword(String type, String login, String passwordHash) {
EntityManagerFactory entityManagerFactory
= Persistence.createEntityManagerFactory("kwestionariuszFor" + type);
EntityManager entityManager
= entityManagerFactory.createEntityManager();
type = type.substring(0, 1).toUpperCase() + type.substring(1, type.length());
List<Object> entities
= entityManager.createNamedQuery(type + ".findByLogin").setParameter("login", login).getResultList();
if (passwordHash.equals(entities.get(0).Password)) {
return true;
}
else {
return false;
}
}
The Java doesn't "know" that there IS Password column in any of the tables. I was thinking that the way to tell it so may look like this:
List<type.toClass()>
or something... is there any way to achieve what I want? I don't want to create if, after if, after if... -_-'
You must create a common type for all of your classes that represent database tables.
Like this:
public abstract class PasswordObject {
private String password;
public PasswordObject(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
}
I don't know if the method createNamedQuery would be able to return a List<PassowrdObject>, but if not, you can just cast it like this (as long as it's safe to do so, which you can only tell by the way you use it):
PasswordObject po = (PasswordObject) entities.get(0);
String password = po.getPassword();

Categories

Resources