Over a million developers have joined DZone.

OGL Explorer

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

Today, let’s display some data, some search results for example, on a little unusual graphical component.

First of all, search the data … Where ? On some well known search engine, such as Google or Bing.
For Google, it’s a little tricky, because the Google API still does not have so much sample code on the web to help (in Java I mean). So let’s try with something simple, and we’ll see later for more complex.
How about the Youtube’s API, that is pretty simple to access. First download the Google-api-java-client from here, and extract the useful jars.
Ok, now with a little bit of debug, we can understand how it works and provide some Video class that will be populated with the search result. Especially, we want this Video to include the URL of the thumbnail of the Video.

    public static class VideoFeed {  
        @Key List<Video> items;  
    public static class Video {  
        @Key String title;  
        @Key String description;  
        @Key Player player;  
        @Key Thumbnail thumbnail;  
        @Key String[] tags;  
    public static class Player {  
        @Key("default") String defaultUrl;  
    public static class Thumbnail {  
        @Key("sqDefault") String lowThumbnailURL;  
        @Key("hqDefault") String highThumbnailURL;  
    public static class YouTubeUrl extends GenericUrl {  
        @Key final String alt = "jsonc";  
        @Key String author;  
        @Key("q") String words;  
        @Key("max-results") Integer maxResults;  
        @Key("start-index") Integer startIndex;  
        YouTubeUrl(String url) {  

Finally, our client looks like something like that, which works pretty fine.

So what about Bing ? Bing is pretty cool here, as the procedure described here, we just need to download Axis2, get a Bing API Key, generate some classes with the WSDL of the search web service, and use a quite simple client code and everything works fine.
In a couple of minutes, we got a functional client, that can request videos, images and web contents.

Last search engine: a local drive search component. Here the trick will be not to search the entire file system, but to search by page, in order to have a search component quite dynamic. I don’t talk here of database, B-Tree or indexing, just a pure in memory Java implementation. Not the most optimal, but anyway we are not here to implement a file system. And this is what I got.

Fine, we have some pretty simple client prototypes, that works on command line, now how do we structure our model to include these three search engines, and potentially more, and their different contents. I suggest a simple design, probably not the better but anyway, something that looks like that :

The SearchProvider will be the entry point to search data. It will provide synchronous and asynchronous search.
Concerning asynchronous search, it means that search process will be done in threads, so the SearchEngine component will need to be fully synchronized, which means use of CopyOnWriteArrayList and synchronized block all around the code.

Also, to optimize the creation and the use of thread, we’ll use a thread pool :

    ExecutorService _threadPool = Executors.newCachedThreadPool();  
    public void asyncNext(final AsyncResponseHandler responseHandler) {  
        if (_currentSearchEngine != null) {  
            _threadPool.execute(new Runnable() {  
                public void run() {  
                    try {  
                        responseHandler.asyncResponse(new SearchResult[] { next() });  
                    } catch (Throwable t) {  

Now, we’ll wrap the different engines specific results into some model object, that will be displayed generically in the GUI.
Basically, a search result is an URL or a Path in case of local drive file search, and a thumbnail (an image).
The thumbnail will be retrieve on the Internet, or computed on the fly, anyway the computation of this image need to be done in background, because it can take some time, and while the computation is in progress, we need to display some pending image, and not just wait that the image is ready to display it.
For such purpose, the abstract SearchResult will use a basic volatile boolean _isAdjusting, and implements such a method :

    private ByteBuffer imageToDraw() {  
        if (_isAdjusting) {  
            // this one is synchronous, we need it now  
            return pendingImage();  
        } else if (_thumbnailByteBuffer == null) {  
            // compute the real image in a thread  
            THREAD_POOL.execute(new Runnable() {  
                public void run() {  
                    try {  
                        _isAdjusting = true;  
                        BufferedImage image = imageToDrawImpl();  
                        _thumbnailByteBuffer = Util.bufferedImagetoByteBuffer(image);  
                        _thumbnailSize = new Dimension(image.getWidth(), image.getHeight());  
                    } catch (Exception e) {  
                        _thumbnailByteBuffer = pendingImage();  
                    } finally {  
                        _isAdjusting = false;  
        return _thumbnailByteBuffer;  

Here again, we will use a static Thread pool to manage the creation of thread.
Finally, draw the results on a custom GLCanvas component : the OGLPanel by calling some :

    if (_searchResults != null) {  
        synchronized (this) {  
            for (int i = Math.min(9, _searchResults.size() - 1); i >= 0; i--) {  
                _searchResults.get(i).drawGL(gl, glut, glu, getWidth(), getHeight(), 1000 - (i + 1) * 100);  

Where the drawGL method will look like :

    public void drawGL(GL gl, GLUT glut, GLU glu, int width, int height, int distance) {  
        try {  
            // Change to projection matrix.  
            // Perspective.  
            float widthHeightRatio = (float) width / (float) height;  
            glu.gluPerspective(45, widthHeightRatio, 1, 20000);  
            // Change back to model view matrix.  
            Dimension dim = imageDimension();  
            int normalizeDistance = (int) (distance * distanceFactor());  
            // draw the image on the GL  
            gl.glBindTexture(GL.GL_TEXTURE_2D, 13);  
            gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);  
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP);  
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP);  
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);  
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);  
            gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, dim.width, dim.height, 0, GL.GL_RGBA,  
                    GL.GL_UNSIGNED_BYTE, imageToDraw());  
            int left = left();  
            int top = top();  
            gl.glBindTexture(GL.GL_TEXTURE_2D, 13);  
            gl.glTexCoord3d(0, 1, normalizeDistance);  
            gl.glVertex3d(left, top, normalizeDistance);  
            gl.glTexCoord3d(1, 1, normalizeDistance);  
            gl.glVertex3d(left + dim.width, top, normalizeDistance);  
            gl.glTexCoord3d(1, 0, normalizeDistance);  
            gl.glVertex3d(left + dim.width, top + dim.height, normalizeDistance);  
            gl.glTexCoord3d(0, 0, normalizeDistance);  
            gl.glVertex3d(left, top + dim.height, normalizeDistance);  
        } catch (IndexOutOfBoundsException e) {  

The setCamera(), top() and bottom() methods will be used to give a good perspective that will depend on the data type displayed.

To finish, the current selected object will be the first of the visible list, and will be displayed in details in a custom JEditorPane, especially, hyper-links will be opened in the default web browser, or in the OS default program, by invoking a the Java 1.6 Desktop API :

    if (Desktop.isDesktopSupported()) {  
        try {  
        } catch (Exception e) {  
            JOptionPane.showMessageDialog(null, Resources.getLabel("error.open.url", file.getAbsolutePath()));  
    } else {  
        JOptionPane.showMessageDialog(null, Resources.getLabel("error.open.url", file.getAbsolutePath()));  

Build the all stuff with an Ant script, and we are done.

Edit : add the Twitter search feature. For that, use the pretty well done Twitter4J API.

Edit2 : add the Google books search feature. And redesign the search engine component to make it more friendly.

Edit3 : add Wikipedia search feature, using Gson. Internationalization of the interface in French and Japanese.

Edit4: add Bing News search feature, enhance performances, especially Jogl CPU usage.

Edit5 : add Flickr search feature and correct a bug which is the exact same trap that I commented in my previous post about JNI and dev env !

Edit6 : add Myspace search feature (using the Myspace open API and Gson).

Edit7 : add iTunes search feature. Add the possibility to hide nodes.

Edit8 : add the Wiktionary search feature. Add the auto restart the application when changing interface language.

Edit9 : Optimize the local search engine by using Lucene. Add the WordPress search feature.

Edit10 : Implement an autocomplete component relying on previous indexed searched (by Lucene) and Wikipedia search results. Change to Liquid Look and feel.

Edit 11 : Implement a bookmarks system. Use of Lucene stemmer in the autocomplete component.

Download and run OGL Explorer.

Sourceforge project.

Complete sources under license LGPLv3.


From http://leolewis.website.org/wordpress/2011/06/04/ogl-explorer/

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.


The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}