AMF/JAX-RS questions (some general, some Enunciate-specific)
-
25-02-2021 - |
Domanda
Please forgive me if any of this is wrong -I'm completely new to Java. My task is to set up the client/server architecture for an upcoming Facebook game. On the server-side, I have:
- Java
- Tomcat
- RestEasy
- BlazeDS
- Enunciate
All held together with Maven. I can annotate RESTful endpoints with @Path() and they will spit out objects serialized in AMF when I hit them in the browser. So far so good. Now I need to consume these endpoints on the client/Flex-side. Enunciate has generated AS files for the types I have annotated with @XmlRootElement in Java, and I can use these types in my AS3 code. The problem is that hitting REST endpoints in AS3 is pretty ugly. It looks something like this:
function resourceRetrieved(event:Event):void {
var stream:URLStream = URLStream( event.target );
var resource:SomeJavaClass = ( stream.readObject() as SomeJavaClass );
lblResult.text = resource.message;
}
var request:URLRequest = new URLRequest("http://localhost:8080/rest/somefunc");
request.method = URLRequestMethod.GET;
var variables:URLVariables = new URLVariables();
variables.message = "This is my test string!";
request.data = variables;
var resourceStream:URLStream = new URLStream();
resourceStream.addEventListener("complete", resourceRetrieved)
resourceStream.load(request);
Ugly -and I have to write this by hand in order to get the benefits of strong typing. However! I noticed when digging through the source code that if the @WebService and @WebMethod tags are used instead of @Path, wonderful strongly-typed AS3 wrappers for my service classes are generated by Enunciate, along with corresponding AS3 events. It also generates the correct services-config.xml! The usage then becomes something like this:
function onSomeFuncEvent(event:SomeJavaServiceEvent):void {
lblResult.text = event.result;
}
var service:SomeJavaService = new SomeJavaService();
service.addEventListener( SomeJavaServiceEvent.SomeFuncEvent, onSomeFuncEvent );
service.someFunc("This is my test string!");
As you can see, the consumer of the generated code does not need to know where the endpoint is, what types are returned from the events, etc. I would like to go this route because I believe it will be easier to maintain. That brings me to my questions:
- Why are the wonderful Service and ServiceEvent objects only generated for @WebService and @WebMethod (which the Internet tells me is JAX-WS) but not @Path? Is it work that hasn't been done, or work that can not be done given the spec differences between JAX-RS and JAX-WS? (I see that the as3-endpoint.fmt is specifically only applied to @WebService in the code)
- Am I wrong in wanting to use REST here? The Java/Tomcat/RestEasy/BlazeDS stack was recommended by my CTO but it seems to me (after fiddling for a day or two) that BlazeDS/Flex don't get along that well with REST.
- Is there a Java->AMF->Flex stack I should be considering?
Thank you for your time, and again I am sorry if these are obvious issues. My background is in game development, not web development.
Soluzione
Why are the wonderful Service and ServiceEvent objects only generated for @WebService and @WebMethod (which the Internet tells me is JAX-WS) but not @Path? Is it work that hasn't been done, or work that can not be done given the spec differences between JAX-RS and JAX-WS? (I see that the as3-endpoint.fmt is specifically only applied to @WebService in the code)
It's work that could be done, but hasn't yet. And there's an unanswered question of whether it should be done.
REST is hard. Service-oriented APIs (e.g. SOAP, AMF) are much more intuitive to developers. JAX-RS has made creating REST APIs easy to do, but at the cost of giving developers more rope to hang themselves with. More specifically, JAX-RS makes it easy to create HTTP-based APIs, but just because it's using HTTP doesn't make it REST. For a better understanding of what I'm talking about I'd suggest Martin Fowler's essay on the Richardson Maturity Model:
http://martinfowler.com/articles/richardsonMaturityModel.html
So there's a lot more to REST than just making an HTTP request and parsing the response. By extension, there is a lot more to creating a client-side service that calls a JAX-RS resource (i.e. @Path) than just wrapping HTTP calls in a convenient AMF service class. Cacheing, layering, HATEOAS, etc., etc., all come into play and would have to be "hidden" in a client-side service generated by Enunciate.
Am I wrong in wanting to use REST here?
You're not wrong but it appears that you might be underestimating what it means to "use REST". So IMO, you've got two options:
- Just create a service-oriented API using JAX-WS.
- Go learn what REST really is and how to really apply it to your problem space. And don't underestimate the complexity in this. REST is hard.
The Java/Tomcat/RestEasy/BlazeDS stack was recommended by my CTO but it seems to me (after fiddling for a day or two) that BlazeDS/Flex don't get along that well with REST.
Perhaps. At least one thing is for sure: the designers of BlazeDS/AMF weren't thinking REST when they designed their stack.
Is there a Java->AMF->Flex stack I should be considering?
BlazeDS and GraniteDS are the only two I can think of. They're both good IMO, so just take your pick.