How to code
Connection with the database
All the direct operations with the database are made through the class DatabaseOP.
For connecting with sqlserver, the driver jtds was used.
See the details of the connection:
private void connect() throws ClassNotFoundException, SQLException {
String URL = "jdbc:mysql://192.168.0.31/tutorialSite";
String DRIVER = "com.mysql.jdbc.Driver";
String USUARIO = "kaique.ferreira";
String SENHA = "griaule123";
Class.forName( DRIVER );
con = DriverManager.getConnection(URL,USUARIO,SENHA);
}
Most things this class do, are basic operations with database, however there is one that is remarkable: the functions of the class LoadDataToMemory, that is the class responsible for bringing the information from the database to the memory, making the fingerprint identification faster.
See the details of the method from DatabaseOP , which uses the methods from LoadDataToMemory to bring information to the memory.
private void loadToMemory() throws Exception{
selectStmt = con.prepareStatement("select * from tabela");
ResultSet rs = selectStmt.executeQuery();
/* In order to load the data from the database the method loadDataToMemory expects a result set as a
* parameter.
* This result set should be obtained by a select that brings all the templates.
*/
loadData = new LoadDataToMemory();
loadData.loadDataToMemory(rs);
}
The LoadDataToMemory class
Many customers complain about their search speed, they claim we promise a matching speed of 35.000 fingerprints per second, but they forget that it was measured with no other operations between the matching itself. This is why is so important bringing the templates to memory before comparing them, database access costs much time to a computer. LoadDataToMemory class is the responsible for this important quest. It's core is its method loadDataToMemory, which is shown below. It basically loops the database (parameter received as a result set) and stores it on an array.
public void loadDataToMemory(ResultSet rs) throws Exception{
int counter = 0;
array = new Register[3000];
while (rs.next()){
byte[] template1 = rs.getBytes("template1");
byte[] template2 = rs.getBytes("template2");
byte[] template3 = rs.getBytes("template3");
String name = rs.getString("name");
int ID = rs.getInt("id");
Register reg = new Register(ID,name,template1,template2,template3);
array[counter] = reg;
counter++;
}
this.numberOfRegisters = counter;
}
Interacting with the fingerprints
The program has two main classes that do the operations with fingerprints, one class for each form that manages fingerprints. Notice they are very similiar , they could have been made using inheritance.
Let's see some interesting stuff about those classes.
User authentication
The user authentication part is made by the class FormAuth along with the class FingerprintOPFormAuth. When the program detects that a fingerprint was read, he automatically compares it with the fingerprint stored in the database related to the name the user selected. Notice that on the onImageAcquired event , the program immediately after extracting the template , tries to compare the fingerprints by calling the method authenticate.
public void onImageAcquired(String IDSensor, FingerprintImage fingerprint) {
try {
template = fingerprintSDK.extract(fingerprint);
}
catch (GrFingerJavaException e) {}
this.fingerprint = fingerprint;
frmAuth.showImage(fingerprint);
try {
authenticate();
} catch (IllegalArgumentException e) {
} catch (GrFingerJavaException e) {
e.printStackTrace();
}
}
public void authenticate() throws IllegalArgumentException, GrFingerJavaException{
String name = null;
if (frmAuth.comboNames.getItemCount() > 0){ //check if the user selected a name
name = frmAuth.comboNames.getSelectedItem().toString();
//the matrix templates receives a array containing the 3 templates related to the user name
byte[][] templates = frmAuth.databaseOP.authenticate(name);
boolean matched = false;
// if one single template matches, the user is authenticated
for (int i = 0; i < 3; i++){
Template temp = new Template(templates[i]);
matched = fingerprintSDK.verify(template,temp);
if (matched)
break;
}
frmAuth.handleAuth(name, matched);
}
}
User management
The user authentication part is made by the class FormMain along with the class FingerprintOPFormMain.
Basically, the insert button and the search button define the action the program is going to take when recognizing an image. One more time is used the onImageAcquired event. Let's see this function by parts.
Insert:
If the class property function is set as 0, it means the program is on insertion mode. In this mode, it is read to read 3 users fingerprint. To know how much were read the templateCounter is used. On the two first fingerprints it just extracts the template and keeps it on the classes variables
On the last, besides extracting and keeping ,it gives the order to FormMain to insert in the database the templates that he kept , and the user's id and name
if (this.function == 0){
try {
switch (this.templateCounter){ //extracts the template into the correct variable
case 0:
template1 = fingerprintSDK.extract(fingerprint);
break;
case 1:
template2 = fingerprintSDK.extract(fingerprint);
break;
case 2:
template3 = fingerprintSDK.extract(fingerprint);
this.templateCounter = 0; //restarts the counting
this.function = -1; //the program is no long is insertion mode
try {
frmMain.commitInsert(); //tells FormMain to insert in the database the templates above extracted
} catch (Exception e) {}
break;
}
} catch (GrFingerJavaException e1) {
e1.printStackTrace();}
this.templateCounter++;
}
Search:
If the class property function is set as 1, it means the program is on searching mode.
This is an interesting example of how to make comparisons between 3 fingerprints brought by the database and kept in the memory.
A LoadDataToMemory object is created, this object receives the object used on the program , therefore, it has all the database informations in the memory.
As on fingerprint identification is necessary to compare one by one, a loop, that in the worst case checks every database register , is made.
Notice that the method prepareForIdentification must be called just one time , outside the loop.
else if (this.function == 1){
try {
Template temp = fingerprintSDK.extract(fingerprint); //temp receives the current fingerprint that was read
LoadDataToMemory lm = frmMain.frmAuth.databaseOP.getData(); //An object with the templates in the memory
fingerprintSDK.prepareForIdentification(temp);
boolean matched = false;
int i;
// if one single template matches, the user is authenticated
for (i = 0; i < lm.numberOfRegisters(); i++){
matched = false;
matched = fingerprintSDK.identify(new Template(lm.getTemplate1(i)));
if (!matched)
matched = fingerprintSDK.identify(new Template(lm.getTemplate2(i)));
if (!matched)
matched = fingerprintSDK.identify(new Template(lm.getTemplate3(i)));
if (matched)
break;
}
if (matched){
this.registerIndex = lm.getID(i); //the index tha was found is keeped
String msg = "Template found, id:" + Integer.toString(registerIndex);
JOptionPane.showMessageDialog(null,msg, "Found", JOptionPane.INFORMATION_MESSAGE);
frmMain.btnRemove.setEnabled(true);
}
else
JOptionPane.showMessageDialog(null,"Template not found", "Not found", JOptionPane.INFORMATION_MESSAGE);
} catch (GrFingerJavaException e) {
e.printStackTrace();}
}