- Protocol and API
- JXTA Goals
- JXTA Peer and Java
- Overview of the JXTA Protocols JAVA API
- Summary of Java API for JXTA Protocols
- Where JXTA Applications Begin
- The Peer
- Starting JXTA
- Peer Discovery Protocol API
- Peer Resolver Protocol API
- Peer Information Protocol
- Peer Membership Protocol
- Pipe Binding Protocol API
- Peer Endpoint Protocol
Peer Endpoint Protocol
Peer endpoint routing is not really a public API. Endpoint routing is used to enable pipes or simplistic messaging, such as that found in the peer info, peer resolver, and pipe binding protocols.
The EndpointService class provides a front-end API and environment to all endpoint protocols. Applications can use the Endpoint API directly to control or examine the topology of the JXTA network. The Endpoint API would normally be used to help implement a new endpoint protocol.
We will only touch on a few aspects of this protocol. The more interesting functionality to most JXTA developers is how routes are formed.
Use in Applications
In Chapter 2, we talked about the many reasons for routing in JXTA. You do not need to worry about using the actual protocol in your application. For example, the pipe binding protocol uses the Peer endpoint protocol to build routes. As a result, there is no need to supply the pipe with a route, just the other endpoint.
There are reasons for using the protocol directly if you are writing your own implementation of a pipe or other method of P2P communication. Knowing the protocol is also very important for understanding how routes are built.
Accessing the Service
To access the endpoint service, you get the service from your peer group as in the following line:
The EndpointService interface (shown in Figure 3.23) contains multiple and very useful methods:
addEndpointProtocolThis method allows us to add a new type of communication protocol.
addFilterListenerUsed to add a listener to filter endpoint messages.
addListenerUsed to listen for messages to a specific endpoint address.
demuxUsed to de-multiplex a message. Given an incoming message this method calls the appropriate listener by the destination returned by the getDestAddress() method of the message.
getEndpointProtocolByNameThis is a convenience method used to fetch an endpoint protocol.
getEndpointProtocolReturns an enumeration of endpoint protocols.
getGroupReturns the group of which this service is a member.
GetMessengerCreates an EndpointMessenger given an EndpointAddress. The messenger is used to send messages to the specific address defined by the EndpointAddress.
newEndpointAddressCreates a new endpoint at a specific URI.
newMessageCreates a message to be used to send a message to an endpoint.
pingUsed to determine if a peer exists.
propagateUsed to continue sending the message to other peers.
removeEndpointProtocolUses to remove a protocol that is no longer valid.
removeEndpointListenerUsed to remove the endpoint listener.
removeEndpointFilterListenerUsed to remove the endpoint filter listener.
Figure 3.23 UML of EndpointService interface.
The filter is a fun and useful part of the endpoint API. What the system allows you to do is snoop on any of the messages in the system. You simply specify an XML tag name, the listener, and a Boolean that specifies whether you are interested in oncoming or outgoing messages.
The following is the method from the EndpointService interface:
void addFilterListener(String elementName, EndpointFilterListener listener , boolean incoming) throws IllegalArgumentException;
There is also an equivalent remove method:
void removeFilterListener( String address , EndpointFilterListener listener , Boolean incoming);
The listener is easy to use, as you can see by the UML diagram in Figure 3.24. The method gives you the message, the source address, and the destination address. Of course, the purpose of the listener is to filter messages. Consequently, the return value is a message. Normally, you would either modify the message or return a null if the message is to be blocked.
Figure 3.24 UML of EndpointFilterListener interface.
One of the more interesting messages to listen for with the EndpointFilterListener is the EndpointRouterMessage. The message is used to build a path between gateway peers to connect endpoints. By looking for these messages, you can determine the route.
Figure 3.25 UML of EndpointRouterMessage interface.
The messages that are passed between peers are the EndpointRouterQuery, EndpointRouterAnswer, and the EndpointRoute messages. Note that the EndpointRouter class is the source of these messages.
The query is used to request a route, and the answer is a response that contains a route to the destination peer. Note that there is no guarantee that there is a route to the peer, and you may not get the answer message.
The DTD specification for the EndpointRouterQuery message is as follows:
<!ELEMENT EndpointRouterQuery (Credential, Dest, Cached)> <!ELEMENT Credential #PCDATA> <!ELEMENT Dest #PCDATA> <!ELEMENT Cached #PCDATA>
The DTD specification for the EndpointRouterAnswer message is as follows:
<!ELEMENT EndpointRouterAnswer (Credential, Dest, RoutingPeer, RouterPeerAdv, Gateway)> <!ELEMENT Credential #PCDATA> <!ELEMENT Dest #PCDATA> <!ELEMENT RoutingPeer #PCDATA> <!ELEMENT RouterPeerAdv (PeerAdvertisement)> <!ELEMENT Gateway #PCDATA>
The DTD specification for the EndpointRoute message is as follows:
<!ELEMENT EndpointRoute (Src, Dest, TTL, Gateway)> <!ELEMENT Src #PCDATA> <!ELEMENT Dest #PCDATA> <!ELEMENT TTL #PCDATA> <!ELEMENT Gateway #PCDATA>
Another useful method is ping. The method, shown next, simply takes an endpoint address and returns a Boolean value of true if the address can be reached:
boolean ping (EndpointAddress addr);
The ping method is not as useful as the ping you are used to in normal networking. This ping does not return any useful information; it only lets you know that can reach the peer. The actual processing may also be much different. For example, the ping method may return true if the peer knows about the peer in some endpoint protocols. In HTTP, you do not ping the client because you really can't do so. Remember that the HTTP client must initiate the connection. If you did this, you have no reasonable guarantee that the client will check the gateway any time soon. So, for the sake of time and effort, you assume you can talk to an HTTP endpoint if you find its gateway.
Given how an HTTP ping works, the quality of the ping method may seem suspect compared to a traditional network ping that always connects to a machine if successful. However, the usefulness of ping is that it is implemented by each of the protocols. This essentially gives you a transmission protocol-independent ability to test for an endpoint. In JXTA, this is the primary goal, so other aspects, such as the actual connection or timing, is less important. Simply put, ping is less a network ping than a test for existence according to the protocol implemented by the endpoint.
Depending on the protocol of the endpoint, you may be able to sniff a returning ping message with the filter listener. You should look at the specific implementation of the protocol to understand what the message looks like.
If you are looking for a traditional ping, you will need to implement it yourself. Your ping will only work with peers in your group with your ping code.
One method of the EndpointService interface that is very useful for applications is getMessenger. The getMessenger method takes an endpoint and returns an object that implements an EndpointMessenger interface. The EndpointMessenger (UML seen in Figure 3.26), has two methodsclose and sendMessage. Messages sent via the sendMessage method are processed by an EndpointListener that will be covered in a moment.
Figure 3.26 UML for EndpointMessenger interface.
The EndpointMessenger should seem very familiar to you from the previous discussion of output pipes. The simple fact is that a pipe can use the EndpointMessenger code implemented by the endpoint.
To get an endpoint messenger, you must first create an endpoint address. You do this with the following method in the EndpointService:
EndpointAddress newEndpointAddress (String uri);
The URI in this case is a unique string. The URI consists of a unique identifier that should be distinguishable between groups and services. For example, you could use the peer group ID and a service name like Message Queue. You could further refine the address by concatenating the peer group id, the service name, and a third parameter, such as a sequence number. In this way, you could create multiple addresses on a single endpoint. This is similar to how you would implement a type of pipe and create multiple pipe connections.
To retrieve the messenger, you supply the EndpointAddress object you created with the newEndpointAddress method, as seen by the following method signature from the EndpointService interface:
EndpointMessenger getMessenger (EndpointAddress addr) throws IOException;
Where Is the Router?
You might ask, if this is the endpoint router, where is the router? The router is deep in the bowels of this API and is actually a part of the platform as a module. The getMessenger method eventually results in the execution of methods to obtain a route between peers. The UML for the EndpointRouter is shown in Figure 3.27.
You can access the EndpointRouter by calling the loadModule method on your peer group. The following is an example that creates a router for a peer group:
EndpointRouter router; router = peerGroup.loadModule( "net.jxta.impl.endpoint.EndpointRouter" , Platform.refRouterProtoSpecID , PeerGroup.Both);
Figure 3.27 UML of EndpointRouter class.
Note that there is no need to access the router in your code. The router is access via other classes in the JXTA API.
There is another listener interface you can use. The addListener method in the EndpointService interface adds an incoming message listener to a specifically named address that is usually formed by concatenating the name of the invoking service and a parameter unique to that service across all groups.
The listener is called when you send a message through an EndpointMessenger to an EndpointAddress constructed with matching serviceName and serviceParam.
The address parameter is really the same string used to create the EndpointAddress. Although the parameters are called two different things, uri and address, they are the same thing (expect the parameter names to be one or the other in a future version).
The following is the method signature from the EndpointService interface:
public void addListener( String address , EndpointListener listener ) throws IllegalArgumentException;
The method may throw an IllegalArgumentException if the address is deemed incorrect by the protocol.
The EndpointListener interface is shown in Figure 3.28.
Figure 3.28 UML of EndpointListener interface and EndpointAddress class used to process endpoint