Last Modified 2022.2.8

Modularization - JavaBank

This article covers the modularization of the JDBC Example JavaBank.

Download the JavaBank source with the following command:

git clone https://github.com/kimjonghoon/JavaBank

Download the followings:

Copy ojdbc6.jar, slf4j-api-1.7.30.jar and slf4j-simple-1.7.30.jar to lib/ directory.

src/
├── net
│   └── java_school
│       └── bank
│            ├── Account.java
│            ├── Bank.java
│            ├── BankDao.java
│            ├── BankUi.java
│            ├── MyBank.java
│            ├── MyBankDao.java
│            └── Transaction.java
├── simplelogger.properties
lib/
├── ojdbc6.jar
├── slf4j-api-1.7.30.jar
└── slf4j-simple-1.7.30.jar

Connect to the SCOTT account with SQL*PLUS and create the following tables and a trigger that inserts transaction history data in the transaction table whenever the account balance changes.

create table bankaccount (
  accountno varchar2(50),
  owner varchar2(20) not null,
  balance number,
  kind varchar2(10),
  constraint PK_BANKACCOUNT primary key(accountno),
  constraint CK_BANKACCOUNT_NORMAL 
    CHECK (balance >= CASE WHEN kind='NORMAL' THEN 0 END),
  constraint CK_BANKACCOUNT_KIND CHECK (kind in ('NORMAL', 'MINUS'))
);  

create table transaction (
  transactiondate timestamp,
  kind varchar2(10),
  amount number,
  balance number,
  accountno varchar2(50),
  constraint FK_TRANSACTION FOREIGN KEY(accountno)
    REFERENCES bankaccount(accountno)
);

create or replace trigger bank_trigger
after insert or update of balance on bankaccount
for each row
begin
  if :new.balance > :old.balance then
    insert into transaction 
    values 
    (
      systimestamp,
      'DEPOSIT',
      :new.balance - :old.balance,
      :new.balance,
      :old.accountno
    );
  end if;
  if :new.balance < :old.balance then
    insert into transaction 
    values 
    (
      systimestamp,
      'WITHDRAW',
      :old.balance - :new.balance,
      :new.balance,
      :old.accountno
    );
  end if;
end;
/

Before modularization, check if the program works.

Test on Windows

Compile

C:\ Command Prompt
mkdir out
set classpath=lib\slf4j-api-1.7.30.jar
javac -d out src\net\java_school\bank\*.java

Copy properties to out/ directory.

C:\ Command Prompt
copy src\simplelogger.properties out\

Run

C:\ Command Prompt
set classpath=lib\slf4j-api-1.7.30.jar;lib\slf4j-simple-1.7.30.jar;lib\ojdbc6.jar;out
java net.java_school.bank.BankUi

Test on Linux

Compile

CP=lib/slf4j-api-1.7.30.jar
javac -cp $CP -d out -sourcepath src $(find src -name "*.java")

Copy properties to out/ directory.

cp src/simplelogger.properties out/

Run

CP+=:lib/slf4j-simple-1.7.30.jar
CP+=:lib/ojdbc6.jar
java -cp $CP:out net.java_school.bank.BankUi

Run the following to check the external library on which JavaBank depends.

jdeps -summary -cp lib/*.jar out
..
out -> lib/slf4j-api-1.7.30.jar
..

We found that JavaBank depends on slf4j-api-1.7.30.jar. Remember that a library like this should be in the module path. Jars that are not modules in the module path become automatic modules.

Modularization

Download the custom connection pool modules.

git clone https://github.com/kimjonghoon/java-module-test

Place the JavaBank sources in the src/ folder of java-module-test and Remove the main.app and net.java_school.db.dbpool.mysql modules in java-module-test.

src/
├── net.java_school.javabank
│   ├── net
│   │   └── java_school
│   │       └── bank
│   │            ├── Account.java
│   │            ├── Bank.java
│   │            ├── BankDao.java
│   │            ├── BankUi.java
│   │            ├── MyBank.java
│   │            ├── MyBankDao.java
│   │            └── Transaction.java
│   ├── module-info.java
│   └── simplelogger.properties
├── net.java_school.db.dbpool.api
│   ├── net
│   │   └── java_school
│   │       └── db
│   │           └── dbpool
│   │               └── api
│   │                   └── ConnectionManageable.java
│   └── module-info.java
├── net.java_school.db.dbpool
│   ├── net
│   │   └── java_school
│   │       └── db
│   │           └── dbpool
│   │               ├── DBConnectionPool.java
│   │               ├── DBConnectionPoolManager.java
│   │               └── ConnectionManager.java
│   └── module-info.java
├── net.java_school.db.dbpool.oracle
│   ├── net
│   │   └── java_school
│   │       └── db
│   │           └── dbpool
│   │               └── oracle
│   │                   └── OracleConnectionManager.java
│   ├── module-info.java
│   └── oracle.properties
lib/
├── slf4j-simple-1.7.30.jar
jars/
├── ojdbc6.jar
└── slf4j-api-1.7.30.jar

Add jars/ to the module path. Non-module jars in the module path become automatic modules.

Add lib/ to the classpath. Non-module jars in the classpath become unnamed modules.

Only automatic modules can read unnamed modules. You can easily infer that slf4j-api will read slf4j-simple from their name.

Create the module-info.java of the net.java_school.javabank module.

module net.java_school.javabank {
  requires net.java_school.db.dbpool.api;
  
  uses net.java_school.db.dbpool.api.ConnectionManageable;
}

Compile to see how the names of the automatic modules are determined.

Compile on Windows

C:\ Command Prompt
javac -p jars -d out --module-source-path src ^
-m net.java_school.javabank,net.java_school.db.dbpool.api,
net.java_school.db.dbpool,net.java_school.db.dbpool.oracle

Compile on Linux

javac -p jars -d out --module-source-path src $(find src -name "*.java")

Compile error occurs.

src/net.java_school.javabank/net/java_school/bank/MyBankDao.java:12: error: package org.slf4j is not visible
import org.slf4j.Logger;
          ^
  (package org.slf4j is declared in module org.slf4j, but module net.java_school.javabank does not read it)
src/net.java_school.javabank/net/java_school/bank/MyBankBankDao.java:13: error: package org.slf4j is not visible
import org.slf4j.LoggerFactory;
          ^
  (package org.slf4j is declared in module org.slf4j, but module net.java_school.javabank does not read it)
2 errors

(package org.slf4j is declared in module org.slf4j, but module net.java_school.javabank does not read it)
You found the module name is org.slf4j from the error message. Edit the module-info.java in the net.java_school.javabank module as follows.

module net.java_school.javabank {
  requires net.java_school.db.dbpool.api;
  requires org.slf4j;
  
  uses net.java_school.db.dbpool.api.ConnectionManageable;
}

Test on Windows

Compile

C:\ Command Prompt
javac -p jars -d out --module-source-path src ^
-m net.java_school.javabank,net.java_school.db.dbpool.api,
net.java_school.db.dbpool,net.java_school.db.dbpool.oracle

Copy properties to the module directory.

C:\ Command Prompt
copy src\net.java_school.db.dbpool.oracle\oracle.properties ^
out\net.java_school.db.dbpool.oracle\
copy src\net.java_school.javabank\simplelogger.properties ^
out\net.java_school.javabank\

Run

C:\ Command Prompt
set classpath=lib\slf4j-simple-1.7.30.jar
java -p jars;out ^ 
-m net.java_school.javabank/net.java_school.bank.BankUi

Test on Linux

Compile

javac -p jars -d out --module-source-path src $(find src -name "*.java")

Copy properties to the module directory.

cp src/net.java_school.db.dbpool.oracle/oracle.properties \
out/net.java_school.db.dbpool.oracle/
cp src/net.java_school.javabank/simplelogger.properties \
out/net.java_school.javabank/

Run

CP=lib/slf4j-simple-1.7.30.jar
java -cp $CP -p jars:out \
-m net.java_school.javabank/net.java_school.bank.BankUi
Related Articles References