I wrote a Google+ Library

Because of a project, I have been trying out several Google+ Libraries. The following libraries were the ones I tried:

The first being made by Google and the second by… Not Google.

I cannot say I was satisfied with any of those two. The first one required what seemed like a thousand dependencies while the second one refused to work due to a JSON exception that seemed to have no documentation on-line. So, I decided I’d do myself a favor and make something that works the way I want it to work: with as few dependencies as possible and very easy to use.

I used three dependencies:

I picked these three (well, two actually, commons-codec was required by scribe) because they are easy in use and do not require other dependencies.

And this is the result: My very own Google+ library

I designed it with a few guidelines in mind:

 1. Easy to get it working

GooglePlus gPlus = new GooglePlus(apiKey, secret);
 Desktop.getDesktop().browse(new URI(gPlus.getAuthorizationUrl()));
 gPlus.verifyUser(new Scanner(System.in).next()); 

Three lines and we’re connected to the G+ api.

 2. Cope with calls that weren’t predefined

 private static final String apiUrl = "https://www.googleapis.com/plus/v1/";

public Response getResponse(String apiCall) {
 OAuthRequest request = new OAuthRequest(Verb.GET, apiUrl + apiCall);
 oAuthService.signRequest(accessToken, request);
 Response response = request.send();
 return response;
}

The library provides predefined calls to the api, such as “findUser(String query)”. Normally the inner workings would be shielded from external use, but if you need to make your own calls to G+, you can call the above method in net.mymilkedeek.social.gplus.core.Manager with your custom api call.

This will come in handy if Google updates its G+ api and this library doesn’t get updated. No need to wait, just put in the new api calls and process the Json response.

3. Easy to expand

This is awesomely achieved. To add the functionality for Comments I needed to:

  1. Create a Comment class (with fields)
  2. Create CommentManager (extends Manager<Comment>)
  3. Create CommentJsonParser (implement JsonParser<Comment>)
  4. Parse the Json to the Comment object
  5. Write one line functions in the Manager

The to-do’s

  • Add optional parameters.
  • Write more comments.
  • Better exception handling.

Download it, browse the source code, don’t download it. Do with it as you please. As long as you report bugs/notify me of things that could have been better.

  Some Example

import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Scanner;

import net.mymilkedeek.social.gplus.GooglePlus;
import net.mymilkedeek.social.gplus.activity.Activity;
import net.mymilkedeek.social.gplus.activity.ActivityManager;
import net.mymilkedeek.social.gplus.comment.Comment;
import net.mymilkedeek.social.gplus.comment.CommentManager;
import net.mymilkedeek.social.gplus.person.Person;
import net.mymilkedeek.social.gplus.person.PersonManager;

import org.json.JSONException;

public class Main {

private static final String apiKey = &quot;XXX&quot;;
private static final String secret = &quot;XXX&quot;;

 public static void main(String[] args) throws JSONException, IOException,
 URISyntaxException {
 GooglePlus gPlus = new GooglePlus(apiKey, secret);
 Desktop.getDesktop().browse(new URI(gPlus.getAuthorizationUrl()));
 gPlus.verifyUser(new Scanner(System.in).next());

 ActivityManager activityManager = gPlus.getActivityManager();
 List&lt;Activity&gt; activities = activityManager
.getActivitiesFromUser(&quot;111486046861792612952&quot;); // that's me!

 for (Activity a : activities) {
 System.out.println(a.getId());
 PersonManager personManager = gPlus.getPersonManager();
 List&lt;Person&gt; persons = personManager.findByActivityId(a.getId(),
 PersonManager.PLUSONERS);

 for (Person p : persons) {
 System.out.println(p);
 }

 persons = personManager.findByActivityId(a.getId(),
 PersonManager.RESHARERS);

 for (Person p : persons) {
 System.out.println(p);
 }
 }
 }
}

This piece of code gets all of my activities (or posts) and then gets all the users who +1’d my post or shared it. Easy peasy.

Spring Social Facebook Application on the Desktop

So, you want to access Facebook from your application from a non-web, non-mobile environment? I looked around for a bit and found Spring Social. There was “facebook-java-api”, but I didn’t get very far using it. Spring Social is exactly what it says on the tin: a module in Spring that allows you to easily access the (more popular) social networks. Documentation on how to use it in a non-web environment is pretty scarce, so I decided to throw my working Hello World online.

Things you need before we start:

There also maven support:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
<groupId>net.mymilkedeek</groupId>
 <artifactId>social</artifactId>
 <version>0.0.1-SNAPSHOT</version>
<name>MME Social</name>
<dependencies>
 <dependency>
 <groupId>org.springframework.social</groupId>
 <artifactId>spring-social-core</artifactId>
 <version>1.0.1.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.social</groupId>
 <artifactId>spring-social-facebook</artifactId>
 <version>1.0.1.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>3.1.0.RELEASE</version>
 </dependency>
 </dependencies></project>

As you can see from the pom.xml: each social network is going to require an added dependency. For this example we’re going to stick with Facebook.

Now, onto the code:

FacebookConnectionFactory connectionFactory = new FacebookConnectionFactory(apiKey, secretKey);
OAuth2Operations oauthOperations = connectionFactory.getOAuthOperations();
 OAuth2Parameters params = new OAuth2Parameters();
 params.setRedirectUri("https://www.facebook.com/dialog/oauth?client_id=" + apiKey + "&amp;redirect_uri=" + redirectUri);
 params.setScope("user_about_me,user_birthday,user_likes,user_status,publish_stream");
String authorizeUrl = oauthOperations.buildAuthorizeUrl( GrantType.AUTHORIZATION_CODE, params);

In this first bit, we are configuring our application. We set our api and secret key and we add a redirect URI, which is provided to us by Facebook. We also set the scope of our program. The scope are the permissions our application will have and what the user will see when he has to allow our application access to his Facebook data.

As you can see, Facebook uses OAuth2. For more information on OAuth, check out various tutorials and articles online.

java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
 if (!desktop.isSupported(java.awt.Desktop.Action.BROWSE)) {
 System.out.println("No browsing allowed...");
 System.exit(1);
 }

 try {
 java.net.URI uri = new java.net.URI(authorizeUrl);
 desktop.browse(uri);
 } catch (Exception e) {
 System.err.println(e.getMessage());
}

Because we have a desktop application, we have to either start a browser and point it to the authorization url or implement a browser into our application. The latter has the benefit of not relying on the user to provide you with the Token, but on the returned url. But, that’s beyond the scope of this application, so we’re just going to have the user copy paste the url into our console.

System.out.println("Token : ");
 Scanner scanner = new Scanner(System.in);
 String input = scanner.next();
 input = input.replace("https://www.facebook.com/connect/login_success.html?code=", "");
System.out.println(input);

If I have to explain this then you’re looking at the wrong tutorial.

AccessGrant accessGrant = oauthOperations.exchangeForAccess(input, redirectUri, null);
Connection<Facebook> connection = connectionFactory.createConnection(accessGrant);
Facebook facebook = connection.getApi();

This is the code of the Facebook application.  We request an Access Token from Facebook and use that to create a Facebook object. The Facebook object will allow you to utilize Facebook’s functions and data. And it will allow us to write “Hello World” to our wall by writing:

facebook.feedOperations().updateStatus("Hello World");

And that’s it. I wanted to post this because I could not find any resource that wasn’t out of date or incorrect.

Things to note:

  • Do not rely on your users to copy paste the authorization tokens. Implement a small browser into your application. This will make it that much more idiot-proof.
  • The Facebook redirect url is “https://www.facebook.com/connect/login_success.html”

Source Code

Now for the entire source code:

HelloWorld.java

package net.mymilkedeek.social;

import java.util.Scanner;

import org.springframework.social.connect.Connection;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.connect.FacebookConnectionFactory;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.GrantType;
import org.springframework.social.oauth2.OAuth2Operations;
import org.springframework.social.oauth2.OAuth2Parameters;

public class HelloWorld {
private static final String apiKey = "xxx";
private static final String secretKey = "xxx";
 private static final String redirectUri = "https://www.facebook.com/connect/login_success.html";

 public static void main(String[] args) {
 FacebookConnectionFactory connectionFactory = new FacebookConnectionFactory(apiKey, secretKey);
 OAuth2Operations oauthOperations = connectionFactory.getOAuthOperations();
 OAuth2Parameters params = new OAuth2Parameters();
 params.setRedirectUri("https://www.facebook.com/dialog/oauth?client_id=" + apiKey + "&amp;redirect_uri=" + redirectUri);
 params.setScope("user_about_me,user_birthday,user_likes,user_status,publish_stream");
 String authorizeUrl = oauthOperations.buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);

 java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
 if (!desktop.isSupported(java.awt.Desktop.Action.BROWSE)) {
 System.out.println("No browsing allowed...");
 System.exit(1);
 }

 try {
 java.net.URI uri = new java.net.URI(authorizeUrl);
 desktop.browse(uri);
 } catch (Exception e) {
 System.err.println(e.getMessage());
 }

 System.out.println("Token : ");
 Scanner scanner = new Scanner(System.in);
 String input = scanner.next();
 input = input.replace("https://www.facebook.com/connect/login_success.html?code=", "");
 System.out.println(input);

 AccessGrant accessGrant = oauthOperations.exchangeForAccess(input, redirectUri, null);
 Connection<Facebook> connection = connectionFactory.createConnection(accessGrant);
 Facebook facebook = connection.getApi();

 facebook.feedOperations().updateStatus("Hello World");
 }
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
<groupId>net.mymilkedeek</groupId>
 <artifactId>social</artifactId>
 <version>0.0.1-SNAPSHOT</version>
<name>MME Social</name>
 <dependencies>
 <dependency>
 <groupId>org.springframework.social</groupId>
 <artifactId>spring-social-core</artifactId>
 <version>1.0.1.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.social</groupId>
 <artifactId>spring-social-facebook</artifactId>
 <version>1.0.1.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>3.1.0.RELEASE</version>
 </dependency>
 </dependencies>
</project>

Comments, suggestion and/or corrections are always welcome.