Grails OAuth and LinkedIn APIs

Back in November, I wrote about how to talk to LinkedIn APIs with GWT. A week later, I figured out how to do it with Grails and contributed a patch to the grails-oauth plugin.

Since then, a few folks have asked how I did it. Since code speaks louder than words, I took some time and 1) verified the oauth plugin works as expected and 2) created an example application demonstrating functionality. You can find the results in my fork of grails-oauth on GitHub. You can also view the example online.

Below is a quick tutorial explaining how to integrate LinkedIn into your Grails application.

  1. Download and install Grails 1.1.2.
  2. Run grails create-app to create your application.
  3. Add the following to the bottom of grails-app/conf/Config.groovy:
    oauth {
        linkedin {
            requestTokenUrl="https://api.linkedin.com/uas/oauth/requestToken"
            accessTokenUrl="https://api.linkedin.com/uas/oauth/accessToken"
            authUrl="https://api.linkedin.com/uas/oauth/authorize"
            consumer.key="XXX"
            consumer.secret="XXX"
        }
    }
    
    You can get your consumer.key and consumer.secret at https://www.linkedin.com/secure/developer. Make sure to set the OAuth Redirect URL to http://localhost:8080/{your.app.name}/oauth/callback for testing.
  4. Download the oauth-plugin, extract it and build it using grails package-plugin. Install it in your project using grails install-plugin path/to/zip.
  5. Add a link to the GSP you want to invoke LinkedIn Authentication from:
    <g:oauthLink consumer='linkedin' returnTo="[controller:'profile']">
        Login with LinkedIn
    </g:oauthLink>
    
  6. Create grails-app/controllers/ProfileController.groovy to access your LinkedIn Profile.
    class ProfileController {
        def apiUrl = "http://api.linkedin.com/v1/people/~"
        def oauthService
        
        def index = {
     
            if (session.oauthToken == null) {
                redirect(uri:"/")
            }
     
            if (params?.apiUrl) apiUrl = params.apiUrl
            
            def response = oauthService.accessResource(
                    apiUrl, 'linkedin', [key:session.oauthToken.key, secret:session.oauthToken.secret], 'GET')
     
            render(view: 'index', model: [profileXML: response, apiUrl: apiUrl])
        }
     
        def change = {
            if (params?.apiUrl) {
                println("Setting api url to " + params.apiUrl)
                apiUrl = params.apiUrl
            }
            
            redirect(action:index,params:params)
        }
    }
    
  7. Create grails-app/views/profile/index.gsp to display the retrieved profile and allow subsequent API calls.
    <html>
    <head><title>Your Profile</title></head>
    <body>
    <a class="home" href="${createLinkTo(dir:'')}">Home</a>
    <g:hasOauthError>
        <div class="errors">
            <g:renderOauthError/>
        </div>
    </g:hasOauthError>
    
    <g:form url="[action:'change',controller:'profile']" method="get">
        Your LinkedIn Profile:
        <textarea id="payload" style="width: 100%; height: 50%; color: red">${profileXML}</textarea>
        <p>
            <g:textField name="apiUrl" value="${apiUrl}" size="100%"/>
            <br/>
            <g:submitButton name="send" value="Send Request"/>
        </p>
    </g:form>
    </body>
    </html>
    
  8. Start your app using grails run-app and enjoy.

As mentioned earlier, you can download the grails-oauth-example or view it online.

One improvement I'd like to see is to simplify the parsing of XML into a Profile object, much like the linkedin gem does for Rails.

If you're interested in learning more about LinkedIn and OAuth, I encourage you to checkout Taylor Singletary's presentation LinkedIn OAuth: Zero to Hero.

Update: I updated the oauth-plugin so it's backwards-compatible with OAuth 1.0 and added Twitter to the example application to prove it. If you're seeing "Cannot invoke method remove() on null object", it's likely caused by your redirect URL pointing to an application on a different domain.

Posted in Java at Dec 22 2009, 03:37:57 PM MST 7 Comments

Comparing Kick-Ass Web Frameworks at The Rich Web Experience

Yesterday, I delivered my Comparing Kick-Ass Web Frameworks talk at the Rich Web Experience in Orlando, Florida. Below are the slides I used:

Although it's difficult to convey a presentation in a slide deck, I can offer you my conclusion: there is no "best" web framework. I believe web frameworks are like spaghetti sauce in that everyone has different tastes and having so many choices is necessary to satisfy everyone. You can read more about the plural nature of perfection in Malcolm Gladwell's The Ketchup Conundrum (a written version of What we can learn from spaghetti sauce). Even though there is no "best" web framework, I believe GWT, Flex, Rails and Grails are frameworks that every web developer should try. They really do make it fun to develop web applications.

You can find the slides for my other RWE talk at Building SOFEA Applications with GWT and Grails.

Kudos to Jay Zimmerman for putting on a great show in Orlando this year. I had a great time talking with folks and learning in the sessions I attended. I particularly enjoyed bringing my parents and kids and staying at such a nice resort. Disney World (Magic Kingdom) and Universal Studios was very enjoyable due to the short lines. Also, the weather was perfect - especially considering the freezing cold in Denver this week. ;-)

Posted in Java at Dec 04 2009, 08:16:48 AM MST 3 Comments

Introduction to Objective-J and Cappuccino with Tom Robinson

This morning, I attended Tom Robinson's talk on Objective-J and Cappuccino. Tom is one of the founders of 280 North and creators of the Cappuccino framework and Objective-J language, so I was very interested in hearing about Cappuccino from the source. The text below are my notes, but they're also mostly Tom's words, not mine. I've added a "Thoughts" section at the end that are my words.

Tom's Team was Cocoa programmers before they started building Cappuccino. They wanted to focus on building Desktop Class Web Applications (for example, Google Maps, Meebo and 280 Slides). Tom showed a demo of 280 Slides and how it can rotate and scale images very easily, something you don't often see in web applications.

To build desktop class web applications, you can use Flash or Silverlight, but they're controlled by Adobe and Microsoft. Also, they have no iPhone support and poor Mac and Linux performance. The other option is JavaScript + DOM. They're open standards, available almost everywhere (including mobile devices) and its a very rich ecosystem with lots of competition. The downside to JavaScript is standards bodies, many incompatibilities, technical limitations (e.g. can't access web cam) and the DOM is very document-centric.

The bottom line is we can't fix Flash, but we can fix JavaScript.

This is what 280 North is trying to do with Objective-J. It's a proper superset of JavaScript, has a few syntax additions, has a powerful runtime and is implemented in JavaScript. Objective-J is analogous to Objective-C. It adds to JavaScript like Objective-C adds to C.

One of the first things Objective-J adds is Dependency Management. You can import from search paths:

@import <Foundation/CPObject.j>

Or from relative paths:

@import "ApplicationController.j"

@import prevents duplicate loads has asynchronous downloading and synchronous execution. That means all files are downloaded before evaluation begins, but to the programmer, it seems to happen synchronously.

The thing that sets Cappuccino apart from other libraries is its inheritance model. It uses classical OO inheritance (using Objective-C syntax).

@implementation Person : CPObject {
    String firstName @accessors;
    String lastName @accessors;
}

- (String) fullName {
    return firstName + lastName;
}

@end

The type definitions (String) are ignored for now and primarily used for documentation. In the future, they plan to add optional static typing, hence the reason for having them. Tom is unsure if you can leave off the String type or if the compiler requires it.

@implementation has proper support for super and language syntax support. One of the reasons they chose Objective-C is because classical inheritance works great for UI Frameworks.

Objective-J uses "send a message" syntax instead of "call a method" syntax. In the code snippets below, the first line is JavaScript, the second is Objective-J:

object.method()
[object method]

object.methodWithFoot(arg1)
[object methodWithFoo:arg1]

object.methodWithFooBar(arg1, arg2)
[object methodWithFoo:arg1 bar:arg2]

Dynamic Dispatch is one of the most interesting parts of Objective-J. forwardInvocation in Objective-C is like method_missing in Ruby. Methods can be used as references, for example:

var action = @selector(someMethod:);

Runtime mutability is important for KeyValueCoding (KVC) and KeyValueObserving (KVO). KVC allows you to swap classes at runtime and KVO allows you to listen for when property values change. At runtime, a $KVO_ClassName is generated. This class notifies any registered observers when values are changed and then calls the original class to change the property.

Cappuccino
Cappuccino is an application framework, not a library. It uses the Hollywood Principle: "Don't call us, we'll call you".

The Framework handles document management (open, save, revert), content editing (undo, redo, copy, paste) and graphics manipulation. The DOM is designed for documents (same is true for HTML and CSS). Tom doesn't like the DOM as its not a good API for building applications. Proof is all the JavaScript libraries built to make the DOM better.

Cappuccino has an MVC framework and CPView is its View. It's analogous to a <div> and represents a rectangle on the screen. Everything visible is a CPView or one of its subclasses. It defines resizing and layout behavior. CoreGraphics is Cappuccino's canvas-like drawing API. It uses VML on IE, canvas on everything else.

Very little of the code in Cappuccino talks to the DOM (less than 2%). It's not just about providing widgets that work in all browsers, it's a way to write platform independent display code.

Events are done very differently than most JavaScript libraries. Browser's dispatching is not used. A single event listener is registered for each type of event on the window. These events are captured and sent to the objects that need to know about them. This allows for consistent events across all browsers, even keyboard events. It also allows for creating custom event flows and easily creating custom events. Cappuccino events allow you to get around a common problem with DOM Events where you can't click on overlapping rectangles.

Notifications can be registered and sent very easily. Both "scoped" and private notifications can be created.

Undo Management is included in Cappuccino. It manages a stack of undos for you. Redos are "free" and undo functionality is part of the document architecture. This makes it easy to integrate with auto-save functionality.

Run loops (also called event loops) are an advanced feature of Cappuccino. They allow you to perform actions on every run loop. This enables complex optimizations for DOM/Graphic operations and undo grouping.

The final part of Cappuccino is Keyed Archiving. Keyed Archiving stores a graph of Objective-J objects. It handles reference cycles, conditional inclusions, has an efficient data format and works on the client and server (Objective-J can be run on the server). The data format is similar like binary, but it's UTF-8. Keyed Archiving is used for archiving views and used heavily in 280 Slides for storing, retrieving, and exporting presentations.

Other applications implemented with Cappuccino include almost.at and Mockingbird. EnStore uses it too, but only for its admin interface.

An interesting extension for Rails developers is CPActiveRecord, a reimplementation of Rails' ActiveRecord in Cappuccino.

There are several tools included with Cappuccino:

  • objj: command line Objective-J
  • objcc: "compile" ahead of time
  • press: optimize code and resources
  • nib2cib: convert Mac OS X nibs
  • capp: project creation

All these tools are built on Narwhal (which conforms to the CommonJS standard).

CommonJS
CommonJS is an effort among server-side JavaScript projects to standardize non-browser JavaScript APIs. There's numerous API specifications (so far):

  • Binary, File, IO
  • stdin, stdout, stderr, args, env
  • Web server gateway (JSGI) - similar to WSGI and Rack for Python and Ruby

To learn more about CommonJS, see CommonJS effort sets JavaScript on path for world domination.

Narwhal is 280 North's implementation of CommonJS APIs. It works with multiple JavaScript engines, including Rhino, JavaScriptCore (SquirrelFish) and XUL Runner. According to Tom, Rhino is an order of magnitude slower than JavaScriptCore and V8. Of course, Narwhal supports Objective-J too.

Aristo
Aristo is the new default theme in Cappuccino and was created by the Sofa design firm. It includes windows, tabs and menus and is open source so you can modify.

Atlas
Atlas is an IDE for Cappuccino, focused on building user interfaces graphically. Atlas is a downloadable application for OS X. It's written almost entirely in Cappuccino. The desktop version bridges Cappuccino windows to native windows. Tom did a demo of Atlas and showed how its layout feature allows you pin, center and align very easily. It's all done with JavaScript because doing layouts with CSS is often very painful. After that, he showed us how can you Atlas to very easily build a Web Application and then export it as a native OS X application without changing a line of code. Atlas includes Mozilla's Bespin for code editing.

To learn more about Aristo and Atlas, you might want to checkout Ajaxian's Big News from Cappuccino: Aristo and Atlas from earlier this year.

Atlas has a $20 Beta Program if you're interested in trying it out.

My Thoughts
Cappuccino looks like a very cool web framework. It reminds me of GWT in that you have to learn a new language to use it. However, Atlas takes a lot of that pain away. I particularly like how it has document and undo/redo support built-in. On my current GWT project, this would be very useful as we've had to build this functionality by hand.

Posted in The Web at Dec 03 2009, 11:21:59 AM MST 2 Comments