Illustration: Example 3: A Pseudo-Constructor Example
Notice, in this code, that neither applet “app” nor Frame
“ShopFrame” contain any variables at all. All variables are
contained in the class ShopPanel. The applet, in its method init(),
refers to ShopPanel, which in and of itself forces all of
ShopPanel’s declared variables, all of which here are static, to be
instantiated. In particular, shopFrame and counter are formed. The
applet’s life cycle then calls init() in the applet, which
transfers the call to init() in ShopPanel. ShopPanel’s init() calls
formPanelElements() in ShopPanel, which sets the characteristics of
the already instantiated objects in ShopPanel. The next call is to
shopFrame, which now exists, and has defined characteristics, and
in particular to its method formPanel(), which takes the frame
elements defined in ShopPanel, and sets them into shopFrame, which
is also defined in ShopPanel. Event handling can now be set up, in
shopFrame’s formPanel(). Events are caught in shopFrame, but the
event handlers are all located as static methods in ShopPanel.
Notice that this structure is not dependent upon the applet at all:
there is a call from “app” to ShopPanel, but
nothing from ShopPanel back to applet “app.” The
frame shopFrame, which is created indirectly by the applet through
its reference to ShopPanel, in fact knows absolutely
nothing about its parent– it is aware
only of the class ShopPanel, which is not being
instantiated. When page transfers are made, it is the
applet which is altered from active to inactive.
Notice how short it is, and how little time will be required to
reload it. The frame doesn’t change at all; it simply sits there,
and watches as you browse.
Create the following applet:
import java.applet.*; public class app extends Applet{ public void init(){ ShopPanel.init(); } } import java.awt.*; import java.awt.event.*; public class ShopFrame extends Frame implements ActionListener{ void formPanel() { add(ShopPanel.counter); ShopPanel.counter.addActionListener(this); } public void actionPerformed(ActionEvent e){ ShopPanel.increment(); } } import java.awt.*; //notice that it can be public class ShopPanel, not just abstract class ShopPanel. We will discuss this. public class ShopPanel{ static ShopFrame shopFrame = new ShopFrame(); static Button counter = new Button("Click"); static int r = 0; static void formPanelElements(){ shopFrame.setBounds(200,200,100,100); } static void init(){ formPanelElements(); shopFrame.formPanel(); shopFrame.show(); } static void increment(){ counter.setLabel(new Integer(r).toString()); r++; } }
Place it into the following HTML page:
<HTML> <HEAD> </HEAD> <BODY> <applet code=app.class name=app width=1 height=1 VIEWASTEXT></applet> </BODY> </HTML>
Let’s look now at what our example does. The applet indirectly
creates a frame. Clicking this frame increments a number (There may
be problems in some browsers– we are not including minor tweaking
elements, composed solely of standard JAVA, that solve these
“glitches.”). Moving away from the HTML page does not destroy the
said frame. Rather, it continues to operate as a kind of “terminate
and stay resident” web program. Notice that the said frame now
maintains its position from page to page automatically, without any
user intervention, unlike the previous two examples. This is
because it is independent of what happens to the pages. When
created, it is tied to the JAVA virtual machine through the static
variables, and is then never destroyed. This demonstrates that we
have moved a stage further in establishing persistence. Since the
frame is only created once, there are none of the stability
problems that were previously associated with the Abstract Windows
Toolkit. Transition between pages is essentially instantaneous;
whenever access to the underlying HTML is desired, then the very
small source applet is simply reloaded on that page. It provides
the link to ShopPanel, from the underlying HTML.
Incidentally, if you look closely, you will notice that
ShopPanel this time is not an abstract class. A pseudo-constructor
for an abstract class must follow a very specific initialization
procedure in order to work. It turns out that if the
same sequence is followed within a normal class,
using the same static variables and static methods. This will then
also lead to an object that “lives forever.”
However, a normal class can contain a constructor, and thus it can
do more things. We have come further.
The two methods for creating persistence (reloading and
pseudo-constructors) cooperate beautifully. Our shopping cart, for
instance, is created once, and then never destroyed. Applet reload
gives it continuing access to the underlying HTML, through
Javascript and LiveConnect, and through the applet lifecycle, which
can pass current context information to the persistent class.
Creation of the shopping cart can occur on any of the pages that
are being reloaded– one simply sets a boolean variable “firstTime”
to true in the initialization statements in ShopPanel, and when the
frame is created, one resets it to false. The change in the
variable is remembered at a reload; the frame is created only when
“firstTime” is true.
Open Source Shopping Cart Code
The following two lines of code are inserted into any HTML page
that wishes to offer items for sale; I usually place them right
after the <BODY> tag:
As mentioned earlier, one must add a CODEBASE=../, or some
equivalent, to the <APPLET> tag when the HTML file is in a
directory other than the one that contains the applet. A look at
the source code posted elsewhere will give examples.
<APPLET code=app.class height=1 id=app name=app width=1 archive="app.zip"></APPLET> <SCRIPT LANGUAGE=javascript>function buy(a,b, c,d){document.app.prod(a,b,c,d)}</SCRIPT>
These lines load an applet called app.class. The code for “app”
is as follows:
import java.applet.*; public class app extends Applet { public void start() { ShopPanel.initValues(this); } public void prod(String iD, String it, String pr, String sh) { ShopPanel.prod(iD,it,pr,sh); } }
Let me make some comments for Open Source developers. First, the
applet is the segment that is being reloaded, and it is short. This
makes page to page transfer essentially instantaneous.
Second, HTML memory depends upon the applet being
restarted, not reloaded. This appears to happen
invariably, with an applet this size, in all current browsers.
However, as features are added to the applet, one can begin to
trigger a reload rather than a restart, particularly in HTML pages
that are very complex. Pseudo-constructors continue to do their
job; the result is a frame which persists, and whose purchases can
still be finalized, but which is no longer accessible by any HTML
page. It has become “detached.” Further purchases bring up a second
frame, which also persists. All further purchases are now added to
the second frame. In order to keep size down, and to ensure
restarting rather than reloading, Open Source programmers will
probably find, as I have, that it is best to make changes in
classes other than “app.”
Third, notice that we call start() in the applet, and not
init(). This is because init() is called the first time that an
applet is loaded, whereas start() is called every time that a page
transfer is made. Our goal is to update the rest of the code with
the current address of the restarted applet every time the applet
is reloaded. By passing on the value of “this”, we can then use
commands like “this.showDocument().” This continual updating can
only be done by calling start().
Extended Examples
As in the simple pseudo-constructor example given previously,
class ShopPanel uses an extension of the Frame class called
ShopFrame. The code for ShopFrame is as follows:
Click here to view the first .java code example
Notice that no variables are declared in ShopFrame. It does not
contain a constructor. It will be instantiated by means of a
pseudo-constructor, contained in ShopPanel.
The core of the Open Source shopping cart program is contained
in class ShopPanel. This is probably where most future program
modifications would occur.
Click here to view the second .java code example
As mentioned in the pseudo-constructor example, the shopping
cart works just as well if a normal, rather than an abstract class,
is used. I keep the class abstract because I am then warned, by the
fact that the program won’t compile, whenever I step outside of the
proper rules for generating persistence by means of a
pseudo-constructor.
You will notice that some graphics commands are repeated twice.
This is because either Netscape or Explorer is not responding
correctly to the first command. Probably, there is a timing problem
with the peer. Repeating the command at a later point appears to
solve the problem. Open Source developers may wish to experiment
extensively if they choose to change the position of these
repetitions.
Notice that all variables are declared here in ShopPanel, and
that many of them are static. Single-stepping through program
execution will demonstrate clearly how a simple reference to
ShopPanel in the applet “app” causes all static variables in
ShopPanel to be instantiated before ShopPanel is
ever given control of program execution; everything is always
defined, and it is done in the proper order.
A call to “parent.isActive()” is used to determine whether the
applet, in its updated form, has been reloaded by the current HTML
page. This check could be ommitted, but a security exception would
then be thrown by any call to showDocument() that occurred when
off-site, and this would need to be handled by the browser. I felt
it was better to do things explicitly.
As you notice from the code, the program attempts to load a file
called “update.txt” from the directory in which the applet “app” is
located. Here’s a sample “update.txt”:
"1",$14.97 "2",$22.93 "3",$6.22 "4",$5.55 "5",$6.66 "6",$7.77
“update.txt” is a text file written in a format consistent with
a two-field Access database, in text format. It allows a merchant
to alter prices temporarily, should he want to offer a sale. This
file can be multiple megabytes in size. It is cached by the applet.
Page to page transfer in HTML is always instantaneous.
The Shopping Cart and Database
A non-commercial site is altered into a commercial site through
the inclusion of two lines of “boilerplate code” into the HTML of
all pages that wish to present items for sale. A specific item is
then offered for sale by including an
onClick="buy('itemID','itemName','item Price','itemShippingProcedures')"
event handler into any page object which is able to support it:
this may be a button, a diagram, some region of an image, or even a
JavaScript program. When the client operator triggers an event in
this object on his browser, a call is made by the event handler to
the applet or object which was loaded into the page, and the applet
or object adds the item to a shopping cart frame or form which this
applet or object brings up whenever a sale is made. None of this
involves any interaction whatsoever with the host server.
When the “buy” event is triggered by the browser operator, the
applet or object, in our particular implementation, checks to see
whether an item with “itemID” is located in a cached database on
the browser. If it is, then it assigns the associated cached price
to the object, and displays this in the shopping cart frame or
form. If it is not, then it uses the number that is hardcoded into
the HTML as “itemPrice.” Again, this involves no interaction with
the host server. The fact that everything occurs on the client, and
can use the full power of the client’s processor, means that
database access involves no noticeable delay, even when the
database is quite large.
“itemID” is the key and must always be present. “itemPrice” may
be an empty string. When it is, then the database must always be
present, and it must contain “itemID” and a corresponding
“itemPrice.”
The database in our implementation is designed with Microsoft
Access, and can thus be integrated into any large-scale database.
It is a two column table in text format, and can thus also be
designed by a novice operator using a simple text editor. To be
recognized by the said applet or object, the database in our
implementation must be stored on the merchant’s server in the same
directory as the applet or object, and it must be called
“update.txt.” When the applet or object is first loaded by some
particular page, it checks for the presence of this file in its
codebase directory. If the file is found, then the applet or object
loads it, and it then generates a cache, on the client, for
subsequent pages. In our implementation, this cache is a static
String in an abstract JAVA class, and it persists. The string may
be well in excess of 1 Meg in length, and could thus include more
than 40,000 revisions. If the database file is absent, the applet
or object remembers this as well– in our case as an altered
boolean variable in the JAVA code. No further server-client
interaction is attempted, or necessary.
Once “itemPrice” has been checked with the (optional) database,
which is cached on the client, then the applet or object, which
also resides on the client, places the result in a frame or form on
the desktop window. Sales information, as it accumulates, is stored
as a static Vector in the JAVA code, and it persists. The result of
the purchase can therefore be collated with prior purchases, and a
running total developed and displayed.
Since cumulative sales information has persistence, it is
possible to alter previous purchases without going back to the
pages on which they were presented, and without interacting in any
way with the host server. “UP” and “DOWN” buttons allow scrolling
through the list of purchases, and “MORE” and “LESS” buttons allow
prior purchasing decisions to be altered.
If “CLEARCART” is pressed, then the frame is made invisible. The
“Window Close” button on the frame is not enabled because, as Open
Source developers will discover, its use causes undesirable side
effects.
Checkout
When the client operator is ready to finalize his purchases,
then, in our implementation, he presses “CHECKOUT…” This sends
the purchase information, as name-value pairs appended to a
hard-coded HTTP address, to a central server that is equipped to
ask for name, address, and credit-card information. The codebase of
the applet or object is also included; this is used to check that
the merchant’s site has registered with the central server, and
that it is authorized to do business.
When the said “CHECKOUT..” button is pressed, the cart is
automatically cleared. Pressing “RESET”, however, brings the
information back, in case the user wishes to change his mind.
In our implementation, one of the fields in the
“onClick=buy(a,b,c,d)” event handler is a string that encodes every
possible variation of tax and shipping instructions. This
information is passed, when a purchase is made, to the said applet
or object, which in turn passes it through unaltered to a central
server, when the order is finalized, and the said central server
processes the order accordingly. I would imagine that there will
need to be a table of hundreds of strings; the merchant, in
programming the HTML, would flip through the choices and choose the
right one, for each item. For instance, one string might means:
“Charge $10 shipping and send by UPS.” It seems logical that each
particular merchant’s location– country, and then state or
province– would be recorded initially when he signed up with the
order-processing company. That would be one less thing to encode.
If it was done that way, then access to a database at the central
computer could work out the proper taxes. The important point is
that people at the central location would not ever
need to talk to the various multiple merchants. It would then be
cost effective for them to provide quality services for a low
price.
This shopping cart front end is Open Source. Any commercial
company that wishes to provide back end checkout services is free
to adapt it to its use, in whatever manner it wishes. However, the
techniques of applet reloading and pseudo-constructors used to
generate persistence are covered by patent. I give unlimited
permission for anyone to use the patents for a shopping cart, and
an associated database cache. Any extension of these methods
beyond a shopping cart and an associated database
cache not only destroys bandwidth for the shopping cart, but is
also a violation of my patent rights.
If some company requires a more formal arrangement, before
committing resources, I can sign a legal form guaranteeing
non-exclusive permission to exploit the patents, as the company
wishes, for a shopping cart, and an
associated database cache.
In closing, let me suggest one alteration that allows a company
to handle multiple merchants on the same cart, at the same time
that it also handles orders from the previous small business
cart.
Cart for Multiple Merchants
When I demonstrated the small business version of the shopping
cart to a firm in Seattle, they asked whether it would be possible
to place multiple merchants, all hosted on the same site, onto one
frame, so that all purchases could be updated at any time in the
browsing experience, and finalized simultaneously. You can see the
result at http://209.87.142.42/is2.
To handle multiple merchants, I rewrote class ShopPanel as
follows:
Click here for the third .java code example
The boilerplate code for each HTML page was altered in the
following way:
<APPLET code=app.class height=1 id=app name=app width=1 archive="app.zip" VIEWASTEXT> <param name=start value="25"> <param name=length value="3"> </APPLET> <SCRIPT LANGUAGE=javascript>function buy(a,b,c,d){document.app.prod(a,b,c,d)}</SCRIPT>
The <APPLET> tag of course would also need an appropriate
CODEBASE=”whatever” addition, as described previously, and
demonstrated in the source code at http://209.87.142.42/is1.
The big change in ShopPanel was the addition of two applet
parameters and their associated code, and the removal of the
optional database. This resulted in code that was now only 13K in
length.
Conclusion
The coding challenge was to find some way to distinguish the
companies, all of which now resided on the same server, and thus
had the same applet codeBase. I chose to have the applet read the
documentBase for the particular HTML page, and to snip out the
portion which represented the merchant’s particular root directory.
No matter what sub-directory the browser was in, the portion at the
beginning of the http:// address, up to and including the root for
that merchant, would always be the same. The first applet
parameter, named “start,” told the applet where to begin snipping.
The second, named “value,” told it where to stop. For instance, if
the merchant address was http://www.infinitestores.com/oneMerchant,
“start” in the zero-based count would be 29, and length would be
11. This would snip out the string “oneMerchant,” and ShopPanel
could then place it in the slot reserved in the small business
version for shippingAndHandling.
Every merchant would call the same applet, preferably using a
CODEBASE=http://www.absoluteAddressOnServer call (for an example,
view the source at http://209.87.142.42/is1). The fact
that the absolute call was for an applet on the same server
as the document would ensure HTML memory. However, an
absolute call would mean that there would be no
need to keep track of directories and sub-directories. This could
be important on a large site with multiple servers. Every time the
applet was reactivated on some page, it would reload the parameters
from that particular HTML page, and if these were
different from those in some other reactivation on another page,
the values would be modified. Merchants could thus be
distinguished.
The company director told me that, in his experience, many
orders were canceled at checkout when buyers realized the full
impact of shipping and handling. He wondered if it was possible to
place a price in the cart that reflected the full cost of shipping
and handling. I suggested that he include a call in ShopPanel to
the appropriate database on his site, and update the price as
desired. There would be an initial result, from numbers placed into
the HTML (probably by his databases, perhaps using active server
pages), and then a few moments later an update (taking account of
volume discounts based on amount purchased, if applicable, and so
on). Since JAVA is multi-threaded, and separate from HTML, this
could take place simultaneously with other purchases, and
independently of HTML page transfers. Since pseudo-constructors
maintain the JAVA frame and code when off-site, it would not matter
if the buyer jumped elsewhere in the middle of an update. With code
size reduced to 13K, there was plenty of room.
Using this modified cart, the company could now handle both a
multi-merchant cart, and small business carts. If the applet
codebase in the checkout querystring was the company’s site, then
the company would know that the shippingAndHandling slot for each
product provided the respective merchant’s unique directory name,
and interact with databases appropriately in order to finalize the
order further. Alternatively, if the applet codebase was something
different, then that codebase would be the merchant’s identity – it
would be unique because every http:// address is different. All
aspects of a small business transaction would be automated – from
initial sign-up, to database maintenance through an optional text
file on the merchant’s server, to shipping and handling
calculations (according to coded instructions in the
shippingAndHandling string for each product). Since there would be
no need for personal communication, it would make economic sense to
deal with the small merchant.
Everything would be interrupt driven: from JavaScript event
handlers inserted into elements on an HTML page calling the applet
to indicate a purchase; by the applet calling an appropriate
database for information; or by the user finalizing an order and
through this, sending a querystring to an order-handling section.
Persistence would be maintained on the browser, freeing up central
server resources, and ensuring a fast connection. There would be
smooth interaction between merchants hosting on the same site, and
those hosting on other servers.
The multi-merchant version of the cart at present retains the
shippingAndHandling field in the HTML coding, even though this
information is no longer needed by the multi-merchant site –
shipping and handling would be handled through interaction with
various databases. The fact that the HTML is unchanged allows a
particular merchant to move back and forth easily from hosting at
the Seattle company– with the advantage of placing his orders on a
single shopping cart with those of others– to hosting elsewhere
for less money, with the penalty of having his own cart. He does
not have to make HTML modifications to his site. Class ShopPanel in
the multi-merchant version in turn overrides any
ShippingAndHandling information that it receives and instead passes
on the merchant’s directory string. The fact that the querystring
format is unchanged in the multi-merchant version presumably should
make things easier at the server end.
I look forward to seeing modifications that will be made by
other Open Source developers, and implementations by various
companies. I trust that competition will bring us quality service
for a low price.