Linux Today: Linux News On Internet Time.
Search Linux Today
Linux News Sections:  Developer -  High Performance -  Infrastructure -  IT Management -  Security -  Storage -
Linux Today Navigation
LT Home
Contribute
Contribute
Link to Us
Linux Jobs


More on LinuxToday


JavaBoutique: Open Source Shopping Cart [Part 1]

Jul 02, 2000, 13:32 (0 Talkback[s])
(Other stories by Lane Friesen)

by Lane Friesen, JavaBoutique

Directives for Browser-based Memory and Multiple Merchants on One Cart With a Dumb Server and No Cookies

Every browser contains a JAVA virtual machine that remains unchanged no matter where the user jumps in cyberspace. I have developed a way to link data and program elements to the JAVA virtual machine so that they can be accessed from one HTML page to another as a kind of HTML "memory." In another technique, I instantiate GUI elements that break free from the launching page and persist until the browser is closed. Both methods use standard JAVA, and respect security limits. I have combined these two methods to write a shopping cart front end that I am releasing as Open Source.

I watched, recently, as a small web service provider developed commercial sites for small businesses. The biggest expense was a shopping cart - a good one cost hundreds of dollars per site. It placed large amounts of JavaScript on each HTML page. The designer's creativity was restricted. Some months later, I spoke with a Seattle-based company that is preparing to host multiple corporate sites on the same shopping cart. Large Sun computers maintained memory at the server. Thousands of JAVA threads were left open for up to an hour. Design freedom was available, but only at the expensive cost of an superstructure beyond the financial means of smaller corporations.

The Open Source shopping cart solves these problems. It comes in two versions-- one for the small web designer, the other for the large company. We will first examine the small business version.

Any existing web site can be transformed into a commercial site through the addition of two lines of boilerplate code-- the first line loads an applet, the second line defines a JavaScript function called " buy." These two lines launch a frame which persists for as long as is desired, no matter where you browse, and which keeps a running total of purchases, from page to page within a site. If another merchant uses the same cart, then a separate frame is launched. There are no delays when purchases are made, because everything occurs on the client browser. Except for a one-time initial download of the applet and its classes (14K of code), there are also no delays when jumps are made from one commercial page to another. This is because the applet (414 bytes in size) and its memory are simply transferred without a reload. An optional database of price updates is downloaded from the server, cached on the browser, and also carried from page to page. Again, there are no delays, except for the initial download. In the current version, orders are finalized by sending them to a fixed address. Open Source modifications could easily be made that allow the merchant to process his own order.

The purchaser need not finalize his order straight off, since the shopping cart travels with him throughout cyberspace. When he finally does choose to check out his cart, he still has the option of changing his mind; he can later restore the cart and send out another finalization.

Items are sold by triggering a JavaScript event which calls the pre-defined function "buy," giving a web designer total freedom. Suppose that a merchant has already spent several thousand dollars on a web site and wishes to make it commercial. His web site designer can now do this for him, using his existing pages, probably in less than one hour. Since the shopping cart is Open Source, an hour's charge for labor will be the merchant's only cost. This design freedom is possible with a host that is completely "dumb," because memory is maintained on the browser, through links to the JAVA virtual machine. The merchant will not need to change his hosting or use active server pages.

The cart can be run off-line. For instance, large mail order companies presently distribute expensive catalogs by mail. In place of a $5 catalog, and associated mailing costs, these companies could send out 50 cent CD-ROMs, for much lower mailing charges, containing the artwork for their catalogs, converted to web pages and then commercialized through the insertion of the two lines of boilerplate code and appropriate event triggers. CD-ROMs for different areas of the country could contain differing "update.txt" files to allow for regional price variations. Since the CD-ROM would be run on a local computer, large update files could be used and would be loaded almost instantaneously. The customer could browse at his leisure, on a fast local connection, and then finalize his order by going on-line briefly and checking out.

I look forward to seeing commercial sites that are fast and clever, and go beyond the grid-like lists that are currently generated by our present shopping carts.

Persistence: Method 1

Examine the cart at http://209.87.142.42/shopcart/Page1.htm. It uses JDK 1.1, and thus requires Explorer 4 or 5, or versions 4.5 and higher of Netscape. Try pressing Reset when the cart comes up. On Explorer, the cart will even survive a Shift-Reset. You can press Reset fast and repeatedly, and you probably won't crash the cart.

Let's look at how it's done. There are two methods, one that involves applet reloading: JAVA applets are in an active state for as long as the HTML page in which they are loaded is on the browser screen. When a jump is made to another page, then the applets that were loaded on the previous page become inactive.

Unless there is a shortage of memory, they are not unloaded. Whenever the browser returns to an applet's page, then the particular applet for that page is not usually reloaded, but rather it is changed from an inactive state back again to an active state. Variables that were set in a previous active stage are remembered during times of inactivity, and can be accessed when an applet again becomes active.

Now, what happens if the same applet (same name, same codebase) is loaded by two separate pages? An applet is identified only by its name and codebase. Thus, if a page loads an applet with the same name as one that was loaded by a previous page, and if this involves a relative (in contrast to an absolute) call to the same codebase, then the applet for the previous page becomes active again - just as if it had been called by the previous page. A new instance of the applet is not usually loaded. This feature is used by the shopping cart to store information between HTML pages. It works much better than cookies.

An applet, however, contains program code as well as variables. Thus, since it is a program that is being re-activated, persistent processing can be carried out on the persistent memory. A program can thus be written that appears to live on from page to page: all that is necessary is to reload the same code. When the user leaves the applet's page, this exit alters the page's applet from an active to an inactive state, and when the user enters a different page that reloads the previous applet through a relative call. This entry changes the applet back again to an active state which uses its previous memory. The new page, as part of the applet's life cycle, calls the applet's init() and start() methods; apart from that, applet program function picks up at the point where it left off on the previous page. If one desires to keep certain variables, then it is enough to declare them as static, and make sure they are linked to static entities - the garbage collector will then leave them alone.

If an applet with the same name but a different codebase is loaded, then, for security reasons, it is assigned a new address space. The same shopping cart code, even when it is run simultaneously on separate commercial sites from the same browser, can therefore develop and maintain distinct shopping carts for the separate merchants. JAVA security, which we exploit here to our advantage, takes care of all the details!

If an HTML document in a subdirectory of a site wishes to participate in the persistence, then it is sufficient to add the line CODEBASE=../ to the APPLET tag. This technique can be extended throughout a directory and subdirectory structure, so that persistence spreads freely throughout any given site. Alternatively, it is often possible to access the applet absolutely, as in CODEBASE=http://www.myserver/myAppletDirectory as long as the applet and the HTML pages are located on the same server. This absolute call is then treated as relative. The boilerplate code now becomes independent of directories and sub-directories.

Applet download time is of course decreased greatly when all classes are placed into a single uncompressed .zip file. It is my understanding that earlier versions of Explorer 4 can find .zip files confusing; the solution is to place the unzipped classes in the same directory as the .zip file. Most browsers simply ignore these extra files, and they may in fact no longer be necessary.

Functionality

Since Active X, as implemented in Microsoft's Dynamic HTML, is based in the JAVA language, it turns out that it can also generate persistence. The said applet has in fact been successfully ported to an Active X object. The said "boilerplate code," in the previous section may be altered so that it is an <OBJECT> that is loaded, rather than an <APPLET>. With a few minor adjustments, there is the same functionality.

The applet or object that is continually being reloaded does not need to be entirely identical from page to page. In particular, it may have different parameters, as expressed in varying <PARAM> tags under the <APPLET> tag. Clever use of freedom with parameters can enable massive changes in the classes that are instantiated from one page to the next, generating genuine alterations in the code itself. The fact that init() and start() are called when a page is entered, and stop() is called when the page is left, can be used to do some very useful things: the garbage collector is always there to get rid of discarded elements. The program can vary in ways that would never be possible if it were not being continually re-activated. Alternatively, boolean variables can be set or cleared in an abstract class, or in some other non-instantiated region, which also determine ways in which the said applet or Active X object re-incarnates itself.

It is not necessary to load an applet or object into every page of a site in order to gain persistence. It is enough to load the said applet or object into those pages in which access to the accumulated information is necessary. Browser mechanisms and the functionality of JAVA make sure that the information is maintained (for as long as memory permits) until it is needed. The information will persist even through extended access to pages or sites which know nothing about the applet or object. The applet simply sleeps, in an inactive state, until reloaded through a relative call by some HTML page that desires access to its program code or memory.

Of course, if the applet is inactive, and if memory is needed for other JAVA programs, then the virtual machine will eventually overwrite the inactive program. There is room on the web, therefore, for only a limited number of programs that use this technique. Any particular intranet of course would have its own separate limitation.

To protect the functionality of the Open Source shopping cart, I have taken out a patent on the techniques used to develop persistence. As long as developers change the source code of the Open Source shopping cart in such a way that the program remains a shopping cart with an associated database cache, then they have permission to use these patented techniques. This should protect the bandwidth, and I retain rights to any use of these techniques elsewhere.

Persistence of memory throughout other pages or sites is not a security issue because an applet or Active X object is resurrected (or made accessible to other programs) only if it resides at the same codebase, or at some relative offset.

Persistence: Method 2

Let us now look at the second method for developing persistence between HTML pages. Although it uses abstract classes, we will see that this limitation can be bypassed. In nature, we observe objects like robins and crows, but never things such as "birds." Robins and crows are birds, but birds as such do not exist; they are an abstraction. Similarly, abstract classes in JAVA are a tool for dealing with things that are common to various objects (in nature, for example, commonalities would be wings or beaks)-- they are not themselves instantiated. What we are going to do, in general terms, is take an abstract class which is an abstraction of nothing, and inject code into it, just as a virus inserts its DNA into a cell and takes over the machinery for its own purposes. An infected cell turns out copies of the virus; the abstract class, in our case, simply chooses to "live forever." It is all done, as you will see, with completely standard JAVA coding. The principle will then be extended through standard coding, to classes which are not abstract.

If one looks at abstract classes in JAVA, one notices that they are tied very closely to the JAVA virtual machine. If they could be instantiated, then certainly they would persist; programs could then be remembered along with data, even when the applet was inactive. However, abstract classes cannot contain constructors.

Suppose that applet code is composed solely of pointers to static variables defined in some abstract class (sample code is presented further on). Suppose further that static components for a frame (buttons, etc.), as well as the static name of the frame itself, are also defined in the abstract class. Then, suppose that init() or start() in the applet calls a static function in the abstract class which instantiates the static frame and assigns the static components to it. It then sets a flag in the abstract class that tells it not to do this again. One now has a kind of pseudo-constructor for the abstract class. The resulting frame and its components, are tied through the abstract class, to the JAVA virtual machine itself, and they persist from HTML page to HTML page, even when the applet is not being loaded. The applet that originally launched both the frame and the abstract class may move back and forth from an active to an inactive state, as the user browses from one HTML page to another. This makes no difference to the frame itself, for it is no longer dependent upon the applet.

Now, how do we enable events within this "terminate and stay resident" frame so that it will carry out actions when "off site?" It is done in the following manner (sample code follows):

Events must be caught in the frame itself, but all variables and interrupt methods are contained as static variables and static methods in the abstract class. The frame event handlers simply make jumps to these static variables and methods. Through a use of these two separate persistence techniques-- loading a program repeatedly, and forming a pseudo-constructor for an abstract class-- we have now created a program that lives beyond the page in which it was launched. It also remembers data that is collected from page to page for as long as a page accesses the launching applet through a relative call, and carries out event handling within the frame itself, on applet data, when off-site.

The JAVA program has now broken away from the launching page, and it "lives forever." It is interesting to reduce the browser to a partial window, and to place the shopping cart frame on the desktop beside it. Browse from page to page, and watch the frame: it doesn't flicker, and the buttons continue to work. JAVA in the frame is fully enabled at all times.

There appears to be a small restriction. If you are running JAVA off-site (if you force the cart to do something by pressing a button), and if the resulting event-handling uses "new" to create a variable, and if at the same time the browser is working very hard at carrying out programming in a page, then it is theoretically possible to crash the browser. In plain language, suppose that the shopping cart frame breaks free of the launching site and you go to some other point in cyberspace, such as the Mars Lander site, starting some big VRML program. Then, as it is in the middle of calculations, and things are changing on the screen, if you bring up the persistent shopping cart frame and begin pushing buttons, you can probably provoke a crash. However, it takes a good deal of careful manual dexterity.

The solution here is simple: Avoid the use of "new" in any JAVA programming that is triggered when off-site. I have tested this, and it appears to make it impossible for even the most obnoxious person to crash the cart. This step has not been taken in the current code because it can involve the use of global static variables, and these make further program development very difficult. Also, the slight potential instability off-site does not appear to be a problem at all for this shopping cart in every-day usage.

An Illustration of These Techniques

The following code will place a frame on a web page, and then save its position as it is moved, so that it appears at the altered position when a new page is loaded. This demonstrates persistence.

An Applet Example

import java.awt.*;
import java.applet.*;

public class Applet1 extends Applet{
  public void init(){
    if(Constants.frame == null){
      Constants.frame = new Frame();
      Constants.frame.reshape((int)Constants.framex.intValue(),
        (int)Constants.framey.intValue(),300,300);
    }
    Constants.frame.show();
  }

  public void stop(){
    Constants.framex = new Integer(Constants.frame.bounds().x);
    Constants.framey = new Integer(Constants.frame.bounds().y);
    Constants.frame.dispose();
    Constants.frame = null;
    }
}

abstract class Constants{
  static Frame frame;
  static Integer framex = new Integer(225);
  static Integer framey = new Integer(150);
}

Compiling this code will generate the two files Applet1.class and Constants.class.

Place the following code in HTML Page 1:

<HTML>
<HEAD>
</HEAD>
<BODY>
        <applet code=Applet1.class name=Applet1 width=1 height=1> </applet>
<A HREF="Page2.htm">Page2.htm</A>
</BODY>
</HTML>

Place the following code in HTML Page 2:

<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
        <applet code=Applet1.class name=Applet1 width=1 height=1 id=Applet1> </applet>
<A HREF="Page1.htm">Page1.htm</A>
</BODY>
</HTML>

When the applet is loaded, method init() is called. This creates a frame, and places it at the (x,y) position defined by variables framex and framey. A look at class Constants tells us that these are initialized at 225 and 150 respectively. Suppose that while Page1 is up, the user moves the frame. Method stop() is called automatically when Page1 is left by the user, and this determines the (x,y) position to which the frame was moved by the user, and remembers it by changing variables framex and framey. When the page is reloaded, method init() is called again. It seems obvious that the frame should be placed again at coordinates (225,150), as defined in class Constants, however, the values of variables framex and framey, when a reload occurs, are those set by method stop() when the previous page was left. The initialization in class Constants is ignored by a reload. Why? The program is not being restarted; it is simply being re-activated. That is the essence of persistence as generated by applet reloading.

There will be stability problems with the frame in some browsers, for it is constantly being destroyed and recreated again (our later examples remove this problem). This is associated with the Abstract Windows Toolkit, and is not linked to persistence. The said instability is present even when the applet is not being continually reloaded, and is caused by the fact that the applet must interact with a peer, which does the actual work of constructing the frame. The said instability is removed in three ways: the first is to adjust the order of frame operations so as to minimize pressure on the peer. The second is to follow every frame operation with a call to pack(). This appears to place a modal stop on further execution until the peer has completed its task. The third is to introduce delay loops at critical points. For instance, one might define the method pause(200), in which pause(time) is defined as follows:

void pause(int time){
  long startTime = System.currentTimeMillis();
  while(System.currentTimeMillis() < startTime + time){
    //infinite loop: time slicing creates a pause to give the peer an opportunity to finish
  }

Notice in the applet code that the frame name is defined in the abstract class Constants. This is absolutely essential for stability. Notice also that the class Constants is never instantiated. You can see already, in this example, that we have started to manipulate an abstract class.

Illustration: Example 2: An Active X Example

In contrast to the applet example, which uses the Abstract Windows Toolkit, there appears to be no stability problem at all in the Active X implementation of persistence, which uses Windows Foundation Classes. This demonstrates graphically that persistence can be used to generate very dependable code.

import com.ms.wfc.html.*;
import com.ms.wfc.ui.*;

public class Class1 extends DhDocument{
  public Class1() {
    if(Constants.form == null){
      Constants.form = new Form();
      Constants.form.setBounds((int)Constants.formx.intValue(),
        (int)(Constants.formy.intValue()),300,300);
      Constants.form.setVisible(true);
      }
    Constants.form.bringToFront();
  }

  public void dispose() {
    Constants.formx = new Integer(Constants.form.getBounds().x);
    Constants.formy = new Integer(Constants.form.getBounds().y);
    Constants.form.dispose();
    Constants.form = null;
    super.dispose();
    }
  }

  abstract class Constants{
    static Form form;
    static Integer formx = new Integer(225);
    static Integer formy = new Integer(150);
  }

This code is interpreted by Microsoft Visual J++ Version 6, and is used to form an Active X object which will be loaded by the following two HTML pages. The first, or something similar to it, is generated automatically by the said Visual J++ compiler and saved as HTML Page1.htm. Notice that we have inserted, into the said automatically generated code, a hyperlink to a Page2.htm.

<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<OBJECT classid="java:com.ms.wfc.html.DhModule"
        height=0 width=0 ... VIEWASTEXT id=OBJECT1>
<PARAM NAME=__CODECLASS VALUE=Class1>
<PARAM NAME=CABBASE VALUE=Project3.CAB>
</OBJECT>
<A HREF="Page2.htm">Page2.htm</A>
</BODY>
</HTML>

Page2.htm is produced by copying the contents of Page1.htm into an empty HTML page, naming this said page Page2.htm, and altering the hyperlink to Page2.htm, in the said copied code from Page 1.htm, into a return link to Page1.htm:

<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<OBJECT classid="java:com.ms.wfc.html.DhModule"
        height=0 width=0 ... VIEWASTEXT id=OBJECT1>
<PARAM NAME=__CODECLASS VALUE=Class1>
<PARAM NAME=CABBASE VALUE=Project3.CAB>
</OBJECT>
<A HREF="Page1.htm">Page1.htm</A>
</BODY>
</HTML>

The previous two examples can be tested in the following manner. 1) Place all relevant files into the same directory. 2) Load Page 1 into a browser. 3) Use the mouse to move the frame (or in the case of Active X, the form) to a different location. 4) Use the browser to jump to Page 2. Notice that the frame does not come up in the original location but rather retains its new position. 5) Use the browser to jump to an unrelated page and then reload either Page 1 or Page 2. You will notice that the frame returns and maintains its latest position. 6) Repeat steps 3) to 5) as often as you wish.

Related Stories: