📜 ⬆️ ⬇️

Access to the COM port from a Java applet

Hello to all. I want to share the solution of one task that stood before me some time ago. It consisted in the fact that it was necessary to allow the web service to access and exchange information with some device (in my case, a card reader) via the COM port on the user's computer. For this, it was decided to use a Java applet, and in the implementation process there were several difficulties, the solution of which I want to describe in the article. I note that on the Internet I did not manage to find a single guideline “from beginning to end” on how to solve my problem, so I hope someone my article can save a few hours of time.



Formulation of the problem


')
You need to write a Java applet that is loaded by the browser from some site that can read and write information to the com port. At the same time, the main requirement is its ease of use for the user, the absence of complicated settings and, if possible, the installation of any additional libraries or programs into the user's system.

User computer requirements:
1. Microsoft Windows XP, Vista, Seven
2. Any modern browser that supports Java applets, the main focus on IE, Firefox
3. Installed JRE1.6.

Overview of available methods for accessing the COM port from Java applets



As you know, the standard JRE does not include any class or method that allows access to the COM port. I have found two of the most popular external libraries: javax.comm and RXTX . After looking at the information about them, I decided to use the RXTX, because javax.comm no longer develops, and besides, RXTX has a wider range of supported operating systems, which may be useful to me in the future.

Both libraries access the COM port through the use of native libraries. For RXTX, this is the rxtxSerial.dll library.

In terms of functions for working with a COM port, both libraries have an identical set of classes.

Test applet for working with a COM port



I will give the code of the applet, which we will “distribute”. This applet, naturally not the one that I used in my project, I made it specifically for this article. So:

package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .


This code simply lists all the COM ports found in the system (and this operation is performed each time the applet is redrawn).

Add RXTX library



Based on the formulation of the problem, it is necessary to make our applet as simple as possible for the user. And there is nothing simpler than a single jar file, which includes our applet and the RXTX library. In order to integrate the library into the jar, first of all, download its source code .

In the downloaded archive from the src folder, take all the .java files and add them to our project. If you, like me, are working with NetBeans, then simply create a gnu / io directory structure in the src-folder of the project, where you put the above files.

After compilation in one applet, our code and the RXTX library will be merged immediately.

Adding the native rxtxSerial.dll library



As noted above, RXTX uses the native rxtxSerial.dll library to access the COM port under Windows. This library is loaded by the RXTX classes via the System.loadLibrary () method.
Therefore, for our applet to work, the rxtxSerial.dll library must be located on the user's computer, and in one of the directories, from where the RXTX will be able to download, i.e. in directories written in java.library.path. One such directory is the bin directory in the JRE installation folder.

The most obvious method is to pre-install the rxtxSerial.dll library into the specified directory, but this requires additional actions from the user (not always qualified), so another solution was applied.

Any file, including the dll-library can be included in the jar-file as a resource. To do this in NetBeans, simply create the resources folder in the directory where your applet’s .java file is located and put rxtxSerial.dll there. But how to connect it now? The method described here comes to the rescue.

Taking into account the described method, the source code of our applet becomes:

package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

static {
try {
System. out .println( "CardReader {}" );
/* Get DLL from JAR file */
URL res = CardReader. class .getResource( "resources/rxtxSerial.dll" );
InputStream is = res.openStream();

/* Define the destination file */
File dll = File.createTempFile( "rxtxSerial" , ".dll" );

/* Open the destination file */
FileOutputStream fos = new FileOutputStream(dll);

/* Copy the DLL fro the JAR to the filesystem */
byte [] array = new byte [1024];
for ( int i= is .read(array);
i!=-1;
i= is .read(array)
) {
fos.write(array,0,i);
}

/* Close all streams */
fos.close();
is .close();

/* Load the DLL from the filesystem */
System.load(dll.getAbsolutePath());
System. out .println( "CardReader loaded" );
}
catch (Throwable e)
{
e.printStackTrace();
}
}

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

static {
try {
System. out .println( "CardReader {}" );
/* Get DLL from JAR file */
URL res = CardReader. class .getResource( "resources/rxtxSerial.dll" );
InputStream is = res.openStream();

/* Define the destination file */
File dll = File.createTempFile( "rxtxSerial" , ".dll" );

/* Open the destination file */
FileOutputStream fos = new FileOutputStream(dll);

/* Copy the DLL fro the JAR to the filesystem */
byte [] array = new byte [1024];
for ( int i= is .read(array);
i!=-1;
i= is .read(array)
) {
fos.write(array,0,i);
}

/* Close all streams */
fos.close();
is .close();

/* Load the DLL from the filesystem */
System.load(dll.getAbsolutePath());
System. out .println( "CardReader loaded" );
}
catch (Throwable e)
{
e.printStackTrace();
}
}

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

static {
try {
System. out .println( "CardReader {}" );
/* Get DLL from JAR file */
URL res = CardReader. class .getResource( "resources/rxtxSerial.dll" );
InputStream is = res.openStream();

/* Define the destination file */
File dll = File.createTempFile( "rxtxSerial" , ".dll" );

/* Open the destination file */
FileOutputStream fos = new FileOutputStream(dll);

/* Copy the DLL fro the JAR to the filesystem */
byte [] array = new byte [1024];
for ( int i= is .read(array);
i!=-1;
i= is .read(array)
) {
fos.write(array,0,i);
}

/* Close all streams */
fos.close();
is .close();

/* Load the DLL from the filesystem */
System.load(dll.getAbsolutePath());
System. out .println( "CardReader loaded" );
}
catch (Throwable e)
{
e.printStackTrace();
}
}

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .



But that's not all. The RXTX library is still trying to load rxtxSerial.dll using System.loadLibrary () , which of course fails. To solve this problem, it would be possible to save the dll in one of the java.library.path directories, but I went a simpler way: I commented out the library loading line in the RXTX source codes (it is still loaded with the CardReader class).

Applet signing



Since our applet is trying to perform file operations on the user's computer, it needs a digital signature. Instructions on how to do this very much on the Internet, for example, you can do as written here .

Total



The applet distributed by us had the opportunity to work with the COM port, and at the same time everything you need is contained in a single jar file. No libraries are required on the user's computer, i.e. the user simply needs to go to the page with the applet (and in our case, confirm in the appeared window the permission to launch the applet).

PS Not enough karma to transfer the article to the appropriate blog.

Source: https://habr.com/ru/post/71072/


All Articles