Biometric System

Table of Contents

INTRODUCTION

The increasing threat of identity fraud necessitates the strengthening of security features in passports and identity cards. For that reason, more and more countries will use these electronic devices. In Romania electronic passports have been already used since 2009 and electronic identity cards will be introduced in 2011 [15].

These electronic devices include biometric data like fingerprints and are almost impossible to be cloned. The police security systems must be updated to fingerprint-based biometric systems in order to deal with them.

Fingerprints can identify an individual even more effectively than a picture and personal information. They are very distinctive and permanent; even if they temporarily change slightly due to cuts, burnings and bruises on the skin, the fingerprint reappears after the finger heals, according to T. Putte and J. Keuning [17]. The fingerprints cannot be lost or stolen and they are very useful for identifying children that get lost.

As a response to this tendency of using on large scales the electronic passports and ID-cards, this paper proposes a distributed system for fingerprint identification; this system provides the ability for law enforcement and security personnel to quickly and accurately retrieve important information about individuals in the field, using fingerprint recognition techniques.

Introduction to Biometrics

Biometrics is the science and technology of measuring and analyzing biological data. The word "biometrics" is derived from the Greek words 'bios' and 'metric', which means life and measurement respectively. This directly translates into "life measurement".

The first reference found for the term “biometrics” was in a 1981 article in The New York Times, according to James L. Wayman [9].

There are two main classes of biometric characteristics: physiological and behavioral.

Behavioral biometrics measures the traits that are acquired naturally over a time. Examples of behavioral biometrics include:

Speaker Recognition – analyzing vocal behavior

Signature – analyzing signature dynamics

Keystroke – measuring the time spacing of typed words

Physiological biometrics measures the inherent physical traits on an individual. Examples of physical biometrics include:

Bertillonage – measuring body lengths (no longer used)

Fingerprint Recognition- analyzing fingertip patterns

Facial Recognition – measuring facial characteristics

Hand Geometry – measuring the shape of the hand

Iris Scan – analyzing features of colored ring of the eye

Retinal Scan – analyzing blood vessels in the eye

Vascular Patterns – analyzing vein patterns

DNA – analyzing genetic makeup

Figure 1.1 illustrates some examples of biometrics traits.

According to Anil K. Jain, Arun Ross and Salil Prabhakar [8], any human physiological or behavioral characteristic can become a biometric identifier, provided the following properties are met:

Universality: each person should have the characteristic;

Distinctiveness: any two persons should be sufficiently different in terms of the characteristic;

Figure 1.1 Examples of biometric characteristics that are commonly used: (a) face, (b) fingerprint, (c) hand geometry, (d) iris, (e) signature, and (f) voice.

Permanence: the characteristic should be sufficiently invariant (with respect to the matching criterion) over a period of time;

Collectability: the characteristic can be measured quantitatively;

Performance: refers to the achievable recognition accuracy and speed, the resources required to achieve the desired recognition accuracy and speed, as well as the operational and environmental factors that affect the accuracy and speed;

Acceptability: indicates the extent to which people are willing to accept the use of a particular biometric identifier (characteristic) in their everyday life;

Circumvention: reflects how easily the system can be fooled using fraudulent

methods.

Biometric System

A biometric system is a computerized system that implements biometric recognition algorithms. A typical biometric system consists of sensing, feature extraction, and matching modules, as one can see in Figure 1.2. Biometric sensors (e.g., fingerprint sensor, digital camera for face) capture the biometric trait of an individual to produce its digital representation. A quality check, represented by the “Pre-processing” block in Figure 1.2, is generally performed to ensure that the acquired biometric sample can be reliably processed by the subsequent feature extraction and matching modules. The feature extraction module discards the unnecessary information from the acquired samples, and extracts salient and discriminatory information called features that are generally used for matching. During matching, the query biometric sample is matched with the reference information stored in the database to establish the identity associated with the query.

Generally, a biometric system has two stages of operation: enrollment and recognition. Enrollment refers to the stage in which the system stores some biometric reference information about the person in a database. This reference information may be in the form of a template (features extracted from the biometric sample) or the biometric sample itself (e.g., face image or fingerprint image). In many applications, some demographic information about the person (name, ID number, etc.) is also stored along with the biometric reference.

In the recognition stage, the system scans the user’s biometric trait, extracts features, and matches them against the reference biometric information stored in the database.

Figure 1.2 The block diagram of a biometric system

Error Rates

In an ideal system, there are no errors, but in a real biometric system, two kinds of errors can occur: false rejection and false acceptance.

False Rejection Rate (FRR) represents the probability that a legitimate user is rejected (the system does not find the user’s current biometric data similar enough to the template stored in the database)

False Acceptance Rate (FAR) represents the probability that an impostor is accepted as a legitimate user (because the system finds the impostor’s biometric data similar enough to the template of a legitimate user).

Figure 1.3 Dependency of error rates and security threshold

In a real system, the FRR and FPR are non-zero and depend on the security threshold of the system. If the threshold is high, more false rejections and less false acceptances are encountered, and if it is low, then less false rejections and more false acceptances appear, as can be seen in Figure1.3. The threshold is selected according to the purpose of the entire biometric system.

In Figure 1.3, the curves FAR and FRR cross at a point where the two errors are equal. This value is called Equal Error Rate (ERR) or crossover accuracy. ERR is an indicator of how accurate the device is.

Fingerprint Technology

Fingerprint recognition is one of the oldest biometric techniques. According to G. Moore [14] fingerprints where used in the Old China as means of positively identifying a person as an author of a document. Today, fingerprint verification technology is the most prominent biometric technology, used by millions of people worldwide.

Fingerprints have been used in law enforcement since the last century and people usually associate fingerprint with crime. This caused some worries about the user acceptance of fingerprint-based systems but the situation has improved as the systems spread around and become more common.

There are several reasons for which fingerprints are the most used biometric identifiers:

Familiarity – Fingerprints have been collected for law enforcement and various identification purposes for decades

Large database – The FBI has a database consisting of over 44 fingerprint sets.

Accuracy – Fingerprints are among the most accurate biometrics; the more fingers used and the more area of the finger used, the more accurate they can be; studies have shown that at least four fingers should be used for larger-scale identification systems [4].

Latent prints – Latent fingerprints are the only biometric traits obtainable when the subject is not present. This can be extremely useful. For example, the FBI fingerprint database contains latent prints left behind at terrorist training camps [4].

Beside these, fingerprint patterns are stable throughout one’s lifetime; they are also unique and easily analyzed and compared. Fingerprint systems are easy to use, in most cases requiring the user to simply touch a platen with his/her forefinger. In addition to being secure, most fingerprint systems are relatively inexpensive.

The term recognition refers in this paper to either verification or identification, operations illustrated in the Figure 1.4.

Verification is the operation of authenticating a person’s identity by comparing the captured fingerprint with her own biometric template pre-stored in the system. It drives a one-to-one (1:1) comparison to establish whether the identity claimed by the person is true. Identification is the operation of finding the identity of a person by searching the entire template database for a match. It drives one-to-many (1: n) comparisons to determine the identity of the individual.

Fingerprints are either flat (capture by placing a finger directly on the scanner) or rolled (rolling the finger from one edge of the fingernail to the other).

Rolled fingerprints have been used for identification for decades [14], most commonly known from police dramas where the suspect’s fingerprints are inked and rolled side-to-side on a white paper, and provide an accurate means of identification. Operators, however, must be well trained to collect good quality rolled fingerprints; the process is slow and requires manual rolling of each of the subject’s fingers by the operator.

Single-finger flat fingerprints are typically used for verification systems and/or in small to medium-sized identification systems. Accuracy and reliability are good for most applications.

Slap fingerprints (slaps) are taken by simultaneously pressing four fingers of one hand onto a scanner or fingerprint card. Slaps are also known as four-finger simultaneous plain impressions [2]. They are, simply, multiple flat fingerprints captured at the same time. Slap fingerprints have received increasing attention for possible use in large-scale fingerprint identification systems as a possible compromise between the use of rolled fingerprints and single-finger flat fingerprints. According to U. Bradford, A. Hicklin, C. Watson, M. Indovina, and K. Kwong [2], slap fingerprint scanners tend to be larger and more expensive than single-finger fingerprint scanners.

Figure 1.4 Block diagrams for Verification and Identification operations

Limitations of fingerprint technology

Fingerprint devices can suffer from usage errors when users are not properly trained in system usage and/or motivated to cooperate when placing their finger(s) on the reader. Conditions must be right for accurate authentication; for example, wet or moist fingers, cuts on fingers, or dirt or grease can sometimes affect the authentication process [17]. Additionally, as with other biometric methods where a platen must be touched, some people are uncomfortable with touching something that other people have touched repeatedly before them.

Short Description of the Distributed Systems

A distributed system is a collection of computers that appears to its users as a single coherent system. The computers are interconnected through a network and they communicate using a certain protocol. The components of the system cooperate to perform a small set of related tasks.

According to T. Letia and M. Hulea [11], a distributed system has the following characteristics:

Resource sharing – hardware and software resources can be shared between system’s components; this resources can be statically or dynamically allocated; in case they are statically allocated, the deadlocks can be easily avoided

Openness – the system is open to hardware and software extensions; each component of the system is continuously open to interaction with other components

Concurrency – many users can simultaneously interact with the application; the concurrent access must be synchronized in order to maintain the consistency of the shared resources

Scalability – the system can easily be altered to accommodate changes in the number of users, resources and computing entities

Fault-Tolerant – the system can recover from component failures without performing incorrect actions

Highly Available – the system can restore operations, permitting it to resume providing services even when some components have failed

Recoverable – Failed components can restart themselves and rejoin the system, after the cause of failure has been repaired

Transparency

Transparent Access – local and remote resources can be accessed using the same operation

Transparent Concurrency – several processes run in parallel using shared resources but do not interfere with each other

Transparent Replication – users and applications do not know about the replicas (information multiplied between components in order to increase system’s performance)

Transparent Failure – users and application programs complete their operations despite the failure of hardware and software components

Transparent Migration – the information can be moved within the system without affecting the users and the application programs

Predictable Performance – The ability to provide desired responsiveness in a timely manner

Secure – The system authenticates access to data and services

When a distributed system is built, eight assumptions, also known as the “8 Fallacies”, according to Arnon Rotem-Gal-Oz. [1], are made:

The network is reliable.

Latency is zero.

Bandwidth is infinite.

The network is secure.

Topology does not change.

There is one administrator.

Transport cost is zero.

The network is homogeneous – a single network protocol is running

As the system is developed and maintained, these assumptions prove to be false and all cause big problems to the designers.

Advantages and disadvantages of distributed systems

The advantages of a distributed system are:

Speed – a distributed system may have more total computing power than a centralized system

Inherent Distribution – some applications involve spatially separated machines

Reliability – if a machine crashes, the system as a whole will continue functioning

Data Sharing – allows many users access a common database

Device Sharing – allows many users to share expensive peripherals

Flexibility – spread workload over available machines in most cost effective way

One of the disadvantages of the distributed systems is that the information interchange between components is performed with variable delays relative to data processing speed.

In addition, for a proper functioning of the system, software components must be synchronized in order to perform some operations or to use some shared resources (hardware or software).

An easy access also applies to confidential data so cryptography mechanisms must be used in order to secure the system and to protect the data.

OBJECTIVES AND SPECIFICATIONS

Objectives

The main objectives of the proposed system are:

Performing remote operations like verification, identification and enrollment, via a mobile device; verification and identification operations should be distributed in order to increase the execution time

Managing and assuring the consistency of a distributed database that contains the demographic information and the fingerprints of individuals

Secure all personal and biometric data against unauthorized access

Ensure the entire process is nearly instantaneous and fully automated

Create a highly intuitive and easy to use graphical user interface that any authorized individual could easily use

Specifications

Structural specifications of the system

The architecture of the system is presented in Figure 2.1. An unknown and unlimited number of servers (workstations) and clients compose the system. The workstations are interconnected through the internet composing a distributed system. The client includes two devices: a mobile device and a fingerprint reader.

The Mobile Device (MD) can connect to a workstation via GSM/GPRS (Global System for Mobile Communications / General Packet Radio Service Protocol) service. A mobile device communicates with a fingerprint reader (FPR) via Bluetooth (an open wireless protocol, for exchanging data over short distances).

The workstation (the server)

Each workstation should be a computer that has the following properties:

has its own database to store the demographic information and the fingerprints

has a real IP address and is connected to the internet in order to communicate with mobile devices and with other workstations

it supports multithreading operations in order to handle multiple clients at the same time

The communication between workstations or between mobile devices and workstations is based on the TCP/IP (Transmission Control Protocol/Internet Protocol) network protocol.

The mobile device

The mobile device must be either a mobile phone or a Personal Digital Assistant (PDA) and must support:

Java applications

communications via Bluetooth in order to connect to a fingerprint reader

communications via GPRS service in order to connect to a workstation

The fingerprint reader

The fingerprint reader must support:

communications via Bluetooth in order to connect to a mobile device

115200 BPS (bits per second) communication speed

256 gray levels (8 bits/pixel)

508 DPI (dots per inch) resolution or higher

Figure 2.1 The Architecture of the System

Functional specifications of the system

The system can perform three kinds of operations:

Finding the identity of a person based on her fingerprint (identification)

Confirming the identity of a person based on her fingerprint and a personal identification number (verification)

Remote enrollment of fingerprint together with the demographic information of an individual.

The three main functionalities of the system are illustrated in Figure 2.2 – Remote Enrollment, Figure 2.3 – Identification, Figure 2.4 – Verification, and are described in the following sections.

Figure 2.2 Remote Enrollment Operation

Figure 2.3 Identification

Figure 2.4 Verification

Functional specifications of the mobile device

The mobile device can perform the following operations:

CONNECT – Before performing any other operations, the mobile device must be

connected to a server; the user must provide an ip address and a port number on which the server waits for connections

LOGIN – After connecting to the server the user must authenticate, providing a username and a password; this operation increases the security of the system and prevents unauthorized access to the server

LOAD_FINGERPRINT – this operation involves a sequence of steps:

– Scan for Bluetooth devices (only the first time)

– Connect to the fingerprint reader

– Send a command to FPR for capturing the fingerprint

– Receive the fingerprint

The fingerprint is saved in the memory of the mobile device as an array of bytes for further operations

ADD_IDCARD_RECORD – The user can remotely add a new record on the workstation (remote enrollment – see Figure 2.2); it must provide a fingerprint, the corresponding finger number and all the demographic data from an Identity Card, including a picture; the data is transmitted to the server via GPRS

ADD_PASSPORT_RECORD – This is similar with the previous operation, but the user must provide the demographic data from the passport together with a fingerprint, in order to perform the remote enrollment

ADD_FINGERPRINT – The user is able to remotely add a single fingerprint to an existing record on the workstation; he must provide the fingerprint, a finger number and the PIN number of the existent record on the server

IDENTIF (see Figure 2.3) – The user can perform remote identification by providing only a fingerprint and the corresponding finger number of a person; the fingerprint is sent to the server and if it is identified, some information about that person (like name, surname, pin) is sent back to the mobile device, becoming visible to the user

VERIF (see Figure 2.4) – For performing remote verification operation, the user must provide a fingerprint, the finger number and a personal identification number; the data is sent to the server and a response (match/non-match) is send back to the mobile device after the operation is finished; in case of a non-match response, if the fingerprint sent does not correspond with the existent fingerprint from the server, for the corresponding pin, the personal data (name, surname, pin) is also included in the answer of the server

LOGOUT – The user can logout from the server to allow other users to use the mobile device; the device remains connected to the server, but the new user must authenticate in order to have access to operations

DISCONNECT – The connection between the mobile device and the workstation is interrupted

The mobile device can perform only one operation at a time.

Functional specifications of workstation

The server is a multithreaded application that can handle multiple connections at the same time, from clients and from other servers. The communication protocol between the server and the client is based on the request-answer model. The server receives a request from a client, performs the specified operation and sends back an answer.

It allows the following operations:

Starting the server – The administrator of the server can start it by providing a port number, on which the server accepts the connections

Authentication of connected users – When receiving a „LOGIN” message followed by a user and a password, the server checks in its database if the provided data is valid, and sends back an answer to the client. The server stores the logged users in a list that is visible to the administrator of the server; it does not allow the login of two different users with the same username

Adding of new records in its database (see Figure 2.2)

When receiving an „ADD_IDCARD_RECORD” message followed by a PIN (Personal Identification Number), the server checks if there is any record in the database with the provided PIN; if no record is found, the fingerprint, the finger number and the demographic data about the user (from the Identity Card) are received from the client and a new record is created into the database; an informing message about the result of the operation is sent back to the client

When receiving an „ADD_PASSPORT_RECORD” message, the operation is similar with the previous one, but the demographic data from the passport is provided together with the fingerprint

When receiving an „ADD_FINGERPRINT” message, the server allows adding/replacing a fingerprint to an existent record

Identification (see Figure 2.3) – This operation starts when the „IDENTIFICATION” message followed by a fingerprint and a finger number are received from the client. The fingerprint is compared with all the fingerprints from the database, for the corresponding fingerprint number. If the fingerprint is not locally identified, the distributed operation is started and the current server (initiator) sends the fingerprint to other known and online servers and waits for answers; if a positive answer is received, the initiator interrupts the other servers and sends the answer to the client. If no positive answer is received, the client is informed that the identification has failed

Verification (see Figure 2.4) – This starts when the „VERIFICATION” message followed by the fingerprint, finger number and PIN are received from the client. It is similar with the identification operation, but instead of comparing the fingerprint with all the fingerprints in the database, only a single comparison is realized (between the provided fingerprint and an existing fingerprint that corresponds to the provided PIN); if local verification fails, the distributed verification is started, in a similar way as the distributed identification operation, described before

Converting the fingerprint into a template – In all previously described operations, the fingerprint received from the client is in the form of an array of bytes. This is further converted into a bitmap file and after that, a feature set is extracted from it and saved as a template (see Figure 2.4). The template is stored into the database instead of the actual fingerprint file, because it has a smaller size. In addition, during identification and verification operations the comparisons are realized between templates.

Disconnecting a user – The administrator of the server has the privilege to disconnect a user, interrupting all the currently performed operations related to him

Stopping the server – The administrator of the server can stop the server and thus interrupting all the currently performed operations

Security specifications

To prevent unauthorized access to the server, all users must authenticate in order to be able to perform other operations. In addition, two different users cannot use the same username and password in the same time.

Both the server and the mobile device applications include a cryptography module used to protect the transmitted data. Before transmission, the data is encrypted with a key by the transmitter device (workstation or mobile device). The same key is used to decrypt the data when the receiver (workstation or mobile device) intercepts it.

The Bluetooth Sensor must use a password for connections, in order to restrict the access to the fingerprint to unauthorized mobile devices.

The access to the database of the server is restricted. Any application that wants to connect to the database must provide a valid username and password.

Database specifications

Each workstation must have its own database able to store ID-card (Identification card) records and password records. Each ID-card record and passport record should be uniquely identified by the personal identification number of the individual. More records with the same PIN should not be allowed in the database.

The database of a workstation must contain a table with authorized usernames and passwords. In addition, a table containing the IP (Internet Protocol) addresses of other servers is required, for realizing the distributed operations.

The server application must manage the consistency of the database by using transactions. If any transaction fails, rollback mechanisms should assure that the tables does not contain inconsistent data.

The user and the mobile device application must assure that the data provided by the user, that will be transmitted and stored in the database, is valid.

The records could be multiplied between workstations, in order to increase the performance of the system.

The database should be normalized in order to ensure that its structure is suitable for general-purpose querying and free of certain undesirable characteristics (insertion, update, and deletion anomalies) that could lead to a loss of data integrity.

Reliability specifications

The system is open to hardware and software extensions; each workstation of the system is continuously open to interaction with other workstations. If a workstation crashes, the system as a whole will continue functioning. After repairing, the workstation can rejoin the system.

If a workstation fails during a distributed search, the server application that has initiated the search should consider it when waiting for answers; this is necessary for avoiding deadlock situations.

The server application provides synchronization mechanisms in order to protect shared resources and to avoid deadlocks.

If an operation fails, the client should be informed about the reason that caused the failure.

Testing specifications

The system must be tested under the following situations:

Low-loading conditions:

A single workstation is running

A client connects to a workstation and performs an operation

The database of the server contains 0 records or few records

High-loading conditions

Multiple workstations are running and they can communicate through a network

Multiple clients connect to the same workstation and perform operations

Multiple clients connect to each workstation and perform operations

The database of each server contains hundreds or thousands of records

The network is busy

Testing specifications for the client

The client must be tested in the following situations:

It connects to an invalid server

It connects using an invalid port number

It authenticates using wrong username or password

It tries to log in with a username that is already logged in on the server

It performs any operation without loading the fingerprint

It tries to perform an operation while other operation is in progress

It performs any operation providing invalid data (like a finger number greater then ten)

It disconnects while an operation is in progress

A low quality image is transmitted during an operation

Testing specifications for the server

The server must be tested in the following situations:

The connection with the client is interrupted while an operation is in progress

During a distributed operation, some workstations crash because of a power breakdown

An operation involves inserting data in two tables of the database and the second insertion fails

The server disconnects a user while operations related to that user are in progress

The server is stopped while multiple clients are performing operations

The database of the server contains 0 records/few records/hundreds of records/thousands of records

BIBLIOGRAPHIC STUDY

Fingerprint Recognition Applications

According to D. Maltoni, D. Maio, A. K. Jain, and S. Prabhakar [13], the main categories of biometric recognition applications are:

Physical access control: access is restricted to facilities such as nuclear plants, bank vaults, corporate boardrooms, and even health-clubs, amusement parks, and lockers.

Logical access control: access to desktop computers or remote servers and databases is restricted to authorized users. Increasingly, access to software applications is also being restricted to only authorized users.

Device access control: laptops, PDA (Personal Digital Assistant), cell phones, and other electronic devices often contain personal and sensitive data. To protect such data, fingerprint recognition systems are used to conduct recognition on the stand-alone device.

Time and attendance: time and attendance systems are used to keep track of employee-working hours and to compute payrolls. Use of fingerprint recognition systems in these applications is fairly well received to improve efficiency for employees and also for preventing various types of payroll frauds

Civil identification: in civilian identification application, the most important objective is to prevent multiple enrollments and to find duplicates (e.g., duplicate passport, driver license, national identification card). The size of the database can be the order of millions (e.g., the entire population of a country). In some applications (such as border control to prevent suspected terrorists from entering the country), the identification is not needed to be conducted against the entire population but rather against a “watch-list” database.

Forensic identification: in forensic identification, latent fingerprints lifted from the crime scenes are matched against a criminal database to identify the suspect (and sometimes the victims).

The following main industries benefit the most from the use of fingerprint systems:

Health care

Financial

Gaming and hospitality (casinos, hotels, etc.)

Retail

Education

Manufacturing

High technology and telecommunications

Travel and transport

Federal, state, or other governments

Military

Law enforcement

Fingerprints represent the transition from a manual biometric to the automated form of the technology. The first fingerprint-based systems had a manually maintained repository that contained fingerprint cards (also known as ten-print fingerprints, contain the fingerprints from all the ten fingers). Substantial delays were a normal part of the fingerprint identification process, because fingerprint cards had to be physically transported and processed. A fingerprint check could often take three months to complete [18].

As the technology has developed, Automated Fingerprint Identification Systems (AFIS) replaced the old and hard to maintain systems [18]. AFIS systems are computerized and have a large database, able to store the records of millions of people.

Fingerprint recognition is the most used biometric method to determine the identity of an individual. Figure 1.3 shows a report of International Biometrics Group [7] that illustrates the revenue for each biometric technology in 2009. Among the technologies, finger scan is the undisputed leader with more than 60% (including Fingerprint with 28.4% and Automated Fingerprint Identification System – AFIS with 38.3%) market share.

Figure 3.1 Biometric Revenues by Technology, 2009

Existent Fingerprint Recognition Systems

Integrated Automated Fingerprint Identification System

The Integrated Automated Fingerprint Identification System, known as IAFIS, is a fingerprint and criminal history system maintained by the Federal Bureau of Investigation (FBI), Criminal Justice Information Services (CJIS) Division, in the United States of America [4]. It provides automated fingerprint search capabilities, latent searching capability, electronic image storage, and electronic exchange of fingerprints and responses.

The IAFIS maintains the largest biometric database in the world, containing the fingerprints and corresponding criminal history information for more than 55 million subjects [4]. The fingerprints and corresponding criminal history information are submitted voluntarily by state, local, and federal law enforcement agencies.

The fingerprints are acquired by local, state, and federal law enforcement agencies during criminal arrests, or during background checks for employment purposes. They are locally processed and then they are forwarded to FBI’s IAFIS for processing. The FBI then catalogs the fingerprints along with any criminal history linked with the subject. The system supports both ten-print fingerprint and latent submissions. A ten-print fingerprint submission contains ten-rolled fingerprint impressions and corresponding flat fingerprint impressions.

This system also supports remote ten-print and latent fingerprint searches by law enforcement agencies. The results of remote ten-print and latent searches are returned electronically and include a list of potential matching candidates and their corresponding fingerprints for comparison and identification by the requesting agency.

Civil searches are also performed, but the FBI charges a small fee and the response time is slower.

US-Visit Security System

The Department of Homeland Security from United States has developed a system to fingerprint and to monitor foreign visitors in the United States, as a response to terrorism. This system has the capability to match against a very large database of fingerprints and return information about individuals in a matter of seconds.

The US-Visit program helps identify the 23 million foreigners who visit the United States every year [5]. It includes capturing fingerprints and taking photographs of all the visitors and building a database to store all this data.

In order to obtain a visa, the traveler must go to an U.S. visa issuing post where his fingerprint is captured and checked against a watch list of known criminals and suspected terrorists. When the traveler arrives in the United States, his fingerprint is collected again to verify if he is the person who received the visa.

Secure Mobile Identification System

T. Bulka, C. Agarwal, and P. Pozdnyakov [3] have proposed a Secure Mobile Identification System that can quickly identify individuals via mobile devices using a person’s fingerprint. The purpose of the device is to connect to an off-site computer database of fingerprints via some network communications link, and submit a person’s fingerprint for identification. The database would then check for a matching fingerprint and return any information stored on that person.

Figure 3.2 shows the mobile device used in the system proposed by T. Bulka. It is a tablet and has a USB port for connecting the fingerprint scanner. The data from the mobile device is transmitted to a server via GPRS or via WI-FI (Wireless networking technology), where it is processed and an answer is sent back to the mobile device.

Figure 3.2 Mobile Device – Tablet PC

Fingerprint Recognition Distributed System

M. Hulea, A. Astilean, T. Letia, R. Miron and S. Folea [6] have proposed and implemented a complex distributed system that integrates fingerprint recognition and Global Positioning System (GPS) Methods.

The system includes a number of data processing units interconnected through internet. Mobile fingerprinting terminals can connect to a data processing unit via GPRS. The communication between components of the system is encrypted in order to assure the security. In addition to this, the security is increased by integrating the Global Positioning System, which assures access based on area localization.

Fingerprint Recognition Technique

Most of the Automated Fingerprint Identification Systems follow the steps described in Figure 3.3 in order to perform fingerprint recognition operations like verification or identification.

Figure 3.4 Fingerprint recognition steps

During the first step, a sample of a person’s fingerprint is captured using a fingerprint sensor. After that, the orientation of the sample and the optical quality is checked and if necessary adjusted automatically. If the result of this step is insufficient for further processing, a new scan is taken.

Next, the papillary lines are extracted from the picture and it is assigned to one of three defined classes of fingerprints: arch, whorl, and loop. According to C. Traeger and H. Falk [16] , when fingerprint patterns are captured and analyzed, about 5% of all fingerprint patterns are arches; 30% are whorls; and 65% are loops, divided approximately equally into left and right loops. Figure 3.5 shows fingerprints samples belonging to the main classes.

In the next step, the individual pattern such as ridge ends and ridge bifurcations and their position on the fingertip are identified using different algorithms.  With the extracted feature set a template is created and checked against one (in access control applications) or more (AFIS) stored templates.

Fingerprint sensors

There are many types of fingerprint sensors:

Optical sensors (also used for latent fingerprints on a crime scene)

Electromagnetic field sensors

Polymeric thin film transistor sensor

Thermal sensors

Capacitive sensors

Pressure sensors

Ultrasonic sensors

These sensors are used online and the picture of the finger tip is directly taken from the sensor. The traditional offline method of scanning a picture of a fingerprint is now used only in rare cases. 

Figure 3.5 Fingerprint Classes

From all the categories of sensors, optical and capacitive sensors are used the most in fingerprint based applications.

The structure of an optical sensor is described in Figure 3.6. It is composed of a right-angled triangle prism (1), light source (5), a diffusion plate (4), a lens group (2) and an image sensor (3).

When a fingerprint is placed on the contact surface, its ridges are closely pressed onto the surface while its valleys are detached from it. The light radiated from light source becomes uniform after undergoing the diffusion plate. The light reaches the fingerprint contact surface after passing through the prism. If the light touches the valley, total internal reflection happens so that it reaches the image sensor composed of CCD (Charge Coupled Device) element or CMOS (Complementary Metal Oxide Semiconductor) element after going through the lens group. On the other hand, if the light reaches the ridges closely pushed onto the surface, some light goes to the image sensor after the total internal reflection and some light is absorbed in the ridges.

There are changes in luminous intensity between light reflected from valleys and light from ridges and the image sensor obtains the fingerprint image by calculating the changes in the reflected light intensity between the two. The absorption optical fingerprint sensor needs several LEDs (15-20) since the light should be two-dimensionally uniform after going through the diffusion plate. To capture a fingerprint image without distortion brought on by different optical paths, enough distance is required between the prism and the image sensor.

The optical sensors are very safe; they have high perception rates and are strong against external shocks and scratches. The disadvantages of these sensors include relatively big modules necessary for encapsulating the sensor and high production and maintenance costs.

A capacitive fingerprint sensor is illustrated in Figure 3.7. It contains tens of thousands of small capacitive plates, each with its own electrical circuit embedded in the chip. When the finger is placed on the sensor, extremely weak electrical charges are created, building a pattern between the finger's ridges or valleys and the sensor's plates. Using these charges, the sensor measures the capacitance pattern across the surface. The sensor digitizes the measured values.

Figure 3.6 Optical Sensor’s Structure: (1) right-angled triangle prism, (2) group of lens, (3) image sensor, (4) diffusion plate, (5) light source

The surface of a capacitive sensor is a neat array of plates, able to measure the capacitance between these plates and the fingerprint contour. This can be done directly by applying an electrical charge to the plate.

The capacitive sensors are almost impossible to duplicate. They have a low production and maintenance costs. They are sensitive to environmental changes such as static electricity and temperatures.

Figure 3.7 Capacitive Sensor

Feature extraction algorithms

Fingerprint-based systems can be categorized into four broad groups: minutiae-based matching (analyzing the local structure), direct correlation techniques, optical comparison, and spectral ridge-pattern matching (analyzing the ridge or global structure) of the fingerprint. Most fingerprint technology algorithms analyze minutiae points.

Minutia-based algorithms

Minutia-based algorithms consist in converting an image of a fingerprint to a set of data points that can be numerically compared to other data sets. These data “points of interest” are called minutiae.

Figure 3.8 Magnified fingerprint for minutiae identifying

Minutiae are individual unique characteristics within the fingerprint pattern such as ridge endings (or terminations), bifurcations, deltas, crossovers, pores, cores or islands. Figure 3.8 identifies the minutiae on a fingerprint sample. The FBI minutia-model takes into consideration only the terminations and the bifurcations [4].

A typical fingerprint image may produce between 15 and 70 minutiae, depending on the portion of the image captured. According to C. Traeger and H. Falk [16], the most encountered minutiae are ridge endings.

Minutiae files are smaller than image files and are ideal for storage at the point of application, but are not typically interoperable between equipment from different vendors. To ensure future usability of the biometric, the image must be stored. It remains to be seen whether a standardized minutiae template model will be widely adopted.

In a typical system, type, location, and angle are recorded for each point of interest. Proposed standards specify that a Cartesian Coordinate System (CCS) is used to represent the location of a minutia, in units of pixels. Image resolution is also required and the origin of the coordinate system is located in the upper left, with values increasing to the right and downward.

The problem with minutiae algorithms is that it is difficult to extract the minutiae points accurately when the fingerprint is low quality. This method also does not take into account the global pattern of ridges and furrows.

The main steps followed for extracting minutiae are presented in Figure 3.9.

Figure 3.9 Steps for minutiae extracting

A fingerprint image is corrupted by various kind of noise such as creases, smudges and holes. It is impossible to recover the true ridge/valley structures in the unrecoverable regions; any effort to improve the quality of the fingerprint image in these regions is useless. Therefore, an enhancement algorithm is used to improve the clarity of ridges/valley structures of fingerprint images in recoverable regions and to mask out the unrecoverable regions. In the absence of an apriory enhancement step, most of the binarization techniques do not provide satisfactory results when applied to low-quality images.

The enhanced fingerprint image is binarized and the result is usually submitted to the thinning algorithm, according to Lam, L., Lee, S.W., Suen, C.Y [10]. The thinning procedure reduces the ridge thickness to one pixel wide. The resulted skeleton image is further processed and the fingerprint image is reconstructed by removing small isolated lines and by merging all the lines, that have ends with similar direction and the distance between them is small. From the reconstructed image, the minutiae points are extracted.

Not all the steps presented in the Figure 3.9 are compulsory in the process of extracting the singular points. D. Maio and D. Maltoni [12] proposed a direct gray-scale minutiae extraction technique that works directly on the gray scale images, without binarization and thinning. This choice is motivated by the significant amount of information that may be lost during the binarization process and by the fact that thinning is time consuming and may introduce a large number of false minutiae.

The most commonly used method of minutiae extraction is the Crossing Number (CN) concept. The minutiae are extracted by scanning the local neighborhood of each ridge pixel in the image using a 3×3 window, as shown in Figure 3.11. The CN value is then computed, which is defined as half the sum of the differences between pairs of adjacent pixels in the eight-neighborhood. Using the properties of the CN the ridge pixel can then be classified as shown in Figure 3.10.

ANALYSIS AND DESIGN

Analysis of the system – Use Case Diagram

The functionalities of the system, including server and client functionalities, were described in detail in chapter two. In Figure 4.1, a use case diagram presents a graphical overview of the functionality provided by the system.

Figure 4.1 – Use case diagram of the system

Figure 4.1 shows the actors of the system: the user of the mobile device, the fingerprint reader and the administrator of the server. The goals of the actors are illustrated as use cases, and the dependencies between those use cases are described with dashed lines.

After starting the mobile device application and connecting to the server, the user can perform the “Login” operation. Only after logging in, he is able to load the fingerprint into the memory of the mobile device or he can log out. Note that all the other use cases that are related to the user (remote enrollment, verification, identification) are dependent of the fingerprint; if the fingerprint is not loaded, they cannot be performed.

Remote enrollment is a general term for three kinds of operations: adding a new fingerprint record, adding a new id card based record or adding a new passport based record.

The administrator can to start the server on a certain port. After that, he is able to view the online users and to disconnect any one of them. Disconnecting a user interrupts all the operations related him and involves logging him out. When the administrator stops the server, all the users are disconnected and all the operations are interrupted.

System’s Design

The architecture of the system is described in chapter two, in Figure 2.1. The architecture of the server and the architecture of the client are described in the following sections.

The architecture of the server

The server application is structured on multiple layers as shown in Figure 4.1.

The presentation layer contains the application's user interface (UI). The user interface components (controls) provide a way for users (the administrators of the server) to interact with the server application. This layer makes the link between the user and the application logic.

All the forms that make up the user interface are placed into the „fpserver.ui“ package. Each form contains a number of fields that display output from lower layers and collect user input.

Figure 4.2-Layered Architecture of the Server

The business layer, also called logic layer or application layer, represents the core of the application. It is used to describe the functional algorithms that handle information exchange between data access layer and the user interface. The components that build this layer are included in the following packages: „fpserver.logic“, „fpserver.imgproc“, „fpserver.util“.

The server application must access data that is stored in a database. The data access layer, also called persistence layer, is responsible for exposing the data stored in the database to the business layer. Data access components isolate the business layer from the details of the specific data storage solution. This isolation provides the following benefits:

Minimizes the impact of a change in database provider

Minimizes the impact of a change in data representation (for example, a change in database schema).

Encapsulates all code that manipulates a particular data item in one place (in “fpserver.db” package)

This greatly simplifies testing and maintenance of the server.

The data sources represent the relational database servers. Here information is stored and retrieved. These servers keep data neutral and independent from business logic. Giving data its own layer also improves scalability and performance of the server.

The server application includes a communication module that makes possible the interaction between the servers and between the server and the clients, via the Internet. The components that form the communication module are included in the package “fpserver.net”.

All the messages and data that are transmitted between the components of the system (between servers or between clients and servers) are encrypted and decrypted at the receiver, using a security module. This module includes the “Cryptography” class that is implemented, but is not integrated in the application.

The architecture of the client

The client includes the mobile device and the fingerprint reader. The mobile device proposed by this paper is a Nokia 6288 mobile phone and is illustrated in Figure 4.3.

Figure 4.3 – The Mobile Device

The mobile device supports data transfer via the General Packet Radio Service (GPRS) class ten, 32 – 48 kbps (kilo bits per second) and via Bluetooth. It supports java applications using Java 2 Micro Edition (J2ME) platform with Mobile Information Device Profile (MIDP) 2.0 and Connected Limited Device Configuration (CLDC) 1.0.

The fingerprint reader proposed by this paper (see Figure 4.4) is an embedded system (Aimgene BioFlex IV) that consists of a powerful processor and a semiconductor fingerprint sensor. It has the following specifications:

115200/57600/19200/9600 bps (bits per second) communication speed

3D image capture of 236×92 pixels

256 gray levels (8 bits/pixel)

508 DPI (dots per inch) resolution

communications via Bluetooth in order to connect to a mobile device

Figure 4.4 – The Fingerprint Reader

The mobile device application is similar with the server application, being structured on several layers, as shown is Figure 4.5.

The presentation layer contains the user interface of the application. The user interface’s components render and format data for users, acquire and validate data coming in from them. All the forms that make up the user interface are placed into the “fpclient.ui” package.

The application layer makes the connection between the presentation layer and the data access layer. This layer controls the application’s functionality by performing detailed processing. The components that represent this layer are included in “fpclient.logic” package.

The data access layer separates the application layer and the data sources. It provides access to files (data sources) stored in the mobile device. The components that form this layer are placed into the “fpclient.io” package.

The communication sub layer contains modules for transmitting data via Bluetooth and via GPRS. The components that realize data transmission are also included into “fpclient.io” package.

The client application contains a security module responsible for protecting the data and the messages during transmissions. It includes the “Cryptography” class and it is used for encrypting and decrypting data and messages. This class is implemented but is not integrated in the application.

Figure 4.5- Layered Architecture of the Client

UML Diagrams

The Unified Modeling Language (UML) is a graphical language for visualizing, specifying, constructing and documenting a software system. The first UML diagram introduced in this paper was the use case diagram of the system, in Figure 4.1. In the following section, class diagram and sequence diagram are introduced.

Sequence Diagrams

A UML sequence diagram is a kind of interaction diagram that shows how processes of the system operate with one another, what are the messages sent between them and in what order.

The following sequence diagrams describe the messages sent between different components of the system: mobile device – fingerprint reader, client-server, and server-server.

Figure 4.6 illustrates the sequence diagram of the load fingerprint operation. The user starts the mobile device application and must provide an ip address and a port number in order to connect to the system. The server is multithreaded and supports multiple connections at the same time. For each connection intercepted on the listening port, the server creates a new “Treat Client” thread, for dealing with that client. A new thread of execution represents a new concurrently running task.

After connecting to the server, the user must authenticate in order to have access to other operations and to interact with the server. The user provides a username and a password and the mobile device begins the login operation by sending the authentication information to the server. The server receives the request from the client and checks in its database for the specified username and password. If the username and the password correspond with the existent information in the database, a positive message is replied to the client, otherwise an informing message that specifies the cause of the failure is sent back.

Figure 4.6 – Load fingerprint operation

The client processes the response from the server and the user is informed about the result of the login operation. If the authentication succeeds, the user is able to load the fingerprint into the memory of the mobile device.

When the user initiates the load fingerprint operation, the fingerprint sensor must be turned on. The mobile device sends a command to the sensor for capturing the fingerprint. The user must press his finger against the scanner while a led is blinking. The fingerprint is captured and stored in the RAM (Random Access Memory) of the fingerprint reader. After that, the mobile device sends a command to the fingerprint reader in order to transmit the fingerprint via Bluetooth. The fingerprint is stored in the memory of the mobile device for further operations.

Figure 4.7 presents the messages that are exchanged between client and server during the remote enrollment process. The user who provides the data initiates the operation. The client makes a request and sends the data to the server. After the operation is performed, the client receives back an answer with the result.

The user can make three types of remote enrollment: adding a new fingerprint to an existing record from the database, adding a new id-card record and adding a new passport record. For the first type of operation, the data provided by the user is the finger number and a PIN. For the other two types of operation, the user must provide the demographic information from ID card or from the passport, respectively.

Figure 4.7 – Remote Enrollment

Figure 4.8 represents the messages exchanged between system’s components during identification operation. The user provides a number representing the finger from which the fingerprint was captured and initiates the operation. The mobile device sends the fingerprint and the finger number to the server. At the server side, a new thread is created for solving the identification operation.

The server receives the fingerprint as a byte array, converts it into a bitmap file and then extracts the feature set saving the result as a template. A local search is started and the resulted template is compared with the templates from the database for the specified finger number. If no match is encountered, the server starts other threads called “Virtual Clients” that initiate the identification operation on other servers. They send the necessary data for the operation to be performed and wait for an answer. The number of virtual clients started is equal with the number of ip addresses existent in the database.

The server also starts another thread, called “Waiting Thread” that waits for answers from the virtual clients threads. If a positive answer is received from a virtual client, the waiting thread sends the answer to the client and stops the other virtual clients.

Figure 4.8 treats the case in which the local search does not return any match and the fingerprint is identified during the distributed search. If the local search succeeds, then the answer is sent back to the client, without initiating any distributed search. If the distributed search is initiated and no positive answer is received from the servers, the answer returned by the local search is send back to the client.

The sequence diagram for the verification operation is similar with the diagram presented in Figure 4.8. The difference is that the user provides also a personal identification number in addition to the finger number. The verification operation is performed much faster because the resulted template is compared only with an existing template from the database, which corresponds to the provided PIN.

Figure 4.8 – Identification

The administrator of the server is able to disconnect any client from the application. The sequence diagram for client disconnecting operation is illustrated in Figure 4.9. When a client is disconnected, is important to stop all the threads that are related to that client, otherwise the performance of the server might be affected.

When the administrator disconnects a user, a destroy message is sent to the “Treat Client” thread to stop the operation currently performed. The local search is interrupted and a destroy message is also sent to the thread that is responsible for the search. This thread forwards the destroy message to all the running virtual clients and to the waiting thread. All the threads that are related to the disconnected users are finished, as one can see the “x” mark at the bottom of the threads in Figure 4.9.

Figure 4.9 Disconnect User Operation

Class Diagrams

The class diagram is a type of static structure diagram that describes the structure of a system by showing the system's classes, their attributes, and the relationships between the classes.

The following section presents the server class diagrams and the client class diagrams. The server and client applications contain many classes that cannot be included in only one diagram. For that reason, each class diagram that is presented in this section is a simplified form and includes most of classes from one package.

Class Diagrams of the Server Application

The class diagram of the user interface package (“fpserver.ui”) for the server application is presented in the Figure 4.10. The diagram contains a window, named “MainWindow” that is a specialized form of frame; the “MainWindow” class extends the “JFrame” class from the “javax.swing” package, relationship represented in Figure 4.10 with a line and an empty triangle at the top.

The window is composed by many components like: buttons, labels, text fields, and a list for displaying the online users. The composition relationship is represented with the solid diamond shape.

The user interacts with the application by pressing the buttons for starting or stopping the server, or for disconnecting a user.

Figure 4.10 Class diagram of the “fpserver.ui” (user interface) package

The class diagram of the logic package (“fpserver.logic”) is described in Figure 4.11. The classes have suggestive names. There are several classes like “Server”, “TreatClient”, “SearchThread”, “WaitingThread”, “VirtualClient” that extend the “Thread” class from the “java.lang” package.

The “Server” thread waits for new connections from clients. It maintains a list of references to all the currently treated clients, as one can see in Figure 4.11. This list is named “clients” and can contain any number of elements or no elements at all. The server class has methods for disconnecting a certain client and for stopping the server.

The “TreatClient” thread sends and receives messages and data to and from the client. When it receives a request from the client, this thread performs the specified operation and then replies an answer to the client. The operations that can be performed at the server side are included in the “fpserver.logic.operations” package. All the operations from that package implement the “Operation” interface; the implementation relationship is represented through a dotted line with an empty triangle at the top. The “TreatClient” class holds a reference to the currently performed operation. When the operation type is distributed, a reference to the list of virtual clients is also kept, for interrupting the distributed search when the fingerprint has been identified. In addition to this, the “TreatClient” holds a list of ips of known servers, for initiating the distributed operations.

The searching thread is started when the operation is identification or verification. The “SearchThread” class holds all the necessary data (like fingerprint, finger number, operation type, etc.) to perform the local search and to initiate the distributed search. It searches for a match of the client fingerprint template with a fingerprint template from the local database. The local search is performed on this thread and not on the “TreatClient” thread to allow the second one to receive messages from the client and eventually to interrupt the search. If the local operation does not return a positive result, this thread starts a number of virtual clients, one for each entry in the ip addresses list, and the waiting thread. The “SearchThread” class has methods for stopping the local search and for stopping the waiting and virtual client threads.

During the distributed operation, the server initiates the search on other servers and becomes a “virtual client” with respect to them. Each “VirtualClient” thread connects to a server and transmits the necessary data for performing the distributed operation (verification or identification). The “VirtualClient” class has a method that sends a “stop” message to the remote server (where it is connected) in order to interrupt the operation.

The diagram in Figure 4.11 contains the “ResponseManager” class. This class is responsible for sending the response back to the client. It has only static methods that transmit messages to the client.

The “Result” class holds the result of the currently performed operation so that multiple threads can access it. The result is stored in a map of (key: value) pairs. It contains the answer of the operation, the source (the ip address of the server that identified the fingerprint) and the demographic information about the identified person (name, surname and PIN).

Figure 4.11 Class diagram for the “fpserver.logic” package

Figure 4.12 presents the class diagram of the “fpserver.net” package. The classes that make up this package form three levels of abstraction. At the lowest level there are two main classes “ClientConnection” and “ServerConnection” that implement both the “NetworkConnection” interface. Those classes provide the access to socket and server socket respectively. The next level contains “NetworkClientAccess” and “NetworkServerAccess” classes that are able to read/write to/from a connection. The first class is used for transmitting messages and data between virtual clients and servers (server-server) while the second class is used for communicating between mobile devices and servers (client-server).

At the highest level is the “NetworkManager” class that assures the good functioning of the entire process of network communication.

Network access classes use the “Cryptography” class from the “fpserve.util” to encrypt and decrypt messages and fingerprints (represented as byte arrays).

Figure 4.12 Class diagram of the “fpserver.net” package

The classes that form the “fpserver.imgproc” package are presented in Figure 4.13. The class diagram integrates some classes from the “com.neurotechnology” package and other classes that are used for image processing.

The “FpTemplate” class is used to create a template from a bitmap image file and to compare two templates. For saving the template, the “NImage” class is used to load the fingerprint file. Next, the “NFExtractor” class extracts the feature set from the fingerprint and creates a “NFRecord”. This record is further used to create the template. When two templates are compared, two records are extracted from them and are given to the “NMatcher” class, which verifies if they correspond.

The class diagram presented in Figure 4.13 also includes the “BMPFile” class. This is used for converting the byte array representing the fingerprint, received from the client, to a bitmap image.

Figure 4.13 Class diagram of the “fpserver.imgproc” (image processing) package

The class diagram of the database package (“fpserver.db”) is represented in Figure 4.14. It contains table managers, the “DatabaseConnection” and “DatabaseException” classes.

The “DatabaseConnection” class loads the driver necessary for accessing the database and creates the connections to the database. The database contains several tables and the access to the tables is realized through managers. Each manager is responsible for reading or writing the records to or from a certain table. The manager must have a connection to the database in order to access the data from a table; the dependency relation between the managers and “DatabaseConnection” class is represented through a dotted line with a simple arrow on top.

The link between the persistence layer (data access layer) and the logic (or business) layer is realized through the “SearchThread” class.

If there is an error while a database operation is performed, a “DatabaseException” is thrown in order to inform the higher levels about the operation failure.

Figure 4.14 Class diagram of the “fpserver.db” (database) package

Class Diagrams of the Client Application

The class diagram of the logic package for the client application is presented in Figure 4.15.

The “Client” class represents the starting point of the client application. It is a specialized type of MIDlet (a Java application framework for the Mobile Information Device Profile (MIDP)). The “Client” class represents the core of the application and coordinates the activities of all other classes. It holds a reference that represents the currently performed operation. All the operations that can be performed at the client side are included in the package “fpclient.logic.operation” and implement the “ClientOperation” interface, as one can see in Figure 4.15.

The “ClientStatus“ and “LoginInfo” classes are included in “fpclient.util” package. The first one holds the name of the currently performed operation, while the second one retains the information about the user.

The link between logic layer and the other layers (user interface layer and communication layer) is realized through the “Client” class. This class implements the “CommandListener” interface that is assigned to the forms from the user interface.

Figure 4.15 Class Diagram for the “fpclient.logic” package

Figure 4.16 represents the class diagram of the input/output package from the client application. It contains classes that access the network, the memory for reading files and the Bluetooth.

The “NetworkAccess” class is used for communicating via GPRS. It has methods for sending messages and files (fingerprints) and for receiving messages. The communication is secured using the “Cryptography” class from the “fpclient.util” package.

The “FileAccess” class is used to read the picture file and transforming it into a buffer, for remote enrollment operations.

The “Bluetooth Access” class is used for communicating with the Bluetooth sensor and is included in “fpclient.io.bluetooth” package. The same package contains another class that is used for scanning the Bluetooth device in order to find the fingerprint sensor.

Figure 4.16 Class diagram of the “fpclient.io” (input/output package)

The class diagram for the user interface of the client application is drawn in Figure 4.17. It contains the forms and the other components that make up the user interface.

Each window (screen) extends the “Form” class from the “javax.microedition.lcdui” package, and has its own components (buttons, text fields, choice groups etc.). Each form has assigned (by the “Client” class) a command listener. The events that occur from the interaction of the user with the application’s user interface are transmitted to the application layer and analyzed. The response is transmitted back to the user interface, becoming visible to the user.

At each moment, only one screen (or form) is visible to the user. The “DisplayManager” class is used to change the currently visible form.

Figure 4.17 Class Diagram of the “fpclient.ui” package

All the diagrams presented in this chapter were simplified by not including all the classes or all the relationships between the classes. Some fields and methods were not displayed in order to keep the diagrams simple and easy to understand. Also, the diagrams for the “fpserver.util” and “fpclient.util” packages were not represented, but some classes included in this packages will be briefly described in the implementation chapter.

IMPLEMENTATION

Software Solutions

Software Technologies used for the server application

The software technologies used for implementing the server application are:

Java Standard Edition 6 (Java SE 6)

MySQL Server 5.0

JUDE Community 5.5

Java Standard Edition 6 (Java Se 6)

Java is an object-oriented programming language built by Sun Microsystems and used to develop cross-platform (portable) applications. Any java application can be deployed on a computer that has the Java Virtual Machine (JVM) installed.

Java Platform is open-source and provides a wide library of classes for easy development of applications. The JRE (Java Runtime Environment) and JDK (Java Development Kit) are the actual files that are downloaded and installed on a computer in order to run or develop java programs, respectively.

An Integrated Development Environment (IDE) is a work environment that allows the development of applications using supported programming languages. Many IDE support Java language:

JCreator – free

Eclipse – free

NetBeans – free

BlueJ – free

CodeGuide – commercial

DrJava – free

IntelliJ IDEA – commercial; free for open-source projects

JBuilder – free

JDeveloper – commercial

KDevelop – free (GNU/Linux, Cygwin platforms)

The server application was developed using NetBeans IDE 6.5.1.

MySql Server 5.0

MySQL is a relation database management system (RDBMS) owned and sponsored by the Swedish company MySQL AB and is distributed under terms of the GNU General Public License. The program runs as a server providing multi-user access to a number of databases.

To administer MySQL databases one can use the included command-line tool (commands: „mysql“ and „mysqladmin“). Also, downloadable from the MySQL site are GUI administration tools: MySQL Administrator and MySQL Query Browser.

MySQL is the most used relational database management system at present. It has become the world's most popular open source database because of its consistent fast performance, high reliability and ease of use.

In order to connect to the MySQL Server, the Java application loads a special driver (mysql-connector-java-3.1.7).

The database of the server was administrated using MySQL Administrator and MySQL Query Browser and EMS SQL Management Studio 2005, which is another solution for database administration and development.

JUDE Community 5.5

JUDE is a tool for UML modeling. JUDE Community is a free edition of the application with basic features. It is rich in functionality, offering features, such as editing and printing UML1.4 diagrams, import/export of Java source code, graphics output, and auto layout.

The available types of diagrams of JUDE Community are:

Class Diagram

Use-Case Diagram

State-Machine Diagram

Activity Diagram

Sequence Diagram

Communication Diagram

Component Diagram

Deployment Diagram

Composite Structure Diagram

Software Technologies used for the client application

The client application was developed using Java programming language and Java Platform Micro Edition (Java ME or J2ME). Java ME is designed for mobile devices and embedded systems.

Java ME devices implement a profile. The most common profiles are the Mobile Information Device Profile, aimed at mobile devices, such as cell phones, and the Personal Profile, aimed at consumer products and embedded devices like PDAs. Profiles are subsets of configurations, of which there are currently two: the Connected Limited Device Configuration (CLDC) and the Connected Device Configuration (CDC).

The Connected Limited Device Configuration contains a strict subset of the Java-class libraries, and is the minimum amount needed for a Java Virtual Machine to operate. The mobile device proposed by this paper has the configuration CLDC 1.0. and implements the profile MIDP 2.0.

The client application was developed using NetBeans IDE 6.5.1 and Wireless Toolkit (a software tool for developing applications for mobile devices).

Implementation of the server application

The details regarding the implementation of the server application are presented in this section, following its layered architecture.

User Interface

The server’s user interface contains only one class that is included in “fpserver.ui” package. The class is named “MainWindow” and has a method with the signature:

“public static void main (String args[])”

This method (with the exact signature) represents the starting point of any standard java application. The classes from all the packages of the server application are included into a JAR file (Java Archive File) name “FPServer.jar”. When this file is opened, the main method is called and the application starts running.

The “MainWindow” class represents a frame and contains several components:

Buttons:

“start_button” – for starting the server

“stop_button” – for stopping the server

“disconnectButton” – for disconnecting a selected user

Labels – for describing the status of the server and the content of edit boxes

Text field – for entering the port number on which the server will accept connections

List – for displaying the users that are logged in

The important methods of this class are described in Table 5.1. The signatures presented include only the name of the method and the parameters.

Table 5.1 Methods of “MainWindow” class

Application Logic

The logic of the server application is implemented in the “fpserver.logic” package.

The “Server” class (see Annex pg.70) makes the link between the user interface and the logic layers. In addition, it refers the “NetworkManager” class, thus realizing the link between logic layer and communication layer.

The task of the “Server” class is to wait for connections from the clients, through the “NetworkManager”. When a connection is detected, a new “TreatClient” object is created, to treat that specific client. The server maintains a list with al the clients currently connected. These clients can be either mobile devices ore other servers, but they are treated in the same way by the “TreatClient” class.

The main methods of “Server” class are the following:

“stopClient(String user)”

“stopServer()”

They are called from the “MainWindow” class as described in Table 5.1.

The “TreatClient” class is a thread (see Annex pg.72) and receives requests from the client through “NetworkServerAccess” class. When receives a message from the client, this thread performs the specified operation.

“TreatClient” class realizes the link between the logic layer and data access layer, by holding a reference to “FingerManager” and “IpManager” classes that belong to “fpserver.db” package. The “TreatClient” class also holds a list with the ip addresses of all known servers, list obtained through the “IpManager”. The database manager classes will be described later in this chapter.

The operations that can be performed by the “TreatClient” class are included in “fpserver.logic.operations” package. They have suggestive names:

“LOGIN”

“LOGOUT”

”ADD_IDCARD_RECORD”

“ADD_PASSPORT_RECORD”

“ADD_FINGERPRINT”

“IDENTIFICATION”

“VERIFICATION”

“STOP”

For each operation there is a specific class with the same name, that has a method called “performOperation()” (all these classes implement the “Operation” interface). The “ThreatClient” thread realizes all the operations except identification and verification. When performing identification and verification, a new thread, called “SearchThread” is created. The creation of this thread is necessary because otherwise the communication with the client would have been interrupted during a search operation; the same thread cannot perform a search and receive messages from the client in the same time. So, when the “TreatClient” receives a “Stop” message from a “VirtualClient”, it interrupts the operation (identification or verification) performed on the “SearchThread” (see Annex pg.82).

Before performing identification and verification operations, the server receives from the client a message indicating the type of operation: local or distributed. Virtual clients (other servers) request local operations while the other clients (mobile devices) request only distributed operations.

Figure 5.1 presents the state machine diagram for the “SearchThread”. The “TreatClient” thread creates it during a recognition operation (verification or identification) and starts it after setting all the information necessary to perform the task.

Figure 5.1 State Machine Diagram for the search thread

Once started, the thread performs a local search, comparing the template (extracted from client’s fingerprint) with the existent templates in the database. If the client stops the search, the thread finishes and enters the “Dead” state. If the template is not identified, the distribute search is started and the “SearchThread” starts waiting.

When initiating the distributed search, the “SearchThread” starts the “WaitingThread” class (see Annex pg.79) that waits for answer, and a sequence of “VirtualClient” threads (see Annex pg.75), that make requests to other servers.

From the waiting state, the “SearchThread” can reach the “Dead” state if the administrator disconnects the user, and the “interrupt()” method is called, or if the template is identified during distributed search. If the connection to the other servers is interrupted and the distributed search fails, or if the template is not identified, the “SearchThread” calls the “setResult()” method of the “Result” class notifying the “WaitingThread” that a result is available. This can also be visualized in Figure 5.2.

Figure 5.2 Threads Activity Diagram during Distributed Operations

The activity of the main threads involved in a recognition-distributed operation is illustrated in Figure 5.2. (“SearchThread” on the left, “VirtualClient” in the middle and “WaitingThread” on the right).

After the distribute search is initiated, the “SearchThread” and “WaitingThread” start waiting. The “VirtualClient” thread connects to a server and initiates the recognition operation. After receiving the answer from the server, it sets the result in a map of key-value pairs, by calling “setResult()” method of the class “Result” (see Annex pg.87.). This is a synchronized method and allows only one thread to enter its block. Only one thread is allowed to set the result at a time and no thread should modify the result while the “WaitingThread” processes it. For that reason, while the “WaitingThread” is processing the result, the “VirtualClient” waits into the synchronized method to restrict the access of other threads. The synchronization mechanism is realized with three “CyclicBarriers”.

After setting the result, a notification is send to the “WaitingThread” in order to wake it up, for processing the result. If the result is positive, the “WaitingThread” returns a response to the client, through “ResponsManager” class (see Annex pg.86), and the operation finishes. Otherwise, if the template was not identified yet, the “WaitingThread” re-enters in the waiting state and sends a notification to the thread that waits in the “setResult()” method.

Network Communication

The network communication is realized trough the classes from the “fpserver.net” package. This communication is realized using TCP/IP protocol and sockets. The sockets classes, “Socket” and “ServerSocket” provided by Java library are wrapped with the “ClientConnection” class and “ServerConnection” class respectively. These two both implement the “NetworkConnection” interface, with “getConnection()” and “close()” methods for returning an established connection or closing a connection, and provide the first level of abstraction.

The “NetworkServerAccess” and “NetworkClientAccess” (see Annex pg.107) represent the second level of abstraction. The first class is used for client-server communication and the second one for virtual client-server communication. They both implement the “NetworkAccess” interface and provide the methods described in Table 5.2.

Table 5.2 Methods of “NetworkServerAccess” and “NetworkClientAccess” classes

The third level of abstraction is realized through “NetworkManager” class (see Annex pg.105), which provides methods for returning “NetworkAccess” classes. The “getNetworkAccess()” method returns an “NetworkServerAccess” object that contains two connections. One of the connection is used for sending messages and the other for sending files. When a server intercepts a connection from a client, it generates a port and transmits it to the client. The client uses this port to create the second connection for transmitting the picture file, during enrollment operations.

Image processing

All the classes used for image processing are placed into the “fpserver.imgproc” package. The server application integrates some classes from “VeriFinger” application. This software is owned and copyrighted by Neurotechnology Company. „VeriFinger“ application must be activated in order to use the classes from „com.neurotechnology“ package.

The server application has a resources directory (named “res”). This directory contains four folders:

“fingerprints” – for storing the bitmap images

“templates” – for storing the template extracted from fingerprints

“workspace” – for temporarily storing files resulted from storing the byte sequences (that represent the fingerprint) received from client

“pictures” – for storing the pictures of enrolled persons

The fingerprint are saved in the following format: “PIN:F:FINGER_NR.bmp”, where PIN is the Personal Identification Number of the person, “F” is a standard letter separating the PIN from the finger number, “FINGER_NR”. The same format is applied to the name of the templates. The “fingers” table contains only the relative paths of the templates to the root directory of the server application. The path names have the following format:

“res\templates\PIN:F:FINGER_NR.bmp”,

where “res” represents the resources directory of the application and “templates” is the folder that contains all the template files.

The fingerprint is received from the client as a byte sequence. This sequence is converted into a temporary file that is placed into the “workspace” folder. The “BMPFile” class has a method (“convertDataToBMP(String dataFile,String bmpFile)”) used for converting the temporary file in a bitmap image. After conversion, the temporary file is deleted.

The Table 5.4 describes some classes and methods from the “com.neurotechnology” package.

Table 5.4 Classes from “com.neurotechnology” package

“FPTemplate” class (see Annex pg.93) uses the classes presented in Table 5.4. This provides two main methods: “saveTemplate(String dest,String source)” and “verify(String template1,String template2)”. The first method takes as parameters the path of the source file (the bitmap fingerprint) and the path of the destination file (resulted template) and creates the template in the “res\templates” directory.

Data Access

The server application contains classes for database access in “fpserver.db” package. There is one class for managing the access to each table from the database.

The manager classes and their main methods are described in Table 5.3.

Table 5.3 Table manager classes and methods

When a new ID-card or passport record is inserted, the data is placed in three tables. The demographic data is stored in “idcards” or “passports”, the path of the template in “fingerprints” and the PIN in “cnps”.

A search for the PIN is performed before a fingerprint is added to an existing record. If the PIN is found then the template of the fingerprint is added to the existing record in “fingers” table and the corresponding PIN is added to “cnps”.

All the “insert” operations add records in more then one table. The methods use transactions and “rollback” mechanisms in order to maintain the data consistent. The transaction is committed only if all the records were successfully added in the corresponding tables. If a record was added in a table and an error occurred while adding another record to a second table, the “rollback” mechanism deletes the record from the first table, assuring the consistency of the database.

The “identif()” method selects all the templates (or template paths) from the “fingers” table, for a certain finger number. The list of templates is traversed and the template extracted from the client’s fingerprint is compared with each template from the list. The operation continues until a match is encountered or the “stopSearching” flag is set to “true”.

The “verify()” method performs first a search for the PIN transmitted as a parameter. If the PIN is found then the template for the specified finger number is selected and compared with the template extracted from client’s fingerprint. If the fingerprint from the server does not match with the fingerprint provided by the client for the corresponding PIN, the result return by the verification operation contains the name and surname of the record from the server.

Database Sources

The database of the server is named “fingerprints” and contains the following tables:

Ips – stores the location and the ip addresses of servers

Users – stores the usernames and corresponding passwords

Cnps – stores the Personal Identification Numbers

IDCards – stores the demographic information form the ID-card

Passports – stores the demographic information from the passport

Fingers – stores the relative paths of the templates

Figure 5.3 The structure of the database

Each tables contain a primary key that uniquely identifies each record. The relationships between the tables are illustrated in Figure 5.3. The “cnps” table is a parent table and ”idcards”, “passports” and “fingers” are child tables. There is a foreign key relationship between parent and childs, and “cnp_id” is the foreign key. This means that all the records from the child tables must have a correspondent in the parent table, or, in other words, there should not be any record without a corresponding Personal Identification Number.

Security

Both client and server applications implement a “Cryptography” class (see Annex pg.109) that is included in “fpclient.util” and “fpserver.util”, respectively. This class contains four methods that have the following signature:

encrypt(String a):String – encrypts and returns the string message received as parameter;

decrypt(String d):String – decrypts and returns the string message transmitted as parameter

encrypt(byte[] sir):byte[] – encrypts and returns the fingerprint transmitted as parameter in the form of a byte array

decrypt(byte[] sir):byte[] – decrypts and returns the fingerprint transmitted as parameter in the form of a byte array

Figure 5.4 illustrates the process of encryption and decryption of a message.

Figure 5.4 Process of encrypting and decrypting a message between client and server

The encryption process of a message is realized through an “exclusive or” (XOR) operation. Each character of a message is altered using a secrete key with “XOR” function. The decrypting process is similar, but the “XOR” function is applied to the encrypted message using the same key. Fingerprint (represented as byte arrays) are encrypted and decrypted in a similar way.

The “Cryptography” classes are used for assuring the security of client-server, server-client and server-server communications.

Implementation of the client application

The client application represents a J2ME application, or a MIDlet. For developing a MIDlet application, the following steps must be followed:

Designing – This step was described in chapter four

Coding – Involves implementing all the classes that compose the application; each MIDlet application contains a class that extends the abstract class “MIDlet”, and overrides three methods of this class: „startApp()“, „pauseApp()“, and „destroyApp()“

Compiling – MIDlets are compiled just like other java applications, using “javac” command; the source code (files with “.java” extension) is compiled, resulting a byte code (files with “.class” extension)

Preverification – Verification of byte code is a step performed by the JVM (Java Virtual Machine) before it runs any class file to ensure that the class file is structurally and conceptually correct, according to JVM specifications. MIDlet applications run on devices with limited resources. For that reason, the developer preverifies his classes using „preverify.exe“ ommand, thus limiting the amount of work needed to be performed when the classes are verified in the device

Packaging – This step involves creating a JAR file (Java Archive File with “.jar” extension) containing all the classes of the application, and a descriptor file (with the “.jad” extension) that contains the necessary information so that the J2me device can install the application

Testing – Before deploying the application, it must be tested by using a base common emulator device that mimics the functionality of an actual device. This emulator is part of the Wireless Toolkit and provides functionality that is sure to be present in the majority of devices for which the MIDlet is targeted

Deployment – This step involves downloading the “.jar” and “.jad” files on the mobile device (using a USB cable or via Bluetooth) and installing the application

In the following section, the implementation of the main classes of the client application will be described. The description will follow the main packages of the client application.

User Interface

The user interface for the client application is implemented through the classes from “fpclient” package. All this classes are forms that contain graphical-user components like:

text fields – implemented as “TextField” objects

labels – implemented as “StringItem” objects

buttons – implemented as “Command” objects

choice lists – implemented as “ChoiceGroup” objects

Each form (or screen) class has its own components through which the interaction between user and application is realized. Table 5.4 describes the commands that are provided by the screens of the client application.

Table 5.4 The commands of the client application

The “DisplayManager” class is used to manage the screens. It has a setCurrentScreen(Screen s)” method that changes the current displayed screen to the one transmitted as a parameter.

Application Logic

The “Client” class (see Annex pg.116) implements “MIDlet” and provides the “startApp()” which represents the starting point of the client application. The constructor of the class “Clients” initializes all the screens of the user interface and the “NetworkAccess” object.

The “commandAction(Command arg0, Displayable arg1)” method is invoked when the user presses a button of a screen. This method analyzes the command that generated the call and the screen from which the command was sent and performs a certain operation.

When the application is closed the “destroyApp()” method is invoked. This method assures that the user has been logged out from the server before it is disconnected. In addition to this, it closes all the network connections through the “NetworkAccess” class.

Each operation that can be performed by the client application is implemented in a class that extends the Java “Thread” class and implements the “ClientOperation” interface. When the “performOperation()” method from a certain class is called, a new thread is created and started for realizing that operation. Realizing different operations on other threads than the ones used for the user interface, makes the application’s UI more responsive to user interactions. Thus, the user interface is not blocked during different operations.

Input/Output Access

The access to the network, to the memory of the mobile device and to the fingerprint reader is realized through “NetworkAcces”, “FileAccess” and ”BlueToothAccess” classes from the “fpclient.io” package.

The “NetworkAcces” (see Annex pg.113) is used to establish connections with the server through sockets. One socket is used for transmitting messages through “sendMessage(String msg)” and “receiveMessage():String” methods, and another socket is used for transmitting data (through “sendFile(byte[] data,int n)” method). This class is similar with the corresponding class from the server applicatio. The difference between those classes is that the “NetworkAccess” uses byte oriented streams (like “InputStream”, “OutputStream”) while the other class uses character oriented wrapper classes (like “BufferedReader” and “PrintWriter”).

The picture of a person can be read by “FileAccess” class (see Annex pg.115) and used in remote enrollment operations. The pictures should be placed in the memory card ( “file:///E:/Apps/“) of the mobile device in order to be accessible from the client application.

The communication between mobile device and fingerprint reader is realized through the classes from “fpclient.io.bluetooth” package. The “BTManager” class has a method “findServices” for detecting all the Bluetooth devices in the area of the mobile device.

“BlueToothAccess” class (see Annex pg.110) gets the list of Bluetooth devices from “BTManager” and selects the fingerprint reader according to its name, “Tayo Spp”. This is realized through “findTaiyoSpp()” method. The connection to the fingerprint reader is realized with “connect()” method, that also opens data output and input streams for receiving and sending data to and from the sensor.

There are several commands that can be transmitted to the fingerprint reader. Table 5.5 presents and describes them. From all the commands, only two of them are used in the client application, in the “getFingerprint()” method of ”BluetToothAccess” class. The two commands are the following: “C” for capturing the fingerprint and “B” for uploading the fingerprint raw image to the mobile device.

Table 5.5 Overview of commands transmitted to the fingerprint reader

User Instructions

Both client and server applications have friendly user interfaces that are easy to use and contain components with suggestive names.

Server Use

The user of the server application is the administrator of the server. When he starts the server application by double clicking the “FingerPrint.jar” file, the main window, presented in Figure 5.5, is opened. The administrator can start the server by providing a port number. The recommended value for the port number should be an integer included in the interval [1050, 5000]. The first 1024 ports are not recommended because they might be used by the operating system. If the provided port is already in use, an informing message is displayed to the administrator at the bottom of the window.

The administrator is able to visualize all the logged in users. He can select one user and click on the “Disconnect” button in order to close the connection with the client and to stop all the operations related him. The “Disconnect” button becomes visible when a user is selected, and disappears after it is pressed.

At any moment after the server is started the administrator can stop the server, by pressing the “Stop Server” button. This button is not enabled when the server is already stopped. If the administrator closes the window and the server is running, then the server is stopped first and then the application finishes.

Figure 5.5 User Interface of the Server

Mobile Device Use

When the user opens the “FingerPrintClient.jar” application installed on the mobile device, a screen that contains two text field appears. The user is able to provide an ip address in the first text field and a port number in the second field, for connecting to the server. When trying to connect, a new form is displayed and the user is requested to confirm the rights of the application to access the network. If the user does not allow the application to access the network, an alert is displayed and the application must be reinstalled for further use.

If the user grants the access to the network, the mobile device tries to connect to the server. If the operation fails, an informing message is displayed to the user, otherwise a new screen that allows the authentication becomes visible.

The user must provide data (username and password) in order to log in to the server. If the authentication process succeeds, a new screen is displayed. The user is able to access a menu and to view all the operations that can be performed with the application.

Figure 5.6 displays the operations that can be performed from an emulator.

The user must perform the “LOAD_FINGERPRINT” operation in order to load a fingerprint in the memory of the mobile device. Before initiating the load operation, the user must start the fingerprint reader. After the led of the FPR stops blinking, the user can press the “LOAD_FINGERPRINT” command. He must allow the application to switch on the Bluetooth and to access to the Bluetooth device. A message appears on the screen when the user should press his finger against the fingerprint scanner. The finger should be kept on the scanner until the led stops blinking. When the finger is released, the fingerprint is transmitted to the mobile device via Bluetooth.

Figure 5.6 Operations overview for the mobile device

A message is displayed on the screen after the entire fingerprint is loaded on the mobile device.

Once loaded, the fingerprint remains in the memory of the mobile device until the application is closed or another fingerprint is loaded. After loading the fingerprint, the user is able to perform all the other operations described in this paper.

If the user accesses the “ADD_RECORD” command, a screen with a choice group is displayed. The choice group contains the type of addling that the user can perform. For this two operations, the application must have the right to read from the memory of the mobile device. This right can be granted before lunching the client application, from the data access settings of the mobile device. If the user provides wrong filename for the picture that will be used during enrollment, the operation fails and an informing message is displayed in the “AnswerScreen”.

The “AnswerScreen” appears when an operation is in progress. It displays messages to the user, informing him about the results of the operation. The user is able to clear the messages displayed on the screen.

TESTING AND VALIDATION

In order to evaluate the system's compliance with its specified requirements, several types of tests were performed:

Functionality and GUI testing

Performance testing

Error handling testing

Reliability testing

The tests were applied to the system in the following conditions:

Three servers were used; One of the servers had a real ip address (“78.89.175.85”) and the other two were connected in a local network; the server with the real ip can communicate with one of the servers from the local network, via the internet, through a gateway (a router that has a real ip address, “78.97.170.91”); all the connections intercepted by the router on the ports from the interval [1050,5000] were forwarded to one of the servers from the local network

The three servers had dual-core processors; Two of them were desktop computers and the third one was a laptop

One of the mobile terminals that connects to a server is a Nokia 6288 cell phone; the connection to the server is realized through Orange GPRS Service

The client application also runs using NetBeans Emulators on two of the servers

The fingerprint reader used was BioFlex4 from Aimgene Technology; it was a capacitive sensor and supports Bluetooth communication

Functionality and GUI testing

The system successfully performes three main operations:

Remote enrollment

Verification

Identification

The system can be viewed as a black box; the user provides a set of input data to it through the GUI (graphical user interface); the system behaves in a specific way according to the data provided, and returns a set of output data. The functionalities of the system were tested for several sets of input data, as shown in Table 6.1.

Table 6.1 The output of the system for different inputs

Performance testing

Table 6.2 Temporal Performances of the Workstation

Table 6.3 Temporal Performances of the Client (or the performances of the whole system)

The performances presented in Tables 6.2 and 6.3 were obtained when the database of the server contained few records (less then five records). One can observe that the time elapsed during loading the fingerprint is almost a minute. The reason is that the communication via Bluetooth between fingerprint reader and mobile device is relatively slow and the fingerprint that must be transmitted is large (it is represented as a sequence of 45313 bytes).

One can see that the insertion of a new id-card record operation is faster than the insertion of the passport record, because, for a passport record, more information must be inserted to the database.

The identification operation (see Annex pg.89) usually takes longer than the verification operation, because more comparisons are made. This is true only when the database contains more then one record. If the database contains only one record, the identification is performed faster than the verification, because the second operation performs an extra search for the PIN. For the data presented in the previous tables, the identification and verification operations were performed only on the connected server.

The performances of the client, which are in fact the performances of the whole system, are worse than the performances of the workstation. This is because the transmission of messages via the internet and GPRS brings an extra overhead.

The time elapsed for each operation was computed by making the difference between the instance of time when the operation starts and the instance of time when it finishes. This time depends on the overhead of the internet network, and on the overhead of the workstations. If there are multiple clients connected at the same time at a workstation, the response time increases. Also, the response time increases directly proportional with the number of records in the database.

Error handling testing

Different tests were applied to the system in order to observe its reaction to errors.

Database errors

The database errors were generated in the following conditions:

The administrator of the server has changed the structure of the “fingers” table, replacing the name of the column “fingerprint1” with “fingerprint0”

The user of the mobile device performed a remote enrollment operation (“ADD new id-card record”) and provided “1” as a finger number

When this test was run an “SQLException” was generated at the server side, informing that the column “fingerprint1” does not exists; this was reported to the client as a “Database Error!” Usually remote enrollment involves inserting records in two or three tables during one operation. For the generated test case, before the exception was thrown, two successful insertions took place, for the table “cnps” and “idcards”. Because the insertion of the record in the “fingers” table failed, the two records inserted in “cnps” and “idcards” were also removed, keeping the database consistent.

For this situation, the transaction-rollback mechanism assures that there is not any record in the database without a corresponding fingerprint.

In addition, if a record from the parent („cnps“) table is deleted, all the coresponding records from the child tables are also deleted.

Connection failure errors

The connection errors were generated in the following conditions:

The user of the mobile device has started an identification or verification operation

During the operation, the computer that holds the server application has been powered off

In the generated situation the connection between the mobile device and the server has failed. An “IOException” was thrown at the client side and further reported to the user interface as an informing message: “The connection to the server has been lost!” in addition to this, the displayed screen was changed to “ConnectScreen”.

Reliability testing

The reliability of the system was analyzed in the following conditions:

The user of the mobile device has started a recognition operation (identification or verification)

The fingerprint was not locally identified by the server and the distributed search was started

During the distributed search one or more servers fail

In this situation, one or more “IOExceptions” were generated at the server side but the operation was not interrupted and a response was successfully sent to the client. Even if all the other servers involved in the distributed search have failed, the client has received a response from the server he was connected to.

Even if some workstations crash, the system as a whole is still functioning. Failed servers can restart themselves and rejoin the system, after the cause of failure has been removed.

CONCLUSIONS

Summary

This paper proposed a distributed system for fingerprint recognition. Some notions about biometry, fingerprint technology and distributed systems were introduced. The architecture of the system, the implementation and the tests applied to it were presented and described. The results obtained were analyzed according with the specifications of the system.

All the functionalities present in the specifications of the system were implemented and successfully tested. The system integrates fingerprint recognition, and provides the following functionalities:

Remote enrollment

Fingerprint Identification

Fingerprint Verification

Conclusions

The biometric methods are the best in uniquely recognizing individuals. They are increasingly used in different categories of applications. Even if the accuracy of the biometric techniques is not perfect, there are many mature biometric systems, like IAFIS, available now.

Biometrics is a good trade-off between security and ease of use. That is why biometric security systems tend to replace in time the traditional password-based security systems.

Despite the fact that iris recognition is widely regarded as the most accurate biometric technology, fingerprint recognition is the most used technology all over the world. It is used in different applications from different industries, as described in chapter four.

More and more fingerprint based applications will appear once the electronic id-cards and passports are introduced. The method of using fingerprints with ID cards and passpornts is especially useful for identifying children. If a child gets lost, he can easily be identified by his fingerprint.

As the technology develops, the tendecy is to decrease the size and cost of fingerprint scanners required by different applications. By reducing the size of a fingerprint sensor, its acquisition area, which is its most critical parameter, is also reduced and thus reducing the quality of the image. Advanced fingerprint capturing techniques must be developed in order to maintain the quality of the captured image, even if the fingerprint scanner used is smaller.

Among all the fingerprint matching techniques, the minutiae-based aproach is the most used. Even so, the correlation-based methods are receiving renewed interest, because they are able to overcome some of the difficulties of the minutiae-based approach.

The distribution of the database on many servers brings many advantages to the proposed system:

Resource Sharing – different servers can manage the database of the system in the same time

Scalability – the database can be increased when necessary, by adding new workstations to the system

Increased speed – the response time required to perform a recognition operation is relatively small because the task can be performed by different servers at the same time

Reliability – even if some workstations fail, the system as a whole continues functioning

Recoverable – failed workstations can rejoin the system after the cause of failure has been removed

Openness – the users can connect/disconnect to/from the system at any moment, without affecting the proper functioning of the system

Security – the security of the system is realized through authentication operations and through data encryption

The proposed system has a fixed part, formed by the workstations that communicate with each other through the internet, and a mobile part. The mobile devices and the fingerprint readers compose this mobile part. The mobile part brings two advantages to the system:

Flexibility – the mobile device and the fingerprint reader have a low power consumption and are easy to use

Portability – the mobile device and the fingerprint reader are small and can be easily moved in order to perform in field operations

The proposed system can be used as a:

Physical access control system

Civil identification system

Physical access control

The access to certain areas, buildings, parks, rooms, etc. can be restricted through fingerprint recognition. In this way, the access is granted only to authorized persons and certain equipments and data are protected.

Classical security systems have fixed equipments. If the area that must be restricted is changed to another location, the identification equipments must also be carried and reinstalled on the new location. This involves extra work and expenses.

The proposed system has the advantage that if the restricted area changes, the mobile part (MD and FPR) can be easily moved to the new location, for restricting the access.

Civil identification system

The proposed system allows law enforcement personnel to perform in field enrollment and fingerprint recognition operations.

Through fingerprint verification, law enforcement personnel can detect false documents (ID-cards, passports or driver licenses). Identification is useful for analyzing the information about an individual that does not carry any identity document. In border control, identification can prevent terrorists to enter the country.

In addition, if a suspect foreigner does not have any identity document, his fingerprint and picture can be enrolled in the system, for further use.

Using fingerprint recognition becomes a major factor in upgrading and transforming the society, in improving the quality of life both in terms of access, and in terms of increased personal safety.

Future development

Future development of the system will include:

Adding of new functionalities

Improving the existent algorithms

Implementing a image processing module or integrating a free one

Improving the security of the system

Integrating a more accurate and a faster Bluetooth fingerprint reader

By adding new functionalities to the system, the administrator of the server will be able to perform local enrollment, local identification and local verification operations. Local means that no mobile device is involved. In addition, both the administrator of the server and the user of the mobile device will be able to delete records from the database.

The algorithms that perform the searches in the database will be modified in order to improve the performances of the system.

The current server application integrates the “VeriFinger” trial version software for image processing. This module is not free and requires verifying the license every time it is used. Future releases of the system will integrate or implement a free module for image processing.

The security of the system is assured through authentication operations and through encryption of the data and messages during transmission. The module that realizes the encryption and decryption of data will be integrated in the system. In addition, it will be improved by using random generated keys for data encryption and decryption.

A new fingerprint reader will be integrated for providing faster loading of the fingerprints to the MD.

Bibliography

[1] Arnon Rotem-Gal-Oz, “Fallacies of Distributed Computing Explained”, SmartHouse, 2008

[2] Bradford Ulery, Austin Hicklin, Craig Watson, Michael Indovina, and Kayee Kwong,

“Slap Fingerprint Segmentation Evaluation”, Analysis Report (NISTIR 7209), 2004

http://fingerprint.nist.gov/slapseg04/ir_7209.pdf

[3] Bulka Tomas, Chaitanya Agarwal, and Pavel Pozdnyakov, “Secure Mobile Fingerprint Identification System”, submitted for the degree of Bachelor of Science in Computer Engineering School of Engineering Santa Clara University, 2005

[4] Criminal Justice Information Services, “Electronic Fingerprint Transmission Specification”, Int. Report. CJIS-RS-0010 (V7), 1999, available at: http://www.fbi.gov/hq/cjisd/iafIs/efts70/cover.htm

[5] Homeland Security, “US-VISIT What to Expect When Visiting the United States”, 2009, available at: http://www.dhs.gov/xtrvlsec/programs/editorial_0525.shtm

[6] Hulea M., Letia T, Astilean A., Folea S. and Miron R, “Fingerprint Recognition Distributed System”, AQTR Cluj-Napoca, 2007

[7] International Biometrics Group, “Biometrics Market Report 2003-2007”, 2002, available at: http://www.biometricgroup.com/reports/public/market_report.html

[8] Jain A., Ross A., and Prabhakar S., “An Introduction to Biometric Recognition”, IEEE Transactions on Circuits and Systems for Video Technology, 2004

[9] James L. Wayman, „Biometrics Now and Then: The de development of biometrics over the last 40 years, Biometrics in the Reflection of Requirements“, Macquarie Scientific Publishing, 2004

[10] Lam L., Lee S.W. and Suen C.Y, “Thinning Methodologies: A Comprehensive Survey”, IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 14, no. 9, 869−885, 1992

[11] Letia T. and Hulea M., “Sisteme de control distribuit”, Cluj-Napoca, Mediamira, 2005

[12] Maio D. and Maltoni D., “Direct Gray-Scale Minutiae Detection in Fingerprints”, IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 19, no. 1, 1997

[13] Maltoni D., Maio D., Kain A. L., and Prabhakar S., “Handbook of Fingerprint Recognition”, Springer, NY, 2003

[14] Moore G., “Brief History of Fingerprint Identification”, Fingerprint Consulting Service, Retrieved March 23, 2004

[15] “Romanian Identity Card”, 2009, http://en.wikipedia.org/wiki/Carte_de_identitate

[16] Traeger Cynthia and Howard Falk, “Biometric Technologies”, doc id 00016761, Faulkner Information Services, 2002

[17] Van Der Putte T. and Keunung J, “Biometrical Fingerprint recognition: don't get your fingers burnt”, Kluwer Academic Publishers, 2000

[18] Wegstein J.H, “An Automated Fingerprint Identification System”, U.S. Government

Publication, Washington, DC: U.S. Dept. of Commerce, National Bureau of Standards, 1982

Acronyms

AFIS – Automated Fingerprint Identification Systems

Bps – Bits per second

CCD – Charged Coupled Device

CCS – Cartesian Coordinate System

CDC – Connected Device Configuration

CLDC – Connected Limited Device Configuration

CMOS – Complementary Metal Oxid Semiconductor

CN – Crossing Number

DPI – Dots Per Inch

ERR – Equal Error Rate

FAR – False Acceptance Rate

FBI – Federal Bureau of Investigation

FPR – Fingerprint Reader

FRR – False Rejection Rate

GPRS – General Packet Radio Service

GPS – Global Positioning System

GSM – Global System for Mobile Communications

GUI – Graphical User Interface

IAFIS – Integrated Automated Fingerprint Identification Systems

ID – Identification

IP – Internet Protocol

J2ME – Java 2 Micro Edition

JDK – Java Development Kit

JRE – Java Runtime Environment

JVM – Java Virtual Machine

Kbps – Kilo Bits Pers Second

LED – Light Emitting Diode

MD – Mobile Device

MIDP – Mobile Information Device Provile

PIN – Personal Identification Number

PDA – Personal Digital Assistent

RAM – Random Access Memory

RDBMS – Relational Database Management System

TCP/IP – Transmission Control Protocol / Internet Protocol

UML – Unified Modelling Language

WI-FI – A type of Wireless LAN (Local Area Network)

Annex

/*

* Created on Oct 15, 2008

* @author alin ciupeiu

* Source code for the file: Server.java

*/

package fpserver.logic;

import fpserver.util.Users;

import fpserver.net.NetworkManager;

import fpserver.net.NetworkServerAccess;

import java.io.IOException;

import java.net.UnknownHostException;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;

public class Server extends Thread

{

private volatile boolean stopServer=false;

private NetworkManager networkManager;

private static Users onlineUsers;

private String localhost;

private static List<TreatClient> clients;

public Server(int port) throws IOException

{

networkManager=new NetworkManager(port);

onlineUsers=new Users();

clients=new ArrayList<TreatClient>();

}

@Override

public void run()

{

try {

localhost=NetworkManager.getLocalHost();

System.out.println("Server : " + localhost + " started on port : " + networkManager.getPort());

} catch (UnknownHostException ex) {

ex.printStackTrace();

}

while (!stopServer)

{

NetworkServerAccess networkAccess;

try {

networkAccess = networkManager.getNetworkAccess();

TreatClient client = new TreatClient(networkAccess,onlineUsers);

clients.add(client);

client.start();

} catch (IOException ex) {

// ex.printStackTrace();

}

catch(SQLException ex)

{

ex.printStackTrace();

}

}

}

public void stopServer(){

new Thread()

{

@Override

public void run(){

System.out.println("Stopping thread started");

stopServer=true;

networkManager.closeServerConnection();

for (TreatClient client:clients){

client.stopThread();

}

System.out.println("Stopping thread finished");

}

}.start();

}

public static void stopClient(String user){

for (TreatClient client:clients){

if (client.getUser().equals(user)){

onlineUsers.removeUser(user);

client.stopThread();

clients.remove(client);

break;

}

}

}

}

/**

*

* @author alin

* Source code for the file: TreatClient.java

*/

package fpserver.logic;

import fpserver.util.Counter;

import fpserver.util.Users;

import fpserver.util.UserInfo;

import fpserver.db.IpManager;

import fpserver.logic.operations.LoginOperation;

import fpserver.logic.operations.AddPassportRecord;

import fpserver.logic.operations.Identification;

import fpserver.logic.operations.StopOperation;

import fpserver.logic.operations.Verification;

import fpserver.logic.operations.Operation;

import fpserver.logic.operations.AddIdcardRecord;

import fpserver.logic.operations.AddFingerprint;

import fpserver.logic.operations.Operations;

import fpserver.logic.operations.LogoutOperation;

import fpserver.db.FingerManager;

import fpserver.net.NetworkServerAccess;

import java.io.IOException;

import java.sql.SQLException;

import java.util.concurrent.CyclicBarrier;

public class TreatClient extends Thread

{

private Thread[] threadSeq;

private String msgReceived;

private String[] ipSeq;

private int nrOfIps;

private Counter onlineServers;

private CyclicBarrier barrier1;

private CyclicBarrier barrier2;

private CyclicBarrier barrier3;

private Users onlineUsers;

private FingerManager fingerManager;

private NetworkServerAccess networkAccess;

private Result result;

private UserInfo userInfo;

private Operation operation;

TreatClient(NetworkServerAccess networkAccess,Users onlineUsers) throws SQLException, IOException

{

this.networkAccess=networkAccess;

this.setName("Tratare Client – main thread");

this.onlineUsers=onlineUsers;

ipSeq=IpManager.getIpManager().getIpSeq();

nrOfIps=ipSeq.length;

onlineServers=new Counter(nrOfIps);

fingerManager=new FingerManager();

barrier1=new CyclicBarrier(2);

barrier2=new CyclicBarrier(2);

barrier3=new CyclicBarrier(nrOfIps+1);

result=new Result(barrier1,barrier2);

String fileport=""+networkAccess.getFilePort();

System.out.println(fileport);

networkAccess.sendMessage(fileport);

userInfo=new UserInfo();

}

@Override

public void run()

{

System.out.println(Thread.currentThread().getName()+ " started");

try {

msgReceived=networkAccess.receiveMessage();

while (msgReceived!=null && !msgReceived.equals("end"))

{

if (msgReceived.equals("LOGIN")){

operation=new LoginOperation(networkAccess,userInfo,onlineUsers);

operation.performOperation();

}

else

if (userInfo.getLogState()){

switch(Operations.valueOf(msgReceived))

{

case LOGIN: operation=new LoginOperation(networkAccess,userInfo,onlineUsers);

operation.performOperation();

break;

case LOGOUT: operation=new LogoutOperation(onlineUsers,userInfo);

operation.performOperation();

break;

case ADD_IDCARD_RECORD:

operation=newAddIdcardRecord(networkAccess,fingerManager);

operation.performOperation();

break;

case ADD_PASSPORT_RECORD:

operation=new AddPassportRecord(networkAccess,fingerManager);

operation.performOperation();

break;

case ADD_FINGERPRINT:

operation=new AddFingerprint(networkAccess,fingerManager);

operation.performOperation();

break;

case IDENTIFICATION:

operation=new Identification(result,onlineServers,networkAccess,ipSeq,barrier1,barrier2,barrier3,userInfo);

operation.performOperation();

break;

case VERIFICATION:

operation=new Verification(result,onlineServers,networkAccess,ipSeq,barrier1,barrier2,barrier3);

operation.performOperation();

break;

case STOP: if (operation.getName().equals("IDENTIFICATION")){

Identification identifOp=(Identification) operation;

operation=

new StopOperation(networkAccess,identifOp.getSearchThread());

}

else

if (operation.getName().equals("VERIFICATION"))

{

Verification verifOp=(Verification) operation;

operation=

new StopOperation(networkAccess,verifOp.getSearchThread());

}

operation.performOperation();

break;

}

}

else {

networkAccess.sendMessage("Authentication Required!");

}

msgReceived=networkAccess.receiveMessage();

}

}

catch(IOException e){

}

finally{

if (userInfo!=null && onlineUsers.containsUser(userInfo.getUsername())){

onlineUsers.removeUser(userInfo.getUsername());

userInfo.setLogState(false);

System.err.println("User "+userInfo.getUsername()+" logged out");

}

System.out.println("Client "+networkAccess.getClientAddress()+" disconnected!");

networkAccess.closeSockets();

System.out.println(Thread.currentThread().getName()+ " finished");

}

}

public Thread[] getThreadSeq()

{

return threadSeq;

}

public void stopThread(){

try {

if (operation!=null && operation.getName().equals("IDENTIFICATION")) {

Identification op = (Identification) operation;

op.getSearchThread().stopSearching();

op.stopSearchThread();

} else if (operation!=null && operation.getName().equals("VERIFICATION")) {

Verification op = (Verification) operation;

op.getSearchThread().stopSearching();

op.stopSearchThread();

}

networkAccess.sendMessage("Operation interrupted by the server!");

networkAccess.closeSockets();

} catch (Exception ex) {

ex.printStackTrace();

}

}

public String getUser(){

return userInfo.getUsername();

}

}

/**

*

* @author alin

* Source code for the file: VirtualClient.java

*/

package fpserver.logic;

import fpserver.util.Counter;

import fpserver.net.NetworkManager;

import fpserver.net.NetworkClientAccess;

import java.io.File;

import java.io.IOException;

import java.net.UnknownHostException;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

public class VirtualClient extends Thread

{

private String fingerPrintName;

private String cnp;

private File fingerPrint;

private String fingerNumber;

private String operation;

private String operationType;

private boolean isConnected=false;

private Counter onlineServers;

private Result result;

private NetworkClientAccess networkAccess;

private String destIp;

private String localhost;

private CyclicBarrier barrier3;

VirtualClient(String dest,int port,Counter onlineServers,Result result,CyclicBarrier barrier3)

{

this.barrier3=barrier3;

this.onlineServers=onlineServers;

this.result=result;

this.destIp=dest;

try {

localhost = NetworkManager.getLocalHost();

} catch (UnknownHostException ex) {

ex.printStackTrace();

}

try

{

networkAccess=NetworkManager.getClientConnection(port, dest);

isConnected=true;

}

catch (IOException ex)

{

// ex.printStackTrace();

System.err.println("The connection to : "+dest+" has been lost!");

onlineServers.countDown();

}

}

public boolean getStatus()

{

return isConnected;

}

public void setOperation(String s)

{

operation=s;

}

public void setOperationType(String s)

{

operationType=s;

}

public void setFingerPrintName(String s)

{

fingerPrintName = s;

}

public void setFingerNr(String s)

{

fingerNumber = s;

}

public void setCnp(String s)

{

cnp=s;

}

public void stopThread(){

networkAccess.closeSockets();

}

public void setFingerPrint(File f)

{

fingerPrint = f;

}

@Override

public void run()

{

if (isConnected){

System.out.println("Client thread : "+Thread.currentThread().getName()+ " started");

try {

// authenticate first

networkAccess.sendMessage("LOGIN");

// send auth data

networkAccess.sendMessage("server");

networkAccess.sendMessage("1234");

// receive answer from server

String ans=networkAccess.receiveMessage();

if (ans.equals("ok")){

if (operation.equals("identification"))

{

System.out.println("Client : current operation=identification");

System.out.println("Client: "+localhost+": the fingerprint "+fingerPrintName+" is being sent to"+destIp);

networkAccess.sendMessage("IDENTIFICATION");

networkAccess.sendMessage(operationType);

networkAccess.sendMessage(fingerNumber);

networkAccess.receiveMessage();

// send the fingerPrint file

networkAccess.setFileConnection();

// send the fingerPrint file

System.out.println(fingerPrint.getAbsolutePath());

networkAccess.sendFile(fingerPrint);

//read the answer from the server

String str = networkAccess.receiveMessage();

System.out.println("Client: "+localhost+": the answer from "+destIp+" is : "+str);

String answer="";

cnp="";

String name="";

String surname="";

String source="";

if (str.equals("Identification succeded"))

{

answer="am gasit";

cnp=networkAccess.receiveMessage();

name=networkAccess.receiveMessage();

surname=networkAccess.receiveMessage();

source=networkAccess.getSource();

}

else

{

answer=str;

}

networkAccess.sendMessage("end");

if (!result.getFingerFoundFlag().getFlag())

result.setResult("",answer,cnp,name,surname,source,Thread.currentThread().getName());

System.out.println(localhost+" inchide socketurile");

}

else

{

System.out.println("Client : current operation=verification");

System.out.println("Client: "+localhost+": the fingerprint "+fingerPrintName+" is being sent to"+destIp);

networkAccess.sendMessage("VERIFICATION");

networkAccess.sendMessage(operationType);

networkAccess.sendMessage(cnp);

networkAccess.sendMessage(fingerNumber);

networkAccess.receiveMessage();

// send the fingerPrint file

networkAccess.setFileConnection();

// send the fingerPrint file

networkAccess.sendFile(fingerPrint);

//read the answer from the server

String str = networkAccess.receiveMessage();

System.out.println("Client: "+localhost+": the answer from "+destIp+" is : "+str);

String answerVerif="";

String answer="";

cnp="";

String name="";

String surname="";

String source="";

answer=str;

if (str.equals("am gasit amprenta si corespunde cu cnp-ul"))

{

answerVerif="am gasit cnp";

source=networkAccess.getSource();

}

else

if (str.equals("am gasit amprenta si nu corespunde cu cnp-ul"))

{

answerVerif="am gasit cnp";

cnp=networkAccess.receiveMessage();

name=networkAccess.receiveMessage();

surname=networkAccess.receiveMessage();

source=networkAccess.getSource();

}

else

if (str.equals("nu exista nici o amprenta pentru degetul cerut"))

{

answerVerif="am gasit cnp";

}

networkAccess.sendMessage("end");

if (!result.getFingerFoundFlag().getFlag())

result.setResult(answerVerif,answer,cnp,name,surname,source,Thread.currentThread().getName());

System.out.println(localhost+" inchide socketurile");

}

}

else

{

System.out.println("Authentication Failed! Wrong server username or password!");

}

networkAccess.closeSockets();

}

catch(IOException e)

{

// e.printStackTrace();

System.err.println("The connection to :"+destIp+" has been lost!");

onlineServers.countDown();

}

catch (Exception ex)

{

ex.printStackTrace();

}

}

try {

barrier3.await();

} catch (InterruptedException ex) {

ex.printStackTrace();

} catch (BrokenBarrierException ex) {

ex.printStackTrace();

}

System.out.println("Client thread : "+Thread.currentThread().getName()+ " finished");

}

void sendStop() throws IOException

{

if (networkAccess!=null)

networkAccess.sendMessage("STOP");

}

}

/**

*

* @author alin

* Source code for the file: WaitingThread.java

*/

package fpserver.logic;

import fpserver.util.Counter;

import fpserver.net.NetworkAccess;

import java.util.Map;

import java.util.concurrent.CyclicBarrier;

public class WaitingThread extends Thread

{

private String op;

private String cnpCode;

private String fingerNumber;

private CyclicBarrier barrier1;

private CyclicBarrier barrier2;

private NetworkAccess networkAccess;

private Result result;

private Counter onlineServers;

private Thread[] threadSeq;

public WaitingThread(NetworkAccess networkAccess,Result result,CyclicBarrier barrier1,CyclicBarrier barrier2,Counter onlineServers,Thread[] threadSeq)

{

this.networkAccess=networkAccess;

this.barrier1=barrier1;

this.barrier2=barrier2;

this.onlineServers=onlineServers;

this.result=result;

this.threadSeq=threadSeq;

}

public void setCnpCode(String s)

{

cnpCode=s;

}

public void setFingerNumber(String s)

{

fingerNumber=s;

}

public void setOp(String s)

{

op=s;

}

@Override

public void run()

{

try{

System.out.println("Waiting thread started!");

if (op.equals("identification"))

{

int i=0;

while (!result.getFingerFoundFlag().getFlag() && i<=onlineServers.getIndex())

{

barrier1.await();

Map resultObject=result.getResultObject();

String answer = (String) resultObject.get("answer");

if (answer.equals("am gasit"))

{

result.setFingerFoundFlag(true);

String cnp= (String) resultObject.get("cnp");

String name= (String) resultObject.get("name");

String surname= (String) resultObject.get("surname");

String source=(String) resultObject.get("source");

String threadName=(String) resultObject.get("threadName");

ResponseManager.sendResponseToClient("Identification succeded", cnp, name, surname, source, networkAccess);

System.out.println("Identification answer from "+source+": am gasit "+name+" "+surname+" cu cnp-ul "+cnp);

for (int j=0;j<onlineServers.getIndex();j++)

{

Thread t=threadSeq[j];

if (t!=null)

if (!t.getName().equals(threadName))

{

VirtualClient c=(VirtualClient) t;

c.sendStop();

}

}

}

barrier2.await();

i++;

}

if (!result.getFingerFoundFlag().getFlag())

{

ResponseManager.sendResponseToClient("The fingerprint from the finger: "+fingerNumber+", was not identified!", networkAccess);

}

}

else

{

int i=0;

boolean gasitCnp=false;

while (!result.getFingerFoundFlag().getFlag() && (i<=onlineServers.getIndex()))

{

barrier1.await();

Map resultObject=result.getResultObject();

String answerVerif = (String) resultObject.get("answerVerif");

if (answerVerif.equals("am gasit cnp"))

{

gasitCnp=true;

String answer = (String) resultObject.get("answer");

String source= (String) resultObject.get("source");

if (answer.equals("am gasit amprenta si corespunde cu cnp-ul") || answer.equals("am gasit amprenta si nu corespunde cu cnp-ul"))

{

result.setFingerFoundFlag(true);

if (answer.equals("am gasit amprenta si corespunde cu cnp-ul"))

ResponseManager.sendResponseToClient(answer, source, networkAccess);

else

{

String name=(String) resultObject.get("name");

String surname=(String) resultObject.get("surname");

String cnp=(String) resultObject.get("cnp");

ResponseManager.sendResponseToClient(answer, cnp, name, surname, source, networkAccess);

}

String threadName=(String) resultObject.get("threadName");

System.out.println("Answer from : "+source+" : "+answer);

for (int j=0;j<onlineServers.getIndex();j++)

{

Thread t=threadSeq[j];

if (t!=null)

if (!t.getName().equals(threadName))

{

VirtualClient c=(VirtualClient) t;

c.sendStop();

}

}

}

}

barrier2.await();

i++;

}

if (!gasitCnp)

{

ResponseManager.sendResponseToClient("Nu exista nici o inregistrare cu cnp-ul : "+cnpCode, networkAccess);

System.out.println("Server : there is no record in the database with the provided cnp\n");

}

else

if (!result.getFingerFoundFlag().getFlag())

{

ResponseManager.sendResponseToClient("Nu exista nici o amprenta pentru degetul "+fingerNumber, networkAccess);

System.out.println("Server : there is no record in the database for the specified finger number "+fingerNumber+"\n");

}

}

}

catch(Exception e){

e.printStackTrace();

}

System.out.println("Waiting Thread finished");

}

}

/**

*

* @author alin

* Source code for the file: SearchThread.java

*/

package fpserver.logic;

import fpserver.util.Counter;

import fpserver.db.FingerManager;

import fpserver.net.NetworkServerAccess;

import java.io.File;

import java.io.IOException;

import java.sql.SQLException;

import java.util.Map;

import java.util.concurrent.CyclicBarrier;

public class SearchThread extends Thread {

private String fingerNr;

private String operation;

private String fingerPrintName;

private File fingerPrint;

private String cnp;

private FingerManager fingerManager;

private Map resultMap;

private String opType;

private Result result;

private NetworkServerAccess networkAccess;

private Thread[] threadSeq;

private Counter onlineServers;

private String[] ipSeq;

private int nrOfIps;

private CyclicBarrier barrier3;

private WaitingThread waitingThread;

public SearchThread(String s,String opType,Result result,NetworkServerAccess networkAccess,Counter onlineServers,String[] ipSeq,CyclicBarrier barrier3){

super(s);

this.opType=opType;

this.result=result;

this.networkAccess=networkAccess;

this.onlineServers=onlineServers;

this.barrier3=barrier3;

this.ipSeq=ipSeq;

nrOfIps=ipSeq.length;

fingerManager=new FingerManager();

}

public void setFingerPrint(File f){

fingerPrint = f;

}

public void setFingerPrintName(String s){

fingerPrintName=s;

}

public void setFingerNr(String s){

fingerNr = s;

}

public void setOperation(String s){

operation=s;

}

public void stopSearching(){

if (fingerManager!=null)

fingerManager.setFlagState(true);

}

public void stopThread(){

if (waitingThread!=null)

waitingThread.interrupt();

if (threadSeq!=null)

for (Thread t:threadSeq){

if (t!=null)

((VirtualClient)t).stopThread();

}

}

public void setCnp(String cnp){

this.cnp=cnp;

}

@Override

public void run(){

try

{

if (operation.equals("identification")){

resultMap=fingerManager.identif(fingerPrintName,fingerNr);

if (!fingerManager.getFlagState()){

String answer=(String)resultMap.get("answer");

cnp=(String)resultMap.get("cnp");

String name=(String)resultMap.get("name");

String surname=(String)resultMap.get("surname");

String address=(String)resultMap.get("address");

if (opType.equals("local"))

address="";

if (answer.equals("am gasit")){

result.getFingerFoundFlag().setFlag(true);

ResponseManager.sendResponseToClient("Identification succeded", cnp, name, surname, address, networkAccess);

}

else{

if (opType.equals("local")){

ResponseManager.sendResponseToClient("The fingerprint was not identified!", networkAccess);

}

else{

threadSeq = new VirtualClient[nrOfIps];

waitingThread = new WaitingThread(networkAccess,result,result.getFirstBarrier(),result.getSecondBarrier(),onlineServers,threadSeq);

waitingThread.setOp("identification");

waitingThread.setFingerNumber(fingerNr);

waitingThread.start();

int i=0;

int j=0;

while (i<nrOfIps)

{

VirtualClient c=new VirtualClient(ipSeq[i],networkAccess.getPort(),onlineServers,result,barrier3);

c.setFingerPrintName(fingerPrintName);

c.setFingerPrint(fingerPrint);

c.setOperation("identification");

c.setOperationType("local");

c.setFingerNr(fingerNr);

c.setName("client "+j);

if (c.getStatus()){

threadSeq[j]=c;

j++;

}

c.start();

i++;

}

barrier3.await();

if (!result.getFingerFoundFlag().getFlag())

result.setResult("",answer,cnp,name,surname,address,Thread.currentThread().getName());

}

}

}

}

else

{

//fingerPrint.getAbsolutePath()

resultMap=fingerManager.verifCnp(cnp,fingerPrintName,fingerNr);

if (!fingerManager.getFlagState()){

String answerVerif=(String)resultMap.get("answerVerif");

String answer=(String)resultMap.get("answer");

cnp=(String)resultMap.get("cnp");

String name=(String)resultMap.get("name");

String surname=(String)resultMap.get("surname");

String address=(String)resultMap.get("address");

boolean startDistributedSearch=false;

if (opType.equals("local"))

{

address="";

}

if (answerVerif.equals("am gasit cnp")){

if (answer.equals("am gasit amprenta si corespunde cu cnp-ul")){

result.getFingerFoundFlag().setFlag(true);

ResponseManager.sendResponseToClient("am gasit amprenta si corespunde cu cnp-ul", address,networkAccess);

}

else{

if (answer.equals("am gasit amprenta si nu corespunde cu cnp-ul")){

result.getFingerFoundFlag().setFlag(true);

ResponseManager.sendResponseToClient(answer, cnp, name, surname, address, networkAccess);

}

else{

if (opType.equals("local")){

ResponseManager.sendResponseToClient("There is no fingerprint in the database for the provided finger number!", networkAccess);

System.out.println("Server : there is no fingerprint in the database for the provided finger number!");

}

else{

startDistributedSearch=true;

}

}

}

}

else {

if (opType.equals("local")){

ResponseManager.sendResponseToClient("There is no record in the database with the provided PIN", networkAccess);

System.out.println("Server : there is no record in the database with the provided PIN");

}

else{

startDistributedSearch=true;

}

}

if (startDistributedSearch){

threadSeq = new VirtualClient[nrOfIps];

waitingThread = new WaitingThread(networkAccess,result,result.getFirstBarrier(),result.getSecondBarrier(),onlineServers,threadSeq);

waitingThread.setOp("verification");

waitingThread.setFingerNumber(fingerNr);

waitingThread.setCnpCode(cnp);

waitingThread.start();

int i=0;

int j=0;

while (i<nrOfIps){

VirtualClient c=new VirtualClient(ipSeq[i],networkAccess.getPort(),onlineServers,result,barrier3);

c.setFingerPrintName(fingerPrintName);

c.setFingerPrint(fingerPrint);

c.setCnp(cnp);

c.setOperation("verification");

c.setOperationType("local");

c.setFingerNr(fingerNr);

c.setName("client "+j);

if (c.getStatus()){

threadSeq[j]=c;

j++;

}

c.start();

i++;

}

barrier3.await();

if (!result.getFingerFoundFlag().getFlag())

result.setResult(answerVerif,answer,cnp,name,surname,address,Thread.currentThread().getName());

}

}

}

}

catch(SQLException e)

{

try {

e.printStackTrace();

networkAccess.sendMessage("Database error!");

} catch (IOException ex) {

ex.printStackTrace();

}

}

catch(Exception e){

e.printStackTrace();

}

System.out.println("Searching Thread: "+Thread.currentThread().getName()+" finished");

}

}

/**

*

* @author alin

* Source code for the file: ResponseManager.java

*/

package fpserver.logic;

import fpserver.net.NetworkAccess;

import java.io.IOException;

public class ResponseManager {

public static void sendResponseToClient(String answer,String cnp,String name,String surname,String source,NetworkAccess networkAccess) throws IOException

{

networkAccess.sendMessage(answer);

networkAccess.sendMessage(cnp);

networkAccess.sendMessage(name);

networkAccess.sendMessage(surname);

if (!source.equals(""))

networkAccess.sendMessage(source);

}

public static void sendResponseToClient(String answer,NetworkAccess networkAccess) throws IOException

{

networkAccess.sendMessage(answer);

}

public static void sendResponseToClient(String answer,String source,NetworkAccess networkAccess) throws IOException

{

networkAccess.sendMessage(answer);

networkAccess.sendMessage(source);

}

}

/**

*

* @author alin

* Source code for the file: Result.java

*/

package fpserver.logic;

import fpserver.util.Flag;

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

public class Result {

private Map resultObject;

private CyclicBarrier barrier1;

private CyclicBarrier barrier2;

private Flag fingerFound;

public Result(CyclicBarrier barrier1,CyclicBarrier barrier2)

{

this.barrier1=barrier1;

this.barrier2=barrier2;

this.fingerFound=new Flag();

resultObject=new HashMap();

}

public synchronized void setResult(String answerVerif,String answer,String cnp,String name,String surname,String source,String threadName) throws InterruptedException,BrokenBarrierException

{

if (!fingerFound.getFlag())

{

resultObject.put("answerVerif",answerVerif);

resultObject.put("cnp",cnp);

resultObject.put("name",name);

resultObject.put("surname",surname);

resultObject.put("answer",answer);

resultObject.put("source",source);

resultObject.put("threadName",threadName);

barrier1.await();

barrier2.await();

}

}

public Map getResultObject()

{

return resultObject;

}

public Flag getFingerFoundFlag()

{

return fingerFound;

}

public void setFingerFoundFlag(boolean flag)

{

fingerFound.setFlag(flag);

}

public CyclicBarrier getFirstBarrier(){

return barrier1;

}

public CyclicBarrier getSecondBarrier(){

return barrier2;

}

}

/**

*

* @author alin

* Source code for the file: Identification.java for the server application

*/

package fpserver.logic.operations;

import fpserver.util.Counter;

import fpserver.util.UserInfo;

import fpserver.imgproc.BMPFile;

import fpserver.imgproc.FpTemplate;

import fpserver.logic.*;

import fpserver.net.NetworkServerAccess;

import java.io.File;

import java.io.IOException;

import java.util.concurrent.CyclicBarrier;

public class Identification implements Operation{

private Result result;

private Counter onlineServers;

private String opType;

private NetworkServerAccess networkAccess;

private SearchThread searchThread;

private String[] ipSeq;

private CyclicBarrier barrier1;

private CyclicBarrier barrier2;

private CyclicBarrier barrier3;

private UserInfo userInfo;

private int nrOfIps;

public Identification(Result result,Counter onlineServers,NetworkServerAccess networkAccess,String[] ipSeq,CyclicBarrier barrier1,CyclicBarrier barrier2,CyclicBarrier barrier3,UserInfo userInfo){

this.result=result;

this.onlineServers=onlineServers;

this.networkAccess=networkAccess;

this.ipSeq=ipSeq;

this.barrier1=barrier1;

this.barrier2=barrier2;

this.barrier3=barrier3;

this.userInfo=userInfo;

nrOfIps=ipSeq.length;

onlineServers.setIndex(nrOfIps);

}

@Override

public void performOperation() throws IOException{

result.setFingerFoundFlag(false);

onlineServers.setIndex(nrOfIps);

opType=networkAccess.receiveMessage();

System.out.println("Identification in progress; operation type: "+opType);

String fingerNr=networkAccess.receiveMessage();

networkAccess.sendMessage("ok");

networkAccess.acceptFileConnection();

if (!opType.equals("local")){

String filename="res//workspace//"+userInfo.getUsername()+"F"+fingerNr;

File fingerPrint=networkAccess.receiveFile(filename);

BMPFile.convertDataToBMP(filename, "res//fingerprints//"+userInfo.getUsername()+"F"+fingerNr+".bmp");

}

else{

String filename="res//fingerprints//"+userInfo.getUsername()+"F"+fingerNr+".bmp";

File fingerPrint=networkAccess.receiveFile(filename);

}

try {

FpTemplate.getInstance().saveTemplate("res//templates//"+userInfo.getUsername()+"F" + fingerNr, "res//fingerprints//"+userInfo.getUsername()+"F" + fingerNr+".bmp");

searchThread=new SearchThread("localSearch",opType,result,networkAccess,onlineServers,ipSeq,barrier3);

searchThread.setOperation("identification");

searchThread.setFingerNr(fingerNr);

searchThread.setFingerPrint(new File("res//fingerprints//"+userInfo.getUsername()+"F"+fingerNr+".bmp"));

searchThread.setFingerPrintName("res//templates//"+userInfo.getUsername()+"F"+ fingerNr);

searchThread.start();

}

catch (Exception ex) {

ex.printStackTrace();

networkAccess.sendMessage("identification failed : image quality to low");

}

}

@Override

public String getName() {

return "IDENTIFICATION";

}

public SearchThread getSearchThread(){

return searchThread;

}

public void stopSearchThread(){

searchThread.stopThread();

}

}

/**

*

* @author alin

* Source code for the file: AddIdcardRecor.java for the server application

*/

package fpserver.logic.operations;

import fpserver.db.CnpManager;

import fpserver.imgproc.BMPFile;

import fpserver.imgproc.FpTemplate;

import fpserver.db.IdCardManager;

import fpserver.db.FingerManager;

import fpserver.net.NetworkServerAccess;

import java.io.IOException;

import java.sql.SQLException;

public class AddIdcardRecord implements Operation{

private NetworkServerAccess networkAccess;

private FingerManager fingerManager;

public AddIdcardRecord(NetworkServerAccess networkAccess,FingerManager fingerManager)

{

this.networkAccess=networkAccess;

this.fingerManager=fingerManager;

}

@Override

public void performOperation() throws IOException {

try {

System.out.println("Add new idcard record!");

//accept first

String cnp=networkAccess.receiveMessage();

if (!CnpManager.getCnpManager().searchCnp(cnp))

{

networkAccess.sendMessage("ok");

String name=networkAccess.receiveMessage();

String surname=networkAccess.receiveMessage();

String series=networkAccess.receiveMessage();

String no=networkAccess.receiveMessage();

String father_name=networkAccess.receiveMessage();

String mother_name=networkAccess.receiveMessage();

String address=networkAccess.receiveMessage();

String issuedby=networkAccess.receiveMessage();

String fingerNumber=networkAccess.receiveMessage();

String validity=networkAccess.receiveMessage();

networkAccess.acceptFileConnection();

String fingerFilename="res//workspace//"+cnp+"F"+fingerNumber;

networkAccess.receiveFile(fingerFilename);

BMPFile.convertDataToBMP(fingerFilename, "res//fingerprints//"+cnp+"F"+fingerNumber+".bmp");

networkAccess.receiveMessage();

networkAccess.acceptFileConnection();

String pictureFilename="res//pictures//"+cnp+".bmp";

networkAccess.receiveFile(pictureFilename);

try {

FpTemplate.getInstance().saveTemplate("res//templates//" + cnp + "F" + fingerNumber, "res//fingerprints//" + cnp + "F" + fingerNumber+".bmp");

} catch (Exception ex) {

ex.printStackTrace();

throw new OperationFailedException(ex.getMessage());

}

IdCardManager.getIdCardManager().insert(name,surname,cnp,series,no,father_name,mother_name,address,issuedby,pictureFilename,"res//templates//" + cnp + "F" + fingerNumber,validity,fingerNumber);

networkAccess.sendMessage("Remote Enrollment Succeeded!");

System.out.println("ID-card Remote Enrollment Succeeded!");

}

else

{

networkAccess.sendMessage("exists");

System.out.println("Adding failed : a record with the provided cnp "+cnp+" already exists in the database");

}

}

catch (SQLException ex)

{

ex.printStackTrace();

networkAccess.sendMessage("Database error!");

}

catch (OperationFailedException e) {

e.printStackTrace();

networkAccess.sendMessage("Fingerprint features extracting error! Low quality image!");

}

}

@Override

public String getName() {

return "ADD_IDCARD_RECORD";

}

}

/**

*

* @author alin

* Source code for the file: FpTemplate.java

*/

package fpserver.imgproc;

import com.neurotechnology.Fingers.ImpressionType;

import com.neurotechnology.Fingers.NFExtractor;

import com.neurotechnology.Fingers.Position;

import com.neurotechnology.Library.NativeManager;

import com.neurotechnology.NImages.NImage;

import com.neurotechnology.NLicensing.NLicensing;

import com.neurotechnology.NMatcher.NMatcher;

import com.neurotechnology.Templates.NFRecord;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

public class FpTemplate

{

private NFExtractor extractor;

private NImage image;

private NFRecord record;

private NFRecord rec1;

private NFRecord rec2;

private NMatcher matcher;

private static FpTemplate instance;

public static synchronized FpTemplate getInstance(){

if (instance==null)

return new FpTemplate();

return instance;

}

private FpTemplate()

{

try{

String product = NativeManager.getWrapperLibraryInfo().getProduct();

if("MegaMatcher".equals(product)) NLicensing.licenseObtain("/local","5000","MegaMatcherClient");

if("VeriFinger".equals(product)) NLicensing.licenseObtain("/local","5000","VFExtractor");

extractor = new NFExtractor();

//if (!NFExtractor.isRegistered()) System.out.println("Sorry, you cant use this feature.");

//product = NativeManager.getWrapperLibraryInfo().getProduct();

if("MegaMatcher".equals(product)){

boolean obtained = NLicensing.licenseObtain("/local","5000","MegaMatcherClient");

System.out.println("MegaMatcherClient licence obtained – " + obtained);

obtained = NLicensing.licenseObtain("/local","5000","MegaMatcherServer");

System.out.println("MegaMatcherServer licence obtained – " + obtained);

}

if("VeriFinger".equals(product)){

boolean obtained = NLicensing.licenseObtain("/local","5000","VFExtractor");

System.out.println("VFExtractor licence obtained – " + obtained);

obtained = NLicensing.licenseObtain("/local","5000","VFMatcher");

System.out.println("VFMatcher licence obtained – " + obtained);

}

matcher = new NMatcher();

}

catch (Exception e) {

System.out.println(e.getMessage());

}

}

@Override

public Object clone() throws CloneNotSupportedException {

throw new CloneNotSupportedException();

}

public synchronized void saveTemplate(String dest,String source) throws Exception

{

image = NImage.loadFromFile(source);

//image=NImage.getEmptyImage().loadFromFile(source);

record = extractor.ExtractFromUnpackedImage(image,Position.nfpUnknown,ImpressionType.nfitLiveScanPlain);

File f = new File(dest);

try{

f.createNewFile();

FileOutputStream fos = new FileOutputStream(f);

fos.write(record.getTemplate());

fos.close();

}catch (Exception e) {

System.out.println(e.getMessage());

}

}

public synchronized String verify(String template1,String template2)

{

double score;

try

{

File f = new File(template1);

FileInputStream in = new FileInputStream(f);

byte [] data = new byte[(int)f.length()];

int offset = 0;

int numRead = 0;

while (offset < data.length

&& (numRead=in.read(data, offset, data.length-offset)) >= 0)

{

offset += numRead;

}

in.close();

rec1 = new NFRecord(data);

f = new File(template2);

in = new FileInputStream(f);

data = new byte[(int)f.length()];

offset = 0;

numRead = 0;

while (offset < data.length

&& (numRead=in.read(data, offset, data.length-offset)) >= 0)

{

offset += numRead;

}

in.close();

rec2 = new NFRecord(data);

score = matcher.verify(rec1,rec2);

}

catch(Exception e)

{

e.printStackTrace();

return "there was an error during the verification process!";

}

if (score != 0){

return "Templates match";

}else {

return "This is not the same finger";

}

}

}

/**

*

* @author alin

* Source code for the file: FingerManager.java

*/

package fpserver.db;

import fpserver.imgproc.FpTemplate;

import fpserver.util.Flag;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.sql.Connection;

import java.sql.ResultSet;

import java.sql.Statement;

import java.sql.SQLException;

import java.util.HashMap;

import java.util.Map;

public class FingerManager {

private Flag stopSearching;

public FingerManager()

{

stopSearching=new Flag();

}

public Map identif(String fingerPrintName,String fingerNr) throws SQLException

{

boolean gasitFingerprint=false;

String answer="nu am gasit";

String cnp="";

String name="";

String surname="";

Connection con=DatabaseConnection.connect();

Statement stat;

ResultSet result=null;

try

{

stat = con.createStatement();

switch (Integer.parseInt(fingerNr))

{

case 1: result = stat.executeQuery("SELECT fingers.fingerprint1,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 2: result = stat.executeQuery("SELECT fingers.fingerprint2,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 3: result = stat.executeQuery("SELECT fingers.fingerprint3,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 4: result = stat.executeQuery("SELECT fingers.fingerprint4,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 5: result = stat.executeQuery("SELECT fingers.fingerprint5,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 6: result = stat.executeQuery("SELECT fingers.fingerprint6,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 7: result = stat.executeQuery("SELECT fingers.fingerprint7,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 8: result = stat.executeQuery("SELECT fingers.fingerprint8,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 9: result = stat.executeQuery("SELECT fingers.fingerprint9,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

case 10: result = stat.executeQuery("SELECT fingers.fingerprint10,cnps.cnp FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)"); break;

}

while(result.next() && !stopSearching.getFlag() && !gasitFingerprint)

{

try {

Thread.sleep(50);

}

catch (InterruptedException e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

String aux="fingerprint"+fingerNr;

String fp = result.getString(aux);

if(fp!=null && !fp.equals("")){

if (FpTemplate.getInstance().verify(fp, fingerPrintName).equals("Templates match"))

{

gasitFingerprint = true;

answer="am gasit";

cnp=result.getString("cnp");

}

}

}

if (stopSearching.getFlag())

System.out.println("Cautare intrerupta!");

else

if (gasitFingerprint)

{

Map m=IdCardManager.getIdCardManager().getData(cnp, stopSearching);

if (m!=null)

{

name=(String)m.get("name");

surname=(String)m.get("surname");

}

else

{

m=PassportManager.getPassportManager().getData(cnp, stopSearching);

if (m!=null)

{

name=(String)m.get("name");

surname=(String)m.get("surname");

}

}

}

}

catch(Exception ex)

{

ex.printStackTrace();

}

System.out.println("Rezultatul cautarii locale este : "+answer);

Map resultMap=new HashMap();

resultMap.put("answer", answer);

resultMap.put("cnp", cnp);

resultMap.put("name",name);

resultMap.put("surname",surname);

try {

resultMap.put("address",InetAddress.getLocalHost().getHostAddress());

} catch (UnknownHostException ex) {

ex.printStackTrace();

}

DatabaseConnection.close(con);

return resultMap;

}

public Map verifCnp(String cnp,String fingerprint,String fingerNr) throws SQLException

{

String answer="nu am gasit amprenta";

String answerVerif="nu am gasit cnp-ul";

String name="";

String surname="";

String foundCnp="";

boolean gasitCnp=false;

Connection con=DatabaseConnection.connect();

Statement stat;

ResultSet result;

try {

stat = con.createStatement();

result = stat.executeQuery("SELECT * FROM fingers join cnps on (fingers.cnp_id=cnps.cnp_id)");

while (!gasitCnp && !stopSearching.getFlag() && result.next())

{

try {

Thread.sleep(50);

} catch (InterruptedException ex) {

ex.printStackTrace();

}

foundCnp=result.getString("cnp");

if (foundCnp.equals(cnp))

gasitCnp=true;

}

if (!stopSearching.getFlag())

{

if (gasitCnp)

{

answerVerif="am gasit cnp";

String filename="//";

switch (Integer.parseInt(fingerNr))

{

case 1: filename = result.getString("fingerprint1"); break;

case 2: filename = result.getString("fingerprint2"); break;

case 3: filename = result.getString("fingerprint3"); break;

case 4: filename = result.getString("fingerprint4"); break;

case 5: filename = result.getString("fingerprint5"); break;

case 6: filename = result.getString("fingerprint6"); break;

case 7: filename = result.getString("fingerprint7"); break;

case 8: filename = result.getString("fingerprint8"); break;

case 9: filename = result.getString("fingerprint9"); break;

case 10: filename = result.getString("fingerprint10"); break;

}

if (filename!=null && FpTemplate.getInstance().verify(filename, fingerprint).equals("Templates match"))

answer="am gasit amprenta si corespunde cu cnp-ul";

else

if (filename!=null && !filename.equals(""))

{

answer="am gasit amprenta si nu corespunde cu cnp-ul";

Map m=IdCardManager.getIdCardManager().getData(cnp, stopSearching);

if (m!=null)

{

name=(String)m.get("name");

surname=(String)m.get("surname");

}

else

{

m=PassportManager.getPassportManager().getData(cnp, stopSearching);

if (m!=null)

{

name=(String)m.get("name");

surname=(String)m.get("surname");

}

}

}

else

answer="nu exista nici o amprenta pentru degetul :" + fingerNr;

}

else

{

answerVerif="nu am gasit cnp";

if (stopSearching.getFlag())

{

System.out.println("Verificare intrerupta!");

answer="verificare intrerupta";

}

else

answer="nu am gasit amprenta si nici cnp-ul corespunzator";

}

}

else

{

answer="Cautare intrerupta";

}

}

catch (SQLException ex)

{

ex.printStackTrace();

}

System.out.println("Rezultatul cautarii locale este : "+answer);

Map resultMap=new HashMap();

resultMap.put("answerVerif", answerVerif);

resultMap.put("answer", answer);

resultMap.put("cnp",cnp);

resultMap.put("name",name);

resultMap.put("surname",surname);

try {

resultMap.put("address",InetAddress.getLocalHost().getHostAddress());

} catch (UnknownHostException ex) {

ex.printStackTrace();

}

DatabaseConnection.close(con);

return resultMap;

}

public void insertFingerprint(String cnp,String fingerprint,String fingerNr) throws SQLException

{

Connection con=DatabaseConnection.connect();

Statement stat;

try{

con.setAutoCommit(false);

int cnp_id=CnpManager.getCnpManager().getCnpId(cnp, con);

stat = con.createStatement();

switch (Integer.parseInt(fingerNr))

{

case 1: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT1='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 2: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT2='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 3: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT3='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 4: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT4='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 5: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT5='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 6: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT6='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 7: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT7='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 8: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT8='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 9: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT9='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

case 10: stat.executeUpdate("UPDATE FINGERS SET FINGERPRINT10='"+fingerprint+"' where cnp_id='"+cnp_id+"';"); break;

}

con.commit();

}

catch(SQLException ex){

ex.printStackTrace();

try

{

con.rollback();

}

catch(SQLException e)

{

e.printStackTrace();

}

finally{

throw new DatabaseException("there was an sql exception during the insertion of the passport record",ex);

}

}

finally{

try {

con.setAutoCommit(true);

DatabaseConnection.close(con);

} catch (SQLException ex) {

ex.printStackTrace();

}

}

}

public boolean getFlagState()

{

return stopSearching.getFlag();

}

public void setFlagState(boolean flag)

{

stopSearching.setFlag(flag);

}

}

/**

*

* @author alin

* Source code for the file: IdCardManager.java

*/

package fpserver.db;

import fpserver.util.Flag;

import java.sql.Connection;

import java.sql.Statement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.HashMap;

import java.util.Map;

public class IdCardManager {

private IdCardManager(){

}

public static synchronized IdCardManager getIdCardManager(){

if (ref==null)

ref = new IdCardManager();

return ref;

}

@Override

public Object clone() throws CloneNotSupportedException {

throw new CloneNotSupportedException();

}

public void insert(String name,String surname,String cnp,String series,String no,String father_name,String mother_name,String address,String issuedby,String picture,String fingerprint,String validity,String fingerNumber) throws SQLException

{

Connection con=DatabaseConnection.connect();

Statement stat;

try{

con.setAutoCommit(false);

String day=validity.substring(0,validity.indexOf("/"));

String month=validity.substring(validity.indexOf("/")+1,validity.lastIndexOf("/"));

String year=validity.substring(validity.lastIndexOf("/")+1,validity.length());

String dat=year+"/"+month+"/"+day;

int cnp_id=CnpManager.getCnpManager().insertCnp(cnp, con);

stat = con.createStatement();

stat.executeUpdate("INSERT INTO IDCARDS (name, surname, cnp_id, series, no, father_name, mother_name,address, issuedby, picture, validity) VALUES('"+name+"','"+surname+"','"+cnp_id+"','"+series+"','"+no+"','"+father_name+"','"+mother_name+"','"+address+"','"+issuedby+"','"+picture+"','"+dat+"');");

stat = con.createStatement();

switch (Integer.parseInt(fingerNumber))

{

case 1: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT1) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 2: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT2) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 3: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT3) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 4: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT4) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 5: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT5) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 6: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT6) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 7: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT7) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 8: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT8) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 9: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT9) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

case 10: stat.executeUpdate("INSERT INTO FINGERS (CNP_ID,FINGERPRINT10) VALUES('"+cnp_id+"','"+fingerprint+"');"); break;

}

con.commit();

}

catch(SQLException ex){

ex.printStackTrace();

try

{

con.rollback();

}

catch(SQLException e)

{

e.printStackTrace();

}

finally{

throw new DatabaseException("there was an sql exception during the insertion of the passport record",ex);

}

}

finally{

try {

con.setAutoCommit(true);

DatabaseConnection.close(con);

} catch (SQLException ex) {

ex.printStackTrace();

}

}

}

public Map getData(String cnp,Flag stopSearching) throws SQLException

{

Map m=null;

Connection con=DatabaseConnection.connect();

try

{

Statement stat = con.createStatement();

ResultSet result = stat.executeQuery("SELECT idcards.name,idcards.surname FROM idcards inner join cnps on (idcards.cnp_id=cnps.cnp_id) where cnps.cnp='"+cnp+"';");

if (result.next() && !stopSearching.getFlag())

{

String name=result.getString("name");

String surname=result.getString("surname");

m=new HashMap();

m.put("name", name);

m.put("surname", surname);

}

}

catch(SQLException e)

{

e.printStackTrace();

}

finally

{

DatabaseConnection.close(con);

}

return m;

}

private static IdCardManager ref;

}

/**

*

* @author alin

* Source code for the file: NetworkManager.java

*/

package fpserver.net;

import fpserver.*;

import java.io.IOException;

import java.net.InetAddress;

import java.net.Socket;

import java.net.UnknownHostException;

public class NetworkManager {

private ServerConnection networkCon;

private Socket connection;

private static int fileport=2010;

private int port;

public NetworkManager(int port) throws IOException

{

this.port=port;

networkCon=new ServerConnection(port);

}

public NetworkServerAccess getNetworkAccess() throws IOException

{

connection=networkCon.getConnection();

try {

System.out.println("Serverul: "+InetAddress.getLocalHost()+" a receptionat o cerere");

} catch (UnknownHostException ex) {

ex.printStackTrace();

}

String source=connection.getInetAddress().getHostAddress();

System.out.println("Sursa cererii este : "+source);

boolean portFree = false;

ServerConnection networkFileCon=null;

while (!portFree)

{

try {

networkFileCon = new ServerConnection(fileport);

portFree = true;

}

catch (IOException e)

{

e.printStackTrace();

}

if (!portFree)

fileport++;

}

NetworkServerAccess networkAccess=new NetworkServerAccess(connection,networkFileCon,fileport);

fileport++;

if (fileport==5000)

fileport=2010;

return networkAccess;

}

public int getPort()

{

return port;

}

public static NetworkClientAccess getClientConnection(int port, String destIp) throws IOException

{

ClientConnection clientCon=new ClientConnection(port,destIp);

return new NetworkClientAccess(clientCon,destIp);

}

public static String getLocalHost() throws UnknownHostException

{

return InetAddress.getLocalHost().toString();

}

public void closeServerConnection(){

try {

networkCon.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

}

/**

*

* @author alin

* Source code for the file: NetworkServerAccess.java

*/

package fpserver.net;

import fpserver.*;

import java.io.BufferedReader;

import java.io.DataInputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.net.Socket;

public class NetworkServerAccess implements NetworkAccess{

private Socket connection;

private BufferedReader in;

private OutputStream out;

private ServerConnection networkCon;

private int fileport;

private DataInputStream fileIn;

private Socket fileConnection;

public NetworkServerAccess(Socket connection,ServerConnection networkConnection,int fileport) throws IOException

{

this.connection=connection;

this.networkCon=networkConnection;

in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

//out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(connection.getOutputStream())),true);

out=connection.getOutputStream();

this.fileport=fileport;

}

@Override

public void sendMessage(String msg) throws IOException

{

out.write((msg+"\n").getBytes());

out.flush();

}

@Override

public String receiveMessage() throws IOException

{

return in.readLine();

}

public int getFilePort()

{

return fileport;

}

public void acceptFileConnection() throws IOException

{

fileConnection=networkCon.getConnection();

fileIn = new DataInputStream(fileConnection.getInputStream());

}

public File receiveFile(String fileDestPath) throws IOException

{

File fp = new File(fileDestPath);

FileOutputStream fout = new FileOutputStream(fp);

int bsize = 1024;

byte[] bdata = new byte[bsize];

int n=0;

while ((n = fileIn.read(bdata,0,bsize)) > 0)

{

fout.write(bdata,0,n);

}

fout.close();

fileIn.close();

fileConnection.close();

return fp;

}

public String getClientAddress()

{

return connection.getRemoteSocketAddress().toString();

}

@Override

public void closeSockets()

{

if (connection!=null)

{

try {

connection.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

if (fileConnection!=null)

{

try {

fileConnection.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

if (networkCon!=null)

{

try {

networkCon.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

}

public int getPort(){

return connection.getLocalPort();

}

}

/**

*

* @author alin

* Source code for the file: Cryptography.java

*/

package fpserver.util;

public class Cryptography {

private int stringKey=19364;

private byte byteArrayKey=(byte)193;

public Cryptography(int stringKey,byte byteArrayKey){

this.stringKey=stringKey;

this.byteArrayKey=byteArrayKey;

}

public String encrypt(String a){

String b=new String();

char aux;

char[] sir=a.toCharArray();

for (int i=0;i<sir.length;i++){

aux=(char)((int)sir[i]^stringKey);

b=b+aux;

}

String msg=b.toString();

System.out.println("encrypted message : "+msg);

System.out.println("decripted message : "+decrypt(msg));

return b.toString();

}

public String decrypt(String d){

char aux;

String b=new String();

char[] sir=d.toCharArray();

for (int i=0;i<sir.length;i++){

aux=(char)((int)sir[i]^stringKey);

b=b+aux;

}

return b.toString();

}

public byte[] encrypt(byte[] sir){

byte[] sir2=new byte[sir.length];

for (int i=0; i<sir2.length;i++){

sir2[i]=(byte) (sir[i]^byteArrayKey);

}

return sir2;

}

public byte[] decrypt(byte[] sir2){

byte[] sir3=new byte[sir2.length];

for (int i=0; i<sir3.length;i++){

sir3[i]=(byte) (sir2[i]^byteArrayKey);;

}

return sir3;

}

}

/**

*

* @author alin ciupeiu

* Source code for the file: BlueToothAccess.java

*/

package fpclient.io.bluetooth;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import javax.microedition.io.CommConnection;

import javax.microedition.io.Connector;

import javax.microedition.io.StreamConnection;

public class BlueToothAccess{

/* private CommConnection conn;

private InputStream in;

private OutputStream out;*/

private StreamConnection conn;

private DataInputStream in;

private DataOutputStream out;

private static String btUrl=null;

private static final byte[] CRLF = new byte[]{13,10};

private boolean btFound=false;

private boolean connected=false;

public void findTaiyoSpp() throws IOException{

BTManager.instance().find(BTManager.getRFCOMM_UUID());

int size = BTManager.instance().btDevicesFound.size();

String senzor="TAIYO SPP";

for (int i = 0; i < size; i++) {

String devName=BTManager.instance().getDeviceName(i);

if (devName.equals(senzor)){

btUrl=BTManager.instance().getServiceURL(i);

btFound=true;

}

}

if (!btFound)

throw new BtSensorException("Senzorul nu a fost gasit. Verificati daca este pornit!");

}

public String readLine() throws IOException{

StringBuffer sb = new StringBuffer();

int inputChar=-1;

while ((inputChar=in.read())!=-1 && inputChar!='\n'){

sb.append((char) inputChar);

}

return sb.toString();

}

public void connect() throws IOException{

// search for the bluetooth devices

if (!btFound)

findTaiyoSpp();

// connect to the Taiyo Spp sensor

conn = (StreamConnection) Connector.open(btUrl, Connector.READ_WRITE);

in = new DataInputStream(conn.openInputStream());

out = new DataOutputStream(conn.openDataOutputStream());

/*conn = (CommConnection) Connector.open("comm:COM2;baudrate=115200");

System.out.println("Connected to the sensor");

in = conn.openInputStream();

out = conn.openOutputStream();*/

// after each connection the sensor transmits some useless information

String sb="";

String response=readLine();

sb=sb+response;

if (sb.indexOf("PowerDown")!=-1)

throw new BtSensorException("The sensor is in deep sleep mode. Please restart it!");

response=readLine();

sb=sb+response;

response=readLine();

sb=sb+response;

response=readLine();

sb=sb+response;

if (sb.indexOf("PowerDown")!=-1)

throw new BtSensorException("The sensor is in deep sleep mode. Please restart it!");

response=readLine();

response=readLine();

connected=true;

}

public void write(char ch) throws IOException{

out.write(ch);

out.write(CRLF);

out.flush();

}

public byte[] getFingerPrint() throws IOException{

// first capture the fingerprint

write('C');

// read the answer from the sensor

String response=readLine();

if (response.endsWith("PowerDown"))

throw new BtSensorException("The sensor is in deep sleep mode. Please restart it!");

else if (response.indexOf("00")==-1)

throw new BtSensorException("Fingerprint capturing failed! Please try again!");

readLine();

// ask the sensor to send the fingerprint

write('B');

return readFingerprint();

}

public byte[] readFingerprint() throws IOException{

int length=45313;

byte[] buffer=new byte[length];

int inputChar=-1;

int i=0;

while (i<45313 && (inputChar=in.read())!=-1){

buffer[i]=(byte) inputChar;

i++;

}

return buffer;

}

public boolean getConnectedStatus(){

return connected;

}

public void setConnectedStatus(boolean flag){

connected=flag;

}

public boolean isOutputStreamOpen(){

if (out==null)

return false;

else

return true;

}

public void close() throws IOException{

if (in!=null)

in.close();

if (out!=null)

out.close();

if (conn!=null)

conn.close();

connected=false;

}

}

/**

*

* @author alin ciupeiu

* Source code for the file: NetworkAccess.java

*/

package fpclient.io;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.OutputStream;

import javax.microedition.io.Connector;

import javax.microedition.io.OutputConnection;

import javax.microedition.io.StreamConnection;

public class NetworkAccess {

private StreamConnection streamConnection;

private OutputConnection fileSocket;

private DataInputStream dis;

private DataOutputStream dos;

private OutputStream fileOut;

private String connectString;

private String fileConnectString;

private String filePort;

NetworkAccess(){}

public NetworkAccess(String destIp,String port) throws IOException {

connectString = "socket://"+destIp+":"+port;

streamConnection=(StreamConnection) Connector.open(connectString);

//create IO streams

dos = streamConnection.openDataOutputStream();

dis = streamConnection.openDataInputStream();

StringBuffer sb = new StringBuffer();

int inputChar;

while ( ((inputChar = dis.read()) != -1) && (inputChar != '\n'))

{

sb.append((char) inputChar);

}

filePort=sb.toString();

System.out.println("File port:"+filePort);

fileConnectString = "socket://"+destIp+":"+filePort;

}

public String getConnectString(){

return connectString;

}

public void openFileConnection() throws IOException {

fileSocket = (OutputConnection)Connector.open(fileConnectString);

fileOut = fileSocket.openOutputStream();

}

public void closeFileConnection() throws IOException {

fileOut.close();

fileSocket.close();

}

public void sendFile(byte[] bdata,int n) throws IOException {

fileOut.write(bdata,0,n); // write it to the socket

fileOut.flush();

}

public void sendMessage(String s) throws IOException {

dos.write((s+"\n").getBytes());

dos.flush();

}

public String receiveMessage() throws IOException {

StringBuffer sb = new StringBuffer();

int inputChar;

while ( ((inputChar = dis.read()) != -1) && (inputChar != '\n'))

{

sb.append((char) inputChar);

}

return sb.toString();

}

public void close() throws IOException {

if (dis!=null){

dis.close();

}

if (dos!=null){

dos.close();

}

if (streamConnection!=null) {

streamConnection.close();

}

if (fileOut!=null){

fileOut.close();

}

if (fileSocket!=null) {

fileSocket.close();

}

}

}

/*

* @author alin ciupeiu

* Source code for the file: FileAccess.java

*/

package fpclient.io;

import java.io.IOException;

import java.io.InputStream;

import javax.microedition.io.Connector;

import javax.microedition.io.InputConnection;

public class FileAccess {

private String filename;

private String url;

private InputConnection fileConnection;

private InputStream fis;

public FileAccess(String filename) throws IOException

{

this.filename=filename;

//url = "file:///root1/"+filename;

url = "file:///E:/Apps/"+filename;

fileConnection = (InputConnection)Connector.open(url);

fis = fileConnection.openInputStream();

}

public void sendFile(NetworkAccess networkAccess) throws IOException {

int bsize = 1024;

byte[] bdata = new byte[bsize];

int n=-1;

// read 1kb from file

while ((n = fis.read(bdata,0,bsize))!=-1) {

networkAccess.sendFile(bdata, n);

}

}

public void close() throws IOException{

if (fis!=null)

fis.close();

if (fileConnection!=null)

fileConnection.close();

}

}

/**

*

* @author alin ciupeiu

* Source code for the file: Client.java

*/

package fpclient.logic;

import fpclient.util.ClientStatus;

import fpclient.util.LoginInfo;

import fpclient.util.FingerPrint;

import fpclient.*;

import fpclient.io.NetworkAccess;

import fpclient.ui.DisplayManager;

import fpclient.logic.operations.Connect;

import fpclient.logic.operations.Logout;

import fpclient.logic.operations.Disconnect;

import fpclient.io.bluetooth.BlueToothAccess;

import fpclient.logic.operations.Identification;

import fpclient.logic.operations.LoadFingerprint;

import fpclient.logic.operations.ClientOperation;

import fpclient.logic.operations.AddIdcardRecord;

import fpclient.logic.operations.Verification;

import fpclient.logic.operations.AddPasswordRecord;

import fpclient.logic.operations.Login;

import fpclient.logic.operations.AddFingerPrintRecord;

import fpclient.ui.OptionScreen;

import fpclient.ui.AuthScreen;

import fpclient.ui.AddRecordOptionScreen;

import fpclient.ui.AnswerScreen;

import fpclient.ui.AddFingerPrintScreen;

import fpclient.ui.AddPassportScreen;

import fpclient.ui.IdentifScreen;

import fpclient.ui.ConnectScreen;

import fpclient.ui.WaitScreen;

import fpclient.ui.VerifScreen;

import fpclient.ui.ConnectionFailureScreen;

import fpclient.ui.AddIdcardScreen;

import java.io.IOException;

import javax.microedition.lcdui.Alert;

import javax.microedition.lcdui.Command;

import javax.microedition.lcdui.CommandListener;

import javax.microedition.lcdui.Display;

import javax.microedition.lcdui.Displayable;

import javax.microedition.lcdui.Form;

import javax.microedition.midlet.MIDlet;

import javax.microedition.midlet.MIDletStateChangeException;

public class Client extends MIDlet implements CommandListener

{

private OptionScreen optionScreen;

private ConnectionFailureScreen notConnected;

private ConnectScreen connectScreen;

private WaitScreen connectingScreen;

private AuthScreen authScreen;

private IdentifScreen identifScreen;

private AnswerScreen answerScreen;

private VerifScreen verifScreen;

private AddFingerPrintScreen addFingerprintScreen;

private AddRecordOptionScreen addOptionScreen;

private AddIdcardScreen addIdScreen;

private AddPassportScreen addPassScreen;

private Alert alertWrong;

private LoginInfo loginInfo;

private NetworkAccess networkAccess;

private ClientOperation operation;

private ClientStatus clientStatus;

private BlueToothAccess btAccess;

public Client()

{

clientStatus=new ClientStatus("idle");

optionScreen=new OptionScreen("Select operation",this);

connectScreen=new ConnectScreen("Connect to server",this);

notConnected=new ConnectionFailureScreen("Connection error",this);

connectingScreen=new WaitScreen("Connecting to server…");

authScreen=new AuthScreen("Authentication Required",this);

identifScreen = new IdentifScreen("Identification",this);

answerScreen = new AnswerScreen("Server answer",this);

verifScreen=new VerifScreen("Verification",this);

addFingerprintScreen = new AddFingerPrintScreen("Add fingerprint",this);

addOptionScreen = new AddRecordOptionScreen("Select record type",this);

addIdScreen = new AddIdcardScreen("Add new id-card record",this);

addPassScreen=new AddPassportScreen("Add new passport record",this);

DisplayManager.setDisplay(Display.getDisplay(this));

alertWrong= new Alert("Response from server:");

alertWrong.setString("");

alertWrong.setTimeout(2000);

loginInfo=new LoginInfo();

btAccess=new BlueToothAccess();

}

protected void destroyApp(boolean arg0) throws MIDletStateChangeException

{

try

{

if (loginInfo!=null && !loginInfo.getDisconnectedFlag())

{

if (loginInfo.getLoginFlag())

{

loginInfo.setLoginFlag(false);

if (networkAccess!=null)

networkAccess.sendMessage("LOGOUT");

}

if (networkAccess!=null)

networkAccess.sendMessage("end");

}

}

catch (Exception e)

{

e.printStackTrace();

}

try {

if (networkAccess!=null)

networkAccess.close();

if (btAccess!=null)

btAccess.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}

protected void pauseApp() {}

protected void startApp() throws MIDletStateChangeException

{

DisplayManager.setCurrentScreen(connectScreen);

}

public void commandAction(Command arg0, Displayable arg1)

{

String label = arg0.getLabel();

Form form=(Form) arg1;

if("EXIT".equals(label))

{

try {

destroyApp(false);

} catch (MIDletStateChangeException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

notifyDestroyed();

}

else

if ("CLEAR".equals(label)){

answerScreen.setAnswerText("");

}

else

if("OK".equals(label))

{

if (form.getTitle().equals("Connect to server"))

{

DisplayManager.setCurrentScreen(connectingScreen);

operation=new Connect(this,connectScreen,authScreen,notConnected,loginInfo);

operation.performOperation();

}

else

if(form.getTitle().equals("Authentication Required")){

loginInfo.setUserName(authScreen.getUsername());

loginInfo.setPassword(authScreen.getPassword());

operation = new Login(networkAccess,loginInfo,optionScreen,alertWrong,notConnected,connectScreen,clientStatus);

operation.performOperation();

}

else

if(form.getTitle().equals("Select record type"))

{

if (addOptionScreen.getSelectedIndex()==0)

DisplayManager.setCurrentScreen(addIdScreen);

else

DisplayManager.setCurrentScreen(addPassScreen);

}

else

{

if (!clientStatus.getCurrentStatus().equals("idle"))

{

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Other operation is currently in progress!");

DisplayManager.setCurrentScreen(answerScreen);

}

else

if (FingerPrint.getFingerPrint()==null){

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Please load the fingerprint first!");

DisplayManager.setCurrentScreen(answerScreen);

}

else

if(form.getTitle().equals("Add new id-card record"))

{

clientStatus.changeStatus("Add new id-card record");

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Adding new record…Please wait!");

DisplayManager.setCurrentScreen(answerScreen);

operation=new AddIdcardRecord(networkAccess,addIdScreen,connectScreen,answerScreen,clientStatus);

operation.performOperation();

}

else

if(form.getTitle().equals("Add new passport record"))

{

clientStatus.changeStatus("Add new passport record");

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Adding new record…Please wait!");

DisplayManager.setCurrentScreen(answerScreen);

operation=new AddPasswordRecord(networkAccess,addPassScreen,connectScreen,answerScreen,clientStatus);

operation.performOperation();

}

else

if (form.getTitle().equals("Identification"))

{

clientStatus.changeStatus("Identification");

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Searching…Please wait!");

DisplayManager.setCurrentScreen(answerScreen);

operation=new Identification(networkAccess,identifScreen,connectScreen,answerScreen,clientStatus);

operation.performOperation();

}

else

if(form.getTitle().equals("Add fingerprint"))

{

clientStatus.changeStatus("Add fingerprint");

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Adding the fingerprint…please wait!");

DisplayManager.setCurrentScreen(answerScreen);

operation=new AddFingerPrintRecord(networkAccess,addFingerprintScreen,connectScreen,answerScreen,clientStatus);

operation.performOperation();

}

else

if (form.getTitle().equals("Verification"))

{

clientStatus.changeStatus("Verification");

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Verification in progress…please wait!");

DisplayManager.setCurrentScreen(answerScreen);

operation=new Verification(networkAccess,verifScreen,connectScreen,answerScreen,clientStatus);

operation.performOperation();

}

}

}

else

if("IDENTIF".equals(label))

DisplayManager.setCurrentScreen(identifScreen);

else

if("ADD_RECORD".equals(label))

DisplayManager.setCurrentScreen(addOptionScreen);

else

if ("CANCEL".equals(label))

DisplayManager.setCurrentScreen(optionScreen);

else

if ("BACK".equals(label))

{

if (form.getTitle().equals("Server answer") || (form.getTitle().equals("Select record type")) || (form.getTitle().equals("Add fingerprint")) || (form.getTitle().equals("Verification")))

DisplayManager.setCurrentScreen(optionScreen);

else

if (form.getTitle().equals("Add new id-card record"))

DisplayManager.setCurrentScreen(addOptionScreen);

else

if (form.getTitle().equals("Add new passport record"))

DisplayManager.setCurrentScreen(addOptionScreen);

else

if (form.getTitle().equals("Connection error"))

DisplayManager.setCurrentScreen(connectScreen);

}

else

if ("VIEWRESULTS".equals(label)){

DisplayManager.setCurrentScreen(answerScreen);

}

else

if ("ADD_FINGERPRINT".equals(label))

DisplayManager.setCurrentScreen(addFingerprintScreen);

else

if ("VERIF".equals(label))

DisplayManager.setCurrentScreen(verifScreen);

else

if ("LOGOUT".equals(label))

{

if (!clientStatus.getCurrentStatus().equals("idle"))

{

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Other operation is currently in progress!");

DisplayManager.setCurrentScreen(answerScreen);

}

else

{

DisplayManager.setCurrentScreen(authScreen);

operation = new Logout(networkAccess,loginInfo,connectScreen,clientStatus);

operation.performOperation();

}

}

else

if ("DISCONNECT".equals(label))

{

DisplayManager.setCurrentScreen(connectScreen);

operation=new Disconnect(networkAccess,loginInfo,connectScreen);

operation.performOperation();

}

else

if (!clientStatus.getCurrentStatus().equals("idle"))

{

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Other operation is currently in progress!");

DisplayManager.setCurrentScreen(answerScreen);

}

else

if ("LOAD_FINGERPRINT".equals(label))

{

clientStatus.changeStatus("Load_Fingerprint");

answerScreen.setAnswerText(answerScreen.getAnswerText()+"\n"+"Loading fingerprint… Please wait!");

DisplayManager.setCurrentScreen(answerScreen);

operation=new LoadFingerprint(btAccess,answerScreen,clientStatus);

operation.performOperation();

}

}

public void setNetworkAccess(NetworkAccess networkAccess){

this.networkAccess=networkAccess;

}

}

Similar Posts