These days the dominant way that servers interact with people across the network is by sending HTML documents to Web browsers. Recently, XML has generated a lot of excitement among developers as an alternative document format that offers many advantages over HTML. Like HTML, XML enables servers to interact with people across the network via their Web browsers. But unlike HTML, XML also enables servers to easily interact with client software that has no user present.
In the Jini universe, in contrast to the document approach of both HTML and XML, servers interact with client programs by sending objects across the network. Like XML, Jini enables servers to interact with client programs regardless of whether a user is present at the client.
In this three-part series, I will compare and contrast two fundamental ways that servers can interact with clients: using documents and using objects. In this article, the first of three parts, I'll look primarily at how objects and documents compare when servers interact with client programs that have no user present.
Creating a Java news page
I recently wrote a Python script to generate a Java news page for my Website, Artima.com. I planned to get the news items from Moreover.com, which offered a free news feed devoted to Java. As a Webmaster, I had several options, all of which involved servers sending documents to clients.
Perhaps my most straightforward option was to insert a large, hairy chunk of JavaScript code, kindly provided by Moreover.com, into my page. Whenever a user visited my Java news page, the embedded JavaScript would land in his or her browser, contact Moreover.com, grab the most recent Java news data, and construct the news page on the fly. I discarded this option partly because I have found JavaScript to be unreliable (as a result, my site contains no JavaScript), but primarily because I didn't want the user to have to wait for the JavaScript to make a socket connection to Moreover.com in order to grab the data. One of my main goals for Artima.com is to have pages that load quickly, and every socket connection takes time.
Another option was to use a script that ran on the server. In that approach, the URL of my news page would actually refer to a script. When a user hit the URL, the Web server would run the script. The script would contact Moreover.com and obtain the news information in the same way the JavaScript would. Again, I discarded this option because I didn't want the client to have to wait for that socket connection to Moreover.com.
Ultimately, I decided to write a script that contacted Moreover.com, grabbed the most recent Java news data, generated my Java news page, and saved the page in a file. I planned to set up a cron job that automatically ran the script every hour, so that the file would be refreshed regularly. In this approach, the user wouldn't have to wait for a socket connection, because it would be made behind the scenes once every hour. Given that Moreover.com seemed to be updating the contents of its Java news feed at most once or twice a day, I decided that an hourly poll would yield a sufficiently fresh page for my Website.
Deciding upon a data format
Moreover.com offers its news feeds in several data formats, each available at a different URL. Thus, I next had to decide which data format my script should use for processing.
One data format that I did not choose, but which I'd like to mention here, is HTML. Among other data formats, Moreover.com offers an HTML Webpage full of the latest Java news. The trouble with this approach, of course, is that HTML pages are intended to be consumed by people, not programs. Although the information my Python script needs is contained in an HTML page, the page's markup tags make it difficult for programs like my script to acquire the information. Rather, HTML markup tends to focus on enabling a Web browser to render the information buried in a screen's markup, so that a human user can gaze upon the screen and pull the information into his or her brain.
In HTML, information intermingles freely with directions on presenting that information. For example, here's a snippet of HTML code from the HTML news page at Moreover.com:
<TR BGCOLOR="#ffffff"><TD><FONT FACE="Arial, Helvetica, sans-serif">
<A HREF=http://c.moreover.com/click/here.pl?j6547539 TARGET="_blank"><FONT SIZE="-1" COLOR="#333333"
><B>Java, XML to survive Sun/Microsoft war...</B></FONT></A><BR>
<A HREF=http://www.vnunet.com/ TARGET=_blank>
<FONT SIZE="-2" COLOR="#ff6600">vnunet.com</FONT></A>
<FONT SIZE="-2" COLOR="#ff6600"> Wed Apr 12 09:34:25 GMT-0700 (Pacific Daylight Time) 2000</FONT>
</TD></TR><TR BGCOLOR="#ffffff"><TD BGCOLOR="#ffffff" HEIGHT="5"></TD></TR>
Aside from the trouble of parsing out the information from all this HTML markup, a far more insidious problem exists with the parsed-HTML approach. Given that HTML pages are intended to be rendered by browsers and read by people, Webmasters have no qualms about changing their pages in ways that browsers and people can deal with, but programs cannot. So even if I decided to parse the information out of the HTML, chances are good that eventually Moreover.com's Webmaster would make a change to its Webpages' structure that would break my script.
Looking at XML
The document-style format that looked most promising to me was Moreover.com's XML feed. XML was designed to enable just the kind of software parsing I wanted to do in my Python script. In an XML document, in contrast to one in HTML, information and presentation are cleanly separated. The information contained in the document is marked up in tags that, rather than describe how the information should be presented, hints at the semantic meaning of the information. For example, here's a snippet of XML code from the XML feed at Moreover.com:
<article id="_6547546">
<url>http://c.moreover.com/click/here.pl?x6547539</url>
<headline_text>Java, XML to survive Sun/Microsoft war</headline_text>
<source>vnunet.com</source>
<media_type>text</media_type>
<cluster>Java news</cluster>
<tagline> </tagline>
<document_url>http://www.vnunet.com/</document_url>
<harvest_time>Apr 12 2000 4:34PM</harvest_time>
<access_registration> </access_registration>
<access_status> </access_status>
</article>
Directions on how to present the information contained in the XML document's semantic tags can be defined separately, using a style markup language such as CSS or XSL. In the Moreover.com case, the XML document is intended to be consumed only by programs, not by people, so no style markup is provided. Nevertheless, the primary reason my Python script could parse the XML feed more easily than the HTML feed is that XML is designed to avoid HTML's intermingling of information and presentation.
Settling on tab-separated values
I liked the XML approach, but unfortunately I was unable to figure out quickly enough how to work with XML in Python. All I wanted to do was pass a chunk of XML to some library routine, get back a nice data structure corresponding to the XML document, and use it to effortlessly write out the news page. I was (and still am) on the Python learning curve, and as I was rooting around in the Python documentation looking for my desired library routine, I noticed that Moreover.com also offered a tab-separated value (TSV) feed. At that point I paused and said to myself, "Self, if you just use this TSV feed, then you can get this job done right now." For reasons of speed, therefore, I abandoned my search for the elusive XML-to-data-structure Python library routine and completed my script using the TSV feed.
Here's one line from the TSV feed at Moreover.com. (The single line is split into three lines with \\
and tabs are replaced with \t
here, but not in the actual feed.)
http://c.moreover.com/click/here.pl?t6547539\t\\
Java, XML to survive Sun/Microsoft war\tvnunet.com\ttext\t\\
Java news\t \thttp://www.vnunet.com/\tApr 12 2000 4:34PM\t \t
XML, data models, and DTDs
The structure and tag names in Moreover.com's XML feed form a "data model" of a news feed. Moreover.com thought about what it meant to be a news feed. It identified and gave a name to each piece of information, gave each item the name "article," and decided that its XML document would be an ordered list of articles. (The TSV version also represents a minimalist expression of the same conceptual data model.)
XML lets you express your data model in a Data Type Definition (DTD). In fact, Moreover.com provides the DTD for its XML news-feed documents. The DTD looks like this:
<!ELEMENT moreovernews (article*)>
<!ELEMENT article (url,headline_text,source,media_type,cluster,tagline,document_url,harvest_time,
access_registration,access_status)>
<!ATTLIST article id ID #IMPLIED>
<!ELEMENT url (#PCDATA)>
<!ELEMENT headline_text (#PCDATA)>
<!ELEMENT source (#PCDATA)>
<!ELEMENT media_type (#PCDATA)>
<!ELEMENT cluster (#PCDATA)>
<!ELEMENT tagline (#PCDATA)>
<!ELEMENT document_url (#PCDATA)>
<!ELEMENT harvest_time (#PCDATA)>
<!ELEMENT access_registration (#PCDATA)>
<!ELEMENT access_status (#PCDATA)>
I won't go into the details of the DTD syntax, but basically, Moreover.com's DTD says that each of its news-feed documents (named "moreovernews") are composed of a set of zero or more "articles." Each article is composed of several pieces of information, including a "url," a "headline_text," and so on. In short, an XML DTD is a written definition of the abstract data model to which an XML document adheres.
Data models and network protocols
Lurking behind all the communication approaches between Moreover.com and Artima.com is an important assumption: that the client will fetch the document via the HTTP's GET command. In fact, perhaps a better way to look at Moreover.com's document formats is as a part of several high-level protocols that define the interaction between Moreover.com's clients (such as Artima.com) and its server. The combination of a news category URL, the low-level HTTP GET protocol, and Moreover.com's XML DTD, for example, combine to form a high-level network protocol, which can be summarized as follows:
A fetch protocol
An alternative protocol
The Python script currently executing at Artima.com plays the client role in a protocol that corresponds closely to the Fetch protocol. The difference is that my Python script fetches a TSV, not an XML, document. The TSV format does not come with an official DTD, but conceptually its structure corresponds to the same data model described by the XML DTD.
Now although my Java news page seems to be working fine, the truth is, I'd prefer that Moreover.com notify my Website whenever it changed the contents of its Java news feed. That way I would need to rewrite my Java news page only when its contents actually change. Since I would be notified of changes rather than polling hourly, my news page would be updated more promptly whenever new news appeared.
If Moreover.com is ever to offer such a notification-based approach, it will have to define a protocol that implements one. Given that the server will be "pushing" a notification down to the client, rather than relying on the client to "pull" the latest news from the server, the client will probably have to have some kind of server running. For Moreover.com to know where those client-side servers are, and what categories of news each client-side server wants, a protocol that lets clients subscribe to the notification service will be necessary (in addition to the notification protocol itself). Here are outlines of a subscription protocol and a notification protocol, in which I call the client-side server a "listening" server:
A subscription protocol
A notification protocol
This is a quick first sketch of news-feed subscription and notification protocols. In an actual protocol design project, the details of the DTDs would need to be specified. In addition, many other issues, including what should happen if a listening server disappears from the network without canceling its subscription, should also be considered.
Java news-object style
So far, I've shown that the traditional way of defining client-server interaction across a network is to define protocols, and that when documents are sent across the network, the structure of those documents is really part of a protocol. I demonstrated several protocols that a client at Artima.com could conceivably use to interact with a server at Moreover.com to create an automatically refreshed page of Java news.
Now I'd like you to consider a different approach to the news-feed business. What if, instead of working exclusively with documents and protocols, Moreover.com had also offered an option that raised the level of discourse to objects and interfaces? As a thought experiment, imagine that Moreover.com could send a Jini service across the Internet to Artima.com, and that it also offered a Jini version of its news feed. What might the interface of the Jini service look like? In the next few sections, I'll show some classes and interfaces that form a news-feed API.
A NewsFeed interface
Since some clients may prefer to poll and others may prefer to be notified, perhaps a news-feed API should provide an object whose interface lets clients do both. This functionality is represented in the following interface:
package com.artima.news;
import java.rmi.RemoteException;
import java.rmi.MarshalledObject;
import java.rmi.Remote;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.event.EventRegistration;
import java.io.Serializable;
/**
* Interface implemented by Jini news-feed service object. This interface allows
* clients to register (via the addNewsListener() method) to receive
* NewsFeedEvents, which are propagated whenever the news-feed contents
* change. Alternatively, or in addition, clients can poll the news-feed service at
* any time via the getNews() method.
*/
public interface NewsFeed extends Serializable, Remote {
/**
* Registers a remote event listener as interested in receiving
* NewsFeedEvents for the passed news category. To stop receiving events,
* clients can simply cancel lease returned as part of the EventRegistration.
*/
EventRegistration addNewsListener(RemoteEventListener rel,
int newsCategory, MarshalledObject handback) throws RemoteException;
/**
* Returns an array of news items, ordered from most recent (at array index 0) to
* the oldest (at index array length -1), for the passed news category.
*/
NewsItem[] getNews(int newsCategory) throws RemoteException;
}
The addNewsListener()
method of the NewsFeed
interface lets a client register interest in a breaking news event via the Jini distributed event model. The getNews()
method lets a client poll the news feed for the latest news.
Convenient constants in the NewsCategories interface
When you register a listener via addNewsListener()
, or request the current news via getNews()
, you must provide an int
value that indicates the category of news feed you want. (My Website, for example, is interested exclusively in the Java news category.) For convenience, you could collect the int
values for the categories in an interface that is also included in the news-feed API:
package com.artima.news;
/**
* A collection of constants that represent categories of
* news feeds.
*/
public interface NewsCategories {
int JAVA_NEWS = 99772;
// Other news categories would receive logical numbers
// in here as well....
}
A NewsFeedEvent class
A listener registered with the news service via addNewsListener()
will be notified of changes via the following distributed event:
package com.artima.news;
import net.jini.core.event.RemoteEvent;
import java.rmi.MarshalledObject;
/**
* Remote event that represents a change in a news feed.
* Events that would cause this event object to be propagated
* include:
* <UL>
* <LI>One or more news items have been added to a feed.
* <LI>One or more news items have been deleted from a feed.
* <LI>One or more news items currently part of a feed have been changed.
* </UL>
*/
public class NewsFeedEvent extends RemoteEvent {
private NewsItem[] news;
/**
* Constructs a NewsFeedEvent object.
*/
public NewsFeedEvent(Object source, long eventID, long seqNum,
MarshalledObject handback, NewsItem[] news) {
super(source, eventID, seqNum, handback);
this.news = news;
}
/**
* Returns an array of news items, ordered from most recent (at array index 0) to
* the oldest (at index array length -1).
*/
public NewsItem[] getNews() {
return news;
}
}
A NewsItem class
Whether a client polls a news feed via the getNews()
method or receives a NewsFeedEvent
, the client extracts the actual list of news items from an array of NewsItem
objects. Here's the NewsItem
class:
package com.artima.news;
import java.io.Serializable;
import java.util.Date;
/**
* NewsItem encapsulates one item of news.
*/
public class NewsItem implements Serializable {
private long articleID;
private String url;
private String headlineText;
private String source;
private String mediaType;
private String cluster;
private String tagline;
private String documentURL;
private Date harvestTime;
private String accessRegistration;
private String accessStatus;
/**
* Constructs a NewsItem object.
*/
public NewsItem(long articleID, String url, String headlineText,
String source, String mediaType, String cluster, String tagline,
String documentURL, Date harvestTime, String accessRegistration,
String accessStatus) {
this.articleID = articleID;
this.url = url;
this.headlineText = headlineText;
this.source = source;
this.mediaType = mediaType;
this.cluster = cluster;
this.tagline = tagline;
this.documentURL = documentURL;
this.harvestTime = harvestTime;
this.accessRegistration = accessRegistration;
this.accessStatus = accessStatus;
}
/**
* Returns the article ID of the news item.
*/
public long getArticleID() {
return articleID;
}
/**
* Returns the URL of the news item.
*/
public String getURL() {
return url;
}
/**
* Returns the headline text of the news item for
* the current locale.
*/
public String getHeadlineText() {
return headlineText;
}
/**
* Returns the source of the news item for
* the current locale.
*/
public String getSource() {
return source;
}
/**
* Returns the media type of the news item.
*/
public String getMediaType() {
return mediaType;
}
/**
* Returns the cluster of the news item for the
* current locale.
*/
public String getCluster() {
return cluster;
}
/**
* Returns the tag line of the news item for
* the current locale.
*/
public String getTagline() {
return tagline;
}
/**
* Returns the document URL of the news item.
*/
public String getDocumentURL() {
return documentURL;
}
/**
* Returns the harvest time of the news item.
*/
public Date getHarvestTime() {
return harvestTime;
}
/**
* Returns the access registration of the news item.
*/
public String getAccessRegistration() {
return accessRegistration;
}
/**
* Returns the access status of the news item.
*/
public String getAccessStatus() {
return accessStatus;
}
}
A Jini news-feed service
Those classes and interfaces are a rough sketch of what a news-feed API might look like. If this were an actual API design project, many more design iterations would be in order, in conjunction with one or more peer design reviews.
Some questions I might ask at a design review of this API are:
BreakingNews
events be offered in two separate interfaces that are both extended by JavaNews
?NewsItem
return strings for a specific locale?NewsItems
array, should a class be invented to hold this array and an int
news category?What's the difference really?
In the subsequent two articles in this series, I'll delve into the advantages and disadvantages of objects versus documents. At this point, however, I'd like to try and identify the crux of the difference between the two approaches.
In short, a document is a bundle of information; an object is a bundle of services. Each instance method in an object's public interface offers a service to the outside world. By invoking a method on an object, you are asking the object to do something for you -- to provide a service for you. In Jini, the entire object is called a service, because that's what it represents to the client. Each object offers a bundle of methods that individually provide low-level services and that in combination provide a high-level service. For example, in the news-feed API shown earlier in this article, the low-level services addNewsListener()
and getNews()
combine to form a higher-level news-feed service, offered by any object that implements the NewsFeed
interface.
You can ask an object to perform a service for you by invoking one of its methods. The object will either perform the requested service or throw an exception back at you indicating why it couldn't perform the service. By contrast, you can do things with or to a document, but you can't ask it to do something for you. Well, I suppose you could ask, but the document would just lie there and your coworkers would wonder why you were talking to it.
Deconstructing objects
An object can perform services for clients because objects embody behavior. An object usually has state, defined by the values of its instance variables, and behavior, defined by the code of its instance methods. An object's state is data, like the data contained in a document. But in general, an object uses its state to decide how to behave when its methods are invoked. The key difference between a network-mobile object and a network-mobile document, therefore, is that when you send a document across a network, you're sending data, but when you send an object across the network, you're sending data plus code -- a combination that yields behavior.
To send a Java object across the network, you can simply serialize the object to get a stream of bytes that encode the object's state. You can then send its state across the network by sending those bytes. To send the code, you can send the class files that define the object's class, perhaps embedded in one or more jar files.
But wait a minute, isn't a class file just ones and zeros that adhere to a particular data format? Isn't a class file itself just data? In truth, when you send an object across the network, you're sending state (which is data) and code (which is also data). Thus, an object is made up of data that adheres to certain formats, just as any document is made up of data that adheres to certain formats. An object is a kind of document. So where does the crux of the difference between objects and documents really lie?
A generic model of computation
I believe the answer to the previous question can help illuminate what Java technology is really all about. XML lets you model concepts and express those models in DTDs. You could consider the news-feed DTD given earlier in this article as representing a model of the concept called a "news feed."
You can find far more complicated, already existing XML DTDs for many other conceptual models, such as chemistry, mathematics, and music. What James Gosling did -- in my mind it's the primary innovation of Java technology in its original form -- was create a conceptual model of computation itself.
Of course, conceptual models of computation can come in many forms. You could call many different kinds of data "code." Is it not JavaScript code that sits in a Webpage? Could you not consider HTML itself as code that is understood and executed by a Web browser? If so, then why is Java different or special?
I believe Java is important for two reasons: First, Java is very object oriented. In Java, the object is the unit in which behavior is sent across a network. Programmers that use Java to send behavior across a network, therefore, enjoy the benefits of object-oriented programming. Second, Java's abstract model of computation is as generic as it can be in the context of untrusted code. HTML and JavaScript code, to a great extent, assume that they will be executed in the context of a Webpage. Java, by contrast, assumes only that generic computation will occur, directed by code that is potentially untrusted.
To understand any document sent by a server, a client has to have code written by a programmer who understood (had prior knowledge of) the data model used by that document and the model's semantics. Likewise, to use a network-mobile Java object, which travels across the network as serialized state and class files, a client needs code that was written by programmers who understood Java's object-oriented model of computation. The code needed by the client is called the Java virtual machine (JVM).
To take advantage of Java's conceptual model of computation, therefore, you must have a JVM. In fact, the JVM specification is Java's abstract model of computation. My sense is that the primary purpose of the JVM is to serve as a landing pad for network-mobile objects. It lets you fire tiny bullets of behavior across the network and have them understood and used by the recipient. As Bill Joy said at the first Jini Community Summit, "We built the JVM to let objects move around."
Conclusion
In this article I've tried to accomplish two things. First, I pointed out that network-mobile objects, such as Jini's service object, offer an alternative way to deliver services across a network -- a way distinctly different from the traditional documents and protocols approach. Second, I showed what the crux of the difference between the two approaches actually is: the abstract model of computation embodied in the Java virtual machine. In the subsequent two articles in this series, the first of which will appear in July, I'll discuss the advantages and disadvantages of objects versus documents for delivering services across the network to programs and people.
To discuss the material presented in this article, visit my discussion forum at: http://www.artima.com/jini/jf/objvsdoc1/index.html
subscribe jini-users
.This article was first published under the name Objects versus Documents for Client Server Interaction in JavaWorld, a division of Web Publishing, Inc., June 2000.
Have an opinion? Be the first to post a comment about this article.
Bill Venners is president of Artima Software, Inc. and editor-in-chief of Artima.com. He is author of the book, Inside the Java Virtual Machine, a programmer-oriented survey of the Java platform's architecture and internals. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. Bill has been active in the Jini Community since its inception. He led the Jini Community's ServiceUI project that produced the ServiceUI API. The ServiceUI became the de facto standard way to associate user interfaces to Jini services, and was the first Jini community standard approved via the Jini Decision Process. Bill also serves as an elected member of the Jini Community's initial Technical Oversight Committee (TOC), and in this role helped to define the governance process for the community. He currently devotes most of his energy to building Artima.com into an ever more useful resource for developers.
Artima provides consulting and training services to help you make the most of Scala, reactive
and functional programming, enterprise systems, big data, and testing.