Saturday, December 24, 2011

Google's GSON library to parse JSON

Google's OAuth 2.0 library returns access token related information in JSON format as shown in the sample below:


{
  "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in":3920,
  "token_type":"Bearer"
}


I was looking for a library to parse JSON and stumbled across GSON, which was very straightforward to use. The library has methods to create a java object from JSON or JSON from a java object. The sample program below shows how to do the former.

Download GSON library from here.

Create a class that can be used to create java objects to hold converted JSON.



public class GoogleAccessToken {
String access_token;
String refresh_token;
String token_type;
int expires_in;
@Override
public String toString() {
return "access_token: " + access_token + "refresh_token: " + refresh_token +" - " + "token_type:"+ token_type + " - " + "expires_in:" + expires_in;
}
public String getAccessToken() {
return access_token;
}
public String getRefreshToken() {
return refresh_token;
}
public String getTokenType() {
return token_type;
}
public int getExpiresIn() {
return expires_in;
}
}


Assume myJsonString variable has the JSON that needs to be parsed.

Gson gson = new GsonBuilder().create();
GoogleAccessToken jsonObject = gson.fromJson(myJsonString,GoogleAccessToken.class)



Now that the JSON is converted to java object form, you can access it's variables using the accessor functions.

jsonObject.toString()
//the above line prints the following: 
//access_token: 1/fFAGRNJru1FTz70BzhT3Zg refresh_token: - token_type: Bearer - expires_in: 3920



Monday, October 17, 2011

How to use google app engine's (experimental) federated identity option for providing OpenID support

Google App Engine provides two simple ways for providing authentication services for your app.
  • Google Accounts API
    • Using Google Accounts API, you can allow users to login to your app using their google account (gmail id). 
  • Federated Login
    • Using Federated Login, you can allow users to login using any OpenID identity provider (Yahoo, Google Apps account etc.)
The focus of this post is to explain the latter using Google Apps Domain as the identity provider. If you are interested in learning about the former, you can refer to this link. Google App Engine team did a good job of documenting this approach whereas documentation for federated login approach is not comprehensive. 

Here are the requirements we are going to fulfill in this example:
  • Provide users ability to login using their Google Apps email ID
  • Provide users ability to invoke your app from their google apps universal navigation bar [SSO implementation - users should not be prompted to enter their password again because they are already logged into their google apps]. 

How-to
  • Set authentication option in Google App Engine Settings to Federated Login

  • Set up security constraints in web.xml so that when users go to any of your app urls directly, App Engine will prompt them for authentication. When App Engine encounters a url that needs to be accessed only by logged in users and the user is not logged in, it directs the user to URL /_ah/login_required. You will have to create a servlet that handle requests to this URL.  We will address this an a later step but it's important to keep in mind that /_ah/login_required URL itself should be accessible without user being logged in. Otherwise, it would result in a recursion error. 
          <security-constraint>
                   <web-resource-collection>
                            <web-resource-name>accessible without login</web-resource-name>
                            <url-pattern>/_ah/login_required</url-pattern>
                   </web-resource-collection>
          </security-constraint>

          <security-constraint>
                 <web-resource-collection>
                          <web-resource-name> accessible with login</web-resource-name>
                          <url-pattern>/*</url-pattern>
                 </web-resource-collection>
                <auth-constraint>
                            <role-name>*</role-name>
                </auth-constraint>
           </security-constraint>
  • Create servlet mapping for the servlet you'll be creating to handle requests to /_ah/login_required URL
          <servlet>
                  <servlet-name>LoginRequiredServlet</servlet-name>
                  <servlet-class>com.yourcompany.server.LoginRequiredServlet</servlet-class>
          </servlet>
         <servlet-mapping>
                  <servlet-name>LoginRequiredServlet</servlet-name>
                  <url-pattern>/_ah/login_required</url-pattern>
         </servlet-mapping>
  • Create a simple login page to which LoginRequiredServlet can direct users to for entry of login id/domain
  • In LoginRequiredServlet, use App Engine's UserService class to create login url and redirect user to that url if the user is not already logged in
          UserService userService = UserServiceFactory.getUserService();
          User user = userService.getCurrentUser();
          if (user != null) {
                  //Forward the user to you app start page
           } else {

                //forwardingUrl is the link to which you want user  to be
                // sent to after successful authentication
                String loginUrl = userService.createLoginURL(forwardingUrl,
                 null, domain, null);

                 resp.sendRedirect(loginUrl);
           }

You will find more information the following article useful:
Using Federated Authentication via OpenID in Google App Engine



Thursday, October 13, 2011

Lessons



I am a self taught web programmer. So, everything I do takes a longer that I would like because I have to do a lot research to understand a topic before I code for it. For instance, I wanted to implement openID. So, I had to first learn what OpenID was all about and then try to implement it. Along the way, I have learned a few lessons

  • If, at first, you can't find what you are looking for, try harder - Every day my admiration for search engines increases. It's amazing how you can solve majority of the issues by googling around. Sometime the initial keywords do not work but if you apply some creativity to come up with the right keywords, you can always find the information that can help in solving the problems you are facing. 

  • Main constraint for doing anything is mental tenacity. Serious works requires tremendous amount of concentration and achieving that is very exhausting but if you persist the results will appear.

  • Don't give up - There were several occasions when i felt like giving up on some issues but I continued to persist only to realize I was really close to success. Had I given up I wouldn't have attained success. This theory is exemplified by this video. 

Tuesday, October 11, 2011

Google Apps Integration and App Engine's namespaces

I have integrated our GAE app with Google Apps Marketplace. I set the namespace strategy to GOOGLE_APPS_DOMAIN so that each Google Apps domain will have it's own isolated dataset.

When I enter the app from the app's login page by entering Google App's email id and password, everything works fine. Namespace is being set to the domain name. However, when I enter the app from Google Apps universal navigation link, Namespace is being set to blank instead of the domain name. After a quick troubleshooting session, I found that NamespaceManager.getGoogleAppsNamespace(). method is not returning the domain name when the app is accessed from the universal navigation bar.

After some delving into App Engine's API source code, I came up with a workaround that I can use until I find the root cause of why the original approach didn't work.


case GOOGLE_APPS_DOMAIN: {

/*
* Original code. Commented out because getGoogleAppsNamespace
* not returning the apps domain name. Unable to find out the
* reason
*/

// NamespaceManager.set(NamespaceManager.getGoogleAppsNamespace());



if (NamespaceManager.getGoogleAppsNamespace().equals("")) {

Object userOrganizationObject;
String userOrganization;

userOrganizationObject = com.google.apphosting.api.ApiProxy
.getCurrentEnvironment()
.getAttributes()
.get("com.google.appengine.api.users.UserService.user_organization");

if (userOrganizationObject == null) {
userOrganization = "";
} else {
userOrganization = userOrganizationObject.toString();
}

NamespaceManager.set(userOrganization);

} else {

NamespaceManager.set(NamespaceManager
.getGoogleAppsNamespace());
}

break;
}


Thursday, April 28, 2011

Using Google Refine and Google Maps API to calculate distance between two addresses


Distance Calculation Using Refine and Google Maps API:

·         Create two columns
o   Origin – origin address (address can be anything – complete address, just city, start, zip, country or any combination of tose]
o   Destination – destination address
·         Create a new column “distance api response” based on Origin column using the url option

Copy this in expression field show below [if you use the column names Origin and Destination, you don’t have to change anything in this formula]
"http://maps.googleapis.com/maps/api/directions/json?origin="+escape(value, "url")+"&destination="+escape(cells["Destination"].value, "url")+"&sensor=false"



        
               
·         Create a new column called “distance” – create it based on “distance api response” column and use the following formula in the expression
with(value.parseJson().routes[0].legs[0].distance,pair,pair.text)

Monday, April 18, 2011

How to get GWT DateBox to show only the date part

While searching for tips on this, I found this useful blog post.
The only change i made is I replaced the deprecated function
getShortDateFormat with getFormat method from DateTimeFormat class.

With deprecated method:
So to format a DateBox to display a date like 06/26/2009
dateBox = new DateBox();
dateBox.setFormat(
new DateBox.DefaultFormat(
DateTimeFormat.getShortDateFormat()));

With new method:
fromDate = new DateBox()
fromDate.setFormat(
new DateBox.DefaultFormat(
DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT)));

Saturday, April 16, 2011

Date Operations in GWT

Standard java class java.util.Calendar does not work in GWT. Instead, use GWT class com.google.gwt.user.datepicker.client.CalendarUtil.



Similarly, for formatting and parsing date/time, use com.google.gwt.i18n.client.DateTimeFormat


Convert Date to String - Format

DateTimeFormat.PredefinedFormat.DATE_SHORT).format(newDate())



Convert String to Date - Parse

DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_SHORT).parse(dateString)