ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Brewing Java at the Point of Sale
Pages: 1, 2

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.