Download demo project - 5 Kb
Credits
-
The ideas for the Demo Chat application included along with this
article are my own. All chat applications Ive seen are either
entirely Java based or HTML based. My approach is a good balance
between both of these.
- The technical information for communicating between
Java and JavaScript has been gathered from reading numerous articles
on the Netscape Developer site.
- I first came across the term Faceless
applet while reading an article by Danny Goodman (The
JavaScript Apostle on the Netscape site). Thus I give credit to Danny
for coining this very apt term.
Disclaimers
-
The techniques discussed in this article were tested using Internet
Explorer 5.0 and Netscape Navigator 4.7 on a Windows 2000
Professional machine. To the best of my knowledge, these techniques
should work using versions 4.0+ of either browser but cannot
guarantee this since I did not have the time to test it out with all
these versions.
- Since JavaScript is the only language that is
supported out-of-the-box with both the major browsers, all scripting
code fragments use this language. I have previously used a
commercially available plug-in from http://www.ncompasslabs.com
that enables VBScript support within Netscape Navigator but when
I went to their site to verify the information, the product is no
longer listed there.
Introduction
I have been living and breathing modern COM for over two years now as
a technical lead on the toolkit team of my companys eCommerce
product. I have understood the significance of well-designed
interfaces and of implementations that work well within various
environments like Visual C++, Visual Basic as well as scripting. The
power of interface-based programming is forever entrenched in my mind
and I try to apply it to everything I am involved in as a software engineer.
Over the past one year, experience has taught our industry that all
business logic should be encapsulated within COM objects while ASP +
Scripting should be used only as glue for these objects. Designing
and developing infrastructure and business objects typically requires
a higher skillset as compared to what is required to actually use the
same. The preferred environment for developing these objects (at
least in my organization) is Visual C++ / ATL / STL. Microsoft is
also promoting Visual Basic as an alternative development environment
for these objects.
These objects are typically referred to as faceless because they
implement a lot of logic but no user interface. The presentation tier
is either a rich or thin client that has logic to present information
to and gather information from the end user. Such a client then uses
the faceless objects to do something meaningful with that
information. The whole idea is that the presentation tier typically
requires a lot of customization while the business objects do not
change as frequently. The changes required for the presentation tier
can also be implemented using less experienced programmers.
Applying these same principles to the browser environment, it seems
logical to encapsulate sophisticated client side logic within
faceless, binary modules while using a scripting language to handle
the presentation aspects. The options for these modules on the
Windows platform are Java applets and ActiveX controls / servers. The
focus of this article is on using Java applets for achieving this
goal because applets are browser, platform and processor independent
(for the most part).
A brief history of applets
SUN Microsystems introduced Java applets with much fanfare back in
1995. Applets immediately took the web world by storm because they
added the ability to display dynamic web content within browsers in
what was essentially a static HTML world.
During those initial days, it appeared that using Java applets was
the best way to add dynamic content to web pages. Microsoft initially
tried to counter SUNs offering with their ActiveX Control
technology but there are two primary issues with using controls
within web pages:
When Dynamic HTML finally started taking shape, things changed
drastically. The Document Object Model (DOM) exposes elements within
a web page as programmable components with their own set of
properties and methods. Even though the implementation of dynamic
HTML within the Internet Explorer and Netscape Navigator browsers is
vastly different, the underlying theme of programmatically changing
content using scripting code within the displayed page itself was a
BIG hit. Applets suddenly started to look old and primitive. The
W3Cs endorsement of Dynamic HTML finally set the tone for the
new breed of sophisticated, dynamic web pages.
There are several advantages to using Java applets within a browser
as listed below
The disadvantages to using applets are
A quick overview of using Java applets
Java applets are included in an HTML page with the applet tag.
Section 13.4 of the HTML 4.01 Specification on the W3C site documents
this tag in detail. It also mentions that this tag is deprecated in
favor of the <object> tag.
A sample HTML page containing an applet is shown below:
<html>
<head>
<title>Calculator</title>
</head>
<body>
<applet id="Calculator" width="300" height="500" code ="Calculator.class" codebase=".">
<param name="InitialMode" value="Normal">
</applet>
</body>
</html>
The attributes used in the above example are explained below.
Id |
The identifier for the applet instance. Client side scripting code
can refer to the applet using this id. |
Width |
This attribute specifies the initial width of the applets
display area (excluding any windows or dialogs that the applet
creates). Even though I have successfully used a width of zero (0)
with the browsers mentioned in the Disclaimers section, it is
recommended to use a value of 1 as the smallest width possible. |
Height |
This attribute specifies the initial height of the applets
display area (excluding any windows or dialogs that the applet
creates). Just like with the width attribute, a value of 1 is
recommended as the smallest height possible. |
Code |
This attribute specifies either the name of the class file that
contains the applets compiled applet subclass or the path to
get the class, including the class file itself. It is interpreted
with respect to the applets codebase. |
Codebase |
This attribute specifies the base URI for the applet. If this
attribute is not specified, then it defaults the same base URI as for
the current document. |
Only the code, width and height attributes are required.
The <param> tag contains name value pairs that allow the
applet to be configured when it is first started up.
A sample JavaScript function that invokes a method on the above
applet is shown below.
<script language="Javascript">
function SetCalculatorMode(Mode)
{
document.Calculator.SetCalculatorMode (Mode);
Division of labor
In the Introduction to this article, I suggested an approach wherein
the sophisticated browser side processing is encapsulated within
faceless Java applets while the presentation is managed by JavaScript
code. This approach requires bi-directional communication between
Java and JavaScript. The next few paragraphs investigate the
available options.
Accessing public members and functions exposed by a Java applet from
JavaScript code is straightforward as demonstrated in the
SetCalculatorMode()
function in the previous section. An applet
within a document is referred to either using its Id / Name
or using an index into the applets collection.
For example,
document.Calculator.SetCalculatorMode(Mode);
Communication in the other direction (Java to JavaScript) is achieved
using the netscape.javascript.JSObject
and
netscape.javascript.JSException
classes. In order to find out where
these .class files are located, I searched my hard-drive for all
files that contained the text "JSObject". To my surprise,
these files are widely used in many different applications, including
the Scripting Library that is part of any Visual Interdev project.
If Netscape Navigator 4.0+ is installed on your machine, these .class
files are available in the Java40.jar file which itself is located in
the <Navigator Installation
Directory>\communicator\program\java\classes directory.
I also found these .class files in four different .zip files located
in the <Windows Installation Directory>\Java\Packages
directory. These .zip files were obviously installed by Microsoft
products because they contain many com.ms packages. The point is that
these two classes are available with either browser and you can set
your CLASSPATH environment variable to any of the above paths. An
alternative approach is to extract these files from the .jar or .zip
files into your applets directory using a utility like WinZip.
The JSObject class
A brief description of the JSObject class member functions is
included for better understanding the usefulness of this class.
public static JSObject
getWindow (Applet applet )
This static method returns a JSObject for the window containing the
given applet. For example,
JSObject MainWindow = JSObject.getWindow ( this );
public Object call ( String
methodName, Object args[ ] )
This invokes a JavaScript method from within a Java applet. For example,
JSObject MainWindow = JSObject.getWindow ( this );
String Arguments[ ] = {"90", "2"};
public Object eval ( String
s )
This method evaluates a JavaScript expression. The expression is a
string of JavaScript source code, which will be evalauted in the
context given by this
. For example,
JSObject MainWindow = JSObject.getWindow ( this );
JSObject UserName = MainWin.eval ( "document.UserInfoForm.UserName" );
public Object getMember (
String name )
This method retrieves an indexed member of a JavaScript object.
Equivalent to this.name
in JavaScript. For example,
JSObject MainWindow = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject)MainWindow.getMember ( "document" );
JSObject UserInfoForm = (JSObject) DocumentPage.getMember ( "UserInfoForm" );
JSObject UserName = (JSObject) UserInfoForm.getMember ( "UserName" );
public Object getSlot ( int index)
This method retrieves an indexed member of a JavaScript object.
Equivalent to this [index]
in JavaScript. For example,
JSObject MainWindow = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject)MainWindow.getMember ( "document" );
JSObject Applets = (JSObject) DocumentPage.getMember ( "applets" );
Object theApplet = Applets.getSlot ( index );
public void removeMember (
String name )
This method removes a named member of a JavaScript object.
public void setMember (
String name, Object value )
This method sets a named member of a JavaScript object. It is
equivalent to this.name = value
in JavaScript. For example,
JSObject MainWin = JSObject.getWindow ( this );
JSObject DocumentPage = (JSObject) MainWin.getMember ( "document" );
JSObject UserInfoForm = (JSObject) DocumentPage.getMember ( "UserInfoForm" );
JSObject UserName = (JSObject) UserInfoForm.getMember ( "UserName" );
UserName.setMember ( "value", "Jeremiah S. Talkar" );
public void setSlot ( int
index, Object value )
This method sets an indexed member of a JavaScript object. It is
equivalent to this[index] = value
in JavaScript.
public String toString ()
This method converts a JSObject to a string.
As is clear from the examples presented above, the public methods of
the JSObject class are not restricted to invoking JavaScript
functions from within a JavaApplet. They also enable an applet to
directly manipulate the Document Object Model (DOM) elements.
Full documentation on these classes is available at http://developer.netscape.com/docs/manuals/communicator/jsref/pkg.htm
The documentation also explains how data types are handled between
Java and JavaScript.
Significance of the MAYSCRIPT attribute
Even if an applet uses the JSObject to invoke JavaScript functions or
to directly access the Document Object Model, the JSObject methods
will fail if the <applet> tag does not include the MAYSCRIPT
attribute. This enables the page designer to determine if an applet
can call out to JavaScript.
Communication between faceless applets
When using faceless, reusable Java applets within a web page, it is
possible that one applet may need to directly communicate with
another. Such a call could also be channeled through an intermediate
JavaScript function but it is always better to know all the available options.
The AppletContext interface in the java.applet package
gives an applet limited access to the applets context of
execution like the browser that the applet is runing in, the web page
the applet is on as well as other applets on the same page.
For example, here is an HTML page that contains two applets.
<html>
<head>
<title>Communication between applets</title>
</head>
<body>
<applet code="CircleArea.class" name="CircleArea" width=1 height=1>
</applet>
<applet code="PICalculator.class" name="PICalculator" width=1 height=1>
</applet>
...
</body>
</html>
The following code shows usage of the AppletContext object.
AppletContext context = getAppletContext();
PICalculator PIApplet = (PICalculator) context.getApplet ( "PICalculator" );
PIApplet.getValueOfPI();
Another option is to use the AppletContext::getApplets()
method which returns an enumeration to access all the applets within
the document. Even though communications between applets is part of
the standard Java applet API, it is not supported in all Java enabled
browsers. Hard-coding names of other applets is also inflexible. The
best approach may well be to use an intermediate JavaScript function
to handle such communication.
IUnknown::QueryInterface in Java
Class Object is the root of the class hierarchy. Every class has
Object as a superclass. All objects, including arrays, implement the
methods of this class. The Object::getClass()
method
returns Class which has many useful functions to discover
the details of the Java class itself. While a detailed explanation is
beyond the scope of this article, I would like to point out the getInterfaces()
method that enables dynamic discovery of the interfaces implemented
by a Java class.
I have not tried invoking the getClass()
method from
within JavaScript and hence cannot comment on its feasibility.
But using an infrastructure type applet, this functionality can be
easily made available to scripting code.
Installing the sample files
The sample code for this article is packaged in the
Java2JavaScript.zip file. The sample files demonstrate a chat
application that has been simplified to route messages on the client
side itself. In real life, the users participating in a chat are on
separate machines and a message is sent to a server that then
broadcasts it to all the participants.
The files that comprise the sample are
ISession.java |
Source file that defines the ISession interface. |
ISession.class |
Java byte-codes for the ISession interface. |
ChatClient.java |
Source file for the demo ChatClient applet. |
ChatClient.class |
Java byte-codes for the ChatClient applet class. |
CompileChatClient.bat |
A primitive makefile for the java source files. |
TestChatClient.htm |
HTML file that hosts the ChatClient applet. |
JSObject.class |
Byte-codes for the JSObject class. |
JSException.class |
Byte-codes for the JSException class. |
The steps to install and run the sample program are
Enter some text into the two input fields and click on the
corresponding Send button to see the message displayed in
the chat window.
Sample code explained
Chat applications are a popular collaboration mechanism on the web.
The two types of chat applications that I have seen are
Recently I had to implement a production quality chat application for
our eCommerce product. After a lot of thought, I decided to use a
hybrid approach. First and foremost, the Java applet is a faceless
applet that implements the ISession interface.
public interface ISession
{
I have modified this interface slightly from the production version
of the Chat application to include the Author parameter for both EndSession()
as well as SendMessage()
. This is because my demo uses
one applet to channel chat messages from two different authors.
The ChatClient.java file is the actual implementation of the ISession
interface. The functions init()
, start()
and stop()
are invoked by the browser if they are
implemented. The JSObject representing the document window is
acquired during the init()
method.
Since the Java applet calls out to two different JavaScript
functions, I decided to enable the web developer to be able to
specify the names of these functions as paramerters to the applet,
while providing defaults for the same.
m_strMessageHandler = getParameter("MessageHandler");
m_strErrorHandler = getParameter("ErrorHandler");
BeginSession()
and EndSession()
are dummy
implementations that just call SendMessage()
.
SendMessage()
calls the JavaScript function whose name
is specified in the m_strMessageHandler member variable. The default
value is "HandleSessionMessage". The relevant code is shown here.
if (m_JScriptWin != null)
{
String Arguments[] = {strAuthor, strType, strMessage};
m_JScriptWin.call(m_strMessageHandler, Arguments);
}
HandleSessionError()
invokes a JavaScript function whose
name is specified in the m_strErrorHandler
member
variable. The default value is "HandleSessionError".
The TestChatClient.htm file deals with the presentation aspects of
the chat. The applet is included on the page using the <applet> tag.
<applet id="ChatApplet" width="1" height="1" code="ChatClient.class" codebase="." VIEWASTEXT mayscript>
<param name="MessageHandler" value="HandleSessionMessageEx">
<param name="ErrorHandler" value="HandleSessionErrorEx">
</applet>
The parameters specify names for the two JavaScript functions that
the applet invokes. Ive just indicated names other than the
default to demonstrate how flexible this can be.
The two forms on the page simulate two people chatting with each
other. The corresponding HTML is straightforward.
The actual messages themselves are displayed within the ChatMessages
<DIV>. In the case of Internet Explorer, I use the Table Object
Model to display each message in a separate row. Hence the
ChatMessagesTable definition within the above DIV.
Finally, the HandleSessionMessagesEx()
JavaScript
function handles all the presentation aspects. Within Internet
Explorer, a new row is added to the ChatMessagesTable table for every
message that is sent. The scrollbar is displayed if required. Within
Netscape Navigator, I append the new message to the Messages variable
and use the latter to update the ChatMessages <DIV>. Since
scrollbars cannot automatically be displayed within a Netscape
<DIV> (which is really a LAYER), I display the last message
received at the top. I have found articles on how to support
scrollbars for LAYERs within Navigator, but that is not relevant for
this demonstration.
Final Thoughts
This article attempts to present some (neat) techniques for
implementing your browser side logic. As I have mentioned earlier in
the article, the JSObject
is widely used by many
applications, including Microsoft Corporation. All the same,
carefully consider your individual situation to determine if the
techniques presented here are applicable.
As for the demonstration sample that accompanies this article, I feel
that allowing the presentation of the chat to be implemented in
JavaScript / DHTML enables this code to be maintained by an entry
level / junior programmer. Customization of the user interface is
also easier using DHTML / JavaScript. Additionally, it allows for
more powerful presentation techniques that seem consistent with the
rest of the page contents.
In the production version of this application, Ive added
support for exchanging hyperlinks that open up on the
participants machine, dynamic selection of colors for messages
using cascading style sheets etc.
Any feedback is welcome.