GWT Developer's Tools http://www.gdevelop.com/blog Google Web Toolkit and App Engine development Mon, 20 Dec 2010 13:35:25 +0000 en hourly 1 http://wordpress.org/?v=3.0.4 Apache Shiro on AppEngine http://www.gdevelop.com/blog/2010/12/apache-shiro-on-appengine/ http://www.gdevelop.com/blog/2010/12/apache-shiro-on-appengine/#comments Mon, 13 Dec 2010 17:56:04 +0000 Trung http://blog.gdevelop.com/?p=71 Continue reading ]]> Apache Shiro

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management.

  • Authentication: Support logins across one or more pluggable data sources (LDAP, JDBC, Kerberos, ActiveDirectory, etc).
  • Authorization: Perform access control based on roles or fine-grained permissions, also using pluggable data sources.

Apache Shiro Authentication on AppEngine

We use AppEngine’s User Service to authenticate users. To integrate Apache Shiro with AppEngine User Service, we implement our own AuthenticatingFilter to control the login process

/**
 * An {@link AuthenticatingFilter} which uses UserService
 * to control the authentication process
 */
public class GaeAuthenticatingFilter extends AuthenticatingFilter{
  public GaeAuthenticatingFilter() {
    setLoginUrl(null);
  }

  @Override
  protected AuthenticationToken createToken(
      ServletRequest request, ServletResponse response) {
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();
    return createToken(user.getUserId(), null, request, response);
  }

  @Override
  protected boolean isRememberMe(ServletRequest request) {
    return true;
  }

  @Override
  protected boolean onAccessDenied(ServletRequest request,
                                   ServletResponse response) throws Exception{
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();

    if (user == null){
      saveRequest(request);

      String requestURI = WebUtils.getRequestUri(WebUtils.toHttp(request));

      String loginUrl = this.getLoginUrl();
      if (loginUrl == null){
        loginUrl = userService.createLoginURL(requestURI);
        WebUtils.issueRedirect(request, response, loginUrl);
      }else{
        request.setAttribute("requestURI", requestURI);
        request.getRequestDispatcher(loginUrl).forward(request, response);
      }

      return false;
    }else{
      // Perform the internal login process
      boolean result = executeLogin(request, response);
      return result;
    }
  }
}

Apache Shiro Security Realms

Apache Shiro provides several standard Realms (JndiLdapRealm, JdbcRealm, etc) which translates this application-specific data into Shiro internal format.

AppEngine Authenticating Realm

For AppEngine our realm as below:

/**
 * A {@link Realm} which uses {@link UserService} to authenicate users
 */
public class GaeAuthenticatingRealm extends AuthorizingRealm{
  public GaeAuthenticatingRealm() {
  }

  @Override
  protected void onInit() {
    // We use UserService to authenticate users,
    // thus dont have any credentials
    setCredentialsMatcher(new AllowAllCredentialsMatcher());
  }

  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();
    if (user == null){
      throw new AccountException("Not authenticated.");
    }

    return new SimpleAuthenticationInfo(user, null, getName());
  }

  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    // We perform Authentication only, thus return null
    return null;
  }
}

Put it all in web.xml

<web-app>
  ...
  <filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>
      org.apache.shiro.web.servlet.IniShiroFilter
    </filter-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>
        [main]
        authc = com.gdevelop.security.GaeAuthenticatingFilter
        # Optional, used for OpenId provider selection form.
        # authc.loginUrl=/WEB-INF/openIdLogin.jsp

        authcRealm = com.gdevelop.security.GaeAuthenticatingRealm

        [urls]
        /account/* = authc
      </param-value>
    </init-param>
  </filter>

  ...
  <filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

Build-in Authorizing Realm

For demo purpose, we use the build-in IniRealm. Just configure it in web.xml file.

<web-app>
  ...
  <filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>
      org.apache.shiro.web.servlet.IniShiroFilter
    </filter-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>
        [main]
        authc = com.gdevelop.security.GaeAuthenticatingFilter
        # Optional, used for OpenId provider selection form.
        # authc.loginUrl=/WEB-INF/openIdLogin.jsp

        authcRealm = com.gdevelop.security.GaeAuthenticatingRealm

        [users]
        # format: username = password, role1, role2, ..., roleN
        test@example.com  = ,admin
        test1@example.com = ,president
        test2@example.com = ,darklord,schwartz
        test3@example.com = ,goodguy,schwartz

        [urls]
        /account/* = authc
      </param-value>
    </init-param>
  </filter>

  ...
  <filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

Custom Authorizing Realm

You can implement a custom Authorizing Realm. The JdbcRealm is a good starting point to do so. See also the DatastoreRealm of the http://code.google.com/p/shiro-gae project.

<web-app>
  ...
  <filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>
      org.apache.shiro.web.servlet.IniShiroFilter
    </filter-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>
        [main]
        authc = com.gdevelop.security.GaeAuthenticatingFilter
        # Optional, used for OpenId provider selection form.
        # authc.loginUrl=/WEB-INF/openIdLogin.jsp

        authcRealm = com.gdevelop.security.GaeAuthenticatingRealm

        authzRealm = <full-qualified class name>

        [urls]
        /account/* = authc
      </param-value>
    </init-param>
  </filter>

  ...
  <filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

Secure our application

Now we are ready to perform authorization. For example, in your servlet class, we can check user permission, role as below:

Subject currentUser = SecurityUtils.getSubject();
if (currentUser.hasRole("manager")){
  ...
}
if (currentUser.isPermitted("reports:generate")){
  ..
}

Resources

Sample code base on the Apache Shiro Quickstart

Google App Engine
Apache Shiro

]]>
http://www.gdevelop.com/blog/2010/12/apache-shiro-on-appengine/feed/ 2
Visual GUI Designer in web browser http://www.gdevelop.com/blog/2010/10/visual-gui-designer-in-web-browser/ http://www.gdevelop.com/blog/2010/10/visual-gui-designer-in-web-browser/#comments Fri, 29 Oct 2010 04:33:43 +0000 Trung http://blog.gdevelop.com/?p=58 Continue reading ]]> I spent some my free time to develop a Visual GUI Designer application using GWT and GEF.

Visual GUI Designer

Currently, we have almost all basic editing features:

  • Tools Palette
  • Property Sheet
  • Copy, Cut, Paste, Undo and Redo
  • Keyboard shortcuts

The demo is running at demo.gdevelop.com

The application is currently in early stage, comments and suggestions are appreciated.

]]>
http://www.gdevelop.com/blog/2010/10/visual-gui-designer-in-web-browser/feed/ 0
Invoke GWT RPC services deployed on Google App Engine http://www.gdevelop.com/blog/2010/03/invoke-gwt-rpc-services-deployed-on-google-app-engine/ http://www.gdevelop.com/blog/2010/03/invoke-gwt-rpc-services-deployed-on-google-app-engine/#comments Sat, 13 Mar 2010 12:57:02 +0000 Trung http://blog.gdevelop.com/?p=19 Continue reading ]]> SyncProxy allows you to invoke GWT RPC services from pure Java (no JSNI) code.
From version 0.1.2, you can invoke your RPC services deployed on AppEngine.

This post shows you how to use this new feature of SyncProxy.

The service interface

For example, we have an helloApp application and a RPC service GreetingService

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name);
}

And the service implementation is as below

public class GreetingServiceImpl extends RemoteServiceServlet
      implements GreetingService {
  public String greetServer(String name) {
    return "Hello, " + name;
  }
}

Assume the application is deployed on AppEngine and the servlet URL is configured at http://example.appspot.com/helloApp/greet

Java client code

Create new proxy instance for the service interface:

private static GreetingService rpcService =
  SyncProxy.newProxyInstance(GreetingService.class,
        "http://example.appspot.com/helloApp", "greet");

This will create a new proxy instance which implements your GreetingService.

Then invoke the service method.

String result = rpcService.greetServer("SyncProxy");

Secure your service

We modify our service implement which enforce user to login to access to the service:

public class GreetingServiceImpl extends RemoteServiceServlet
      implements GreetingService {
  public String greetServer(String name) {
    // implement the security
    UserService userService = UserServiceFactory.getUserService();
    if (!userService.isUserLoggedIn()){
      throw new RuntimeException("Access Denied");
    }
    // We can also enforce only admin user can access to the service
    /*
    if (!userService.isUserAdmin()){
      throw new RuntimeException("Access Denied");
    }
    */

    return "Hello, " + name;
  }
}

Invoke the secured service

Before invoke the secured service, you have to login to the application.

SyncProxy.loginGAE("https://example.appspot.com",
    "http://example.appspot.com/helloApp/greet",
    "yourusername@gmail.com", "yourpassword");

Then invoke the service method.

String result = rpcService.greetServer("SyncProxy");

Download SyncProxy

Get SyncProxy (with source code) at http://code.google.com/p/gwt-syncproxy/

]]>
http://www.gdevelop.com/blog/2010/03/invoke-gwt-rpc-services-deployed-on-google-app-engine/feed/ 4
Testing GWT RPC services http://www.gdevelop.com/blog/2010/01/testing-gwt-rpc-services/ http://www.gdevelop.com/blog/2010/01/testing-gwt-rpc-services/#comments Sun, 10 Jan 2010 10:10:03 +0000 Trung http://blog.gdevelop.com/?p=7 Continue reading ]]> You may know that testing with GWTTestCase are very slow. And there are many posts about testing GWT applications without using GWTTestCase.

However, it is still hard to test our RPC remote services. That is the reason I decided to develop SyncProxy which can run directly from pure Java (non JSNI) code.

Simple Test case

For example, we have an helloApp application and we want to test our GreetingService

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name);
}

Assume the server side of application is running (whether in DevMode or deployed to an web server) and the servlet URL is configured at http://localhost/helloApp/greet

The test case

public class GreetingServiceTest extends TestCase{
  private static GreetingService rpcService =
    SyncProxy.newProxyInstance(GreetingService.class,
          "http://localhost/helloApp", "greet");

  public void testGreeting() {
    String result = rpcService.greetServer("SyncProxy");
    assertTrue((result != null) && (result.startsWith("Hello, SyncProxy")))
  }
}

Explanation

SyncProxy.newProxyInstance() method requires a service interface class, a base URL and a relative servlet path.

SyncProxy will search for RPC policy files (*.gwt.rpc files) to determine appropriate policy name for the service interface. Thus, we copy gwt.rpc files from war/helloApp directory to our test case classpath.

SyncProxy.newProxyInstance() will return a new proxy instance which implements our GreetingService interface.

Simulating Async

By design SyncProxy is synchronous, e.g it invoke the remote service and wait for the result. However, our GWT logic code invokes the remote service asynchronously. SyncProxy can simulate the ‘Async’ mode too.

GreetingServiceAsync rpcServiceAsync =
SyncProxy.newProxyInstance(GreetingServiceAsync.class,
          "http://localhost/helloApp", "greet");

The code is almost the same as section above, except we use the Async version of the remote service interface.

rpcService.greetServer("SyncProxy", new AsyncCallback(){
  public void onFailure(Throwable caught) {
    ...
  }
  public void onSuccess(String result) {
    ...
  }
});

Download SyncProxy

Get SyncProxy (with source code) at http://code.google.com/p/gwt-syncproxy/

SyncProxy includes test suite (see the Java source file com.gdevelop.gwt.syncrpc.test.RPCSyncSuite) to test against the standard GTW RPC test.

Updated on 2010/03/13: New post Invoke GWT RPC services deployed on Google App Engine describes using SyncProxy with GWT RPC deployed on Google AppEngine.

]]>
http://www.gdevelop.com/blog/2010/01/testing-gwt-rpc-services/feed/ 76
Bean Properties Editor for JDeveloper 11g http://www.gdevelop.com/blog/2009/12/bean-properties-editor-for-jdeveloper-11g/ http://www.gdevelop.com/blog/2009/12/bean-properties-editor-for-jdeveloper-11g/#comments Wed, 02 Dec 2009 13:48:01 +0000 Trung http://blog.gdevelop.com/?p=34 Continue reading ]]> I developed beans with setter and getter methods frequently. And of course it is tedious to write code repeatedly for every bean’s properties.

How many key strokes for a single bean property? Too many as you guest.

In JDeveloper 10g, there is extension called Simple Java Bean Editor to allow developers to edit bean’s properties easily.

However, there is no one for JDeveloper 11g. That is one of reasons I decided to develop a new one.

Another reason is our projects require property change supports, the bean should fire property change event when setting new value to a property.

The new Bean properties Editor (beanped) has following features:

  • Functionality to edit bean properties
  • Property change supports

Installation

  • Download it in the Downloads page
  • In JDeveloper 11g select menu Help -> Check for Updates
  • In the step 2 of “Check for Updates” wizard select “Install from Local File”
  • Click Browse button and select the downloaded file.
  • Review the license and click button “I Agree”
  • Click button “Next” and then “Finish”

Note: After installed, for your convenience, the Bean Properties Editor will create a new Update Source in the JDeveloper. When a new version is released, your JDeveloper will notify you to perform the update.

Using Bean Properties Editor

Bean Properties Editor
Figure 1. Bean Properties Editor screen shot – Bean Editor tab

Bean Properties Editor
Figure 2. Bean Properties Editor screen shot – Bean Editor screen

Add Property dialog
Figure 3. Add Property dialog

  • Open the bean Java source file. See the figure 1 above.
  • Click on “Bean Editor” tab. You will see the screen as in the figure 2 above. Just a simple user interface, there are two buttons and a table for list of properties at the bottom.
  • To add a new property: Click “Add” button, input the property name and the property type. You can select/deselect check boxes “Generate Read Method” and “Generate Write Method”. Click OK button when done
  • To remove a property: Select the property you want to remove and Click “Delete” button
  • To add/remove the property’s Read method: Select/deselect the check box in the Read column in the properties list
  • To add/remove the property’s Write method: Select/deselect the check box in the Write column in the properties list

Generated code

With few key strokes and mouse click, the Bean Properties Editor generates following code

package com.gdevelop.samples.bean;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Student {
  private String name;
  private transient PropertyChangeSupport changeSupport =
      new PropertyChangeSupport(this);

  public Student() {
  }

  public String getName() {
    return this.name;
  }
  public void setName(String name) {
    String oldName = this.name;
    this.name = name;
    changeSupport.firePropertyChange("name", oldName, name);
  }

  public void addPropertyChangeListener(PropertyChangeListener listener) {
    changeSupport.addPropertyChangeListener(listener);
  }
  public void addPropertyChangeListener(String propName,
                                        PropertyChangeListener listener) {
    changeSupport.addPropertyChangeListener(propName, listener);
  }

  public void removePropertyChangeListener(PropertyChangeListener listener) {
    changeSupport.removePropertyChangeListener(listener);
  }
  public void removePropertyChangeListener(String propName,
                                           PropertyChangeListener listener) {
    changeSupport.removePropertyChangeListener(propName, listener);
  }
}

Feedback and new feature requests

I hope this JDeveloper’s extension is helpful and appreciated for you feedback and/or features requests.

]]>
http://www.gdevelop.com/blog/2009/12/bean-properties-editor-for-jdeveloper-11g/feed/ 1
Using OOPHM to develop XUL applications http://www.gdevelop.com/blog/2009/10/using-oophm-to-develop-xul-applications/ http://www.gdevelop.com/blog/2009/10/using-oophm-to-develop-xul-applications/#comments Fri, 30 Oct 2009 13:45:10 +0000 Trung http://blog.gdevelop.com/?p=29 Continue reading ]]> GWT bootstrap script

This post shows how we can use OOPHM to develop XUL applications in GWT. In this post, we will develop a Firefox extension and you can try yourself on Thunderbird and XulRunner.

In previous versions, GWT uses Hosted Browser and it is the only the supported browser during development cycles.

With new version, GWT 2.0 milestone 2, developers are free to choose their favorite browser, and they can develop applications from multiple browsers with OOPHM – Out Of Process Hosted Mode.

GWT has several linkers which generate the bootstrap scripts for your application.

The default IFrameLinker’s script uses document.write to inject other required scripts. However, because document.write is not available in XUL, the normal GWT bootstrap process does not work for XUL.

In addition, this bootstraps script creates a iframe element to load other scripts. Because for security reasons, content in this iframe can not access its parent chrome. See https://developer.mozilla.org/en/XUL/iframe.

XulLinker

Thus, we created another specific linker XulLinker for XUL applications. XulLinker uses Mozilla’s specific function document.loadOverlay to securely load the other scripts. XulLinker is test to run on Windows and Linux. Its source code is included in the download file.

For the purpose of this demonstration, we write a Hello application. The screenshots is as below:

Test XulLinker
Normal xul application e.g unprivileged mode

Test XulLinker In Chrome Mode
Chrome mode e.g privileged mode

GWT Development Mode
GWT-Development-Mode

The example is simple, and you can discover its source code yourself. However, some key points you need to know:

  1. In TestXulLink.gwt.xml we added a new linker: <add-linker name=”xul” />
  2. The .xul file and .nocache.js must be in same directory
  3. You have to create a Firefox extension stub and install it before writing GWT code. For this example, copy file xullinker@gdevelop.com to your Firefox extension directory and edit it to point to the war directory of this example.

Run the example in Development Mode and then type chrome://xullinker/content/XulLinker.xul?gwt.hosted=localhost:9997 in Firefox’s address bar

After compiling the example, you can run in Web mode using chrome://xullinker/content/XulLinker.xul instead.

Summary

We use XulLinker to load required scripts for GWT application. XulLinker help us to develop Firefox, Thunderbird extensions and XUL applications using Java and GWT.

Source Code: XulLinker.tgz
See the LICENSE.txt in the download file for license details.

]]>
http://www.gdevelop.com/blog/2009/10/using-oophm-to-develop-xul-applications/feed/ 0