jRendezvous: Java and Rendezvous Working Together
Pages: 1, 2
Implementation Example: Integrating Rendezvous with Tomcat
Let's check where we are now. We've reviewed Rendezvous, how Services are named, provided a patched version of jRendezvous, and explored jRendezvous's important classes and interfaces. We're ready now to do something interesting.
With Safari, Apple's browser, users can discover and browse web sites on their local network. One way to do this is to use Apple's mod_rendezvous_apple, already bundled with their Apache distribution. To experience this, display Safari's bookmarks and select the Rendezvous Collection from the left. We'll use this to test our Tomcat integration.
|
|
Why should mod_rendezvous_apple users have all the fun? With jRendezvous and Jakarta's Tomcat Web Server and Servlet container, you can make Java powered web sites become Rendezvous services.
Servlet containers have the concept of a Context, which is a logical
grouping of server resources. For instance, all of Justin's files and
images might be under the /~justin context. Fortunately, Tomcat has
the org.apache.catalina.core.StandardContext class that
encapsulates this concept nicely. We will thus advertise Servlet contexts
as Rendezvous services.
We first create a subclass of StandardContext called RendezvousContext.
This class will have a static Rendezvous member that all
ServiceInfo objects will register with. The entire Tomcat
instance should have only one Rendezvous instance running
within it, so keeping it static ensures this no matter how many RendezvousContexts
are running.
public class RendezvousContext extends StandardContext {
private static Rendezvous rendezvous = null;
private int port = 0;
private InetAddress address = null;
static {
try {
rendezvous = new Rendezvous();
} catch(IOException ioe) {
ioe.printStackTrace();
rendezvous = null;
}
}
public RendezvousContext() {
super();
}
...
The method of StandardContext that is analogous to the
init() method is setParent(Container parent). For explanations
of Tomcat's Containers, consult their source or javadocs. For our purposes,
it's only important to understand that setParent is called
as the object instance is finished being setup by the container. It
is here we will create the instance of ServiceInfo to advertise
this context.
public void setParent(Container parent) {
super.setParent(parent);
createRendezvousService();
}
private void createRendezvousService() {
if (rendezvous == null) {
return;
}
Hashtable props = new Hashtable();
props.put("path", getPath() + "/");
try {
ServiceInfo serviceInfo = new ServiceInfo(
"_http._tcp.local.", getPath(),
getAddress(), getPort(), props,
getAddress().getHostName());
rendezvous.registerService(serviceInfo);
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
The above code sets a "path" property to the context's base
path. For instance, if this was a context for a user's home directory,
the path property would be set to "/~user". This path property
is a standard property for HTTP Rendezvous services. Safari uses this
path property to properly setup a URI from the service advertisement.
The StandardContext class provides a method called getPath()
that provides the path of the context. We also use the getPath
method to name the service, for lack of a better name. A future version
of this context could get its name from the Tomcat configuration file.
The most difficult piece of the RendezvousContext was determining,
at runtime, what the server's address and port number are. The service
advertisement must be able to advertise where the server is hosted.
The StandardContext class does not have any methods that
directly provide this information. Normally, a servlet context does
not care what IP addresses or port numbers are hosting it. The context
might even be hosted via several addresses.
Luckily, the Tomcat API is very flexible; with a little hunting we can find a way to discover an IP address and port number that is hosting the context. Tomcat uses Connectors to physically connect contexts to the outside would. The connector might connect via HTTP/1.1, or through some other protocol to another web server. We want to advertise servlet contexts that can be reached via HTTP/1.1, so we specifically look for those connectors. Below is an example of one way to obtain a connector that is hosting this context. A more advanced version of this code would set up a service advertisement for each connector.
private CoyoteConnector getCoyoteConnector() {
CoyoteConnector coyoteConnector = null;
if (getParent() instanceof Host &&
getParent().getParent() instanceof Engine) {
Engine engine = (Engine) getParent().getParent();
Service service = engine.getService();
Connector[] connectors = service.findConnectors();
for (int i = 0; i < connectors.length; i++) {
Connector connector = connectors[i];
if (connector instanceof CoyoteConnector &&
((CoyoteConnector)connector).getProtocolHandlerClassName()
.toUpperCase().indexOf("HTTP") != -1) {
coyoteConnector = (CoyoteConnector) connector;
break;
}
}
}
return coyoteConnector;
}
Once we have a reference to the connector, we can find the port and IP address that the connector is listening to.
private int getPort() {
if (this.port == 0 && getCoyoteConnector() != null) {
this.port = getCoyoteConnector().getPort();
}
return this.port;
}
private InetAddress getAddress() {
if (this.address == null && getCoyoteConnector() != null) {
String addr = getCoyoteConnector().getAddress();
if (addr == null) {
try {
this.address = InetAddress.getByName(
InetAddress.getLocalHost().getHostName());
} catch(UnknownHostException uhe) {
uhe.printStackTrace();
}
}
}
return this.address;
}
That's all the code required to advertise a Tomcat servlet context as a Rendezvous service. The entire source is available for download, along with a compiled class version.
Installation of this class is quite straight forward. Place the
compiled
class file (RendezvousContext.class) into Tomcat's $TOMCAT_HOME/server/classes
directory. Place the modified, bug fixed jrendezvous.jar into $TOMCAT_HOME/server/lib.
Finally, we must configure Tomcat to use this class when constructing
contexts. Use the contextClass attribute of the
Context element in the Tomcat configuration to specify the
custom RendezvousContext class. Below is the configuration
for hosting user directories via Tomcat with the Rendezvous
functionality. Note that it is specific to Mac OS X, due to its use of the
/Users directory. The O'Reilly article Top
Ten Tomcat Configuration Tips explains this and other configurations
very well.
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="Sites" homeBase="/Users"
contextClass="RendezvousContext"
userClass="org.apache.catalina.startup.HomesUserDatabase"/>
This example was tested with Tomcat 4.1.24 LE JDK1.4 on Mac OS X and
Linux 2.4. The RendezvousContext might be portable over
different Tomcat versions because of its usage of internal APIs that
normally should be hidden from user code.
Once you startup Tomcat, use Safari's Rendezvous bookmarks to find
your
user's home directories. You should see two items for every user, one
for Apache's native mod_rendezvous_apple, and one for your Tomcat server.
Those user directories being served by Tomcat will look like /~user.
If the new entries are missing, check Tomcat's catalina.out or other
log files in the $TOMCAT_HOME/logs directory for any errors.
Final Thoughts
jRendezvous, once we worked through the few bugs, is a joy to work with. I find its API clean and simple. It's a great way to integrate Rendezvous service discovery and advertisement into your Java programs. I hope that it continues to be maintained.
The more I worked with Tomcat's internal APIs, the more I appreciated it. I think the Tomcat developers are doing a wonderful job in constructing a very flexible system that is both user friendly and developer friendly.
There is one small deficiency in the RendezvousContext
class. It does not clean itself up correctly. It should capture a shutdown
type event to correctly stop the Rendezvous instance. Otherwise,
the threads inside Rendezvous continue to run. Issuing
the shutdown command won't actually shutdown Tomcat. A challenge to
the reader: adapt the RendezvousContext class to shutdown
gracefully.
Seth Ladd is Lead Software Architect at Brivo Systems, Inc. He develops servlet and J2EE systems for REST based RDF and Ontology applications.
Return to Mac DevCenter
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 20 of 20.
-
server patch broke jrendezvous?
2003-10-21 20:50:29 anonymous2 [Reply | View]
hi seth, I think your server patch broke jrendezvous when it is used to discover services which aren't already responded by another server (ie the apache mod). in ServiceInfo.java you have added a [String server] to hold the name of the server which is handy for vhosts I think, but you can't key on that value in the DNS cache. the problem is that Rendezvous.handleQuery() populates the TYPE_A dns record with q.name (the rendezvous style name) as a key, and in ServiceInfo.updateRecord() you've changed the comparison to check it against the server name. I managed to get your code to resolve non jrendezvous services (tested with iStorm, apache and subEthaEdit), but couldn't make it resolve the service I was supplying (ie using jrendezvous as the only responder). changing some of these comparisons back to only using the rendezvous name solved the problem. I roughly understand what you were trying to do by adding the server field, but it doesn't affect the project I'm working on so I'll leave it up to you to try to find the best overall solution. perhaps that's what the "text" field was for? you can always pack more info into props.... if you'd like a copy of my source files let me know.. -
server patch broke jrendezvous?
2003-10-22 01:24:12 sethladd1 [Reply | View]
Hi,
It's quite possible that the "patch" I provide only does handle that one case. I'm glad you found a way around it. Honestly I haven't approached this topic in a long time. I hope one day someone is able to collect all these patches and knowledge and release a new version of the library. It looks like people find it useful!
Thanks,
Seth -
server patch broke jrendezvous?
2003-10-22 15:14:37 anonymous2 [Reply | View]
hi seth, after looking through your changes a bit more I don't think I entirely understand your motivation to make the changes you did. your changes make it so tomcat returns an address such as
http://foo.example.com
rather than
http://seth-ladds-computer.local./index.html
however I'm not sure this is a useful change for two reasons:
(a) mod_apache_rendezvous does not exhibit this behaviour, so why
should tomcat try to do something different?
(b) and more importantly any browser capable of doing rendezvous
service discovery should be quite able to handle a URL
of the second type. you say on page one of the article:
"While this server name resolves to a physical IP address,
clients should never cache that address. Rendezvous works so
well because services may move around on the network, even
changing IP addresses. Clients should cache the Service
Instance Name instead, allowing the service the flexibility
of movement."
from that I understand that the _correct url for this service
is the latter type, as it will still be correct even if the
service is no longer available on foo.example.com. I guess
the argument could be made that seth-ladds-computer might
not always be valid either, but one would think that if you've
found the resource via rendezvous, you continue to locate it
in that manner, and if you've found the resource via some other
means then you should stick with that access type. -
server patch broke jrendezvous?
2003-10-23 00:56:18 anonymous2 [Reply | View]
ohh man, this is a mess. I don't know if I can fix this without spending some solid time with the zeroconf protocol spec (which I can't seem to find) and a lot of println()s. apparently you were on the right direction by adding the server field as that's what the TYPE_A records are keyed on. however this means that back in the Rendezvous class we need to register the TYPE_A dnsrecord using the server name rather than the service name. this causes some problems for later lookups in handleQuery() as services are queried by service name, not server name.
-
RendezvousContext code segment
2003-08-01 06:59:03 anonymous2 [Reply | View]
I read the artical but now am lost, where do I place the RendezvousContext code segment?
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="Sites" homeBase="/Users"
contextClass="RendezvousContext"
userClass="org.apache.catalina.startup.HomesUserDatabase"/>
-
RendezvousContext code segment
2003-08-04 16:08:12 sethladd1 [Reply | View]
Sorry I didn't get back to you on this. I think I was a little unclear about this in the article. You place this in server.xml. You should see something similar to the UserConfig already in the file, just commented out. -
RendezvousContext code segment
2003-10-06 07:43:35 craigp [Reply | View]
Apologies for my ignorance here, but I would really like to expand this example a little further to advertise another webpage that I would like to automagically pick up using Rendezvous.
Basically, we're developing a J2EE application and using JBoss with Tomcat to run it. When our webapp is running, we browse to it at 'http://localhost:8080/PServer/Admin/'. What I would really like to happen is for this location to appear in the Rendezvous list in Safari - and when this is done I am also going to use the client features of JRendezvous to pick up locations for use in a Java Swing app we have written.
So, my question to the community is: how can I configure Tomcat with the class you have provided above, to point to an arbitrary location as opposed to '~/Sites'?
Alternatively (and this may be slightly beyond the scope of your article), it would be really nice to be able to declare a new type of Rendezvous service ('pServer_http._tcp.local.' - 'pServer' over http over tcp at local - if such a thing is possible) and I can construct the correct path to the web page in my Java Swing app if this service can tell me the host name and port number the PServer webapp is running on.
Thanks for reading and any help would be greatly appreciated. I will post back anything useful that I discover!
-
Rendezvous vs. Jini
2003-07-30 19:49:42 tom_davies [Reply | View]
The services provided by Rendezvous sound similar to Jini (I've never used either, so I'm not certain).
How would you compare them? -
Rendezvous vs. Jini
2003-07-30 19:57:37 anonymous2 [Reply | View]
Great question. I wish I had space and time to cover that in the article.
Rendezvous is really two different technologies that play together to one common goal: a zero configuration network. It handles both IP allocation and naming services plus service discovery.
Jini, on the other hand, is focused on service discovery. Jini relies on a properly configured IP network (which one can use Rendezvous to accomplish).
Another difference between Jini and Rendezvous is that Rendezvous does not attempt to cover anything about the protocol used the by the services and the clients. Once the service is discovered via Rendezvous, the client must know how to communicate with that service.
Jini, however, solves this problem by making the protocol transparent to the client. Once a client discovers a service via Jini, it receives a service proxy. This service proxy itself implements the protocol between client and server. This way, the client only needs to know how to use the Java interface exposed by the service proxy. How the proxy commicates back to the service is hidden from the client.
Plus, Rendezvous service discovery can be accomplished by many different client implementations in many different languages. AFAIK, to participate in Jini networks the client must be Java. This might not be technically true, but I haven't ever seen a non-Java Jini service.
Now, JXTA is supposed to have different implementations in different languages. From what I can tell, though, the Java implementation is by far the most active port.
-
getName
2003-07-30 12:49:53 anonymous2 [Reply | View]
getname always returns a string with the pattern
hostname._protocol._transport.local.
but I would rather expect
hostname.local.
because that is what the resolver can look up the ip for and as far as I know is supposed to be shown to the user as safari does.
any reason for this behaviour?
-
Wicked!
2003-07-30 08:46:48 anonymous2 [Reply | View]
I was just thinking of doing something very similar with Tomcat. You just saved me some time. Thanks! Have you contacted the folks at Strangeberry to discuss the limitation you speak of in the article?
-
Link to compiled, patched jar for jrendezvous is invalid.
2003-07-30 08:41:44 anonymous2 [Reply | View]
should link to http://www.picklematrix.net/articles/oreilly/jrendezvous/jrendezvous-patched.jar -
Link to compiled, patched jar for jrendezvous is invalid.
2003-07-30 08:53:30 sethladd1 [Reply | View]
Sorry about that. I'll get it fixed right away.
Thanks! -
jxta, rendevous, jini
2003-08-04 12:38:49 anonymous2 [Reply | View]
hie. just wanted to say i think you would help alot of people if you did a comaprison of the technologies mentioned in the title (if u have insider info on uPnP (MSs Rendevous) that would even be better.
there are so msny technologies coming out that one does not know what to learn and what not to. at time they do the same thing , at other times no.
i am a beginner just learniing java but i am interested in learning how to develop p2p and networked apps (from scratch prefferably then using other people's libraries and frameworks), but with all these technologies its difficult to filter what does what, whats necessasry - whats not, (kind of like the problem i am having deciding between jdo and ejb) -
jxta, rendevous, jini
2003-08-04 16:03:46 sethladd1 [Reply | View]
It's a good question. I responded to something similar above. What specifically would you like me to elaborate on? Maybe I can convince O'Reilly to let me writing an article on the subject, since you're the second person to ask. :) -
jxta, rendevous, jini
2003-08-14 02:10:52 anonymous2 [Reply | View]
Yes, lets get a good article on these technologies. It looks like apple, again have kicked what up to now has very much been in the relm of experimenters and research into the mainstream.
But what can Jini do that Jxta can't and what can they do that Rendezvous can't? (I know you outlined it above, but some more depth would not go amiss).
Come on Oreilly, we need this sort of overview as well as these technical drill downs.






