ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Brewing Java at the Point of Sale

by Quentin Olson
09/20/2001

Many of us don't realize it (or think about it), but the point of sale (POS) is a remotely-managed application and it has been for years. Next time you visit a restaurant chain or an enterprise grocer, think about the technology behind the cash register and what must be involved in updating prices and software. In practice, the state of these enterprise systems run the gamut from off-the-shelf standalone registers backed by an army of key entry personnel to highly customized (proprietary) systems using various high-speed technologies to form vast private wide area networks (WANs). Few standards exist, and the implementation of those standards is ad-hoc at a best. One common theme is that all of the software is proprietary and expensive, which puts enterprise functionality out of the reach of smaller operations and single shop owners.

This article examines an open source POS application written in Java and the use of certain Java functionality to reduce complexity, in order to implement a broadly-applicable POS transaction engine. To many Java-literate readers, the Java features described may be old news, but it may be of interest to see how some of the more arcane Java features are used in this non-Web application. Also, since this article describes an open source project for enterprise retailers, it goes into considerable architectural detail regarding POS functionality as it applies to enterprise retail environments.

Why Java?

Java has emerged in recent years as a common platform used by retailers to reduce software complexity and management requirements. Why? Java supplies many of the tools we require to build applications in a smaller footprint -- examine the Java SDK at 50 megabytes, compared to the Windows SDK footprint. Java includes unique functionality not widely available in linked architectures -- dynamic class loading and serialization. As a footnote, it is possible to perform dynamic class loading in C++ under Linux, but it is not widely used and is not regarded as a fundamental language feature as it is in Java.

The resounding argument against the use of Java is its large memory footprint and slow performance. But in practice, this argument is losing its punch; it's no longer possible to buy a new computer that is too slow to use Java and smaller devices are beginning to be well-supported by the Java ME (Micro Edition) platform. To be honest, I can't say that Java is overwhelmingly poised to take the retail world by storm. Many retailers have a large installed base of older hardware that they are not ready to throw away, and if you were to look today, you would not find universal Java support for retail peripherals by the major hardware vendors. The industry is changing, though, and quickly. Most hardware vendors have recognized the advantages in the Java platform.

POS OO Architecture

POS architecture provides a classic exercise in object orientation. First, you have something called an electronic journal, that is basically the memory version of your receipt. The journal contains lines for the various sub-components of a sale, such as an item, a tax record, or a tender (cash, check) record. They all have an amount, a quantity, etc. Are you starting to visualize the abstract interface? You also have devices: receipt printers, customer displays, scanners and scales. Look at these statements, if you still need convincing:

[cw]
receipt().print (ejItem);
receipt().print (ejTax);
[ecw]

and,

[cw]
operatorPrompt().print (ejItem);
operatorPrompt().print (ejTax);
[ecw]

It's quite easy to design an object-oriented POS application, but you could do this in any OO language. Java, however, has some language features that, in a enterprise retail environment, are very attractive. These can generally be categorized in the context of remote support and generalized application-building. But first, let's look at some additional design criteria intended to justify the use of Java's other features.

Event Engine

If you want a POS application that can be applied across retail disciplines (grocery, hard goods, restaurants) and across international borders, what you want to create is an event engine. That is an application that is capable of processing generic events and realizing the results of these events in the context of arbitrary hardware devices. The event concept is pretty easy; many modern development tools revolve around the event model, and Java is no different. What is important about a generalized POS application is that the events need to be user-programmable, and, preferably, not statically linked. You also need a way of stacking them up to create dialogs.

Dynamic Class Loading

Well, we still haven't examined anything that could not be implemented in any OO language, so let's do that now. POS applications makes use of dynamic class loading as part of their central event engine logic. Take a look at the following SQL POS key definition:

[cw]
create table pos_key (  
       key_id integer, 
       key_type integer, 
       key_val integer,
       key_code integer,
       x_loc integer,
       y_loc integer,
       key_class varchar(100));
[ecw]

The Java class that is invoked when the key is pressed (key_class) was dynamically loaded into a PosEvent object when the application initialized (actually when the operator logged on). PosEvent is an abstract class that encapsulates discrete POS business logic. When a key is pressed, the following code is invoked:

posEvent().engage();

The engage() method contains the business logic for the event; posEvent() is the key that was pressed. Events in a POS application are things like pressing the total key or scanning an item. But there are also dialogs, such as a check validation, credit card validation, or simply an operator logon. These are implemented by stacking events and maintaining state through those events.

A Closer Look at Dynamic Class Loading

In its simplest form, dynamic class loading looks something like this:

[cw]
Class class = findSystemClass(className);
PosEvent posEvent = (PosEvent) class.newInstance();
[ecw]

className is the string representation of your class, com.globalretailtech.pos.events.TotalKey, that extends PosEvent. The class loader in this application extends java.lang.ClassLoader (findSystemClass()), and uses the newInstance() method from Class to instantiate an object. You also need to wrap it in exception handlers to catch class not found and class cast exceptions.

Beyond Events, Promotions

Retail computing environments change daily. In the Customer Relationship Management (CRM) world, we call them the three P's: products, pricing, and promotions. It's the same thing in the retail world. New products are added and removed, prices change daily, and new and better (subtler?) promotions are always being invented by crafty sales types. It's this third category that makes dynamic loading very useful in retail environments.

A promotion may be a simple discount (i.e., % off an item), or it may be a more complex operation. Example: if a customer buys three or more bakery products, this may prompt the cashier to upsell the margarine that we double ordered last month. They both work the same; a promotion is applied to one or more items within the sale.

Comment on this articleDo you see Java making a large impact in POS system development?
Post your comments

So what does dynamic loading do for promotions? It would be difficult to capture both of the above logical operations in a single promotion module and then use some parameter to activate them. Well it wouldn't be difficult, but it would be very ugly. This is typically the case in many POS applications in production today. A promotion module captures many of the various common promotions that enterprises like to use. Then the software vendor adds whatever custom promotion types the retailer requests, and they are all managed through heavy parameterization. Some vendors have scripting capabilities but this adds the overhead of the interpreter. In the end, you have a promotion module with a lot of stuff you don't use and too many parameters to manage.

On the other hand, if you load a promotion dynamically, linked to an item or product group, it is very easy to manage and you can pick and choose what promotions you like to use. Furthermore, if a promotion is linked to an item or product group (via the database), you have a consistent mechanism for managing this functionality in the field. A promotion doesn't need to be a promotion, either; it could also be used to collect demographic information related to an item or group of items.

Remote Support, Smaller Deliverables

Related Reading

Java Cookbook: Solutions and Examples for Java DevelopersJava Cookbook: Solutions and Examples for Java Developers
By Ian Darwin
Table of Contents
Index
Sample Chapter
Full Description
Read Online -- Safari

The POS application uses dynamic loading in many places, as previously said. All button/key logic and graphical components are loaded at logon. There are also a number of interfaces used to manage enterprise localization. These include a math interface, because an enterprise may want to add, subtract and round in their own way; a check digit interface for validating credit card numbers; an EAN/UPC (bar code) interface; and, as mentioned before, promotion and item modifier interfaces. I view interfaces as another way of saying "I don't want to get involved in this argument, just let me know when it's over." All of the implementing classes are either loaded at logon or when the associated class or data record is referenced.

Dynamic loading has no perceivable overhead; a class has to be loaded to be used anyway. A class is not loaded until it's referenced, so if you've been writing Java, you've been using dynamic loading already.

Dynamic loading allows us to architect a very flexible application, but there is also a very good business sense behind it. Since events are invoked through interfaces, the actual class can be changed underneath the application without re-linking. More precisely and more advantageous to retailers is that they can insert new logic into their remote locations in a very granular manner. This means not having to deliver a five-megabyte executable or DLL just to add a simple feature or fix a bug. Instead, they need only deliver a 5k class file. In this application, a 2500-byte Java source file compiles to a 1800-byte class file. Look at some of these file sizes and the granularity achieved using dynamic loading:

1203 CashTender.class
1997 CashTender.java
1206 CheckTender.class
2145 CheckTender.java
2917 ClearKey.class
4300 ClearKey.java
1896 CloseCashDrawer.class
2338 CloseCashDrawer.java
1209 CreditTender.class
2150 CreditTender.java
2196 Discount.class
2867 Discount.java

Every retailer has the requirement to update their store operation several times during the year (and many more, if they frequently change the business logic in the store). Since most of this updating is performed over dial-up lines, the size of updates is a serious consideration. As a result, scheduled software updates are limited to just a few per year (three to four). Of course, there are the unscheduled ones too. But again, we are doing more here than giving the retailer a way to reduce their software update task; we are giving them greater functionality.

Promotions can be delivered on an ad-hoc basis, since the promotion class is loaded when the item is looked up. This architecture and granularity also reduces regression testing requirements.

Internationalization

Another Java language feature is the Locale class found in java.util. This class, in combination with the Number and DecimalFormat classes, makes formatting monetary values in different currencies quite easy. A frequent requirement in a POS application is currency conversion, the ability to take a payment in one currency and give change in another. The following code sample formats a double value in the requested currency format:

[cw]
public static String toMoney (double value, java.util.Locale locale) {

 if (locale == null) locale = application.locale();
 Java.text.DecimalFormat decimalFormat =
    (Java.text.DecimalFormat)
Java.text.NumberFormat.getCurrencyInstance(locale);

 return (decimalFormat.format(value));
}
[ecw]

If the locale is not provided, an application default is used; application.locale() returns a static instance of the locale. The NumberFormat factory returns a format object that is capable of generating the local currency format including the currency symbol (if your character set supports it) and even the local representation of a negative value (a credit).

Further internationalization is enabled through the unicode character set supported in the String class and by maintaining all literal strings in the database. And of course, the database also supports unicode.

Devices

What about POS peripherals? Output devices have been captured in two classes: one that handles spooled devices, those that generally just perform output (the receipt class), and one for those that interact with the user (the prompt class). Neither of these have any special properties enabled by Java, except for the fact that these and the devices they control are loaded dynamically. They simply provide an API for lower level devices. Some of their methods were used in the initial code sample.

Hardware devices that generate solicited and unsolicited input are handled as part of the event engine enabled through the JavaPOS DataEvent and DirectIOEvent classes (JavaPOS is a Java retail-peripheral interface standard). For example, a credit card tender would require an operator to enter the credit card number and expiration date. This dialog manifests itself as a series of POS events. If a card reader is present, it completes the required events for the operator.

The POS application also includes a menu interface designed for use in fixed size, touch screen environments. Panels of menu buttons can be defined and attached to POS events or defined as navigation buttons for moving about within the layered panels. Display-panel pseudo devices provide operator feedback in the form of prompts and scrolling operator receipts, and are updated using the same mechanism as hardware peripherals. These devices can be of arbitrary complexity (that is, they can implement their own dialog logic) and communicate with the application by implementing the PosEvent interface.

Java Mobile Agents

This is my favorite use of dynamic loading. A Java class may be serialized, that is, converted (state and logic) to a serial byte stream. The most common use of this functionality is in the storage of persistent objects in a database or file.

This application makes use of mobile Java agents to facilitate remote management functionality. Take a look at the Agent interface:

[cw]
public interface Agent {

 public void init() throws AgentException;
 public void onArrival() throws AgentException;
 public void migrate (String host, int port) throws AgentException;

}
[ecw]

Agents travel from host to host, or application to application within a host, do their duties, and either exit or travel to another location. They may accumulate data as they travel and return to their origin, or perform a task at each host and exit. It's all in how you program them. Agents provide a foundation for an extremely flexible remote management system. I have developed agents that search other POS nodes in order to retrieve sales information, to update data and to duplicate sales information on other systems. Since no logic resides at the target system, the possibilities are endless.

An agent is supported by a server process running on the target system. The server listens on a well-known IP port, receives the serialized agent, instantiates the agent, then calls the onArrival() method; the rest is up to the agent. If the agent has another host to visit, it calls migrate() itself. To start the whole thing off, a standalone process or user interface loads an agent (dynamically), then calls init() for it. This allows it to do any local initialization before migrating; then, migrate() is called.

The server in the POS application runs as a thread. This allows direct interaction with the application, simplifying much of the synchronization required in data updates. Example: an agent delivers price updates, once initiated within the POS application, and it uses the database connection owned by the POS application (synchronized, of course) to update the item database. Since you don't want to update a price in the middle of a sale, additional synchronization is used to block the update until the end of the sale.

Example: I have a user interface written in JFC with a tree on the left and a configuration panel on the right. The tree holds configurable objects, such as the item file, POS dialogs, and users. I choose an item from the tree, drop it on the configuration panel, and make some changes (i.e., changing the price of the an item, or adding a profile privilege to an operator). Then, through a pull-down menu, I can post the changes I make for delivery. This adds the current updates to a vector. Then I can select an agent and assign a list of hosts to that agent. This particular agent understands that it has a list (vector) of database items to deliver and update. Once I have selected the hosts, I press launch. The agent travels to the first host on the list and calls the update method for each database item, then goes on to the next host.

Security-minded readers are jumping up and down right now, and they are quite right. You will want to add additional security, such as signing your agents and securing the transport layer. You may also be able to assume that in a closed enterprise WAN environment, some level of network security exists.

IBM has developed a much broader agent implementation they call aglets. Information can be found at www.trl.ibm.com/aglets, and the project has recently been released as open source (see www.aglets.org).

Java and Linux in Retail?

If you have gotten this far, you may be wondering how Java and, perhaps, Linux are faring in the retail world. The answer is, quite well. Several large retailers have made the move to Java. Mens Warehouse and Home Depot are both running Java in their stores today. Linux is also doing well. The classic argument against Linux, in particular, is the lack of a user interface. In the context of retail POS applications, the application is the interface. Burlington Coat Factory has already rolled out Linux in all of their locations, both as a desktop and POS application. Go buy a coat using Linux. Here are links to some recent news:

Open POS project

The complete project described in this article is available at sourceforge.net/project/mercator -- join in.

Quentin Olson is an expert Java developer, focused on non-Web and client-side Java application solutions for the retail channel.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.