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!
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
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?
Related
So I am trying to build a .Net Core app that has both REST and gRPC.
Expected results: To have one app running that supports a working REST on one port and gRPC on another.
REST is easy. It's where the app starts. But to configure gRPC's port I saw I needed to create a Server instance:
Server server = new Server
{
Services = { Greeter.BindService(new GreeterImpl()) }
Ports = { new ServerPort("0.0.0.0", 5001, ServerCredentials.Insecure) }
};
server.Start();
That's all fine until we actually put it to use and like any other "Controller" GreeterImpl needs Dependency Injection of services:
private readonly IExampleService _exampleService;
public GreeterImpl (IExampleService exampleService)
{
_exampleService = exampleService;
}
Now the first code snippet will not work since the "new GreeterImpl()" requires an IExampleService.
I searched the web on how to get a ServerServiceDefinition (the thing returned from Greeter.BindService() ) without the use of concrete implementations but found nothing. So, how should this be done or am I on a totally wrong path?
So, I was going at it with the wrong idea. Turns our you can use
app.ApplicationServices.GetService(typeof({YOUR_SERVICE}))
Where "app" is "IApplicationBuilder"
And then just use the resulting service in the ".BindService()".
In the end we don't change the ".BindService()" but pass it a working service to bind.
Important note: You have to register your service first. In my case I used AutoFac to register it
I have requirement to store files uploaded (using spring mvc) from client machine to jboss standalone directory .Give step by step solution
I would give the community project called Spring Content a try. This project makes it very easy to handle files by injecting the service and controller implementations for you (so that you don't need to write them yourself).
Adding it would look something like this:
pom.xml (assuming maven. Spring boot starters also available)
<!-- Java API -->
<!-- just change this depdendency if you want to store somewhere else -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-fs</artifactId>
<version>0.8.0</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>0.8.0</version>
</dependency>
StoreConfig.java
#Configuration
#EnableFilesystemStores
#Import(RestConfiguration.class)
public class StoreConfig {
#Bean
FileSystemResourceLoader fileSystemResourceLoader() throws IOException {
return new FileSystemResourceLoader(new File("/path/to/uploaded/files").getAbsolutePath());
}
}
FileStore.java
#StoreRestResource(path="files")
public interface FileStore extends Store<String> {
}
And that's it. The FileStore is essentially a generic Spring ResourceLoader. The spring-content-fs dependency will cause Spring Content to inject a filesystem-based implementation. The spring-content-rest dependency will cause Spring Content to also inject an implementation if an #Controller that forwards HTTP requests onto the methods of the FileStore service.
So you will now have a fully functional (POST, PUT, GET, DELETE) REST-based file service at /files that will use your FileStore to retrieve (and store) files in /path/to/uploaded/files on your jboss server.
So:
curl --upload-file some-image.jpg /files/some-image.jpg
will upload some-image.jpg and store it in /path/to/uploaded/files on your server.
And:
curl /files/some-image.jpg
would retrieve it again.
HTH
The injected controller also supports video streaming too, in case that is useful.
With this you could also remove all of your controller and service code as it is no longer required. Plus, as Spring Content is an abstraction over storage, in future, you could also shift to any of the other storage mediums supported by Spring Content; S3 for example.
I'm using a Grizzly HttpServer which has two HttpHandler instances registered:
under /api/* there is an Jersey REST - style application offering the API of the product, and
under /* there is an StaticHttpHandler which serves static HTML / JavaScript content (which, among other things, talks to the API under /api/
For authentication I'm currently securing only the API using a Jersey ContainerRequestFilter implementing HTTP Basic Auth, which looks quite similar to what is presented in another SO question.
But as requirements changed, now I'd like to require authentication for all requests hitting the server. So I'd like to move the authentication one level up, from Jersey to Grizzly. Unfortunately, I'm completely lost figuring out where I can hook up a "request filter" (or whatever it is called) in Grizzly. Can someone point me to the relevant API to accomplish this?
The easiest solution would leverage the Grizzly embedded Servlet support.
This of course would mean you'd need to do a little work to migrate your current HttpHandler logic over to Servlets - but that really shouldn't be too difficult as the HttpHandler API is very similar.
I'll give some high level points on doing this.
HttpServer server = HttpServlet.createSimpleServer(<docroot>, <host>, <port>);
// use "" for <context path> if you want the context path to be /
WebappContext ctx = new WebappContext(<logical name>, <context path>);
// do some Jersey initialization here
// Register the Servlets that were converted from HttpHandlers
ServletRegistration s1 = ctx.addServlet(<servlet name>, <Servlet instance or class name>);
s1.addMapping(<url pattern for s1>);
// Repeat for other Servlets ...
// Now for the authentication Filter ...
FilterRegistration reg = ctx.addFilter(<filter name>, <filter instance or class name>);
// Apply this filter to all requests
reg.addMapping(null, "/*");
// do any other additional initialization work ...
// "Deploy" ctx to the server.
ctx.deploy(server);
// start the server and test ...
NOTE: The dynamic registration of Servlets and Filters is based off the Servlet 3.0 API, so if you want information on how to deal with Servlet listeners, init parameters, etc., I would recommend reviewing the Servlet 3.0 javadocs.
NOTE2: The Grizzly Servlet implementation is not 100% compatible with the Servlet specification. It doesn't support standard Servlet annotations, or deployment of traditional Servlet web application archive deployment.
Lastly, there are examples of using the embedded Servlet API here
The "hookup" part can be done using a HttpServerProbe (tested with Grizzly 2.3.5):
srv.getServerConfiguration().getMonitoringConfig().getWebServerConfig()
.addProbes(new HttpServerProbe.Adapter() {
#Override
public void onRequestReceiveEvent(HttpServerFilter filter,
Connection connection, Request request) {
...
}
#Override
public void onRequestCompleteEvent(HttpServerFilter filter,
Connection connection, Response response) {
}
});
For the "linking" to the ContainerRequestFilter you might want to have a look at my question:
UnsupportedOperationException getUserPrincipal
I want to use RequestBuilder to make HTTP requests in my PlayN project as described here:
http://code.google.com/webtoolkit/doc/latest/DevGuideServerCommunication.html#DevGuideHttpRequests
I added the tag in my module xml file:
but I still have the following compilation error:
The import com.google cannot be resolved
Is there something else I should do to make my project compile?
Here is the code:
import com.google.gwt.http.client.*;
...
String url = "http://www.myserver.com/getData?type=3";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// Couldn't connect to server (could be timeout, SOP violation, etc.)
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
// Process the response in response.getText()
} else {
// Handle the error. Can get the status text from response.getStatusText()
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
}
If you're using Maven for your build (which I suspect you may be), make absolutely sure that the following dependency is in your html/pom.xml
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>2.4.0</version>
<scope>provided</scope>
</dependency>
You might need to change the version if you're using a version of GWT other than 2.4.0
Edit: Now that I know you are running a Java application (based on the comments below) and not a GWT application, you're likely going to need to make HTTP requests with something other than GWT's HTTP client. You'll want to remove the aforementioned dependency and take a look at the answers to this question for some insight into how to do that...
If you're needing to make HTTP requests in both the GWT and Java PlayN targets, you're likely going to need to abstract the HTTP client interface needed in the core module and provide the appropriate concrete implementations in the java and GWT modules. I describe using Gin and Guice to inject java and GWT specific instances of AsyncService<> objects in this answer here, and a similar approach can be used in injecting the appropriate HTTP client instance required on a per platform basis if necessary...
I'm a bit confused with what is written in the documentation(s) for Freemarker and Restlet's freemarker extension.
Here's the situation: The restlet engine serves an HTML representation of a resource (e.g. www.mysite.com/{user}/updates). The resource returned for this URI is an HTML page containing all the updates, that is created with a freemarker template. This application is hosted on a Glassfish v3 server
Question(s):
The freemarker configuration should only be loaded once as per the freemarker documentation:
/* You should do this ONLY ONCE in the whole application life-cycle:Create and adjust the configuration */
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(
new File("/where/you/store/templates"));
cfg.setObjectWrapper(new DefaultObjectWrapper());
What is the best place to do this in a Java EE app? I am thinking of having it as context-param in web.xml and using a ServletContextListener - but I'm not sure how to go about doing that.
As per freemarker's documentation we could also add a freemarkerservlet and map .ftl url-patterns to it. But this is already mapped by a Restlet servlet (i.e., the url-pattern of "/"). So having another one for *.ftl doesn't make sense (or does it?)
So the question is basically about how best to integrate with the 'configuration' of Freemarker so that it happens only once and what is the 'entry-point' for that piece of code (who calls it). Has anyone successfully used Freemarker + restlet in a Java EE environment? Any ideas?
Thanks!
This was a tricky question - indeed. Required me to go through the implementation of the source files in org.restlet.ext.Freemarker package - Phew!
Here's how you can do it
If you need to create your OWN Configuration Object, set the 'templateLoader' to use and then have TemplateRepresentation 'work' on it for rendering:
Configuration cfg = new Configuration();
ContextTemplateLoader loader = new ContextTemplateLoader(getContext(),"war:///WEB-INF");
cfg.setTemplateLoader(loader);
TemplateRepresentation rep = null;
Mail mail = new Mail(); //The data object you wish to populate - example from Restlet itself
mail.setStatus("received");
mail.setSubject("Message to self");
mail.setContent("Doh!");
mail.setAccountRef(new Reference(getReference(), "..").getTargetRef()
.toString());
Map<String, Object> data = new HashMap<String, Object>();
data.put("status", mail.getStatus());
data.put("subject", mail.getSubject());
data.put("content", mail.getContent());
data.put("accountRef", mail.getAccountRef());
rep = new TemplateRepresentation("Mail.ftl", cfg, data, MediaType.TEXT_HTML);
return rep;
If you are happy with the default and wish to use a class loader based way of loading the templates
//Load the FreeMarker template
Representation mailFtl = new ClientResource(
LocalReference.createClapReference(getClass().getPackage())
+ "/Mail.ftl").get();
//Wraps the bean with a FreeMarker representation
return new TemplateRepresentation(mailFtl, mail, MediaType.TEXT_HTML);
If you want to initialize the Configuration Object once and set the template by calling the setServletContextForTemplateLoading(...) method on the configuration object. You could always do this in a ServletContextListener
public class Config implements ServletContextListener {
private static Configuration cfg = new Configuration();
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
cfg.setServletContextForTemplateLoading(sc, "/WEB-INF");
}
public static Configuration getFMConfig()
{
return cfg;
}
}
And then call the static getFMConfig() and pass it to TemplateRepresentation as in 1
Things to note:
If you do get a protocol not supported Exception it'll be in case 2. Implies that the ServerResource doesn't know what protocol to use to access the file - It'll be the CLAP protocol of Restlet. You may have to set up the init-params for RestletServlet in the web.xml file and have CLAP as one of the param-values
The TemplateRepresentation has quite a few constructors - if you DON'T pass in a configuration object during instantiation (using another overloaded constructor), it will create a new Configuration() for you. So you don't have to do any configuration set up as in 2 (This may strike you as obvious but I assumed that you WOULD still need to set a configuration or it would 'pick it up from somewhere')
If you DO wish to have your OWN configuration setup you MUST pass it to one of the constructors
Have a look at the "war:///" string in the constructor of ContextTemplateLoader in 1. this is important No where is it mentioned what this baseUri reference should be, not even in the docs. I tried for quite a while before figuring it out that it should be "war:///" followed by the folder name where the templates are stored.
For case 2 you'll probably have to store the templates in the same package as the class file from where this code is accessed. If you see carefully you'll notice a LocalReference parameter as an argument to ClientResource saying that the resource is supposed to be locally present and thus you need to use the custom CLAP protocol (classLoader Access Protocol)
Personal Frustration point - why isn't all this even clarified in the documentation or ANYWHERE :)
Hope it helps someone who stumbles upon this post! Phew!