views:

134

answers:

3

How do I implement a java socket in tapestry5? What I want to do is create a socket which I can send an XmlHttpRequest over, through a piece of javascript code.

function sendPost(url, postdata, callback) {

 xmlHttp=GetXmlHttpObject()

 if (xmlHttp==null) {
  alert ("Browser does not support HTTP Request")
  return
 } 

 xmlHttp.onreadystatechange=callback
 xmlHttp.open("POST",url,true)
 xmlHttp.send(postdata);

}

Where the URL is the socket i have just created.

A: 

Use of Sockets is independent of your webapp view framework - you would do it pretty much the same way regardless of how the view is coded. The only thing that changes is once you've implemented your code that uses sockets, is how that's invoked.

I used tapestry with spring, and so injecting services into the spring context is the most natural approach.

The services subpackage in tapestry is mostly for creating implementations that plug into tapestry, like encoders, property conduits, and binding factories. So whether you use this or not depends upon what you are trying to achieve.

For example, if you are creating a component that reads from a socket, and renders the data read in, then you can create that as a regular component, in the components subpackage.

mdma
What I want to do is create a socket which I can send an XmlHttpRequest over, through a piece of javascript code.as the followingfunction sendPost(url, postdata, callback){ xmlHttp.open("POST",MYSOCKET,true); xmlHttp.send(postdata);}where MYSOCKET is the java socket i have created!any help would be great!
shane87
You want to open a socket from the user's browser? That's wasn't clear from your question. You can implement your own component - you can pretty much render anything in that space, including javascript. See http://wiki.apache.org/tapestry/Tapestry5AndJavaScriptExplained for how to create tapestry components that output javascript.
mdma
Sorry I probably didn't phrase it properly I have since rephrased my question.
shane87
A: 

The XmlHttpRequest will just do a web server request which can be handled perfectly well by whatever you use to run Tapestry in. There is no need to open sockets and stuff.

Just define a route in your wep application to accept the XmlHttpRequest and have a handler, servlet, controller, ... collect the necessary data, transform it to xml and send it to the Javascript component.

I found an example here

Peter Tillemans
+1  A: 

So you want to do an AJAX request from your client code to the server, recieve a response and process it in some way? You will not need sockets. Instead, use Tapestry's built-in AJAX functionality.

If you're loading additional content inside your page via Javascript, chances are you will not need to write any code at all. Be sure you have read the AJAX section from the Tapestry docs, and you understand what a Zone is and how it works.

Here's a basic example. Template:

<div id="myZone" t:type="Zone" t:id="myZone">
      ... [Initial content, if any] ...
</div>

<a t:type="ActionLink" t:id="updateContent" t:zone="myZone">Update</a>

And class:

@Inject 
private Zone myZone;

@Inject
private Request request;

@OnEvent(component = "updateContent")
Object updateContent() {
     ... [your code] ....

     if (this.request.isXHR()) {
         return this.myZone.getBody();
     } else {
         return this;
     }
}

Tapestry will do everything else, like registering the proper event listener on the link and inserting the updated content in the proper place. The if (this.request.isXHR()) makes sure your page will degrade gracefully for clients without JavaScript enabled.

If you'd like to do something else entirely, like returning a JSON object and processing it with your own JavaScript code, you can return any of these JSON classes from your event handler.

Also, if you want to write your own client-side code, be sure to use the built-in, cross-browser AJAX functionality of Prototype, which ships with Tapestry.

Edit based on comment:

You won't be able to access a different server (host + port) through AJAX because of the same origin policy. You could, however, proxy the call through your Tapestry app. I've modified my code to illustrate this (assuming the thing listening on port 2112 is an HTTP server, otherwise change as needed):

@OnEvent(component = "updateContent")
Object updateContent() throws IOException {
     final URL url = new URL("http://localhost:2112");
     final HttpURLConnection con = url.openConnection();

     final String content;

     InputSteam input = null;
     try {
         input = con.getInputStream();
         content = IOUtils.toString(input);
     } finally {
         IOUtils.closeQuietly(input);
     }

     return new StreamResponse() {
         @Override
         public String getContentType() {
             return "text/javascript";
         }

         @Override
         public InputStream getStream() throws IOException {
             return new ByteArrayInputStream(content.getBytes("UTF-8"));
         }

         @Override
         public void prepareResponse(Response response) {
             response.setHeader("Expires", "0");
             response.setHeader("Cache-Control",
                 "must-revalidate, post-check=0, pre-check=0");
         }
     }
}
Henning
@Henning: Thanks for your help again. You helped me with a previous question here - http://stackoverflow.com/questions/2801879/how-do-i-create-a-custom-text-field-in-tapestry5-that-renders-some-javascript-ont - What I have is a javascript mixin which runs when a text field gains focus. The javascript mixin should send requests to a jar listening on a port which returns XHR responses which are decoded and drawn onto the HTML canvas element on the page. Numerous request and responses are required!.Should I use tapestrys built in AJAX support.?
shane87
@shane: So you want to poll data from another server and display it? I'm afraid that's not going to work, you can only request from the same domain and port (see http://en.wikipedia.org/wiki/Same_origin_policy). If you must access a second web server, you'll have to do it on the server side, i.e. have your Tapestry app make the request and relay it to the client.
Henning
@Henning: I have a jar and when I run it, it sits and listens for reuests on port 2112. I want to open up a socket connection to that jar, to send the XHR requests. The jar then responds with an XHR response and my javascript will decode this response and draw onto the HTML canvas element!. Sorry I probably dont articulate my questions to good. Hope that makes it a bit clearer!
shane87
@Shane: I've updated my answer.
Henning
@Henning: The thing/jar listening on port 2112 is a ServerSocket. This is why I want to create a clientSocket which forwards information from my piece of javascript which is neccessary for my application to work. So I dont think it is a problem with the same origin policy.
shane87
@Shane: There are no raw sockets available in Javascript, you must work over HTTP. (You previously indicated you wanted to use XmlHttpRequests...?).Also, localhost:2112 counts as a different origin than localhost:8080 or whatever your app server is using, so there *is* a same origin issue, I'm afraid.Using XHRs to get from the client to your app and doing the socket stuff there is your best option.
Henning
@Henning: Thanks hopefully I'll get it sorted that way.
shane87