|
Project Information
Members
Featured
Downloads
Links
|
Xeerkat is a P2P computing framework that utilizes XMPP as a communication protocol. The basic model is that of a agent computing where an agent runs a number of services that available to peers. Each service is available over both HTTP and XMPP. A service is a rest-style service that can communicate using any web-oriented protocol and implemented as a Restlet Application. This allows reuse of any Restlet implementation as a agent service. An agent-oriented set of services are provided throught Restlet context to facilitate building services. News
StatusThe current code base is very stable an usable for applications. The only major missing feature is better discovery mechanisms. The current code relies upon presence management and works well in situations where every "worker" agent knows a common "broker" agent". Those workers who have the same broker agent will know about each other by periodically checking with the broker agent. The current version is 2.1.0 and now uses an installer. Just double-click on the jar file or type: java -jar xeerkat-2.1.0.jar HistoryThe Xeerkat project grew out of a P2P grid computing project that originally used JXTA. Eventually issues with JXTA forced a re-examination of what technologies were needed. As each peer is actually on the edge, XMPP was a good choice for a communication technology. The project was originally hosted as xeerkat at java.net and was moved to this project. The original code is available there with the JXTA support and that is considered the "1.0" version. This code has been completely refactored and removes many of the restrictions to XML and opens up the ability to create P2P REST-oriented services. Underneath, XML is used as appropriate in the XMPP transport. XMPP URI ReferencesXeerkat uses URIs to tunnel requests over XMPP. The general format of the URI is: xeerkat://{sender-id}/{sender-resource}/{receiver-id}/{receiver-resource}/{path}The final {path} part of the URI is the same path as the service over HTTP. For example, if the 'status' service is available from: http://localhost:8080/status then for sender 'test@talk.example.com' and agent host 'peer@talk.example.com', that same service is available (depending on resource names) at: xeerkat://test@talk.example.com/shell/peer@talk.example.com/agent/status You can also omit the resource of the receiver: xeerkat://test@talk.example.com/shell/peer@talk.example.com//status As the local client makes a connection to the XMPP server as themselves, the "host" information is the local connection and that's why the URI starts with your XMPP id. Since XMPP messaging is asynchronous, a client can use the sxeerkat scheme to simulate a synchronous request. Documentation
A Distributed Ping ExampleThe simplest test infrastructure is distributed ping where an single agent is going to "ping" other agents for a certain number of times. All Xeerkat services are just Restlet Application instances and so we need to do is write a simple Restlet Application and then package it for the agent. The main part of a Application in Restlet is the createRoot method. Here we'll create a Router to route requests:
public Restlet createRoot() {
// Create a router for the root of the application
Router router = new Router(getContext());
and then we'll create a main restlet for processing ping requests:
Restlet main = new Restlet(getContext()) {
public void handle(Request request, Response response) {
}
}
and then we attach it to the router:
router.attach("",main);
router.attach("/",main);The two attach statements above let the service respond to ping and ping/. The service receives an XML message with the number of requests. We won't bore you with the details of parsing the XML. Once the number is known, all that is necessary is to loop until a maximum time has been reached or the number of pings have been received. That code looks like: // loop till we've timed out or received all the responses
while(stat.received<stat.requested && (System.currentTimeMillis()-stat.start)<maxWait) {
// If there are no other agents, we can't ping anyone and so we'll pause
if (agentContext.getAgentMonitor().getAgents().size()==0) {
long amount = amount = 3*tick;
getLogger().info("No agents, waiting "+amount);
try {
Thread.currentThread().sleep(amount);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
// Send pings to all agents
int sent = 0;
for (String id : agentContext.getAgentMonitor().getAgents()) {
// We're using the async protocol
String uri = "xeerkat://"+self+"/"+id+"/ping/echo";
getLogger().info("Pinging "+uri);
// Make a GET request on the rest service for echo
Response pingResponse = client.get(uri);
// Success means we could send the request and not much more
if (pingResponse.getStatus().isSuccess()) {
sent++;
// Get the id and add a listener for the response
Form headers = (Form)pingResponse.getAttributes().get("org.restlet.http.headers");
String responseId = headers.getValues("x-response-id");
agentContext.registerResponseListener(responseId,new ResponseListener() {
public void onResponse(String id,Response response) {
stat.received++;
// mark the moment we've satisfied the request
if (stat.received==stat.requested) {
stat.finished = System.currentTimeMillis();
}
}
});
} else {
getLogger().info("Cannot ping "+id+", status="+pingResponse.getStatus().getCode()+", "+(pingResponse.getEntity()==null ? "(no text)" : pingResponse.getEntity().getText()));
}
}
// If we couldn't send anything, pause
if (sent==0 && agentContext.getAgentMonitor().getAgents().size()>0) {
try {
Thread.currentThread().sleep(tick);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
getContext().getLogger().info("Tick: "+(System.currentTimeMillis()-stat.start));
}
}The response is then generated by: // We're done, send the response
response.setStatus(Status.SUCCESS_OK);
response.setEntity(new StringRepresentation("<stats requested='"+stat.requested+"' received='"+stat.received+"' time='"+(stat.finished-stat.start)+"' elapsed='"+(System.currentTimeMillis()-stat.start)+"'/>",MediaType.APPLICATION_XML));Now, pings are received at "/ping/echo" and so we just define a simple restlet to handle them: router.attach("/echo",new Restlet(getContext()) {
public void handle(Request request, Response response) {
response.setEntity(request.getEntity());
response.setStatus(Status.SUCCESS_OK);
}
});The neat bit here is that all these resources are available over both HTTP and XMPP. The last step is to package the service for the agent. The agent currently requires the service to packaged as a separate jar file. At the root of the jar file there must be an 'application.xml' resource that looks like: <application xmlns='http://www.xeerkat.org/Vocabulary/Services/2007/1/0' class='org.xeerkat.services.ping.PingApplication'/> That's it. The full source is available from subversion as PingApplication.java. |