Pages

Showing posts with label Rich Client. Show all posts
Showing posts with label Rich Client. Show all posts

Friday, March 8, 2013

GWT Chrome extension with JSONP Server communication

I thought this post would be a good idea for people who want to know how to make an 'end-to-end'
GWT Chrome extensions, with a connection to a server of their own.

While this demonstrates specifically how to enable to communication from a Chrome extension, there is
no difference in code if you wish to deploy your client code else where (not on Chrome).
Many web applications choose to deploy their Server code & Client code on the same application server, like JBoss or Tomcat.

As you know in GWT there are several ways to communicate with a server.
One of them is RPC for instance, which gives you the ability to invoke methods on a Java interface,
not having to deal with anything but Java code. Which is cool, as it makes a very smooth transition from
the client side code to the server side code.

However, when we want to implement this in a Chrome extension things get a bit trickier.
The reason is that you'd have to separate your server module from your Chrome extension module
(as we can't deploy Server side classes to Chrome - it runs only JavaScript),
and would need a shared model between the two in order to communicate.
It's not hard to do at all, it's only a longer example to make.
(In Eclipse, if you create a new "Web Application Project" using Google's plugin, you will have the client & server code in the same project, with a "shared" directory which serves a model bridge between the two).

Another option that exists, is using JSONP communication to the server.
In our case - this makes it a lot simpler.
We will expose some REST API on a Server we'll implement, for getting images, and send a JSONP request from the QuickPik extension to retrieve those images. Obviously, it can be anything else you want it to be in your application.

TO THE CODE!!!

The Server

In order to create a REST service and expose it, we will use the Jersey library which is an implementation for
building RESTful web services. It's very simple.

The following QuickpikService class, is our REST service:



package quickpik.server.web;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

import com.sun.jersey.api.json.JSONWithPadding;

@Path("/quickpik")
public class QuickPikService {

private final static int BUFFER_SIZE_IN_BYTES = 1024;
private final static String FLICKR_API = "http://api.flickr.com/services/feeds/photos_public.gne?format=json&tagmode=all&tags=" ;

@GET
@Path("searchPhotos")
@Produces({ "application/x-javascript", MediaType.APPLICATION_JSON})
public JSONWithPadding getPhotos(@QueryParam("searchExp") String searchExp,
@QueryParam("callback") String callback) {
// "log" the call
System.out.println("[" + new Date() + "] searching for: " + searchExp) ;
URL flickrUrl = getSearchURL(searchExp) ;
JSONObject data = tryToGetSearchResult(flickrUrl);
return new JSONWithPadding(data, callback);
}

private URL getSearchURL(String searchExp) {
String composedURL = FLICKR_API + searchExp;
try {
return new URL(composedURL);
} catch (MalformedURLException e) {
e.printStackTrace();
throw new RuntimeException("URL composition failed. Please check your URL: " + composedURL, e) ;
}
}

private JSONObject tryToGetSearchResult(URL flickrUrl) {
try {
return getSearchResult(flickrUrl) ;
} catch (IOException | JSONException e) {
e.printStackTrace();
throw new RuntimeException("Failed searching.", e) ;
}
}

private JSONObject getSearchResult(URL flickrUrl) throws IOException, JSONException {
InputStream is = flickrUrl.openStream() ;
String result = readDataFromStream(is);
// Flickr specific string prefix for the JSON feed.
if(result.indexOf("jsonFlickrFeed(") >= 0) {
result = result.substring("jsonFlickrFeed(".length(), result.length()-1) ;
return new JSONObject(result) ;
} else {
return new JSONObject("{}") ;
}
}

private String readDataFromStream(InputStream is) throws IOException {
StringBuilder data = new StringBuilder() ;
byte[] buffer = new byte[BUFFER_SIZE_IN_BYTES] ;
int bytesRead = is.read(buffer) ;
while(bytesRead != -1) {
data.append(new String(buffer, 0, bytesRead)) ;
bytesRead = is.read(buffer) ;
}
is.close() ;
return data.toString() ;
}
}



That's it. This our REST service, and we are exposing our API by using the @Path annotations
on the class and on the public method getPhotos. There are also other annotations such as the
@GET annotation and the @Produces annotation which state that the method is invoked on
an HTTP GET, and returns (@Produces annotation) a JSON (with Padding eventually = JSONP) object.

As you can see, in the class, we are using a Flickr API to get our images data from.

Now all that's left in order to make this service work, is to define the Jersey servlet in the web.xml file,
which is done this way:


<web-app>
...

        <servlet>
    <servlet-name>Jersey REST Service</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>quickpik.server.web</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

...
</web-app>


After doing that, we're able to refer to our REST service by using a URL in the browser:
http://localhost:8080/<web-app-name>/rest/quickpik/searchPhotos?searchExp=<our-search-term>

In order to verify this worked indeed and to get a better understanding of how the strucutre of our JSON result looks like, before even writing code to the GWT Chrome extension client,
i did a small test using jQuery, to see whether this worked. - You can find it in the GitHub repository.
What I did in a nutshell, was to call the REST API:
$.getJSON('http://localhost:8080/qpserver/rest/quickpik/searchPhotos?searchExp=hello&callback=?', jsonCB);

So I executed an AJAX call to search for "hello", and passed a callback - jsonCB to process the result.
jsonCB looks like this:


function jsonCB(result) {
console.log(result);
if (result !== null && result) {
if (result.items.length === 0) {
$($("#serverResponses")[0]).append("No results.")
} else {
for (item in result.items) {
var url = result.items[item].media.m;
var imgItem = document.createElement('img');
imgItem.src = url;
$($("#serverResponses")[0]).append("Server response: ")
.append(url).append("<br>");
$($("#serverResponses")[0]).append(imgItem).append("<br>");
}
}
}
}



Note the highlighted text! - This is how we get the URL information of the photo items being sent back to us from the server.
So now we know that inside "result" which is a JSON object, resides an array of objects, that contain each
an object called media with a field called m.
You can discover this by simply debugging the returned values from the Server in the browser.

So now, we can finally add some code to our GWT Client.


Client side - GWT Chrome extension

In the previous posts of QuickPik, you might have noticed, that in order to add an additional ImageDataSource, all you need is to implement an Interface IImagesDataSource and add that ImageDataSource to the DataSource enum.
It's much easier than it sounds.
So we need to do the following:
1. Write an ImageDataSource that "talks" to our Server.
2. Edit the manifest.json file to allow communication to our server in order to comply with the
    "Content Security Policy" of Chrome's extensions.


IImageDataSource implementation - ServerDS




public class ServerDS implements IImagesDataSource {

private final static String QUICKPIK_SERVER_URL = 
"http://localhost:8080/qpserver/rest/quickpik/searchPhotos?searchExp=" ;

          ...

@Override
public void getImages(final String searchExpression, final FilterLevel filter, 
                                                 final Callback<PhotosSearchResult, Void> callback) {
String url = QUICKPIK_SERVER_URL + searchExpression ;
JsonpRequestBuilder jsonp = new JsonpRequestBuilder();
jsonp.requestObject(url, new AsyncCallback<ServerResult>() {
public void onFailure(Throwable throwable) {
// do some error handling..
}

public void onSuccess(ServerResult result) {
handleLoadedImagesResult(searchExpression, filter, result, callback) ;
}
});
}

private void handleLoadedImagesResult(String searchExpression, FilterLevel filter, ServerResult result, 
Callback<PhotosSearchResult, Void> callback) {
JsArray<ServerImageItem> imageItems = result.getItems();
LinkedList<Photo> photos = collectImages(imageItems);
callback.onSuccess(new PhotosSearchResult(searchExpression, filter, photos, 0, false)) ;
}

private LinkedList<Photo> collectImages(JsArray<ServerImageItem> imageItems) {
LinkedList<Photo> photos = new LinkedList<Photo>();
for (int i = 0; i < imageItems.length(); i++) {
ServerImageItem imageItem = imageItems.get(i);
Photo p = new Photo(i+"", imageItem.getImageURL(), imageItem.getImageURL()) ;
photos.add(p) ;
}
return photos;
}
}


I'll try to explain the code very shortly:
1. At the top of the class you can locate the URL to the server we will be using to get the images from.
2. getImages method which must be implemented is passed a searchExpression a filter and
   a callback. We will ignore the filter to make things simpler.
   GWT offers a class called JsonpRequestBuilder which allows us to invoke an asynchrounous
   call to the server, and passing a callback to deal with the result of the invocation.
3. If the call was successful, we have to handle the result somehow. We do that by calling a handle method.
4. In the handleLoadedImagesResult method, we got an object called ServerResult. 
    ServerResult is a custom object created especially for this operation. It is a wrapper to
    a JavaScriptObject, that gives access to the result.items object array. (Remember from the jQuery test?)

This is how ServerResult looks like:


public class ServerResult extends JavaScriptObject {

   protected ServerResult() {
   }

   public final native JsArray<ServerImageItem> getItems() /*-{
     return this.items ;
   }-*/;
}


The native getItems method, is a convention of GWT to write JavaScript code to the underlying JavaScriptObject that the Java object wraps. So when you invoke getItems, behind the scenes the
JavaScript code "return this.items" is executed, returning the JavaScript items Array.

I also mapped the objects in this array to a Java object in the same way I did with ServerResult.
Following the same idea, ServerImageItem looks like this:


public class ServerImageItem extends JavaScriptObject {

protected ServerImageItem() {
}

public final native String getImageURL() /*-{
    return this.media.m ;
  }-*/;
}


Here we use getImageURL method to return the (JavaScript) object's media.m property.
(This is exactly the same structure that was referred to when testing with jQuery above).


So after this long explanation, all we do in the "handle" method, is basically gathering all of our
images URLs, creating a Photo list, like expected in the callback passed to us in the getImages method
invocation and invoking the callback, passing it an expected PhotoSearchResult object containing
our Photos.

5. Now we must add our ServerDS to the DataSource enum, so it will be included as a data source
    when we run a search.
    We do that simply by adding the (bolded) line below:

public enum DataSource {

// add here your data sources
FLICKR(false, new FlickrDS()),
QUICKPIK_SERVER(true, new ServerDS())
;
         ....
}

Notice how I intentionally turned off FLICKR Data Source, setting its isEnabled flag to false.

6. Last thing that needs to be done, is to enable our Chrome extension to make calls to our server by
    editing the manifest.json file, adding the following line to it:

{
   ....
   // A relaxed policy definition which allows script resources to be loaded from localhost:8080 over HTTP
  "content_security_policy": "script-src 'self' http://localhost:8080; object-src 'self'"
}


That's all folks, all you need to do now, is build the Server (I did it with Gradle in this project), compile
your GWT client, deploy it on Chrome and watch it work.

You can access all the code on GitHub, and download it.

Code on GitHub
All of the project's code can be found on GitHub at: https://github.com/nirgit/Quickpik-with-server



Sunday, August 26, 2012

GWT Chrome extension using version 2 manifest

Hi everyone,

A while ago I wrote a small post about how to create Chrome extension using GWT, claiming
you could use GWT to make powerful Chrome extension.
One of the comments was regarding the usage of the manifest version.
When you write a Chrome extension, you must provide with a file called manifest.json which
serves as some kind of descriptor file to your extension.
It contains all sorts of things, such as the name of the extension, description, icon, action,
javascript files involved, and so on...

One of the entries in that file is the version entry.
As for today Chrome supports the current version - 2, and also supports (for the moment)
version 1.
However, this is changing, and Google already announced that they will stop supporting version 1
in the future (see http://developer.chrome.com/extensions/manifest.html#manifest_version), due
to security reasons.

So I was asked whether it was possible or how is it possible to deploy the GWT extension with the
version 2 attribute in the manifest.json file.

Version 2, is stricter in terms of security than version 1. Especially when it comes to using external JavaScript files.
You can read about security concerns over here:
http://developer.chrome.com/extensions/content_scripts.html#security-considerations
http://developer.chrome.com/extensions/xhr.html

One of the problems I faced, was the inline scripting I had (JavaScript showing inside the HTML).
That problem came not only on my "Hosting" HTML file, but also on the compiled outputs of GWT,
where HTML file which was needed was created and contained JavaScript code.
When that happened, I couldn't execute the extension on Chrome using version 2 in the manifest.json file.

I wrote in response to a comment someone left regarding this problem, that in case Google would have a way to separate JavaScript files from HTML, then problems would be solved.
Back then, I didn't see such options for the GWT compiler.

However, after doing some more searching, I found out that it does exist (!).
And so by adding a simple line in the .gwt.xml file of the application, you can compile all
your GWT application output into a single JavaScript file. Meaning - no HTML files containing
inline JavaScripts.

The line one needs to add is:
...
<add-linker name="sso" />
...

I added it to my Quickpik.gwt.xml file, and so when you run the GWT compiler, you get at the end
one JavaScript file containing the entire code of your app. Awesome!

You can access the entire code on Github and download it from there:
https://github.com/nirgit/Quickpik

You can simply click on the "Downloads" on the right hand of the screen, in order to download
the repository as a ZIP file.

In case you're a GIT user, my suggestion is that you just clone the repository. It's really small.
Simply open your GIT shell and type:
git clone https://github.com/nirgit/Quickpik.git

The extension is already ready to be used in Chrome, and you can deploy it by opening Chrome's
Tools -> Extensions tab, and checking the "Developer mode" box.
Afterwards, you will be able to deploy the extension by selecting the "Load unpacked extension..."
option and selecting the war directory of Quickpik.

I am hoping this is somewhat useful.
I think GWT is an absolutely great tool, and one that can be a lot of fun writing Chrome Extensions.

Until next time!




Tuesday, March 20, 2012

DI with Guice for Java Swing

If you're familiar with Dependency Injection (DI) concepts and frameworks such as Spring,
you know the great benefits it introduces when developing an application.
Spring which I daily use (and praise), is a framework (or an application platform if to be more accurate) that one of its core features and philosophy is DI.

Some of the benefits of DI are well known:

  1. Simplified code.
  2. Reduced dependencies.
  3. Helps 'modularity' and creation of reusable components.
  4. Helps you test your application better.
  5. Lazy loading.


Surely there are other benefits you could think of which were not mentioned above.
So, why not bring all that good stuff to your Rich Client ?

The connection of DI to the title of this post is how to integrate DI in your front-end in case you are building a Rich client application, using Java Swing or GWT for example.

You could follow the MVC pattern (which is well known, and can be great) to build your rich client, and integrate it with a DI framework. However I strongly recommend you consider the MVP pattern for an even better design of your front-end. Which I find it to be much 'cleaner'.
(In MVC some of the business-logic code is scattered between the controller and the View. It's harder
to re-use your View objects/Widgets, especially in case you want to give it to someone else to use, or integrate them in another product).

Smarter people than me talk about it, and you can find great talks on YouTube regarding this subject.

You can later also check Google I/O's excellent talk for "Best Practices for Architecting GWT App"  http://www.youtube.com/watch?v=PDuhR18-EdM

So, if we follow the MVP design pattern and Google's best practices (even if we don't use GWT),
we end up with few key components in our app, i'll try to give some description what they do:

  1. "The" Event Bus - The component where presenters 'listen' to, and can fire events to.
  2. The Presenters - The components which encapsulate the logic of your application.
  3. The Views / Displays - Simply a view - can be a panel with widgets in it. No logic in here!
  4. A Model - Where you keep important data that can be accessed by one or more presenters.


"Show me the code!"

Lets assume you're writing your rich client in Java Swing.
We will use the lightweight DI framework "Guice" by Google:
http://code.google.com/p/google-guice/ to help us achieve our goal.

Lets go over some steps to realize what needs to be done in order to get this to work - don't forget to download Guice and put it's Jars in the classpath.
(Or, scroll all the way down to download the zip file containing the source code).


1) Define a simple View as a dumb object, not knowing anything about logic:
public class ContentPaneDisplay extends JPanel { .... }

2) Define a high level IPresenter interface and the IContentPanePresenter interface:

public interface IPresenter {
/**
* A method of all implementing presenters for presenting themselves on a given container.
* @param c
*/
void go(Container c) ;
}

public interface IContentPanePresenter extends IPresenter {}


3) Define a Presenter that will use view object above as its display:

public class ContentPanePresenter implements IContentPanePresenter {
public static interface IDisplay {
JComponent getAsComponent() ;
}
private final IDisplay display ;
....
}

4) Make ContentPaneDisplay implement the ContentPanePresenter.IDisplay interface.

5) Configure the Display class and the Presenter class to be used by Guice:

public class ApplicationDIModule extends AbstractModule {
@Override
protected void configure() {
// Lets configure some stuff !
bind(IContentPanePresenter.class).to(ContentPanePresenter.class).in(Singleton.class) ;
bind(ContentPanePresenter.IDisplay.class).to(ContentPaneDisplay.class).in(Singleton.class) ;
}
}

6) Add the @Inject annotation to the ContentPanePresenter to be injected the display:

/**
* C'tor
* This is where DI takes place!!!
* Guice will instantiate and provide this presenter with a matching display!
* @param display
*/
@Inject
public ContentPanePresenter(IDisplay display) {
this.display = display ;
...
}


7) Now all that's left is to call the Guice injector to get the ContentPanePresenter:
private static void go(Container container) {
// Guice.createInjector() takes your Modules, and returns a new Injector instance.
   Injector injector = Guice.createInjector(new ApplicationDIModule());
// lets get the 'Main' content pane Presenter !!
   IContentPanePresenter contentPanePresenter =
                                                            injector.getInstance(IContentPanePresenter.class) ;
contentPanePresenter.go(container) ;
}