Collaboration from PlayN client with server
Asked Answered
F

2

2

I have written a game in PlayN, which has to communicate with a JavaEE-Server with Seam. First of all I only need the game running in HTML5.

The current issue is the communication between the PlayN-client and the JavaEE-Server

1) First I tried to communicate over the PlayN.net() interface exchanging information using JSON. Since PlayN is running on port 8888 and the server on 8080 I correctly run into problems with the same-origin-policy.

2) Now I'm looking for a working solution. Which one would you recommend? Do you have other ideas?

a) I'm trying to work with RPC as described in How to handle RPCs in client-server PlayN game? , using GWT-syncproxy.

b) I try that playN runs on the same port as the server i.e. 8080 - so I don't have problems with the same-origin-policy any more. Question: Can the HTML5 playN app run on the same port? So when I start the JavaEE-Server using Eclipse it should also start the PlayN web application, both on port 8080, right?

Is this possible?

c) The most hacky solution (currently working): The server writes the JSON-String into a file and the playN client reads this file out.

What do you recommend? I'd like to implement solution 2, since it is the cleanest solution, but I don't know how hard it is and how it works.

Thanks for your help!

Familiarity answered 29/1, 2012 at 14:10 Comment(1)
there is also a discussion here about the best approach: groups.google.com/group/playn/browse_thread/thread/…Familiarity
S
3

I think the problem is that you are "running" PlayN, separated from your Seam server.

If I understood you correctly, you execute the Maven task to run your game as HTML and on the other hand you run Jboss (or whatever Java EE server), what you should do is run

mvn package

which will create the war of the game, and then publish that war on your Java EE server, then you can use the PlayN.net package with no problems whatsoever, running in a single server

Stabilize answered 30/1, 2012 at 12:35 Comment(1)
Thank you, very helpful. I was able to create the war of the game and deployed it to the server. No I can communicate without any problems using PlayN.net() ;)Familiarity
B
2

This is how we currently handle our client / server communication. We are using a stateless JavaEE architecture and provide everything as REST services. This allows us to scale horizontally by adding more servers and simply adding them to the cluster entry in the Glassfish config.

However due to missing reflection or a working JSON lib, it forces us to implement a toJson()method in every data transfer object BY HAND (be carfull with case sensitivity). We added our server project as a module to the PlayN metaproject and added the core as a dependency to the server. So you can place every DTO on the core project (which is quite awesome). Placing them on the server results in people trying to annotate the classes as entities, which will result in failure during the html build. I am currently thinking about adding a shared project to the build, like in GWT projects.

This is how we send data to the server (for this example without any abstraction, do yourself a favor and implement one):

private void loadMapFromServer() {
    SessionDto session = this.main.getSessionCtrl().getSessionMdl();

    PlayN.net().post("http://localhost:8080/server/rest/map/mapMdl",
        session.toJson(),
        new Callback<String>() {

            @Override
            public void onSuccess(String result) {
                mapMdl = new MapDto();
            }

            @Override
            public void onFailure(Throwable cause) {
                PlayN.log().error("fail " + cause.getMessage());
            }
        });
} 

Notice how we bastardize the POST argument with session.toJson(). This is because of the missing MIME type feature and passing JSON strings via GWT will fail. And this is how it looks on the server:

package com.fact.server;

//I also posted the imports, for clarity.
import com.fact.core.map.MapDto;
import com.fact.core.user.SessionDto;
import com.fact.server.game.map.MapCtrl;
import com.google.gson.Gson;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.log4j.Logger;

@Stateless
@Path("/map")
public class MapSrvs {

@Inject
Logger logger;

@Inject
MapCtrl mapCtrl;

Gson gson = new Gson();

@POST
@Path("/mapMdl/")
@Produces( MediaType.APPLICATION_JSON )
public MapDto getMapMdl(String sessionDtoStr) {
            //logger.info("map was requested: " + sessionDtoStr);

    // Use gson to deserialize the class. Jersey would do this, if PlayN
    // would allow to set a correct MIME type (and @Consumes was set).
    // We could simply write: getMapMdl(SessionDto sessionDto)
    SessionDto sessionDto = gson.fromJson(sessionDtoStr, SessionDto.class);
    if(sessionDto == null) {
        return null;
    }

    // [...] check for a valid session

    MapDto mapMdl = new MapDto();
    mapMdl.foo = "message from server";
    return mapMdl;
}   
}

This would be a bit nicer, if PlayN would allow you to set the MIME type, so that you won't have to cast the String using Gson. However this works quite well. We use Jersey on the server side to handle all the REST stuff. To get it running I had to put the following into the web.xml:

<servlet>
    <!-- We need jersey for the REST stuff -->
    <servlet-name>jersey-serlvet</servlet-name>
    <servlet-class>
        com.sun.jersey.spi.container.servlet.ServletContainer
    </servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.fact.server</param-value>
    </init-param>
    <init-param>
        <!-- This took me hours to find :(. It is needed to automatically
        map POJOs to JSON code. -->
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>jersey-serlvet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

Also Jersey is already included into the Java-EE-Api, so it works out of the box. I hope this helps. If anyone knows how to do client side JSON parsing , please look at this question: How do I convert a POJO to JSON in PlayN?

Belovo answered 30/1, 2012 at 22:33 Comment(1)
I suspect that with GWT, if you could've used the GWT RPC mechanism instead of a json rest api, things would've been much much easier. And you still would be able to keep the server stateless (pass in token as part of the GWT rpc call). Each to his own - some people don't like an opaque api like GWT rpc, and I respect that.Cinereous

© 2022 - 2024 — McMap. All rights reserved.