Posts Tagged 'gwt'

Next: Trying to have nicely styled GWT forms

My next challenge is to get a form going in my GWT/GAE app. I would like it to end up as a nicely styled piece of Java code. I am hoping that the following references help me out.

These seem to fit my model of good advice, well-explained. We shall see.

Displaying Links in GWT FlexTables

Lately I’ve been working on displaying links inside of tables in GWT applications. The situation is this. You have a table of information you want  to display. Each row corresponds to a row in a database table. You want to display the table and allow users to select the different rows. You want the display of links controlled by css.

In the past, I’ve simply generated the html for a table and arranged for the right cells to be links to other parts of the application. With GWT, I’ve found at least three ways I could do this with a FlexTable. With this post, I am trying to explain them and think about which way is the best.

The biggest problem is not getting the data displayed. FlexTable makes that very easy. The challenge is figuring out what to do for the css in the table. I want the following:

  • Java code sets the style names for elements, but does not set individual attributes.
    That means that once the code is right, the display can be changed simply by editing the css.
  • The user gets visual feedback as they move the mouse around over the links.
  • The text parts that are links are styled so the user can see that they are links.
    Visited links are displayed in a different color than unvisited links.

It’s turning out to be a bit more complicated than I expected. There are several different methods that you can use and so far, for me at least, there is no perfect solution that works in the browsers I have tried.

Different Methods

  1. Build your own links by using Hyperlink objects.
  2. Rely on CSS pseudo classes for hover (e.g. name-link:hover).
  3. Rely on  Java code to handle mouse-over and mouse-out events. Those handlers could add and remove dependent styles.

1. Building your own links is not too bad an option. If your css works with your target browsers, you get just about everything: roll-over effects for mouse movements, links, and history reflected in visited links. It’s also easy. The code looks something like this:

   Hyperlink nameLink = new Hyperlink ();
   nameLink.setHTML (nameText);
   nameLink.setTargetHistoryToken ("edit="+new Integer (rowSpecificId));
   flexTable.setWidget (rowNum, 1, nameLink);

One negative is that it might not fit in with your notions of events and event handling in GWT. If you want to generate an event when the link is clicked, you don’t have it. Lack of events may also mean you’ve taken a step away from whatever MVP framework you have adopted.

2. The CSS pseudo class approach, where you add “:hover” css classes, is pretty good. For not much effort, you get the roll-over effects you want — though it looks like there could be a few browsers that do not support them completely. You don’t get history, however, so all the areas that you have hover styles display as linked areas, but since they are not links, they look like links without history.

For example, if you have a name-link style and you attach that to the cell that contains the text you want to show as a link, you’d have definitions like the following:

  name-Link {color: #8800AA; text-decoration : underline; cursor:pointer; }
  name-Link:hover {color: #8800AA;  text-decoration : none; background: #eeeeff; cursor: pointer;}
In your Java code, you would have something like:
 flexTable.setText(rowNum, 1, nameText);
 flexTable.getCellFormatter ().addStyleName (rowNum, 1, "name-Link");

3. If you rely on Java code to adjust styles as the mouse moves over linked text, which is what the tips from StudyBlue suggest, you get roll-over effects, but still no history.  Since you are adding click handlers, it makes a certain amount of sense to do the mouse roll-over handlers at the same time.

You won’t be able to use the technique they describe as is because the mouse listener classes have been deprecated. The new handler methods can do the same thing. You end up doing the following for them:

public class MyMouseEventHandler implements MouseOverHandler, MouseOutHandler {
{
  public void onMouseOver(final MouseOverEvent moe) {
    Widget widget = (Widget) moe.getSource();
    widget.addStyleDependentName("hover");
  }
  public void onMouseOut(final MouseOutEvent moe) {
    Widget widget = (Widget) moe.getSource();
    widget.removeStyleDependentName("hover");
  }
}

The Java code you’d use in your view looks like:

You’d also have to have this code in your view.

  Label nameLabel = new Label (nameText);
  nameLabel.setStyleName ("name-Link");
  MyMouseEventHandler meh = new MyMouseEventHandler ();
  nameLabel.addMouseOverHandler (meh);
  nameLabel.addMouseOutHandler (meh);
  flexTable.setWidget (rowNum, 1, nameLabel);

For styles, you’d have class names “name-Link” and “name-Link-hover” since adding a dependent style name of “hover” results in “-hover” being added to the name.

Conclusion

The way I see it, the Hyperlink method has a lot going for it. It makes the most of standard css and counts on the browsers to do their job in handling history and supporting css. What concerns me is that seems to be leading me away from the MVP framework that I wanted to try out. (For more on this, see my earlier note on MVP).

Because of that, I am going to to stay away from generating Hyperlinks and go with an approach that relies on Java code setting up click events for the rows in the table. I don’t yet see the value in handling mouse roll-over like what was suggested by the StudyBlue people. You have sufficient control using the CSS pseudo classes (e.g. “:hover”), and doing it that way does not require additional Java code.

This analysis is based on my work with GWT 2.0 and the following browsers: IE 8, Firefox 3.6.6, Chrome 5.0.375, and Safari 4.0.5.

Of course, GWT is still pretty new to me, and I may have missed something. I welcome the comments and suggestions of others.

Basics of GWT Authentication

I have been trying to understand how to authenticate users for a GWT application. This is my version of the basics.

Overview

I took the starter application for a GWT app, the greeting app, and modified it to be LoginAndGreet. Before being able to see the greeting from the server, users must sign in with their Google  id and password.

The code that follows looks complicated, but it’s not really. Basically all you are doing is:

  1. Adding some lines to your web.xml file so the server side knows that you want authenticated access.
  2. Doing something on the client side to request user information from the server.
  3. That request triggers a redirect so you are prompted for your user id and password.
  4. When the authentication request succeeds, the client side is notified and continues loading your application.

Details

1. Add security constraint to web.xml. To require a login for all resources in your web application, put these lines before the welcome-file-list section of the file.

<security-constraint>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>

2. Do something in onModuleLoad method that retrieves user information from the server via RPC. It can be something as simple as getUserEmail, as shown here.

/**
* This is the entry point method.
*/
public void onModuleLoad()
{
// Start out by trying to get information about the current user.
// If that succeeds, we will continue to set up the app. See onLoggedIn below.
getUserEmail ();

}

/**
* Show a form for the user to fill in to get a greeting from the server.
*/

public void onLoggedIn()
{
// Note that this is basically the same as the onModuleLoad method in the starter code.

String name = “GWT User”;
if (userEmail == null) name = name + ” (not logged in)”;

// … original onModuleLoaded code goes here

}

3-4. The request goes through a method like getUserEmail below.

Calling it triggers a redirect so you are prompted for your user id and password. Note that getUserEmail, upon success calls onLoggedIn and your application loads as it used to.


/**
* Use RPC to login the current user.
* Save the email address if it succeeds. Otherwise, bring up an alert box.
*/
private void getUserEmail ()
{
greetingService.getUserEmail (new AsyncCallback<String>() {
public void onFailure(Throwable caught)
{
Window.alert ("You have not logged in yet. Refresh this page to try again.");
}
 

public void onSuccess (String result)
{
userEmail = result;
onLoggedIn ();
}
});
}

So the changes to onModuleLoad are minor. You will of course have to add methods to the service classes that define the RPC for getting user information. Those classes look like the following.


@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService
{
static class NotLoggedInException extends Exception {}

String getUserEmail () throws NotLoggedInException;
String greetServer(String name) throws NotLoggedInException;
}

public interface GreetingServiceAsync

{
void getUserEmail (AsyncCallback<String> callback);
void greetServer(String input, AsyncCallback<String> callback);
}

On the server side, calls must be made to UserService methods provide by Google.

@SuppressWarnings(“serial”)
public class GreetingServiceImpl extends RemoteServiceServlet
implements GreetingService
{

/**
* Check whether the user is logged in. Return the current User information or
* throw an exception.
*
* @return String
* @throws GreetingService.NotLoggedInException
*/

public User checkUserLoggedIn () throws GreetingService.NotLoggedInException
{
UserService userService = UserServiceFactory.getUserService();
if (!userService.isUserLoggedIn ()) throw new GreetingService.NotLoggedInException ();
return userService.getCurrentUser ();
}

/**
* Returns email address of the user logged in.
*
* @return String
* @throws GreetingService.NotLoggedInException
*/

public String getUserEmail () throws GreetingService.NotLoggedInException
{
// Before we do anything, check to see if the user is logged in.
User user = checkUserLoggedIn ();
return user.getEmail ();
}

/**
* Returns information about the user and what is running on the server.
*
* @return String
* @throws GreetingService.NotLoggedInException
*/

public String greetServer(String name) throws GreetingService.NotLoggedInException
{
User user = checkUserLoggedIn ();                                                             // added this to ensure user is logged in

// Construct a greeting message.
String serverInfo = getServletContext().getServerInfo();
String userAgent = getThreadLocalRequest().getHeader(“User-Agent”);
return “Hello, ” + name + “!<br><br>I am running ” + serverInfo
+ “.<br><br>It looks like you are using:<br>” + userAgent
+ “.<br><br>You logged in with email: ” + user.getEmail ();                        // added extra lines to show email address
}

} // end class

Once you get that far, you have the basics for authentication with Google accounts for a GWT application. You will know you have succeed if the first thing you see in the browser window is a form to fill in your user id.

Source Code

The example was done originally with Google App Engine v 1.3 and GWT 2.0, but has also been run with GAE 1.4.2 and GWT 2.2.0.

Source code is available in Google Docs at
https://docs.google.com/leaf?id=0B0wYSnCBkoR6ODM4NWJkODctNzcwMy00ZTJiLTgxNWYtMDQ4MDY3MzExODM1&hl=en

References

For Google App Engine on its own, read Google Accounts Java API Overview.

If you do not want to use Google accounts, read this:
http://code.google.com/p/google-web-toolkit-incubator/wiki/LoginSecurityFAQ

Common code for checking is what David Chapman talks about. I’m not sure he follows all the suggestions from the FAQ above.

Great article on security and Javascript: http://groups.google.com/group/Google-Web-Toolkit/web/security-for-gwt-applications?pli=1


Going with Google Code

In my last post, I talked about two different frameworks for MVP that I was studying. Which one should I use for my work?

Well, I really want to use the GWT-Presenter framework. I just have not been able to get it going. You can get the code for it via SVN — version 1 or newer — but I kept finding all sorts of new features and improvements while reading other people’s blog’s (David Chapman’s blog, in particular). Without examples of use of the new features, I was not making the progress I wanted to make on the app side.

So, for now, I am going with the framework illustrated by the Google folks. That’s Large Scale Application Development and MVP.

How to do MVP

I have found a couple of great examples of using the Model-View-Presenter pattern with GWT (Google Web Toolkit).

  1. Large Scale Application Development and MVP – posted in the Google code website. It has a good example of a Contact application. This seems like a very straightforward approach
  2. GWT-Presenter- This framework looks to be very well designed. Their example is a replacement for the greeting test app you get when you create a new GWT application in Eclipse. For more on this framework, see Chris Lowe’s blog.

The big questions for me follow.

  • What are the differences in the two frameworks?
  • Which framework should be the starting point for my work?

What are the differences in the two frameworks?

My sense right now is that there is something very compelling about Framework 1 (from Google Code). It seems so straightforward and takes care of the essential elements: (1) MVP;  (2) events and event bus; (3) getting browser history right so you can bookmark pages; (4) easily tested.  Their discussion of events is good and they make a point that you really only want to have app-wide events on the event bus. They warn against getting “bogged down in event handling”. For the Contact app example, they list 5 events and 5 event handlers that they have defined. It feels about right to me, meaning the events make sense as things you’d have to know about in order to present the user with the right view at the right time.

One thing to note about the example of Framework 1. It does have a server side for updating contacts, but is totally mocked up. It’s not really stored in a database and you can only have one new contact at a time. Each time add a new contact, it updates the list item on the list it is maintaining on the server side.

Framework 1 handles history by having its AppController track ValueChangeEvents from the History object. So AppController implements onValueChange, and it’s there that it checks the history token and locates the next Presenter to run. It looks a bit like:

public class AppController implements ValueChangeHandler { 
  ... 
  public void onValueChange(ValueChangeEvent event) { 
    String token = event.getValue(); 

    if (token != null) { 
      Presenter presenter = null; 

      if (token.equals("list")) { 
        presenter = new ContactsPresenter(rpcService, eventBus, new ContactView()); 
      } 
      else if (token.equals("add")) { 
        presenter = new EditContactPresenter(rpcService, eventBus, new EditContactView()); 
      } 
      else if (token.equals("edit")) { 
        presenter = new EditContactPresenter(rpcService, eventBus, new EditContactView()); 
      } 

      if (presenter != null) { 
        presenter.go(container); 
      }
    } 
}

What I like about Framework 2 (GWT-Presenter) is that it has all the things that Ray Ryan talked about. It makes use of Dependency Injection using Guice and GIN, and it looks like it has a little bit more developed handling of history, as embodied in a PlaceRequest object.

What framework should be the starting point of my work?

I don’t know yet. My next step will be to take the Google Code Contact example and redo it on top of GWT-Presenter. That will test my understanding of GWT-Presenter. I expect to find that GWT-Presenter is just a little bit better in its handling of events and places. Besides, it will force me to come to terms with DependencyInjection (DI), which Ray Ryan insists is not such a big deal and is really good for you.

GWT Best Practices

Like many people, I have been inspired by the talk given by Ray Ryan on “Best Practices for Architecting Your GWT App”.

If you prefer reading to listening, check out the slides and transcripts of the talk.



Follow

Get every new post delivered to your Inbox.

Join 72 other followers