DIY Project: Create a Tracking and Tracing App Part 2

The tracing of contacts through mobile apps became the Number One hot topic in the last few days, governements and institutes of the EU countries are still working on technical solutions to trace transmissions of SARS-CoV-2 (though a bit late for the first wave that has hit most countries worldwide). At the same time there is an intense debate about these apps in terms of data usage, privacy, etc. The apps wont stop the spread or protect the person using the app but they should help to keep the situation under control in the times to come, maybe as a permanent tool to stay for a long period. Even more important not to build a tracking tool following examples of more authoritian states, but to have a solution that protect privacy.

In this blog series, looking at the technical aspects, we still touch both tracing and tracking for the matter of the discussion. In the last post we only touched the Bluetooth basics, now get into discovering nearby devices.

Android to discover Bluetooth devices

About device discovery

  • Discovery of Bluetooth devices is the step before pairing and coummunicating with another device. We can scan for nearby devices without the other devices (its owner) noticing it.
  • But for classic Bluetooth, the device need to be set to discoverable by its user, usually only for a limited period. It is consuming additional energy and would drain the battery faster if left on permanently (putting aside security concerns, see references).
  • BLE works like a beacon permanently being discoverable, certain location type application work like this, eg. to help navigate in buildings equipped with beacons.
  • The 3 key device attributes when discovering devices:
    Name: Not unique, just a label, can be set/changed by the user.
    MAC: The unique identifier (see previous post)
    Signal strength in dBm (more about this later)

Discover classic Bluetooth devices

We need to register a broadcast receiver and listen to the intents for discovery start and end. The discovery need to be triggered, it will run for about 12 seconds.

Register BC Receiver

private void initBCReceiver(){
	final BroadcastReceiver mReceiver = new BroadcastReceiver()
	{
		@Override
		public void onReceive(Context context, Intent intent){
			String action = intent.getAction();
			if (BluetoothDevice.ACTION_FOUND.equals(action))
			{
				BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE); // dBm
				System.out.println("Found: " + device.getName() + "," + device.getAddress() + "," +  rssi);
			} else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
				System.out.println("ACTION_DISCOVERY_STARTED");
			} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
				System.out.println("ACTION_DISCOVERY_FINISHED");
			}
		}
	};

	IntentFilter filter = new IntentFilter();
	filter.addAction(BluetoothDevice.ACTION_FOUND);
	filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
	filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
	filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

	registerReceiver(mReceiver, filter);
}

Now trigger the discovery

bAdapter.startDiscovery();
Discover Classic BT devices

Discover BLE devices

The BLe devices (beacons) constantly send their signal, we can pick it up in an async thread. The Android BT library supports this with less than 15 lines of code to capture the devices. Implement the callback and start/stop the scanning.

private ScanCallback leScanCallback = new ScanCallback() {
	@Override
	public void onScanResult(int callbackType, ScanResult result) {
		System.out.println(result.getDevice().getAddress() + "-" + result.getDevice().getName() + " rssi: " + result.getRssi() + "\n");
	}
};

public void startScanning(View view) {
	System.out.println("start scanning");
	AsyncTask.execute(new Runnable() {
		@Override
		public void run() {
			btScanner.startScan(leScanCallback);
		}
	});
}

public void stopScanning(View view) {
	System.out.println("stopping scanning");
	AsyncTask.execute(new Runnable() {
		@Override
		public void run() {
			btScanner.stopScan(leScanCallback);
		}
	});
}
Discover BLE devices

Interesting observations:
– The MS Designer Mouse is operating in both classic and BLE mode.
– The signal strength of devices can change without being physically being moved.

Conclusion

  • The Bluetooth classic mode is not feasible for the tracing requirement. It would drain batteries quickly and we cant disnguish between phones and other devices using solely the MAC (though we could identify manufacturers).
  • We need to consider the BLE peripheral model for our tracing app. Remember, we need to capture the unique key from another nearby user of the app, we cant achieve this without basic 2 way communication between the two apps.

Fun Facts

Stay safe and tuned..

References

Image by Free-Photos from Pixabay.

DIY Project: Create a Tracking App Part 1

The discussion about mobile phone location tracking of people and tracing back to potential transmissions is one of the hot topics at moment. In Germany we could expect an app officially being launched towards end of April. I attempt to go through the technical considerations by myself. A hands-on coding excursion with Android to use Bluetooth to scan nearby devices and exchange data with them.

The most basic requirements for a tracking app to be successful:

  • A person need to posses and carry a switched-on mobile (smart) phone.
  • The phone must have GPS and Bluetooth feature and both being enabled.
  • The location need to be recorded as fine-grain as possible. Use of GPS is mandatory, the celldata is way too coarse (see previous post). Though we might consider to skip location completely and rely on the paring of fingerprints solely, depending on the approach.
  • Approach 1: We record the location and time of a device (aka person) and transmit the data to a server immediately and try to match data with other devices on the server. Hard to implement in a GDPR compliant way and users most likely wont buy in.
  • Approach 2: We record the location and time on the device and any digital fingerprint of devices nearby. This anonymous pairings we transmit to the server. Once one device is flagged as infected, the server can flag any other device “paired” previously and push (or pull) a notification to the impacted devices. This way most data remains on the device. A more GDPR compliant way of solving this. Some details need to be worked out though in regards of matching and informing the respective user.
  • Approah 3: Even better if we could rely solely on the fingerprint of nearby devices and the timestamp.
  • The more user we have in the system, the bigger the impact and the chance to trace and inform and potentially stop spreading further.
  • We must have a mean to report an infection and inform affected other users (and still stay within the boundaries of GDPR).

Before walking into the Bluetooth space, some facts:

  • The not-for-profit organisation Bluetooth Special Interest Group (SIG) is responsible for thedevelopment of Bluetooth standards since 1998. (Wikipedia)
  • There is a regular update to the Bluetooth standard, by January this year SIG released version 5.2. It takes time for the hardware manufacturers to adopt the newer standards.
  • We need to distinguish between Bluetooth Classic and Bluetooth Low Energy (BLE). BLE was introduced with version 4 and supported by Android 4.3.
  • Bluetooth Classic is designed for continous short distance two-way data transfer at a speed of up to 5 Mbps (2.1 Mbps with Bluetooth 4). BLE was made to work with other devices at a lower speed and greater distance.
  • Android 8.0 onwards support Bluetooth 5 which is a significant milestone for Bluetooth technology in terms of range, speed and power consumption.
  • It is not possible to programmatically check the supported Bluetooth version in Android, though you can check if BLE is available on the phone.
  • The MAC address of the Bluetooth adapter is fixed and can’t be changed (except for rooted phones). This way it becomes the digital fingerprint.

Are we running out of MAC addresses ?

MAC addresses (used by ethernet, wifi and bluetooth adapters), as per IEEE 802 definition, have 48 bits (6×8 bytes).
Sample AC:07:5F:F8:2F:44
This would result in some 281 trillion (2^48) possible combinations, but the first 3 bytes are reserved to identify the hardware manufacturer. For above sample AC:07:5F it is Huawei. The remaining 3 bytes are used as unique identifier, resulting in only 16 million (2^24) unique devices. Quite likely this number would be used up more or less quickly by a big manufacturer. In reality we also could have 16 million unique manufacturer ID’s, Huawei owns about 600 of these, giving a total of currently 10 billion devices. We need to consider this numbers when we talk about unique fingerprints (MAC), though it is unlikely at a country level to have duplicates. In Germany we have ~83 million citizens and about 142 million mobile phones from different manufacturers, small chance that two persons (actually using the tracking app) will have the same MAC address.
You can check/download the identifiers here.

Lets get started with some coding..

Basic: Android to list paired devices

Before we jump into the more complex discovering, pairing and communication between devices (using threads,) we start with the basics. Lets enumerate the paired devices.

Required Permission

At minimum access to coarse location (since Android 6) is needed since Bluetooth can be used to derive the users location. I skip the code to request the permission, only location access being a critical permission. (complete code will be pusblished at the end).

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Check and Activate Bluetooth Adapter

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "bt.MainActivity";
    private BluetoothAdapter bAdapter = BluetoothAdapter.getDefaultAdapter();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        checkAndRequestPermissions();

        if(bAdapter==null){
            Log.i(TAG,"Bluetooth not supported.");
        } else {
            Log.i(TAG,"Bluetooth supported.");
			
	        if(bAdapter.isEnabled()){
				Log.i(TAG,"Bluetooth enabled.");
				if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))
					Log.i(TAG, "BLE not supported.");
				else
					Log.i(TAG, "BLE supported.");
			} else {
				Log.i(TAG,"Bluetooth not enabled.");
				startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE),1);
			}
        }
    }
..

List existing pairings

Quite simple to iterate through the existing pairings and list their name and MAC Address

private void showPairedDevices(){
	Set<BluetoothDevice> pairedDevices = bAdapter.getBondedDevices();
	if (pairedDevices.size() > 0) {
		for (BluetoothDevice device : pairedDevices) {
			String deviceName = device.getName();
			String deviceMAC = device.getAddress();
			Log.i(TAG,"Device: " + deviceName + "," + deviceMAC);
		}
	}
}
I/bt.MainActivity: Device: HUAWEI P20,AC:07:5F:XX:XX:XX
I/bt.MainActivity: Device: moto x4,0C:CB:85:XX:XX:XX

In the next post we will discover nearby Bluetooth devices and setting up a communication channel between two devices.

Stay tuned for more tracking..

References

Image by Brian Merrill from Pixabay

Asymetric Encryption 5min walk-through

2018-09-14 13_05_12-343286-PAMSX1-119.jpg - Windows Photo Viewer

Cryptography is one of the key-elements in the Blockchain world. We were already looking into the one-way encryption with hash function in the previous post. Encryption of data to be decrypted again, is equally essential and covered by symmetric and asymmetric encryption. I would not attempt to explain the mathematical  and rather complex background of cryptography, but show with some sourcecode how easy it is to integrate such powerful tools in any solution.

Essential for the asymmetric encryption is the creation of a pair of keys, a public and a private key. The public key can be shared with anyone, it is “public”, it can be used by anyone to create an encrypted message (or data) and send it to a receiver which is the only one holding the private key. This private key is the only way to decrypt the message. This provides a very secure communication mechanism. On the contrary there is Symmetric encryption which uses the same key for encryption and decryption.

Anyone who want to deep-dive into cryptography and algorithm I can refer to books and courses. Otherwise we do an express walk-through here in Java, with the shortest possible sample for key generation (5 lines of code) and encryption/decryption (8 lines of code) of text.

Using the Java core packages java.security it is boiling down to a few methods to create a key pair. You have to choose the algorithm (RSA,DSA,DiffieHellman) and initialize with the keysize. It is obviously a crucial design decision where and how to create the keys and distribute it to the right party.

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
...

private KeyPairGenerator keyGen;
private KeyPair pair;
static PrivateKey privateKey;
static PublicKey publicKey;
...

keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512);
pair = keyGen.generateKeyPair();
privateKey = pair.getPrivate();
publicKey = pair.getPublic();

To encode and decode a text is similar simple. Take note of the binary format, we have to use Base64 to convert to String and back to binary.

	private String encryptText(String messageText, Key key) {

		Base64.Encoder encoder = Base64.getEncoder();
		try {
			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, key);
			return encoder.encodeToString(cipher.doFinal(messageText.getBytes("UTF-8")));

		} catch (Exception e) {
			e.printStackTrace();
			return "nil";
		}
	}

	private String decryptText(String cipherText, Key key) {

		Base64.Decoder decoder = Base64.getDecoder();
		try {
			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, key);
			return new String(cipher.doFinal(decoder.decode(cipherText)), "UTF-8");

		} catch (Exception e) {
			System.out.println(">>>>>> " + e.getMessage());
			return "nil";
		}
	}

Lets run the sample application, create keys, encode and decode a text.
Take note, attempting to decode with the same key fails and the encoding/decoding works with both keys, you can encode with the public or private key and decode with the respective counterpart. Similar to hash we can see the change of 1 char (“My to MY”) changes the cipher completely.

---- KEY GENERATION ----
Algorithm: RSA
Format: PKCS#8
Private Key:
MIIBVQIB(...obfuscated....)Pk/Vp+iTx64pMSQRiXq7UbXX
Public Key:
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALsDbKCfo55sevpoRL/GjxtlDBFdFLGedfaemCWzh7b/K5ybZbdDrjTVhoyionyGVZuClkZnN5aSRdR6nVXeVL8CAwEAAQ==
------------------------
---- ENCRYPT WITH PUBLIC KEY----
Plain Text: My 2018 Cryptography Sample !
Cipher Text: BkwSG5zczP//7N7AgiFdAyxTvJryPeCLye9zRD1dnKExKR5nABGG3kkiogl8ryujJ+MQB1ISh1EUKSDUm6KYuw==
----------------------------------------------------------
Plain Text: MY 2018 Cryptography Sample !
Cipher Text: Zs8LHPlShaNX/ch8LfrWZrguBJT+WMahMyPQcg06+Nk98i5yd2qyEvP3LfA1QxCmPdFQEPoS7nQxvnPVxE7s0g==
----------------------------------------------------------
---- DECRYPT WITH PRIVATE KEY----
Cipher Text: Zs8LHPlShaNX/ch8LfrWZrguBJT+WMahMyPQcg06+Nk98i5yd2qyEvP3LfA1QxCmPdFQEPoS7nQxvnPVxE7s0g==
Plain Text: MY 2018 Cryptography Sample !
------------------------
---- DECRYPT WITH PUBLIC KEY----
>>>>>> Decryption error
Cipher Text: Zs8LHPlShaNX/ch8LfrWZrguBJT+WMahMyPQcg06+Nk98i5yd2qyEvP3LfA1QxCmPdFQEPoS7nQxvnPVxE7s0g==
Plain Text: nil
----------------------------------------------------------
---- ENCRYPT WITH PRIVATE KEY----
Plain Text: My 2018 Cryptography Sample !
Cipher Text: sjm/MwtAy/MwThhRVKa8lJ0ro1PTHXSK5QfRNLHnYb7X/ezSCLTRPCU7z5TZg7S5ptR2Tvkj4P1J/fk8CNY6xA==
----------------------------------------------------------
---- DECRYPT WITH PUBLIC KEY----
Cipher Text: sjm/MwtAy/MwThhRVKa8lJ0ro1PTHXSK5QfRNLHnYb7X/ezSCLTRPCU7z5TZg7S5ptR2Tvkj4P1J/fk8CNY6xA==
Plain Text: My 2018 Cryptography Sample !

The complete sample sourcecode here on github.
Stay tuned.

Disclaimer: This discussion, datamodel and sourcecode or application is for study purpose solely. It does not reflect or replicate any existing commercial product. It is also not fit for or meant for production.

The Forgotten Sourcecode

I remember the first time I heard the term Public Domain software and Shareware somewhere between the late 1980′ and early 90’s. Towards the end of the Commodore C64 era, where software was almost solely commercial (and not affordable for the average secondary student) creating the vivid software “sharing platform” at the schoolyard as a solid first release of software piracy, I got my hands on my first IBM compatible PC running DOS. Soon after data CD-ROM’s appeared with Shareware, a legal way to use software. Magazines were published with CD-ROM’s attached and I remember regular visits to shareware shops selling nothing but legal CD-ROM’s, years before the internet was available to public. While Public Domain Software was totally free of any license and Shareware was more like a free-to-use model (sometimes under certain conditions or restrictions similar to today’s lite/free versions), it laid the foundation of what we know as Open Source today, in my opinion one of the most important elements of our software landscape. I recommend the title “The Cathedral and The Bazaar” by Eric S. Raymond, the 25 year old book describing the inner parts of open source, a lot of it still applies.

bazaar

The Cathedral and The Bazaar – 1999 Book by Eric S. Raymond

If you are keen to go on a time travel you can download the ISO image of a couple of these shareware CD’s from archive.org and have a hands-on session with 25 year old software, though I doubt you can execute all of them on current hardware and OS.

The640SharewareStudio

Shareware CD anno 1992 (archive.org)

Once the internet was in place platforms emerged where hobbyists could store the software repositories and releases of their software. One of the early ones I remember was Sourceforge which was launched in 1999, it still exists today (after changing ownership 3 times last few years). Few others were coming and going in the same space (BerliOS, Launchpad, java.net, Javaforge, Tigris.org, ..). Though not so dominating today anymore, due to number of alternatives, one of the most prominent is Github, Sourceforge still hosts a huge number of software, some of them quite prominent, it also was the starting platform of some rather known solutions (Pentaho, Firebird, Wireshark, Nagios, Notepad++,..). Over the years I created accounts for some of the platforms, and even forgot some of them, now I solely use Github. Recently I came across a simple tool that I created in 2008 to experiment with repositories in Java and noticed the tool is still there and it was downloaded over 2.300 times in the last nine years. Not that the tool does anything more magic than creating UUID’s and copy them to clipboard. It is just amazing to see, as long the platform does not disappear, the code lives on, no expiry attached.

2017-11-20 14_56_57-Download Statistics_ All Files

Do you have some old forgotten software treasures too?

2017-11-20 15_05_52-UUID Generator download _ SourceForge.net

Build a RESTful Webservice in less than 5 minutes

There are quite some tutorials around about building and exposing a RESTful Webservice, but some of them are outdated and make you wade through complex dependencies and tinkering with deployment descriptors and web.xml files. But using RESTeasy, the JBoss implementation that is fully compliant with the JAX-RS 2.0 JCP specification, and Eclipse you can build a simple webservice (“hello world”) with less than 10 lines of sourceode with annotations and no web.xml used in a few minutes and run it on Wildfly.

Lets build a webservice that creates random numbers.

Continue reading

Snippet: Get the timezone for a geo location with Groovy and Google

I have a list (table) of airport locations, but missing the timezone information (as used in Java, eg. ‘America/Los_Angeles’ which is the timezone Id in java.util.Timezone). We could use the geonames dump to retrieve the timezone from the cityname, but the cityname for some airports might not be unique or distinct, so I rather use the geographical location which I have for each airport and use a webservice to get the timzone for a specific location. We can use the geonames webservice (commercial usage allowed, but you should give credit) or the Google Timezone API (which is experimental and restricted to 2500 calls a day) .

We use Groovy to retrieve this information, using the browser you get this JSON reply for :
https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510&timestamp=1331161200&sensor=false

JSON

We put this into a Groovy Script to read the timeZoneId:

#!/usr/bin/env groovy
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*

def timezone = new RESTClient('https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510&timestamp=1331161200&sensor=false')
def resp = timezone.get( contentType : JSON)

println resp.data.timeZoneName + " - " + resp.data.timeZoneId

We need the HTTP Builder library.
Please note the httpbuilder library has some dependencise ! Put all into your .groovy/lib folder.

  • commons-beanutils-1.8.3.jar
  • commons-codec-1.6.jar
  • commons-collections-3.2.1.jar
  • commons-lang3-3.1.jar
  • commons-logging-1.1.1.jar
  • fluent-hc-4.2.2.jar
  • http-builder-0.6.jar
  • httpclient-4.2.2.jar
  • httpclient-cache-4.2.2.jar
  • httpcore-4.2.2.jar
  • httpmime-4.2.2.jar
  • json-lib-2.4-jdk15.jar
  • xml-resolver-1.2.jar

Result:

Pacific Standard Time - America/Los_Angeles

Now we can iterate through our locations and complete the data.

Alternative with geonames:

geonames JSON

#!/usr/bin/env groovy
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*

def timezone2 = new RESTClient('http://api.geonames.org/timezoneJSON?lat=47.01&lng=10.2&username=xxxxx')
def resp2 = timezone2.get( contentType : JSON)
println resp2.data.countryName + " - " + resp2.data.timezoneId

How to get started with Prefuse and Netbeans

I was looking for a java based visualization toolkit for quite a while. Either they are very static (image rendered and delivered without any interaction) or cost too much money or badly documented or plain buggy and incomplete. I found a toolkit called prefuse (link) on sourceforge which is an amazing piece of work done by Jeffrey Heer (link) of Berkeley University Stanford. Thanks for this and to the people in the forum (link) to continue the effort to answer questions.

Though it’s last release if dating 2007.10 it is feature complete and not really need to carry the beta tag, but never mind. The project migrated to flare (link) based on Flash and AS, but unfortunately that is not always the first choice, even more powerful in terms of graphics. But I wonder what would be missing. It is open source, so with community effort things can be implemented or even added.
It is released under BSD and can be used freely for commercial and non-commercial applications.

I am a true Netbean nerd, aka NB user and spent some time to get started with prefuse.

Today I wan to share with you the steps (i did) to get a running with prefuse and Netbeans running Windows.
(Please note, it might not be the perfect or smartest approach. I dont claim its the right way or complete, but I got it to work this way. )
I am sure this is very basic information for the prefuse experts, but other beginners might need to go through the same steps.

1. Donwload the file prefuse-beta-20071021.zip (link).

2. Unzip the file to folder.

3. Check for a properly set JAVA_HOME path, like

E:\Documents and Settings\SAM>echo %JAVA_HOME%
E:\Program Files\Java\jdk1.6.0_10

4. Open the file build.bat with text editor of your choice and change the follwoing line
%JAVA_HOME%\bin\java.exe -Dant.home=…
to
java.exe -Dant.home=…
(I removed the JAVA_HOME because java already is in the system PATH)

5. Open a DOS-Box (Windows, aka run.. CMD) and navigate to the folder with the build.bat file.

6. Execute ‘build.bat all’. You should get something like this:

Build

prefuse and Netbeans: Build the jarfiles

7. Start Netbeans and create a new project (New, Choose project, Java, Java Application). Lets call it PrefuseDemo.

8. Open the project properties (right click on the project name in the project explorer) and select properties. Go to the libraries sectio and add prefuse.jar and demo.jar (required for the sample code). You find these files in the folder ‘build’ created by our build.bat.

9. Now you change the packagename (with the initial created Main.Java if selected) to prefusedemo.

10. In the build folder you also find a src folder with various sample java code. For this tutorial I took GraphView.java.

11. Create a new javaclass in the prefuse package with the name GraphView.

12. Copy the complete sourcecode from GraphView.java into it and replace the basic skeleton.

13. Fix the package name to package prefusedemo;

14. You can delete the Main.java if NB created it for you.

15. Build the project.

16. Right click onGraphView.java and select Run File. Finished ! You should see this:

t200901300014

prefuse and Netbeans: Run the demo


Remarks:
1. The other files (demos that come with the prefuse package) you can create the same way and add them into your demo application.
2. I tried to import the whole prefuse source folder into Netbeans via Import, but it didnt work.

Conclusion:
Now we got started, lets move on to understand the prefuse concept and adapt some of the samples to our own applications or create new ones from the scratch ! Stay tuned for more prefuse !

Tutorial: Starting with Glassfish and JMS (Part 2)

Today we proceed with last weeks JMS tutorial and create a standalone java application that sends a message to a topic.

It puzzles me to have a client application that I need to start “from within”. Lets find out how an application looks like that can run by itself, connect to a JNDI server and sends a message to topic. The key information I took from this discussion (link, Thanks to Foli and TravelEntity) at forums.sun.com.

Using: Netbeans 6.5 and a local Glassfish V2

1. Lets create a standard SE java project. We call it “JMSClient”

tut09010005_new_java_application

JMSClient: New Java SE project

2. Import the necessary libraries

Applicationserver JNDI Lookup
/lib/appserv-rt.jar
/lib/appserv-admin.jar
/lib/javaee.jar
/lib/j2ee.jar

Client Lib
/imq/lib/jms.jar
/imq/lib/imq.jar
/imq/lib/imqutil.jar
/lib/install/applications/jmsra/jmsra.jar

(You find them in your glassfish home directory)

Libraries

JMSClient: Libraries

3. The complete source


package jmsclient;

import java.util.Hashtable;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Main {

    public static void main(String[] args) {

        Context jndiContext = null;
        ConnectionFactory connectionFactory = null;
        Connection connection = null;
        Session session = null;
        // ---- Same sample with a queue ----
        // Queue queue = null;
        Topic topic = null;
        MessageProducer messageProducer = null;
        MapMessage message = null;

        Hashtable properties = new Hashtable(2);
        properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.appserv.naming.S1ASCtxFactory");
        properties.put(Context.PROVIDER_URL, "iiop://localhost:3700");

        try {
            jndiContext = new InitialContext(properties);
            connectionFactory = (ConnectionFactory)jndiContext.lookup("jms/ConnectionFactory");
            // ---- Same sample with a queue ----
            //queue = (Queue)jndiContext.lookup("jms/Queue");
            topic = (Topic)jndiContext.lookup("jms/Topic");

            connection = connectionFactory.createConnection();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // ---- Same sample with a queue ----
            //messageProducer = session.createProducer(queue);
            messageProducer = session.createProducer(topic);
            message = session.createMapMessage();

            // ---- Preparing Mapped Message ----
            message.setString("lastname", "Myer");
            message.setString("firstname", "Fred");
            message.setString("id", "0200");

            messageProducer.send(message);

            connection.close();

        } catch (NamingException e) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
        }
        catch (JMSException e) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
        }
        finally {
            System.out.println("ENDED.");
            System.exit(0);
        }
    }
}

Remarks:

  • The tutorial is looking for a local server. Change (Context.PROVIDER_URL, “iiop://localhost:3700”) to the relevant server and port info.
  • We use a topic (publish/subscribe) in this sample. If you want to use a queue instead, change to the lines which are commented out and remove the topic related lines.

About unique numbers and ID’s

I am sure everyone of us had the requirement to save data in a DB, a hash or whatever. Most of the times we were creating this unique numbers, often used as keys for reference, by ourselves simply counting +1. Sooner or later we realized, oops I used the number already or I need to merge tables and now we have duplicate ID’s and so on and so on. Most DB offer some auto-increment feature or you make use of the row-id as oracle create one (internally for each record). I came across the UUID (wikipedia link), which is a universal unique ID creation method. In Java its damn simple to create one:

import java.util.UUID;
[..]
UUID uID = UUID.randomUUID(  );
[..]

I worked once for a company which used long integer as their ID field. The max value is 2,147,483,647 and recently they hit the limit facing the problem of hardcoded long integer all over the sourcecode and DB. I guess the UUID would help (using it from the start).
Remark: Putting in a lot of brain power they fixed the problem without refactoring about 1 mill lines of code.

With the help of 122 significant bits in a version 4 UUID you can create 2^122 (5,316,911,983,139,663,491,615,228,241,121,378,304) numbers ! Enough for the lifetime of this universe !