Wednesday, February 1, 2017

Issues Debugging Code Using Spring Roo

Seeing delays for data to show up in your variables window when debugging? Seeing java.lang.reflect.InvocationTargetException in the veriables window? These can be caused by the default toString method added by roo when the class is annotated with @RooToString. The default toString method will utilize:
 ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);

If your object has large collections it will iterate through then before returning a result for toString. This can be quite slow. If your has a null value for some fields like version a null pointer exception will be raised which is converted to  the InvocationTargetException you are seeing. To fix these issues you can either add exclude parameters to the RooToString annotation, push in and fix the toString method, or remove the annotation.

Friday, April 22, 2011

Adding Rich Dynamic Data to jQuery Mobile Apps

In my first post we added simple dynamic content to a jQuery Mobile (jqm) app and in the second we secured the content with Spring Security. In this post we will look at displaying richer dynamic content. Working with jqm we have several options. First we could return complete pages from the server that jqm could load and swap out via ajax. Another option would be to return parts of the page as HTML content that we could swap into the pages. The last option that we will implement is the server returning json content that we will use to create dynamic views. The biggest influence on this decision was that I want to build a app that can also be published in native apps using PhoneGap. By returning too much (good luck quantifying that) HTML content, Apple will get worried that you will make changes to your app without getting it re-approved and smite your application. The other main advantage of transmitting content as json is to minimize the size of the transmitted content on a page request.
First we will update our dynamic data controller method to return a set of books.
@RequestMapping(value="/dynamicData", method=RequestMethod.GET)
public @ResponseBody List getDynamicData(Model model){
  List books = new ArrayList();
  Book book = new Book();
  book.setId(1l);
  book.setTitle("The Road to Serfdom");
  book.setAuthor("Friedrich Hayek");
  books.add(book);
  book = new Book();
  book.setId(2l);
  book.setTitle("Capitalism and Freedom");
  book.setAuthor("Milton Friedman");
  books.add(book);
  book = new Book();
  book.setId(3l);
  book.setTitle("The General Theory");
  book.setAuthor("John Keynes");
  books.add(book);
  return books;
}

private class Book {

  private Long id;
  private String title;
  private String author;
  
  public Long getId() {
    return id;
  }
  public void setId(Long id) {
    this.id = id;
  }
  public String getTitle() {
    return title;
  }
  public void setTitle(String title) {
    this.title = title;
  }
  public String getAuthor() {
    return author;
  }
  public void setAuthor(String author) {
    this.author = author;
  }
}
Now that out ajax call will return the list we have two options for displaying this data to the user. The first would be programmatically generating html from the json content. The second would be to use a javascript templeting plugin. By utilizing a templeting plugin we will have more concise code that is easier to maintain. This demo will use the recently added top level jQuery template plugin, currently in beta.
With the goal of displaying the books in a standard jqm styled list the following simple template was created. It will style title and author and add the books id as a data element that will be helpful for onclick methods.
<script id="bookTemplate" type="text/x-jquery-tmpl">
  <li data-id=${id} class='bookButton'>
 <h3>${title}</h3>
 <p>${author}</p>
  </li>
</script>
As this template will be used repetitively we will precompile it to a named template. This should speed up execution time. See http://boedesign.com/misc/presentation-jquery-tmpl/#13.
$('#bookTemplate').template('bookTemplate');
Next we will update bar with the shell of a jqm list to hold the data.
<div id="bar" data-role="page">
  <div data-role="header">
 <h1>Bar</h1>
  </div>
  <div data-role="content"> 
 <ul data-role="listview" id="dynamicContentHolder">
 </ul>
 <br/>
 <a href="#foo" data-inline="true" data-role="button" >To foo</a>
 <a id="buttonSignOut" name="buttonSignOut" href="#" data-role="button" data-inline="true">Sign Out</a>
  </div>
</div>
Finally we will update the ajax call to parse the json response content, generate html content with the template, and insert the content into bar’s jqm list. Finally we will refresh the listview to allow jqm to apply appropriate styling to the content.
$('#bar').live('pagebeforeshow',function(event, ui){
  $.mobile.pageLoading();
  $('#dynamicContentHolder').text('');
  var dynamicDataResp = $.ajax({
        url: "/dynamicData.json",
        dataType: 'json',
        async: false,
        cache: false            
      });
  if(dynamicDataResp.status == 200){
    var dynamicDataObj = jQuery.parseJSON(dynamicDataResp.responseText);
    $.tmpl('bookTemplate', dynamicDataObj).appendTo('#dynamicContentHolder');
    $('#dynamicContentHolder').listview('refresh');
  }
  ...
The next thing I wanted to be able to do, is control navigation and pass information on the selected book when a user selects one off the list. So let’s add a new page for this content.
<div id="bookDetails" data-role="page">
  <div data-role="header">
 <h1>book details</h1>
  </div>
  <div data-role="content">
 <span id="bookContent"/>
  </div>
</div>
Now as we included the class bookButton on each of our book list items we can register a click handler that will query the id from the element, save it as context information to the page, and navigate to the details page.
$('.bookButton').live('click', function() {
  var bookId = $(this).jqmData('id');
  $('#bookDetails').jqmData('bookId', bookId);
  $.mobile.changePage('#bookDetails');
});
Finally on bookDetail's pagebeforeshow event we can alter the page databased on the bookId metadata stored to the page. The example below simply prints out the info, but using the skills you have learned so far you could easily issue a query here to retrieve additional information on the book.
$('#bookDetails').live('pagebeforeshow', function(event, ui){
  var bookId = $('#bookDetails').jqmData('bookId');
  if(bookId != null){
    $('#bookContent').text("Details about book #" + bookId + " here.");
  }
  else{
    $.mobile.changePage('#error', 'none', false, false);
  }
});
As usual here is the complete jqm app.
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1">
 <title>App Name</title>
 <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" />
 <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
 <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
 <script id="bookTemplate" type="text/x-jquery-tmpl">
      <li data-id=${id} class='bookButton'>
        <h3>${title}</h3>
        <p>${author}</p>
      </li>
    </script> 
 <script type="text/javascript">
 $('#bookTemplate').template('bookTemplate');
    
 $(document).bind("mobileinit", function(){
  
  $('.bookButton').live('click', function() {
   var bookId = $(this).jqmData('id');
   $('#bookDetails').jqmData('bookId', bookId);
   $.mobile.changePage('#bookDetails');
    });
    
   $('#bookDetails').live('pagebeforeshow', function(event, ui){
  var bookId = $('#bookDetails').jqmData('bookId');
  if(bookId != null){
    $('#bookContent').text("Details about book #" + bookId + " here.");
  }
  else{
    $.mobile.changePage('#error', 'none', false, false);
  }
   });
  
  $('#buttonSignOut').live("click", function() {
   $.mobile.pageLoading(); 
   $.ajax({
    url: '/signout',
    complete: function(transport) {
     if(transport.status == 200) {
       $.mobile.changePage('#foo');
      } else {
       $.mobile.changePage('#error', 'none', false, false);
      }
    }
   });
        return false;      
      });
   $('#signInForm').live("submit", function() {
  $.mobile.pageLoading(); 
     // Submit the form
  $.ajax({
   type: 'POST',
   url: '/signin/authenticate',
   data: $('#signInForm').serialize(),
   complete: function(transport) {
    if(transport.status == 200) {
     history.back();
    } else {
     $('#loginError').show();
     $.mobile.pageLoading(true);
    }
      }
  });
  return false;
   });
   
   $('#login').live('pagebeforeshow', function(event, ui){
  $('#loginError').hide();
   });
 
 
  $('#bar').live('pagebeforeshow',function(event, ui){
   $.mobile.pageLoading();
   $('#dynamicContentHolder').text('');
   var dynamicDataResp = $.ajax({
       url: "/dynamicData.json",
       dataType: 'json',
       async: false,
                      cache: false       
     });
   if(dynamicDataResp.status == 200){
    var dynamicDataObj = jQuery.parseJSON(dynamicDataResp.responseText);
    $.tmpl('bookTemplate', dynamicDataObj).appendTo('#dynamicContentHolder');
    $('#dynamicContentHolder').listview('refresh');
   }
   else if(dynamicDataResp.status == 401){
    $.mobile.changePage('#login');
    return false;
   }
   else{
    $.mobile.changePage('#error', 'none', false, false);
   }
  });
 });
 </script>
 <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>
 
  </head> 
  <body> 
    <div id="foo" data-role="page">
      <div data-role="header">
  <h1>Foo</h1>
   </div>
   <div data-role="content"> 
  <h2>Foo</h2>
  <a href="#bar">To bar</a>
   </div>
   
    </div>
    <div id="bar" data-role="page">
      <div data-role="header">
  <h1>Bar</h1>
   </div>
   <div data-role="content"> 
  <ul data-role="listview" id="dynamicContentHolder">
  </ul>
  <br/>
  <a href="#foo" data-inline="true" data-role="button" >To foo</a>
  <a id="buttonSignOut" name="buttonSignOut" href="#" data-role="button" data-inline="true">Sign Out</a>
   </div>
    </div>
 <div id="bookDetails" data-role="page">
   <div data-role="header">
  <h1>book details</h1>
   </div>
   <div data-role="content">
     <span id="bookContent"/>
   </div>
 </div>
    <div id="login" data-role="page">
      <div data-role="header">
  <h1>Login</h1>
   </div>
   <div data-role="content">
  <span id="loginError" class="error">Your credentials are invalid. Please try again.</span>
     <form id="signInForm" data-ajax="false">
       <div data-role="fieldcontain">
            <label for="login">Username or Email</label>
            <input id="login" name="j_username" type="text" size="25" autocorrect="off" autocapitalize="off" />
          </div>
     <div data-role="fieldcontain">
    <label for="password">Password</label>
    <input id="password" name="j_password" type="password" size="25" /> 
   </div>
   <div id="submitDiv" data-role="fieldcontain">    
    <input type="submit" value="login" data-inline="true"/>
   </div>
     </form> 
   </div>
    </div>
 <div id="error" data-role="page">
      <div data-role="header">
  <h1>Error</h1>
   </div>
   <div data-role="content"> 
  Click back to return to the previous page.
   </div>
    </div>
  </body>
</html>

Monday, April 18, 2011

Securing jQuery Mobile Dynamic Content with Spring Security

In my last post we looked at getting started with dynamic content in jQuery Mobile. In this post we will continue where we left off last time with integrating Spring Security to protect this dynamic content or serve user specific content. It is important to note that I am only worried about protecting the dynamic content and not the static page content. As we will see, much of the work is augmenting the default behaviors of both Spring Security and jQuery Mobile to make them play nice together.
Again, I will not go into basic spring security configuration as there are many available resources to help you get up to speed. We will start will augmenting a basic Spring Security config to only allow authenticated users to access /dynamicData.
<intercept-url pattern="/dynamicData" access="isAuthenticated()" />
This will prevent access to the method but Spring Security’s default behavior is to respond with a 302 redirecting to the login page. jQuery will follow this redirect yielding the html login page as the result of the dynamic data ajax request. To fix this problem we will configure a custom entry point utilizing the DelegatingAuthenticationEntryPoint. By looking for the X-Requested-With=XMLHttpRequest header attribute we can augment the behavior for ajax requests while maintaining the original functionality for traditional requests.
<http use-expressions="true" entry-point-ref="entryPoint">
...
<beans:bean id="entryPoint" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">
  <beans:constructor-arg>
    <beans:map>
      <beans:entry key="hasHeader('X-Requested-With','XMLHttpRequest')" value-ref="http401UnauthorizedEntryPoint" />
    </beans:map>
  </beans:constructor-arg>
  <beans:property name="defaultEntryPoint">
    <beans:bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
      <beans:property name="loginFormUrl" value="/signin"/>
    </beans:bean>
  </beans:property>
</beans:bean>
Once the header element has been identified we will need to specify a AuthenticationEntryPoint that will return a HTTP status code. While it might be tempting to use the Http403ForbiddenEntryPoint that is predefined by Spring, this status code should be used for resource requests by an authenticated user that does not have adequate permissions for the resource. Therefore will will need to create a custom entry point that will return the appropriate code, 401.
@Component
public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {

  /**
   * Always returns a 401 error code to the client.
   */
  public void commence(HttpServletRequest request, HttpServletResponse response, 
      AuthenticationException arg2) throws IOException, ServletException {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Not Authenticated");
  }
}
Now that our request will receive the appropriate status code we handle this case in our in our dynamic data request and add a login page.
var dynamicDataResp = 
    $.ajax({
   url: "/dynamicData.json",
   async: false,
   cache: false 
 });
if(dynamicDataResp.status == 200){
  $('#dynamicContentHolder').text(dynamicDataResp.responseText);
}
else if(dynamicDataResp.status == 401){
  $.mobile.changePage('#login');
}
else{
  $.mobile.changePage('#error', 'none', false, false);
}
By default jQuery Mobile will submit forms via ajax with the expectation of receiving an HTML to render. As this functionality does not work with our desired flow, we will disable this feature by setting data-ajax="false".
<div id="login" data-role="page">
  <div data-role="header">
    <h1>Login</h1>
  </div>
  <div data-role="content">
    <span id="loginError" class="error">Your credentials are invalid. Please try again.</span>
    <form id="signInForm" data-ajax="false">
      <div data-role="fieldcontain">
        <label for="login">Username or Email</label>
        <input id="login" name="j_username" type="text" size="25" autocorrect="off" autocapitalize="off" />
      </div>
      <div data-role="fieldcontain">
        <label for="password">Password</label>
        <input id="password" name="j_password" type="password" size="25" /> 
      </div>
      <div id="submitDiv" data-role="fieldcontain">    
        <input type="submit" value="login" data-inline="true"/>
      </div>
    </form> 
  </div>
</div>
Now that we have disabled jQuery Mobile’s ajax form submission we will want to setup our own. By binding to the submit event we can create our own asynchronous ajax call to post the form to Spring Security’s authenticate method.
$('#signInForm').live("submit", function() {
  $.mobile.pageLoading(); 
  // Submit the form
  $.ajax({
 type: 'POST',
 url: '/signin/authenticate',
 data: $('#signInForm').serialize(),
 complete: function(transport) {
  if(transport.status == 200) {
  history.back();
  } else {
  $('#loginError').show();
  }
 }
  });
  return false;
});
Again Spring Security’s default action will not work with our flow. If the login was successful we would get redirected to the entry page (or the last requested page) and if the login failed we would receive the contents of the login form page. To fix this we will add custom success and failure handlers to our form-login.
<form-login login-page="/signin"  login-processing-url="/signin/authenticate"
authentication-success-handler-ref="ajaxAuthenticationSuccessHandler"
authentication-failure-handler-ref="ajaxAuthenticationFailureHandler" />
Below are simple implementations that return HTTP status codes. To maintain the traditional form capabilities for other parts of your site simply extend one of springs handlers, such as SavedRequestAwareAuthenticationSuccessHandler and SimpleUrlAuthenticationFailureHandler to first check for the X-Requested-With=XMLHttpRequest header attribute.
@Component
public class AjaxAuthenticationSuccessHandler implements
    AuthenticationSuccessHandler {

  @Override
  public void onAuthenticationSuccess(HttpServletRequest request,
      HttpServletResponse response, Authentication authentication)
   throws IOException, ServletException {
 response.sendError(HttpServletResponse.SC_OK, "User Authenticated");
  }
}
@Component
public class AjaxAuthenticationFailureHandler implements AuthenticationFailureHandler {
 
  public void onAuthenticationFailure(HttpServletRequest request,
      HttpServletResponse response, AuthenticationException exception) throws  
      IOException, ServletException {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
      "User Could Not Be Authenticated");
  }
}
The last feature needed is sign out capabilities. To accomplish this we will add a signout button to bar.
<div data-role="content"> 
  <h2>Bar</h2>
  <a href="#foo">To foo</a>
  <span id="dynamicContentHolder"></span>
  <a id="buttonSignOut" name="buttonSignOut" href="#" data-role="button" data-inline="true">Sign Out</a>
</div>
Again we will use jQuery to hijack the click of the button.
$('#buttonSignOut').live("click", function() {
  $.mobile.pageLoading(); 
  $.ajax({
      url: '/signout',
      complete: function(transport) {
        if(transport.status == 200) {
          $.mobile.changePage('#foo');
        } else {
          $.mobile.changePage('#error', 'none', false, false);
        }
   $.mobile.pageLoading(true);
    }
  });
  return false;      
});
And configure Spring Security to return status codes. Again extend SimpleUrlLogoutSuccessHandler if you need to maintain existing form functionality.
<logout logout-url="/signout" delete-cookies="JSESSIONID" success-handler-ref="ajaxLogoutSuccessHandler"/>
@Component
public class AjaxLogoutSuccessHandler implements LogoutSuccessHandler {
 
  public void onLogoutSuccess(HttpServletRequest request,
      HttpServletResponse response, Authentication authentication)
      throws IOException, ServletException {
    response.sendError(HttpServletResponse.SC_OK, "User Logged Out");
  }
}
One final note before I show you the front end code all together; I have read that sometimes IE will submit a ajax request with the XMLHttpRequest attribute in lower case. I have not tested this yet, but I would watch out for this.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1">
 <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" />
 <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
 <script type="text/javascript">
 $(document).bind("mobileinit", function(){
  $('#buttonSignOut').live("click", function() {
   $.mobile.pageLoading(); 
   $.ajax({
    url: '/signout',
    complete: function(transport) {
     if(transport.status == 200) {
       $.mobile.changePage('#foo');
      } else {
       $.mobile.changePage('#error', 'none', false, false);
      }
    }
   });
        return false;      
      });
   $('#signInForm').live("submit", function() {
  $.mobile.pageLoading(); 
     // Submit the form
  $.ajax({
   type: 'POST',
   url: '/signin/authenticate',
   data: $('#signInForm').serialize(),
   complete: function(transport) {
    if(transport.status == 200) {
     history.back();
    } else {
     $('#loginError').show();
     $.mobile.pageLoading(true);
    }
      }
  });
  return false;
   });
   
   $('#login').live('pagebeforeshow', function(event, ui){
  $('#loginError').hide();
   });
 
 
  $('#bar').live('pagebeforeshow',function(event, ui){
   $.mobile.pageLoading();
   $('#dynamicContentHolder').text('');
   var dynamicDataResp = $.ajax({
       url: "/dynamicData",
       async: false,
       cache: false 
     });
   if(dynamicDataResp.status == 200){
    $('#dynamicContentHolder').text(dynamicDataResp.responseText);
   }
   else if(dynamicDataResp.status == 401){
    $.mobile.changePage('#login');
   }
   else{
    $.mobile.changePage('#error', 'none', false, false);
   }
  });
 });
 </script>
 <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>
  </head> 
  <body> 
    <div id="foo" data-role="page">
      <div data-role="header">
  <h1>Foo</h1>
   </div>
   <div data-role="content"> 
  <h2>Foo</h2>
  <a href="#bar">To bar</a>
   </div>
    </div>
    <div id="bar" data-role="page">
      <div data-role="header">
  <h1>Bar</h1>
   </div>
   <div data-role="content"> 
  <h2>Bar</h2>
  <a href="#foo">To foo</a>
  <span id="dynamicContentHolder"></span>
  <a id="buttonSignOut" name="buttonSignOut" href="#" data-role="button" data-inline="true">Sign Out</a>
   </div>
    </div>
    <div id="login" data-role="page">
      <div data-role="header">
  <h1>Login</h1>
   </div>
   <div data-role="content">
  <span id="loginError" class="error">Your credentials are invalid. Please try again.</span>
     <form id="signInForm" data-ajax="false">
       <div data-role="fieldcontain">
            <label for="login">Username or Email</label>
            <input id="login" name="j_username" type="text" size="25" autocorrect="off" autocapitalize="off" />
          </div>
     <div data-role="fieldcontain">
    <label for="password">Password</label>
    <input id="password" name="j_password" type="password" size="25" /> 
   </div>
   <div id="submitDiv" data-role="fieldcontain">    
    <input type="submit" value="login" data-inline="true"/>
   </div>
     </form> 
   </div>
    </div>
 <div id="error" data-role="page">
      <div data-role="header">
  <h1>Error</h1>
   </div>
   <div data-role="content"> 
  Click back to return to the previous page.
   </div>
    </div>
  </body>
</html>

Intro to Building Dynamic Apps With jQuery Mobile

The first task in building the mobile focused web application was to select a javascript framework. There are a good dozen frameworks or so on the market and many write-ups about them so I will just list a few links.
To make a long story short, I have started working with jQuery Mobile because it is open source, looks quite slick with very little additional styling work, has a large number of supported platforms, is built with graceful degradation in mind, and appears to have a lot of momentum behind it. It has also been documented to work well with tools that wrap web content into native apps like PhoneGap. In addition, I find jQuery to make JavaScript development tolerable, if not fun from time to time.
JQuery Mobile is currently in Alpha 4.1 of its initial release. Given this, the documentation to get you up and running with a dynamic app is somewhat fragmented or missing. I hope my next few posts will help alleviate this problem.

The first issue is how to populate a page with dynamic content. My example will show server code specific to Spring but any server side technology will do.
First we will setup two pages; foo and bar.

<body>
  <div id="foo" data-role="page">
    <div data-role="header">
      <h1>Foo</h1>
    </div>
    <div data-role="content">    
      <h2>Foo</h2>
      <a href="#bar">To bar</a>
    </div>
  </div>
  <div id="bar" data-role="page">
    <div data-role="header">
      <h1>Bar</h1>
    </div>
    <div data-role="content">    
      <h2>Bar</h2>
      <a href="#foo">To foo</a>
    </div>
  </div>
</body>

These pages have links to each other that will be hijacked by jQuery Mobile. If the page was not currently available in the DOM, jQuery would fetch it via an ajax call. In this case both pages are contained within a single html page so jQuery will simple create the transition between the two. Now let’s say that we wanted to provide some dynamic content on page bar. Here we have added a span to hold the content.

<div data-role="content"> 
  <h2>Bar</h2>
  <a href="#foo">To foo</a>
  <span id="dynamicContentHolder"></span>
</div>

There are several options for how to pull content down from the server (which I will go into in a later post), but for now we will simple treat it as a string. Next I created a Spring controller method to provide the content. If you want to know more about serving ajax content with spring read ajax-simplifications-in-spring-3-0. Additionally if you will have both traditional pages and ajax powered pages displaying the same content check out Spring’s content negotiation capabilities in rest-with-spring-contentnegotiatingview. With content negotiation you can reuse the same controller methods to serve multiple content types. The method below simply replies to a request to /dynamicData with the string “data string”.

@RequestMapping(value="/dynamicData", method=RequestMethod.GET)
public @ResponseBody String dynamicData(Model model){
  return "data string";
}

During the page transition lifecycle, jQuery Mobile provides 4 events; pagebeforeshow, pagebeforehide, pageshow, & pagehide.  As we do not want the partially assembled page to be shown to the user, we will bind our logic to the pagebeforeshow event. The first thing we do is call pageLoading to block the ui and notify the user that their content is loading. jQuery Mobile’s display of this box does not include the time spent executing our code in the 'pagebeforeshow' function. Next we conduct the jQuery ajax call. See http://api.jquery.com/jQuery.ajax/ for more information on the api. As we do not want jQuery Mobile to render and transition to the next page until our dynamic content is in place, we set async to false to stop further execution until the content is loaded. In general you should be careful with synchronous calls as it blocks all other actions from occurring in the browser. Once the data is received we can easily populate the dynamicContentHolder with jQuery. Additionally we can examine the http status code of the response to handle errors retrieving data. In the case of an error changePage is used to divert the page flow to the error page (There might be a better way of doing this and if so please let me know). The only non-default option added to changePage is to not include the transition in the history. This way the jQuery Mobile back button will take the user back to the referring page (foo).

$('#bar').live('pagebeforeshow',function(event, ui){
   $.mobile.pageLoading();    
   var dynamicDataResp = $.ajax({
    url: "/dynamicData.json",
    async: false,
    cache: false
  });
  if(dynamicDataResp.status == 200){
    $('#dynamicContentHolder').text(dynamicDataResp.responseText);
  }
  else{
    $.mobile.changePage('#error', 'none', false, false);
  }
});

<div id="error" data-role="page">
  <div data-role="header">
    <h1>Error</h1>
  </div>
  <div data-role="content">    
    Click back to return to the previous page.
  </div>
</div>

The last thing to note is that page events that are bound to the first page must be put in place before jQuery Mobile loads. The recommended approach is to place code inside a function bound to mobileint.

Putting everything together here is our final front end code.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" />
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
    <script type="text/javascript">
      $('#bar').live('pagebeforeshow',function(event, ui){
        $.mobile.pageLoading();    
        var dynamicDataResp = $.ajax({
          url: "/dynamicData.json",
          async: false,
          cache: false
        });
        if(dynamicDataResp.status == 200){
          $('#dynamicContentHolder').text(dynamicDataResp.responseText);
        }
        else{
          $.mobile.changePage('#error', 'none', false, false);
        }
      });
    </script>
    <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script> 
  </head>
  <body>
    <div id="foo" data-role="page">
      <div data-role="header">
        <h1>Foo</h1>
      </div>
      <div data-role="content">    
        <h2>Foo</h2>
        <a href="#bar">To bar</a>
      </div>
    </div>
    <div id="bar" data-role="page">
      <div data-role="header">
        <h1>Bar</h1>
      </div>
      <div data-role="content">    
        <h2>Bar</h2>
        <a href="#foo">To foo</a>
        <span id="dynamicContentHolder"></span>
      </div>
    </div>
    <div id="error" data-role="page">
      <div data-role="header">
        <h1>Error</h1>
      </div>
      <div data-role="content">    
        Click back to return to the previous page.
      </div>
    </div>
  </body>
</html>

In my next few posts we will look at supporting rich dynamic content and integrating with spring security. If you know of a cleaner way of building this example out please let me know.

Sunday, April 17, 2011

Getting Started With Mobile Development

I created this blog several years ago with the intent of posting articles to help others get started with new technology but never got around to it. Recently I have started looking into building mobile apps. As this is a new area for me, it seems like a great topic to get the blog started.

As I follow the lazy programmer’s doctrine of working smarter not harder, I started off looking for a technology that would enable me to do as little work as possible to support multiple devices. From here I found tools like PhoneGap. PhoneGap creates a native application by running traditional web content (HTML, CSS, & JS) in a browser while exposing native API functionality through JavaScript. As I intended to build a web version of the app in addition to the native ones, this seems like an ideal way to move forward. The following posts will document the evaluation of a framework to build the mobile web application, followed by a comparison of the PhoneGap like tools once the web app has reached a state of maturity.