Wednesday, November 28, 2012

Greasemonkey to rescue!

Greasemonkey is an add-on to Firefox that seems to prove to be really useful, so I wanted to give it a spin.

Basically, what it does is to modify webpages on-the-fly as you load them - using JavaScript. Many times I guess people use it to get rid of nasty ads and so forth. There are plenty of other add-ons able to do that - like removing a specific element each time, which doesn't require any coding. What fun is that?

Nonetheless, my first Greasemonkey-script does just that - removes an ad. But for the site in question - www.di.se (all in Swedish) - it isn't as easy as removing an element. The site is divided into 3 rows using a frameset that looks like this:

 
<frameset frameborder="no" framespacing="0" rows="0,210,*">
<frame class="noprint" frameborder="no" framespacing="0" name="historyFrame" noresize="" scrolling="no" src=""></frame>
<frame class="noprint" frameborder="no" framespacing="0" name="headerFrame" noresize="" scrolling="no" src=""></frame>
<frame class="" frameborder="no" framespacing="0" name="contentFrame" noresize="" scrolling="auto" src=""></frame>
</frameset>
As you maybe can tell, removing the second frame (which contains the 210px ad) doesn't cut it, because the third frame (content) will now take it's place.

This is where Greasemonkey comes to rescue! Creating the following script tells Greasemonkey to change to rows-attribute of the frameset to hide the ad frame, allowing the content frame to use all available space:

// ==UserScript==

// @name          Clean up di.se
// @namespace     http://www.technowobble.com
// @description   Removes the top add from www.di.se
// @include     http://www.di.se/
// @grant       none
// ==/UserScript==

var frameset = document.getElementsByTagName('frameset');

if (frameset[0]) {
 frameset[0].rows="0,0,*";
}
It will only be applied to http://www.di.se/ (notice the trailing slash which seems to be required) and I will never have to see the ad again. Sweet. But what more can you do with it? Anything, from removing ads, changing look & feel etc, to do automatic user interface testing or exploiting vulnerabilities, I guess?

Tuesday, August 28, 2012

Fighting Dell!

Ok - so I've been having trouble with my Dell Latitude e5410. What kind of trouble, you ask? Well, I discovered it when listening in on my favorite tunes on Spotify. Intermittent there was a "buzzing" sound for a brief moment, like if my headphones weren't properly attached, or poorly fitted into the jack.

This happened 5-10 times per song and was really annoying me, but I couldn't really figure out what it was. Tried a couple of things, like testing with different headphones, downloading new audio drivers, but it never when away. It even occurred when listening without headphones. And no matter if it was streaming media or music on from my local library.

So I gave up. Sigh! Stopped listening on music while working, that is.

Half a year later, and some hours to kill, I started searching for a solution (again). But how do you Google it? "Dell sound noise"? "Dell e5410 audio buzz"? No luck.

Turned out the magic word was "music", as this issue is most annoying when listening on favorite music, it seems. I finally found this thread, which didn't specifically mention the e5410. It eventually led me to try to upgrade the Intel Storage Controller provided by their Rapid Storage Technology anyway. Simply downloaded the driver from Intel and installed it.

Problem solved. Thanks to a dedicated community. Really - big thank you! Wish Dell was monitoring their own community and supplied hot fixes to issues like these. The driver download section isn't very helpful, even with your computer's identity tag supplied...

Friday, November 25, 2011

Getting filters to play nicely with Spring

After having some struggle with getting filters to integrate well with my Spring context, I decided to write down a small tutorial for it...

To begin with, filters are defined in web.xml and are therefore not automatically part of the Spring application context, which is normally set up using the DispatcherServlet. A good way to abstract away all this is to use the DelegatingFilterProxy, which is a Spring utility class that acts as a filter, but will delegate the doFilter-method to a Spring-managed bean - normally a class extending GenericFilterBean.

As a filter is defined in web.xml and looks for the bean defined in the Spring context in applicationContext.xml, it's not really the set up that I want. Filters are part of a web application and should have access to what's usually defined in webmvc-config.xml, as part of the DispatcherServlet set up. To be able to use, e.g. request scoped beans in applicationContext.xml, you need to defined them as proxied objects in order to have them looked up at a time where the web context is available.

The small application I'll be showing here is set up with an example filter that stores a request header value into a request scoped variable which is available as a Spring bean, and can therefor be autowired in any other Spring bean later on in the execution of the request. This demonstrates a nice way to have a loose coupling between the different components, without having to e.g. pass the information in method variables. It also gives the ability to test the components outside a web context.

To begin with, a normal filter definition using the DelegatingFilterProxy needs to be added to web.xml:

    
    
        Header Filter
        org.springframework.web.filter.DelegatingFilterProxy
        
        
            targetBeanName
            headerFilter
        
    

    
        Header Filter
        /*
    


Make sure the init param "targetBeanName" is set to the name of the Spring bean to delegate to (or rely on the default, where the filter's name is used to look up the bean). Now, let's have a look at the definition of the Spring filter bean and the request scoped bean in applicationContext.xml, incl. the acutal implementation of the filter:

    
    

     
    
        
   


Note how the request scoped bean is defined to be a proxied, using
.

    package com.technowobble.web;

    import java.io.IOException;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.filter.GenericFilterBean;

    /**
     * Intercepts all incoming requests and parses out Ninaa headers into a session scoped variable.
     */
    public class HeadersFilter extends GenericFilterBean {
        @Autowired
        private Headers headers;

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            if (request instanceof HttpServletRequest) {
                HttpServletRequest httpRequest = (HttpServletRequest) request;
                Headers.Types[] values = Headers.Types.values();
                for (int i = 0; i < values.length; i++) {
                    headers.setHeader(values[i], httpRequest.getHeader(values[i].toString()));
                }
            }

            chain.doFilter(request, response);
        }
    }


For this set up to work and have the filter to acutually be able to look up the real object at runtime, we need to add a RequestListener to web.xml, which will wire up the request context to all beans running outsite of the DispatcherServlet, i.e. our filter.

    
    
      org.springframework.web.context.request.RequestContextListener
    


Ok - so far so good. Let's wire it up together in a controller, which uses an example component that will serve as the component that will use the information gathered from the filter. Note that the component used by the controller is not aware of any request/response objects and doesn't have any parameters in it's methods.

    package com.technowobble.controller;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import com.technowobble.component.MyComponent;

    @Controller
    @RequestMapping("/myController")
    public class MyController {
        @Autowired
        MyComponent myComponent;
        
        @ResponseBody
        @RequestMapping(method = RequestMethod.GET)
        public String createResponse() {
            return myComponent.getSomethingDependingOnHeaders();
        }
    }


The @ResponseBody is just an easy way to get rid of all view lookups and send the header values straight to the browser...

    package com.technowobble.component;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;

    import com.technowobble.web.Headers;

    @Component
    public class MyComponent {
        @Autowired
        Headers headers;
        
        public String getSomethingDependingOnHeaders() {
            return "You are accepting " + headers.getHeader(Headers.Types.Accept);
        }
    }


Now, check if everything workes as expected by launching the application using "mvn jetty:run" and browse to "http://localhost:8080/technowobble/myController/".

The last thing to report is how to test the MyComponent in a separate JUnit-test... First of all, there's no web context in a JUnit-test, and therefor no notion of a request scope. This is solved by defining a custom scope (implemented by a ThreadLocal implementation) in a separate applicationContext-test.xml which is used in the test.

  
    
      
        
          
        
      
    
  


After this, the actual test is straightforward:

    package com.technowobble.component;

    import static org.junit.Assert.assertEquals;

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

    import com.technowobble.web.Headers;

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath*:META-INF/spring/applicationContext*.xml")
    public class MyComponentTest {
        @Autowired 
        private Headers headers;
        
        @Autowired
        private MyComponent myComponent;
        
        private static final String ACCEPT = "text/html";

        @Before
        public void setUp() throws Exception {
            headers.setHeader(Headers.Types.Accept, ACCEPT);
        }

        @Test
        public void test() {
            assertEquals(myComponent.getSomethingDependingOnHeaders(), "You are accepting " + ACCEPT);
        }
    }


Note that the headers bean is setup during the setUp()-method and that the myComponent have access to it using normal dependency injection.

That's it. The full source code can be downloaded from here

Thanks for reading!

Tuesday, September 13, 2011

A quick note on something that's been bugging me while using SpringSource STS with the GWT-plugin on my MacBook Pro...

Sometimes, when shutting down the internal devmode server I get an error dialog saying it wasn't able to shut down the process fully (even though it looks shut down in the console window).

When starting it again, it reports port 9997 to be in use already - and consequently fails to start up again. I haven't found a way to find the process within SpringSource STS, even though there are probably several ways of doing it (which I do not know about). Anyhow - I solved it using the "lsof" package (List Open Files).

To find the PID of the process using port 9997, type "lsof -i :9997" in a Terminal window. A simple "kill -9 <pid>" will take care of the rest.

I'm not sure if this happens on other platforms etc, but at least, now you know how to handle it if it hits you!

Thursday, March 3, 2011

Styling individual (and nested) tabs using GWT

I've read several forum entries trying to explain how to style GWT TabLayoutPanels, and there seems to be several ways to do it. The three most common ways are to:

1) Edit the standard.css-file and update the .gwt-TabLayoutPanel, .gwt-TabLayoutPanelTabs, .gwt-TabLayoutPanelTab, .gwt-TabLayoutPanelTabInner and .gwt-TabLayoutPanelContent.
2) Override the styles by putting your own css-file as part of html hostpage.
3) Override the styles in the ui-binder file using the @external keyword.

None of them really fit my needs... I want to be able to style indidividual tabs, including nesting tabs within tabs (with different styling). The methods above changes the globally set stylenames, and applies to all tabs being used in you application.

What I'm looking for is to style the tabs using defined styles in the ui-binder file. This way, the styles will be obfuscated and possible to apply within it's own namespace - hence only applied to individual tabs using that namespace.

Let's see an example of how I have managed to set this up. (I'm sure there are other/smarter/better ways, but looking at the forums - people aren't sharing the secrets...)

First of all, let's create the ui-binder file:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
 xmlns:g="urn:import:com.google.gwt.user.client.ui">

 <ui:style type="com.technowobble.client.NestedTabWidget.Style"> 
  
  .my-TabLayoutPanel {
   background-color: red !important; 
  }
  
  .myTabLayoutPanelTab {
   background-color: #DCDCDC !important;
   color: gray !important;
   -webkit-border-top-left-radius: 3px;
   -webkit-border-top-right-radius: 3px;
   -moz-border-radius-topleft: 3px;
   -moz-border-radius-topright: 3px;
   border-top-left-radius: 3px;
   border-top-right-radius: 3px;
   margin-left: 11px !important;   
  }
  
  .myTabLayoutPanelTabSelected {
   background-color: #2E8B57 !important;
   color: black !important;
  }
    
  .myTabLayoutPanelTabsContainer {
   background-color: orange;
   -moz-border-radius-topleft: 10px;
   -webkit-border-top-left-radius: 10px;
   -moz-border-radius-bottomleft: 10px;
   -webkit-border-bottom-left-radius: 10px;
   -moz-border-radius-topright: 10px;
   -webkit-border-top-right-radius: 10px;
   -moz-border-radius-bottomright: 10px;
   -webkit-border-bottom-right-radius: 10px;
  } 
  
  .myTabLayoutPanelContent {
   border-color: #2E8B57 !important;
  }   
  
  .myNestedTabLayoutPanel {
   background-color: lime !important; 
  }
  
  .myNestedTabLayoutPanelTab {
   background-color: black !important;
   color: gray !important;
   -webkit-border-top-left-radius: 3px;
   -webkit-border-top-right-radius: 3px;
   -moz-border-radius-topleft: 3px;
   -moz-border-radius-topright: 3px;
   border-top-left-radius: 3px;
   border-top-right-radius: 3px;
   margin-left: 11px !important;
  }
 
  .myNestedTabLayoutPanelTabSelected {
   background-color: #7B68EE !important;
   color: black !important;
  }
  
  .myNestedTabLayoutPanelContent {
   border-color: #7B68EE !important;
   background-color: fuchsia !important;
   color: white;
  }  
 </ui:style>

 <g:TabLayoutPanel ui:field="tabLayoutPanel" barHeight="2" barUnit="EM" width="400px" height="150px" addStyleNames="{style.my-TabLayoutPanel}">
  <g:tab>
   <g:header>Tab 1</g:header>
   <g:TabLayoutPanel barHeight="2" barUnit="EM">
    <g:tab>
     <g:header>Nested tab 1.1</g:header>
     <g:HTML wordWrap="true">Nested tab 1.1 content</g:HTML>
    </g:tab>
    <g:tab>
     <g:header>Nested tab 1.2</g:header>
     <g:HTML wordWrap="true">Nested tab 1.2 content</g:HTML>
    </g:tab>
   </g:TabLayoutPanel>
  </g:tab>
  <g:tab>
   <g:header>Tab 2</g:header>
   <g:TabLayoutPanel barHeight="2" barUnit="EM">
    <g:tab>
     <g:header>Nested tab 2.1</g:header>
     <g:HTML wordWrap="true">Nested tab 2.1 content</g:HTML>
    </g:tab>
    <g:tab>
     <g:header>Nested tab 2.2</g:header>
     <g:HTML wordWrap="true">Nested tab 2.2 content</g:HTML>
    </g:tab>
    <g:tab>
     <g:header>Nested tab 2.3</g:header>
     <g:HTML wordWrap="true">Nested tab 2.3 content</g:HTML>
    </g:tab>    
   </g:TabLayoutPanel>
  </g:tab>
 </g:TabLayoutPanel>
</ui:UiBinder> 

This file defines a tab panel with two tabs, each of which have a separate tab panel as it's content. The specified style tags pretty much mimics the "standard" style names for a TabLayoutPanel and I've named them thereafter. Remember, they could be named whatever as they will be obfuscated anyway.

The only style that is actually applied directly in the ui-binder file is the .my-TabLayoutPanel, which could just as well have had applied at run-time instead.

Now, let's create the corresponding Java-class, which will style the defined tabs using the above styles:

package com.technowobble.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.Widget;

public class NestedTabWidget extends Composite {

 private static NestedTabWidgetUiBinder uiBinder = GWT
   .create(NestedTabWidgetUiBinder.class);

 interface NestedTabWidgetUiBinder extends UiBinder<Widget, NestedTabWidget> {
 }
 
 interface Style extends CssResource {
  // Tab container (containing the .gwt-TabLayoutPanelTabs styling
  String myTabLayoutPanelTabsContainer();
  // General tab styling
  String myTabLayoutPanelTab();
  // Specific styling for selected tab
  String myTabLayoutPanelTabSelected();
  // Applied to tab content
  String myTabLayoutPanelContent();
  // Applied to entire nested tab panel
  String myNestedTabLayoutPanel();
  // General inner tab styling
  String myNestedTabLayoutPanelTab();
  // Specific styling for selected inner tab
  String myNestedTabLayoutPanelTabSelected();
  // Applied to inner tab content
  String myNestedTabLayoutPanelContent();
 }
 
 @UiField 
 Style style;
 
 @UiField
 TabLayoutPanel tabLayoutPanel;

 public NestedTabWidget() {
  initWidget(uiBinder.createAndBindUi(this));
  
  // style the tab container (gray bar)
  ((Element) tabLayoutPanel.getElement().getChild(1)).addClassName(style.myTabLayoutPanelTabsContainer());
  // style the tabs
  styleTabPanel(tabLayoutPanel, style.myTabLayoutPanelTab(), style.myTabLayoutPanelTabSelected(), style.myTabLayoutPanelContent());
  
  // style all inner tabs (in uibinder)
  for (int i = 0; i < tabLayoutPanel.getWidgetCount(); i++) {
   Widget widget = tabLayoutPanel.getWidget(i);
   
   // add content style no matter what the content is
   widget.addStyleName(style.myTabLayoutPanelContent());
   
   if (widget instanceof TabLayoutPanel) {
    final TabLayoutPanel nestedTabLayoutPanel = (TabLayoutPanel) widget;
    // style inner tabLayoutPanel  
    nestedTabLayoutPanel.addStyleName(style.myNestedTabLayoutPanel());
    styleTabPanel(nestedTabLayoutPanel, style.myNestedTabLayoutPanelTab(), style.myNestedTabLayoutPanelTabSelected(), style.myNestedTabLayoutPanelContent());

    // re-style on selects
    nestedTabLayoutPanel.addSelectionHandler(new SelectionHandler<Integer>() {     
     @Override
     public void onSelection(SelectionEvent<Integer> event) {
      styleTabPanel(nestedTabLayoutPanel, style.myNestedTabLayoutPanelTab(), style.myNestedTabLayoutPanelTabSelected(), style.myNestedTabLayoutPanelContent());      
     }
    });       
   }
  }
 }
 
 @UiHandler("tabLayoutPanel")
 public void onTabSelect(SelectionEvent<Integer> event) {
  styleTabPanel(tabLayoutPanel, style.myTabLayoutPanelTab(), style.myTabLayoutPanelTabSelected(), style.myTabLayoutPanelContent());
 } 
  
 private void styleTabPanel(TabLayoutPanel tabPanel, String style, String styleSeleced, String styleContent) {
  for (int i = 0; i < tabPanel.getWidgetCount(); i++) {
   Widget tab = tabPanel.getTabWidget(i);
   
   // style the actual tab
   tab.getParent().addStyleName(style);
   if (i == tabPanel.getSelectedIndex()) {
    tab.getParent().addStyleName(styleSeleced);
   } else {
    tab.getParent().removeStyleName(styleSeleced);
   }
   
   // style the added content
   Widget content = tabPanel.getWidget(i);
   content.addStyleName(styleContent);
  } 
 }
}

You can see what the different styles are used for in the comments (according to the JavaDoc of the TabLayoutPanel) - the only interesting thing to note is that I've added styling to the div-tag containing the .gwt-TabLayoutPanelTabs div, in order to style the background behind the tabs.

When initializing the widget I style all the tabs once, but as I can't use addStyleDependantName() to style select/unselect I also have to apply these styles on every select/unselect. This is applied to both the outer TabLayoutPanels, as the inner TabLayoutPanels. The reason the addStyleDependantName() can't be used is because the names are obfuscated, and adding a "-select" to it doesn't match the name of the non-obfuscated corresponding selected style in the ui-binder file. There are surely a better way of doing this, and I'd be happy to hear if you have any suggestions here...

I haven't put up any running example of this, but you can download the source code as an Eclipse-project here and try for yourself. I apologize for the color-schema I've used in the example - looks like a 5-year old gone crazy, but it fills the purpose of showing where each style gets applied...

Have fun!

Friday, August 13, 2010

Using SmartGWT with Jersey RESTful backend on Spring Roo

I decided to give SmartGWT a run, and specifically the RestDataSource functionality using Jersey. To make things easier, I'm using Spring Roo to set up my project and scaffold much of the boilerplate code, configurations etc.

My approach is to have my domain objects exposed as RESTful web services and create a matching SmartGWT DataSource in order to show them in a GUI.

Let's get started, shall we?

First of all, you'll need Spring Roo (unless you just download the project source code and want to run it directly). I'm using the following Roo script to start things off:

project --topLevelPackage com.technowobble
persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY

entity --class ~.domain.Message
field string --fieldName value

controller class --class ~.ws.MessageResource --preferredMapping rest

dependency add --groupId com.sun.jersey --artifactId jersey-server --version 1.3
dependency add --groupId com.sun.jersey.contribs --artifactId jersey-spring --version 1.3
dependency add --groupId com.smartgwt --artifactId smartgwt --version 2.2

gwt setup

You'll need to add the repositories for Jersey/SmartGWT manually in the genereated pom.xml:

<repository>
 <id>smartgwt</id>
 <url>http://www.smartclient.com/maven2</url>
</repository>
<repository>
    <id>maven2-repository.dev.java.net</id>
    <name>Java.net Repository for Maven</name>
    <url>http://download.java.net/maven/2/</url>
</repository>

Unfortunately the jersey-spring dependency depends on Spring 2.5.6, so that needs to be exluded (manually):

<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-spring</artifactId>
    <version>1.3</version>
    <!-- jersey-spring depends on Spring 2.5.6, so exluding as we're on 3.0.0X -->
    <exclusions>
 <exclusion>
     <groupId>org.springframework</groupId>
     <artifactId>spring</artifactId>
 </exclusion>
 <exclusion>
     <groupId>org.springframework</groupId>
     <artifactId>spring-core</artifactId>
 </exclusion>
 <exclusion>
     <groupId>org.springframework</groupId>
     <artifactId>spring-beans</artifactId>
 </exclusion>
 <exclusion>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
 </exclusion>
 <exclusion>
     <groupId>org.springframework</groupId>
     <artifactId>spring-web</artifactId>
 </exclusion>
 <exclusion>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
 </exclusion>
    </exclusions>
</dependency>

Add the jersey-servlet to web.xml and the corresponding jersey-servlet.xml into webapp/WEB-INF/spring (in accordance to how Spring Roo does it).

<!-- Initialize the Jersey servlet -->
<servlet>
 <servlet-name>jersey</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/jersey-servlet.xml</param-value>
        </init-param>
 <load-on-startup>2</load-on-startup>        
</servlet>

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

(The jersey-servlet.xml doesn't contain anything else than a component scan for Jersey web services).

We also have to update the urlrewrite.xml being used by Roo, to handle our servlet mapping of "/rest/*":

<rule enabled="true">
 <from casesensitive="false">/rest/**</from>
 <to last="true" type="forward">/rest/1</to>
</rule>    

In the generated Message domain object, add instructions to represent it in XML using an @XmlRootElement annotation:

package com.technowobble.domain;

import javax.persistence.Entity;
import javax.xml.bind.annotation.XmlRootElement;

import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;

@XmlRootElement
@Entity
@RooJavaBean
@RooToString
@RooEntity
public class Message {

    private String value;
}


The only thing we're missing on the backend now is the actual implementation of our service... A RestDataSource e.g. expects a response like the following in response to a "fetch" request (taken from the JavaDoc):

 <response>
    <status>0</status>
    <startRow>0</startRow>
   
 <endRow>76</endRow>
    <totalRows>546</totalRows>
    <data>
     
 <record>
          <field1>value</field1>
          <field2>value</field2>
   
 </record>
      <record>
          <field1>value</field1>
         
 <field2>value</field2>
      </record>
      ... 75 total records ... 
   
 </data>
 </response>

I've created some POJOs for Jersey to marshall/unmarshall that would mimic this format in the com.technowobble.ws.util-package. Essentially, there's two abstract classes (DSRequest and DSResponse) containing all common attributes, and two specialized classes (MessageDSResponse, MessageDSRequest) handling the specific marshalling of each domain object. I'm not posting the entire source here, but ask you to look at it from the source code instead...

Before you comment on this - yes, there are probably a smarter way to do this using generics etc, but that's an improvement to be done in a real-world project!

With the xml-mapping in place, now it's time to look at the Jersey resource implementation:

package com.technowobble.ws;

import java.util.Collection;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.stereotype.Component;

import com.technowobble.domain.Message;
import com.technowobble.ws.util.DSResponse;
import com.technowobble.ws.util.MessageDSRequest;
import com.technowobble.ws.util.MessageDSResponse;
import com.technowobble.ws.util.OperationType;

/**
 * Jersey resource for a SmartGWT {@link MessageDS}.
 * <p>
 * 
 * @see http://docs.sun.com/app/docs/doc/820-4867/ggnxo?l=en&a=view
 * @see http://blogs.sun.com/enterprisetechtips/entry/jersey_and_spring
 */
@Component
@Path("/message")
public class MessageResource {
 @Produces( { MediaType.APPLICATION_XML })
 @Consumes( { MediaType.TEXT_XML })
 @POST
 @Path("/add")
 public MessageDSResponse create(MessageDSRequest request) {
  MessageDSResponse response = new MessageDSResponse();
  
  if (request.getOperationType() != OperationType.ADD || request.getMessages().size() != 1) {
   response.setStatus(DSResponse.STATUS_FAILURE);
  } else {
   Message message = request.getMessages().iterator().next();   
 
   try {
    // create the message
    message.persist(); 
    response.addMessage(message);
    
    response.setStatus(DSResponse.STATUS_SUCCESS);
   } catch (Exception e) {
    response.setStatus(DSResponse.STATUS_FAILURE);
    e.printStackTrace();
   }   
  }
  
  return response;
 }

 @Produces( { MediaType.APPLICATION_XML })
 @Consumes( { MediaType.TEXT_XML })
 @POST
 @Path("/update")
 public MessageDSResponse update(MessageDSRequest request) {
  MessageDSResponse response = new MessageDSResponse();
  
  if (request.getOperationType() != OperationType.UPDATE || request.getMessages().size() != 1) {
   response.setStatus(DSResponse.STATUS_FAILURE);
  } else {
   try {
    Message data = (Message) request.getMessages().iterator().next();
    Message message = Message.findMessage(data.getId());
    BeanUtils.copyProperties(message, data);
    message.merge();
    response.addMessage(message);
    
    response.setStatus(DSResponse.STATUS_SUCCESS);
   } catch (Exception e) {
    response.setStatus(DSResponse.STATUS_FAILURE);
    e.printStackTrace();
   }
  }
      
  return response;
 }

 @Produces( { MediaType.APPLICATION_XML })
 @Consumes( { MediaType.TEXT_XML })
 @POST
 @Path("/remove")
 public MessageDSResponse delete(MessageDSRequest request) {
  MessageDSResponse response = new MessageDSResponse();
  
  if (request.getOperationType() != OperationType.REMOVE || request.getMessages().size() != 1) {
   response.setStatus(DSResponse.STATUS_FAILURE);
  } else {
   try {
    Message data = request.getMessages().iterator().next();
    Message message = Message.findMessage(data.getId());
    message.remove();
    response.addMessage(message);
    
    response.setStatus(DSResponse.STATUS_SUCCESS);
   } catch (Exception e) {
    response.setStatus(DSResponse.STATUS_FAILURE);
    e.printStackTrace();
   }
  }
      
  return response;
 }

 @POST
 @Produces( { MediaType.APPLICATION_XML})
 @Consumes( { MediaType.TEXT_XML })
 @Path("/read")
 public MessageDSResponse read(MessageDSRequest request) {
  MessageDSResponse response = new MessageDSResponse();
  
  response.setStartRow(request.getStartRow());
  
  if (request.getOperationType() != OperationType.FETCH) {
   response.setStatus(DSResponse.STATUS_FAILURE);
  } else {
   try {
    Collection<Message> messages = Message.findMessageEntries(request.getStartRow(), 1 + (request.getEndRow() - 

request.getStartRow()));
    long count = Message.countMessages();
    response.setEndRow(response.getStartRow()+messages.size()-1);
    response.setTotalRows((int)count);
    for (Message message : messages) {
     response.addMessage(message);
    }
   } catch (Exception e) {
    response.setStatus(DSResponse.STATUS_FAILURE);
   }
   
   response.setStatus(DSResponse.STATUS_SUCCESS);
  }
  
  return response;
 }
}

As you can see, there's one method per CRUD-reqeust from the SmartGWT RestDataSource (add, update, remove, read). They all basically parse the
incoming DSRequest and answers with a DSResponse, according to the specs of SmartGWT.

Now that the backend is in place, let's create a small GWT application to take it for a test drive!

By using Roo, there are some things to consider when adding a new module to the project, which I have blogged about previously. As with any other module, create a module file (in our case Application.gwt.xml), a host page (Application.html), configure the gwt-maven-plugin to use it (in pom.xml) and add two rules to urlrewrite.xml...

With that in place, let's have a look at the entry-point class:

package com.technowobble.gwt.client;

import com.google.gwt.core.client.EntryPoint;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.RestDataSource;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.RowEndEditAction;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.technowobble.gwt.client.datasources.MessageDS;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Application implements EntryPoint {
 /**
  * This is the entry point method.
  */
 public void onModuleLoad() {

  VLayout layout = new VLayout(15);
  layout.setAutoHeight();

  RestDataSource dataSource = new MessageDS();

  final ListGrid messageGrid = new ListGrid();
  messageGrid.setHeight(300);
  messageGrid.setWidth(500);
  messageGrid.setTitle("Messages");
  messageGrid.setDataSource(dataSource);
  messageGrid.setAutoFetchData(true);
  messageGrid.setCanEdit(true);
  messageGrid.setCanRemoveRecords(true);
  messageGrid.setListEndEditAction(RowEndEditAction.NEXT);

  ListGridField idField = new ListGridField("id", "Id", 40);
  idField.setAlign(Alignment.LEFT);
  ListGridField messageField = new ListGridField("value", "Message");
  messageGrid.setFields(idField, messageField);

  layout.addMember(messageGrid);

  HLayout hLayout = new HLayout(15);

  IButton updateButton = new IButton("Add message");
  updateButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
   public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
    Record message = new ListGridRecord();
    message.setAttribute("value", "...");
    messageGrid.addData(message);
   }
  });
  
  hLayout.addMember(updateButton);

  layout.addMember(hLayout);
  layout.draw();
 }
}

All in all, a ListGrid making use of a customized RestDataSource (MessageDS) - which might be more interesting than the actual code above...

Let's have a look at it:

package com.technowobble.gwt.client.datasources;

import com.smartgwt.client.data.OperationBinding;
import com.smartgwt.client.data.RestDataSource;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.types.DSOperationType;
import com.smartgwt.client.types.DSProtocol;
import com.technowobble.domain.Message;

/**
 * SmartGWT datasource for accessing {@link Message} entities over http in a RESTful manner.
 */
public class MessageDS extends RestDataSource {
 
 public MessageDS() {
  setID("MessageDS");
  DataSourceTextField messageId = new DataSourceTextField("id");
  messageId.setPrimaryKey(true);
  messageId.setCanEdit(false);
  
  DataSourceTextField messageValue = new DataSourceTextField("value");
  setFields(messageId, messageValue);
  
  OperationBinding fetch = new OperationBinding();
  fetch.setOperationType(DSOperationType.FETCH);
  fetch.setDataProtocol(DSProtocol.POSTMESSAGE);
  OperationBinding add = new OperationBinding();
  add.setOperationType(DSOperationType.ADD);
  add.setDataProtocol(DSProtocol.POSTMESSAGE);
  OperationBinding update = new OperationBinding();
  update.setOperationType(DSOperationType.UPDATE);
  update.setDataProtocol(DSProtocol.POSTMESSAGE);
  OperationBinding remove = new OperationBinding();
  remove.setOperationType(DSOperationType.REMOVE);
  remove.setDataProtocol(DSProtocol.POSTMESSAGE);
  setOperationBindings(fetch, add, update, remove);
    
  setFetchDataURL("rest/message/read");
  setAddDataURL("rest/message/add");
  setUpdateDataURL("rest/message/update");
  setRemoveDataURL("rest/message/remove");
 }
}

No surprises here... The RestDataSource is configured to match the operations of the RESTful backend, including the properties of the domain object we're exposing.

Done already? Then download the full source code here and give it a try!

"mvn jetty:run-war" should do the trick, although on my Windows machine I have to force a gwt-compilation using "mvn package gwt:compile jetty:run-war"

Enjoy!

Tuesday, July 13, 2010

GWT and Open-ID using Spring Security

In this post I'll combine the GWT and Spring Security integration from http://technowobble.blogspot.com/2010/05/gwt-and-spring-security.html and the Open-ID using Spring Security from http://technowobble.blogspot.com/2010/06/using-spring-securitys-openid.html. I'm assuming you've read them before reading further... :)

I was also inspired by http://www.sociallipstick.com/?p=86 and http://code.google.com/p/dyuproject/wiki/OpenidLoginWithoutLeavingPage to get this working with a pop-up as my sample application is based on GWT - hence, I don't want to direct the user to another page and loose the application state etc.

I'm also showing how to exchange Open-ID attributes with e.g. Google. As with the previous blogposts, the sample application is runnable on Google App Engine.

With no further ado, this is basically what is needed to add Open-ID support to my previous sample application:

From my second post, add Openid4javaFetcher, MyHttpCacheProvider and OpenIdUserDetailsServiceImpl-classes, update the pom.xml with the necessary Open-ID dependencies and add the customized configuration of the OpenIDAuthenticationFilter into applicationContext-security.xml.

Now that all necessary Open-ID stuff is in place, let's start adding the functionality to the application from my first post:

First of all, let's add a "Sign in with Google" button to the LoginDialogBox:

 @UiHandler("googleLoginButton")
 void googleLogin(ClickEvent e) {
  Window.open("/j_spring_openid_security_check?openid_identifier=https://www.google.com/accounts/o8/id", "openid_popup", 

"width=450,height=500,location=1,status=1,resizable=yes");
 }

It will open up a pop-up window posting to the OpenIDAuthenticationFilter, which will take care of the rest of the Open-ID functionality. As discussed in the links mentioned above, I need a callback function that can be called once the Open-ID-request is return, i.e. from the pop-up window to the GWT application window. I therefor made the following changes:

 // general callback for any type of authentication scheme
 RequestCallback callback = new RequestCallback() {
     public void onError(Request request, Throwable exception) {
      showError();
         Log.error(exception.getMessage());
     }
     
     public void onResponseReceived(Request request, Response response) {
         if (response.getStatusCode() == Response.SC_OK) {
          // notify all interested components
          fireEvent(new LoginEvent(true));
          
          // issue the command that triggered the dialog
          if (cmd != null) {
           cmd.execute();
          }
          
          hide();
          
          Log.debug("[success (" + response.getStatusCode() + "," + response.getStatusText() + ")]");
         } else {
          showError();
          Log.error(response.getStatusCode() + "," + response.getStatusText());
         }
     }
 };

 // make the callback function available from JavaScript
 private native void exportMethods(LoginDialog instance) /*-{
  $wnd.handleOpenIDResponse = function(statusCode, statusText) {
   return instance.@com.myappenginecookbook.gwt.client.LoginDialog::onAuthentication(ILjava/lang/String;)(statusCode, 

statusText);
  }
 }-*/;
 
 public void onAuthentication(final int statusCode, final String statusText) {
  // call callback with the needed parameters
  callback.onResponseReceived(null, new Response() {
         @Override
         public String getHeader(String header) {
          return null;
         }

         @Override
         public Header[] getHeaders() {
           return null;
         }

         @Override
         public String getHeadersAsString() {
           return null;
         }

         @Override
         public int getStatusCode() {
           return statusCode;
         }

         @Override
         public String getStatusText() {
           return statusText;
         }

         @Override
         public String getText() {
           return "";
         }
      });
 }

Note that I've broken out the anonymous RequestCallback so that it can be used with both ways of authenticating.

What's left now is to make sure the callback function will be called, which is the responsiblity of the OpenIdAuthenticationFailureHandler and OpenIdAuthenticationSuccessHandler-classes, which will be called by Spring Security at the end of the Open-ID request:

package com.myappenginecookbook.security;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

public class OpenIdAuthenticationSuccessHandler implements
  AuthenticationSuccessHandler {

 @Override
 public void onAuthenticationSuccess(HttpServletRequest request,
   HttpServletResponse response, Authentication authentication)
   throws IOException, ServletException {
  
  response.setContentType("text/html");
  PrintWriter out = response.getWriter();
  
  String html = 
         "<html>" +
      "<head>" +
      "</head>" +
      "<body onload=\"window.opener.handleOpenIDResponse("+HttpServletResponse.SC_OK+",'Authentication accepted');window.close

();\">" +
      "</body>" +
      "</html>";
        
        out.print(html);          
 }
}

The OpenIdAuthenticationSuccessHandler will render a simple html-fragment which utilizes JavaScript to call the exported GWT-method to signal the sucess/failure of the request. The OpenIdAuthenticationFailureHandler is basically identical, but will call the callback with the SC_UNAUTHORIZED http-code instead.

To finalize the upgraded sample app I searched the forums on how to get hold of the exchanged attributes and came up with this thread, and created a CustomOpenIDAuthenticationProvider-class to deal with it:

package com.myappenginecookbook.security;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationProvider;
import org.springframework.security.openid.OpenIDAuthenticationToken;

public class CustomOpenIDAuthenticationProvider extends
  OpenIDAuthenticationProvider {

 @Override
 protected Authentication createSuccessfulAuthentication(
   UserDetails userDetails, OpenIDAuthenticationToken auth) {
  
  if (userDetails instanceof CustomUser) {
   CustomUser user = (CustomUser) userDetails;
   for (final OpenIDAttribute attribute : auth.getAttributes()) {
        if ("email".equals(attribute.getName())) {
          String email = attribute.getValues().get(0);
          user.setEmail(email);
        }
      }
  }

  return super.createSuccessfulAuthentication(userDetails, auth);
 }
}

Hope this helps in getting your own applications Open-ID aware! Sourcecode can be found here.