Chapter 30. Using Data from Social Networks in Portlets

This chapter describes how to consume data from social networks such as Google+, Facebook and Twitter in portlets. While the kind of data accessible through public APIs varies among the providers, it is generally possible to read data from social networks, and in some cases, write data (in the case of Facebook).

30.1. Social Portlets Example Code

This section cites code from Social Portlets example project from the Quickstarts Collection . There is a portlet that displays the most recent Facebook wall posts, a portlet that displays a list of Google+ circles (and who is in the circles), and a portlet that shows user account details from Twitter.

30.1.1. Prerequisites

Configure the portal with a specific OAuth provider.
Finally, the given portal user must have the OAuth access token saved as part of their User Profile in the portal. To retrieve the access token the user must either:
  • Authenticate or register on the portal with the specific OAuth provider (social network),
  • Link their account with the OAuth Provider - this can be done through the dedicated tab of User Info screen in the portal UI or programmatically from portlets.
Once the user has an OAuth access token saved in their profile, it can be used to call various operations in the particular social network.

30.2. Retrieving the Access Token

The OAuth Provider API is used to retrieve the current user's access token. In the Social Portlets Quickstart, there is an OAuthProviderFilter portlet filter, which retrieves the social network access token of the current user and saves the token into the RequestContext bean. Alternative flows result in one of the following messages:
  • OAuth provider is not enabled in portal configuration.
  • User is not logged in.
  • User's access token does not exist.
  • User's access token is invalid or expired.
These messages are presented by error.jsp or token.jsp . In case the access token is unavailable or invalid, the token.jsp will show a link, which the user can follow to link their GateIn Portal account with the given social network. Once linked, the user will obtain the access token.
Image showing the Facebook User Info Portlet warning, which features a link that allows the user to re-link their Facebook account with the Portal.

Figure 30.1. Token Unavailable Message

Example 30.1. Declaration of OAuthProviderFilter in portlet.xml


<filter>
  <filter-name>FacebookFilter</filter-name>
  <filter-class>org.gatein.security.oauth.portlet.OAuthPortletFilter</filter-class>
  <lifecycle>ACTION_PHASE</lifecycle>
  <lifecycle>RENDER_PHASE</lifecycle>
  <init-param>
    <name>accessTokenValidation</name>
    <value>SKIP</value>
  </init-param>
  <init-param>
    <name>oauthProviderKey</name>
    <value>FACEBOOK</value>
  </init-param>
</filter>

Example 30.2. Mapping of OAuthProviderFilter in portlet.xml

<filter-mapping>
  <filter-name>FacebookFilter</filter-name>
  <portlet-name>Facebook*</portlet-name>
</filter-mapping>
Mapping of OAuthProviderFilter in portlet.xml, specifies that all portlets with the name starting with "Facebook" are handled by this filter. This same mapping configuration can be applied to Google+ and Twitter.
All portlets in the Social Portlets Quickstart extend the AbstractSocialPortlet . It is a subclass of the standard portlet API's GenericPortlet . It contains some basic functionality and helper methods useful for all social portlets, one of which is handling the action to redirect to the Social login.

Example 30.3. actionRedirectToOAuthFlow in AbstractSocialPortlet

@ProcessAction(name = ACTION_OAUTH_REDIRECT)
public void actionRedirectToOAuthFlow(ActionRequest aReq, ActionResponse aResp) throws IOException {
  String customScope = aReq.getParameter(PARAM_CUSTOM_SCOPE);
  getOAuthProvider().startOAuthWorkflow(customScope);
}
If customScope is null, the portal will request scopes only configured in configuration.properties . Otherwise, the portal will request this scope in addition to scopes from configuration.properties . This allows portlets to ask for more scopes than scopes from configuration.properties.

Example 30.4. Widening the Scope On-demand for OAuth Token Permissions

Portlets can request wider scope on demand in cases when wider scope is required to complete a task.
In configuration.properties , Facebook is enabled only with the default scope email.
In FacebookStatusUpdatePortlet , a user wants to publish messages on their Facebook Wall. For this purpose, an access token with scope publish_message is required.
Before the user is able to publish a message on their Facebook wall, the portlet displays an error message that the present scope is insufficient, and offers the user an opportunity to correct the issue.
Screen shot displaying the "insufficient privileges" error a user encounters if they try to publish a status update on their wall without the publish_stream scope.

Figure 30.2. Insufficient Privileges Error

Clicking the link starts an OAuth2 flow. The user is redirected to Facebook and is asked to permit the publish_message scope. After permitting the scope change, the user is able to publish messages.
In this scenario, CDI is used to store the access token. The RequestContext class is annotated as @RequestScoped . Each portlet contains only logic specific to its purpose, and does not need to specifically handle retrieving the access token.

30.3. Facebook

There are three portlets that demonstrate a basic integration with Facebook.

title

FacebookUserInfoPortlet
A simple portlet showing some details of the current user's profile on Facebook, such as first name, last name, username, e-mail and profile picture.
FacebookFriendsPortlet
An advanced portlet showing friends of the current user and their pictures. It also supports pagination (only 10 friends are on screen, but you can switch to different page size to see more friends). When clicking a friend, the portlet displays the last few status messages from the given friend's Facebook Wall.
FacebookStatusUpdatePortlet
A portlet with the capability to publish messages to the Wall of the current user.
All three portlets leverage the third-party library Rest FB( http://restfb.com), which provides the capability to send requests to the Facebook Graph API and convert JSON responses to plain Java objects (POJOs).
To decouple logic from the UI and handle error situations, the helper class FacebookClientWrapper offers multiple methods to retrieve objects from the Facebook Graph API and convert them to POJOs or beans relevant to the portal. These converted methods can be dispatched by PortletRequestDispatcher to JSP pages, which handle the HTML markup rendering.
The example portlets are using a small subset of the Facebook Graph API. It is possible use the whole spectrum of the Facebook Graph API operations in your own portlets. The complete documentation of Graph API is available on the Facebook Developers site, which is located at http://developers.facebook.com/docs/reference/api/ .

30.4. Google+

There are three example portlets for showing integration with Google+. All portlets leverage Google SDK libraries.
GoogleUserInfoPortlet leverages Google OAuth2 API library and it uses an Oauth2 object to call the operation.
GoogleFriendsPortlet and GoogleActivitiesPortlet leverage Google+ API library and they use Plus object to call the operations. Portlets have available access token and they obtain the required object through a call to oauthProvider.getAuthorizedAPIObject as described in Chapter 7, OAuth Provider API.

30.5. Twitter

There is one simple portlet for Twitter: TwitterPortlet . It shows details about the current user, such as their picture, last tweet, number of followers, and other user data commonly available on a twitter user's profile.
TwitterPortlet leverages Twitter4J library to interact with Twitter. Given that the access token is available, the portlet demonstrates how to obtain the Twitter client object from Twitter4J library through calling oauthProvider.getAuthorizedAPIObject() as described in Section 7.1, “Retrieve an Instance of OAuthProvider”.

30.6. Configuration and Deployment Descriptors

pom.xml
In pom.xml file of our Social Portlets Quickstart, we need to declare dependencies on JSR 286 portlet API, GateIn Portal API and CDI API:

Example 30.5. Declaration of basic dependencies in pom.xml


<!--
    The versions of these dependencies are managed in gatein-*-bom.
    Note that artifacts managed in gatein-*-bom are <scope>provided</scope> in most cases.
119.    Name only those artifacts you refer to in your code.
    Look at gatein-*-bom POM file for the complete list of available artifacts.
-->
<dependency>
    <groupId>javax.portlet</groupId>
    <artifactId>portlet-api</artifactId>
</dependency>
<dependency>
    <groupId>org.gatein.api</groupId>
    <artifactId>gatein-api</artifactId>
</dependency>
<dependency>
    <groupId>javax.enterprise</groupId>
    <artifactId>cdi-api</artifactId>
    <scope>provided</scope>
</dependency>
We also need to declare dependencies on 3rd party libraries to be able to access the public APIs of Facebook, Twitter and Google+:

Example 30.6. Declaration of 3rd party dependencies in pom.xml


<!-- Google -->
<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-plus</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-oauth2</artifactId>
    <scope>provided</scope>
</dependency>
<!-- Twitter -->
<dependency>
    <groupId>org.twitter4j</groupId>
    <artifactId>twitter4j-core</artifactId>
    <scope>provided</scope>
</dependency>
<!-- Facebook  (not provided for now as it's not needed in Portal and so it's bundled in this portlet WAR) -->
<dependency>
    <groupId>com.restfb</groupId>
    <artifactId>restfb</artifactId>
</dependency>
You may have noticed that com.restfb dependency is not declared as provided . This is because this library is not used by GateIn Portal itself, and therefore it is not bundled therein as well. We need to provide it in our WAR ourselves. Dependencies on Twitter4J and Google API libraries are provided by GateIn Portal and there is no need to package them inside our portlet WAR.
jboss-deployment-structure.xml
This file is specific for JBoss AS7 and JBoss EAP. In this file, dependencies on JBoss AS7/EAP modules are declared which are required by our portlet application.

Example 30.7. Declaration of dependencies in jboss-deployment-structure.xml

<deployment>
  <dependencies>
    <module name="com.google.apis" />
    <module name="org.twitter4j" />
  </dependencies>
</deployment>
Modules org.twitter4j and com.google.apis are part of GateIn Portal JBoss AS7 packaging and they contain the 3rd party libraries from Google+ and Twitter.
beans.xml
The presence of beans.xml file activates CDI for the application. There is nothing useful in it.

Example 30.8. beans.xml

<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
<!--
portlet.xml
It contains declaration of all social portlets. Very important is also declaration of OAuthPortletFilter and it's filter mapping.
gatein-resources.xml
Declaration of CSS files used by our portlets.

30.7. Further Steps

Import Portlets and Gadgets and Manage Pages in the User Guide for further guidance about deploying and testing the portlets.