University of New York, Tirana
M.Sc. in Computer Science
Advanced Topics
in Operating Systems
Manual for Lab Practices
PART II - Remote Method Invocation
Three Tier Application with a
Database Server
Assoc. Prof. Marenglen Biba, Ph.D
Department of Computer Science E-mail: [email protected]
1. Document Purpose
This document contains explanations on how to run the following programs: RMI Servers, RMI Client and
Database Server.
For running the programs, a correct configuration of the running environment is
necessary (path and classpath variables).
Install JAVA (JDK)
Install Netbeans
Install MySQL
Install MySQL Workbench
Set path and Classpath variables in the operating system
Click on Enviroment Variables.
Find the Path system variable and click Edit. Set the value of the variable to the directory where you have
installed Java, for example:
D:\Program Files\Java\jdk1.6.0\bin
Download and Install MySQL Server:
After you download use MySQL Server Instance Config Wizard
Choose the detailed configuration:
Choose developer machine:
Choose multifunctional:
Choose Drive:
Choose decision support:
Perform the following checks:
Best Support For Multilingualism: Choose this option if you want to use utf8 as the default server character
set. This is a Unicode character set that can store characters from many different languages.
Set the password for root:
Press Execute:
Restart the computer and the installation should be complete.
Install the MySQL Workbench.
You can create the database in two ways:
1. By commands in the MySQL console
2. By graphical user interface in MySQL Workbench
Click on local instance with the right and click Query Database.
Click with the right and select create schema.
Give a name to the database: and press Apply.
Click with the right on the Tables options and select Create Table:
Choose a name for the Table:
Click on Columns and add the columns for the table. At the end click Apply.
Following the above procedure create three tables:
Table Account
Fields: IdAccount (int), Balance (float)
Table Customer
Fields: IdCustomer(int), Name (Varchar), Surname (Varchar)
Table AccountCustomer
Fields: IdAccount, IdCustomer
2. Developing the RMI Client and Server
When you finish this exercise, you will have run your first RMI system.
It consists of three major parts:
The RMI Registry that hold references to the remote services.
The RMI host server program that creates the remote services, registers them with the registry and
waits for client requests.
The RMI client program. A program that obtains references to remote service object from the RMI
registry and then uses those services.
2.1 Fundamentals of RMI
This exercise will introduce you to the definition of RMI remote services using Java interfaces.
Educational goals:
Introduce the UML Description of a banking system
Complete the Java source code for the system interfaces
These are the interfaces to develop in the project.
File Account.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Account extends Remote
{
// Add method to return master BankManager
// Add method to return Client of this account
// Add method to return balance of this account
// Add method to withdraw cash from this account
}
------------------------------------------------
File BankManager.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface BankManager extends Remote
{
// Add method to return an Account service
// Add method to return a Client service
}
------------------------------------------------
File Client.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Client extends Remote
{
// Add method to return master BankManager
// Add method to return the name of this client
}
2.2 Development of a Simple Banking System
In this part you will run your first RMI system. It is based on the Banking System that you started in the
previous exercise.
Educational goals:
Learn to run the RMI Registry as a separate process
Run a server that support remote RMI objects
Implement an RMI client that uses remote services.
The RMI Registry manages the publication of the RMI remote services. You have to run a server program
that creates the actual remote services, and finally, finish coding the program BankUser, which will use the
RMI remote services.
Step 1: Code Development
Develop the following code in Netbeans:
Account.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Account extends Remote {
// Add method to return master BankManager
public BankManager getBankManager()
throws RemoteException;
// Add method to return Client of this account
public Client getClient()
throws RemoteException;
// Add method to return balance of this account
public long getBalance()
throws RemoteException;
// Add method to withdraw cash from this account
public long getCash (long amount)
throws NoCashAvailableException, RemoteException;
}
BankManager.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface BankManager extends Remote {
// Add method to return an Account service
public Account getAccount(String accountNumber)
throws RemoteException;
// Add method to return a Client service
public Client getClient(String clientName)
throws RemoteException;
}
AccountImpl.java
import java.rmi.RemoteException;
public class AccountImpl implements Account {
private BankManager bankManager;
private Client client;
private long balance;
private String accountNumber;
// public constructor
public AccountImpl (
BankManager bankManager,
Client client,
String accountNumber) {
this.bankManager = bankManager;
this.client = client;
this.balance = 0;
this.accountNumber = accountNumber;
}
public void deposit(long amount) {
balance += amount;
}
public BankManager getBankManager()
throws RemoteException {
return bankManager;
}
public Client getClient()
throws RemoteException {
return client;
}
public long getBalance()
throws RemoteException {
return balance;
}
public long getCash(long amount)
throws NoCashAvailableException, RemoteException {
if (amount > balance) {
throw new NoCashAvailableException();
}
balance = balance - amount;
return amount;
}
}
BankManagerImpl.java
import java.util.Hashtable;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.sql.*;
public class BankManagerImpl implements BankManager {
private Hashtable accounts;
private Hashtable clients;
private Connection conn;
private Statement s;
private int CustomerID;
// public No-argument constructor
public BankManagerImpl()
throws java.rmi.RemoteException {
initialize();
}
public Account getAccount(String accountNumber)
throws RemoteException {
AccountImpl account = (AccountImpl)accounts.get(accountNumber);
return account;
}
public Client getClient(String clientName)
throws RemoteException {
ClientImpl client = (ClientImpl)clients.get(clientName);
return client;
}
// public int getCustomerId(int accountId) throws RemoteException {
//return Database.getCustomerId2(accountId);
// }
public void initialize()
throws java.rmi.RemoteException {
// Create the hashtables
accounts = new Hashtable(20);
clients = new Hashtable(10);
CreateConnection();
// Create clients and put them in the hashtable
Client clientCharlie = new ClientImpl(this, "Charlie");
UnicastRemoteObject.exportObject(clientCharlie);
Client clientShannon = new ClientImpl(this, "Shannon");
UnicastRemoteObject.exportObject(clientShannon);
clients.put("Charlie", clientCharlie);
clients.put("Shannon", clientShannon);
/// Threee Tier part: Connect to the Database server and get data
CustomerID = getCustomerId(1);
System.out.println("The customer Id from the database is:" + CustomerID);
Account account;
account = new AccountImpl(this, clientCharlie, Integer.toString(CustomerID));
((AccountImpl)account).deposit(500);
UnicastRemoteObject.exportObject(account);
accounts.put(CustomerID, account);
}
public boolean initializeConnection(String SERVER, String DATABASE, String USER_ID,
String PASSWORD) throws ClassNotFoundException, SQLException {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
String path = ("jdbc:mysql://"+ SERVER + "/" + DATABASE + "?user="
+ USER_ID + "&password=" + PASSWORD);
conn = DriverManager.getConnection(path);
s = conn.createStatement();
return true;
}
catch (SQLException e) {
return false;
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void CreateConnection(){
if(conn == null)
try{
initializeConnection("localhost","bank","root","password");
}catch(Exception e){e.printStackTrace();}
}
public int getCustomerId(int idAccount){
ArrayList<Integer> ids = new ArrayList<Integer>();
try {
Statement s = conn.createStatement();
String sql = "Select IdCustomer from accountCustomer where idAccount ='" + idAccount +
"'";
ResultSet r = s.executeQuery(sql);
while(r.next()){
ids.add(r.getInt("IdCustomer"));
}
} catch (Exception ex) {
ex.printStackTrace();
}
return ids.get(0).intValue();
}
}
BankUser.java
import java.rmi.*;
import java.net.MalformedURLException;
import java.util.Locale;
import java.text.NumberFormat;
public class BankUser {
// Interface reference to BankManager
private BankManager bm;
// No-argument constructor
public BankUser() {
try {
bm = (BankManager)Naming.lookup(
"rmi://localhost:1099/BankSystem");
} catch (MalformedURLException malformedException) {
System.err.println("Bad URL: " + malformedException);
} catch (NotBoundException notBoundException) {
System.err.println("Not Bound: " + notBoundException);
} catch (RemoteException remoteException) {
System.err.println("Remote Exception: " + remoteException);
}
try {
// Lookup account 1
Account account = bm.getAccount("1");
// Get client for account
Client client = account.getClient();
// Get name for client
String name = client.getName();
// Get balance for account
long cash = account.getBalance();
// Format and display output
NumberFormat currencyFormat =
NumberFormat.getCurrencyInstance(Locale.US);
String balanceString = currencyFormat.format(cash);
System.out.println(name + "'s account has " + balanceString);
} catch (RemoteException remoteException) {
System.err.println(remoteException);
}
}
public static void main(String[] args) {
new BankUser();
}
}
Client.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Client extends Remote {
// Add method to return master BankManager
public BankManager getBankManager()
throws RemoteException;
// Add method to return the name of this client
public String getName()
throws RemoteException;
}
ClientImpl.java
import java.rmi.RemoteException;
public class ClientImpl implements Client {
private BankManager bankManager;
private String clientName;
// public constructor
public ClientImpl(BankManager bm, String name) {
this.bankManager = bm;
this.clientName = name;
}
public BankManager getBankManager()
throws RemoteException {
return bankManager;
}
public String getName()
throws RemoteException {
return clientName;
}
}
NoCashAvailableException.java
public class NoCashAvailableException extends Exception {
}
BankSystemServer.java
import java.io.IOException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.net.MalformedURLException;
public class BankSystemServer {
// public No-argument constructor
public BankSystemServer() {
}
public static void main(String args[]) {
new BankSystemServer();
BankManager bm = null;
try {
// Create a BankManager object
bm = new BankManagerImpl();
// Export it to RMI
UnicastRemoteObject.exportObject( bm );
} catch (RemoteException remoteException) {
System.err.println(
"Failure during object export to RMI: " +
remoteException);
}
// Register an external name for the service
try {
Naming.rebind("//localhost/BankSystem", bm);
} catch (RemoteException remoteException) {
System.err.println(
"Failure during Name registration: " +
remoteException);
} catch (MalformedURLException malformedException) {
System.err.println(
"Failure during Name registration: " +
malformedException);
}
System.out.println("Server started.");
System.out.println("Enter <CR> to end.");
try {
int i = System.in.read();
} catch (IOException ioException) {
}
System.exit(0);
}
}
Step 2: Compile the code following these steps:
All the steps should be performed on the same directory where you have your .java files.
1. Compile the interfaces
Commands:
javac Account.java
javac BankManager.java
javac Client.java
2. Compile the implementation classes (Impl files)
javac AccountImpl.java
javac BankManagerImpl.java
javac ClientImpl.java
javac NoCashAvailableException.java
3. Compile with rmic the implementation classes (Impl files)
Commands:
rmic AccountImpl
rmic BankManagerImpl
rmic ClientImpl
4. Compile the Client
javac BankUser.java
5. Compile the Server
javac BankSystemServer.java
In order to connect Java with MySQL we need the following connector:
mysql-connector-java-5.1.15-bin.jar
Add the connector to the libraries of the project in Netbeans as follows:
Click with right of the mouse on the Project.
Select Properties
Select Libraries
Select on the right “Add JAR/Folder”.
Select the file
mysql-connector-java-5.1.15-bin.jar
Now the Java program is properly set to connect to MySQL.
Observe the content of the folder. You will find all the .class files.
3. Run the services and programs
3.1 Run the RMI Registry program.
The RMI Registry program is provided as a separate executable in the rmiregistry program.
Create a console and move to the directory that will contain your code from this exercise.
From that location, run the registry with the following command:
rmiregistry
Do not close this window!
3.2 Run the RMI server that hosts the remote service objects.
You need to instruct your Java program where to find the JDBC driver in order to load it at runtime:
These are several ways with which you can achieve this:
1. You can copy the file mysql-connector-java-5.1.15-bin.jar under the directory of JRE:
Lib/ext/ (for example: D:\Program Files\Java\jre1.6.0\lib\ext)
This approach does not require that you set the classpath.
2. You may also try the following command that sets the classpath when you call the java program:
java –classpath= drive:/directory/mysql-connector-java-5.1.15-bin.jar yourprogram
One of the above methods is sufficient for the program to work correctly.
Having set up correctly the JDBC path, you simply need to start the host program, BankSystemServer.
This is accomplished by creating a new console, moving to the directory which contains your code from this
exercise and running the following program:
java BankSystemServer
3.3 Run a program that will use the exported RMI services.
You simply need to start the client program, BankUser.
This is accomplished by creating a new console, moving to the directory which containts your code from
this exercise and running the following program: java BankUser.
If the database is as follows:
Depending on the above values of the fields in the AccountCustomer table you should see the effects of the
following code in BankManagerImpl:
CustomerID = getCustomerId(1);
System.out.println("The customer Id from the database is:" + CustomerID);
For example, if IDaccount is “1” as above, you will have the corresponding CustomerId printed.
If on your machine you have problems with the JDBC driver, you may also try the following command that
sets the classpath when you call the java program:
Or if you have set the environment variable CLASSPATH you will see the following :
With command: echo %classpath% you may check the value of the CLASSPATH variable.
Top Related