DevX HomePage

OpenSocial: The Power of Social Networks in Your Applications

What is OpenSocial and how can you use it to build web applications that leverage the power of social networks? Find out while going from a basic example application in a local sandbox to a full-featured application deployed in a live container.
penSocial, a set of application programming interfaces (APIs) based on standard HTML and JavaScript, simplifies the creation of web-based applications that interact with social networks. Launched by Google in November 2007, the OpenSocial APIs are supported (or in the process of being adopted) by a number of different social networks, such as orkut, MySpace, Yahoo! , hi5, and Friendster. Thanks to such broad support, a developer has to learn the APIs only once to be able to contribute applications to all these different social networks. Through OpenSocial, you will be able to interact seamlessly with your orkut communities and friends, write applications that leverage your shared interests with your friends on MySpace, and so on.

This article will guide you through the OpenSocial APIs and show you how to build a couple of social applications to share interests with friends. Figure 1 and Figure 2 show the final results: two applications, loaded within the orkut container to share travel experiences and movie preferences with a network of friends.

What You Need
The OpenSocial APIs
Apache Shindig
A Java Development Kit (JDK)
Subversion
Maven2
Java Apache Tomcat


Figure 1. A Travel-Sharing Application Embedded Within orkut: This application is loaded within the orkut container to share travel experiences.
 
Figure 2. A Movie Preferences-Sharing Application Embedded Within orkut: This application is loaded within the orkut container to share movie preferences.

Introduction to Social Networks and OpenSocial
A social network is an ensemble of users who are linked to each other through a series of relationships (being friendly, being work colleagues, sharing common interests). Each user is characterized by a state or profile, which is a collection of all the variables required to describe the user fully, such as name, gender, hobbies, work, or contact information. Each user also has a series of relationships that link him to his own friends on the network. Some networks also support the concept of activities: streams of actions performed by the user within the network that alter his state or the set of his relationships with other people.

The OpenSocial APIs provide access to all these entities and are divided into the following major components, each responsible for a specific task:

A typical OpenSocial application is built completely using HTML to lay out and display information and JavaScript to define the application logic. OpenSocial applications are built on top of the Google Gadgets APIs. For this reason, an OpenSocial application looks and behaves just like a Google Gadget. To learn more about Google Gadgets, read this introductory article published on DevX or the official documentation.

Author's Note: The content is exclusively the personal opinion of the author. Under no circumstances should the content be attributed to any employer, past, present, or future, of the author, unless so stated explicitly by that individual or organization.




Shindig: A Local Development Environment
OpenSocial applications live within an OpenSocial Container that maintains the application state and information about the users and the social network they compose. Other popular containers include orkut, hi5, or MySpace. For OpenSocial application development, you can either run your code within sandboxed environments, which many containers provide, or use a container running on your local machine specifically for development purposes. (The OpenSocial "Getting Started" tutorial lists available containers on the web and the development features they support, in case you prefer that option.) The local environment option is preferable because it gives you unconstrained possibilities to test different scenarios, such as manipulating the list of friends, altering your activities stream, or impersonating different users.

In this article, you will set up a local development environment using Apache Shindig as your container. Shindig is an open source container that provides the reference implementation for the OpenSocial APIs. Therefore, you are assured that whatever application you create on your local environment will work on existing containers on the web. Once the application is finished, you may then deploy it on the web and include it in public directories (such as the orkut application gallery), so that users can include it within their personal pages and profiles and start spreading the word!

Start by downloading the Shinding container from the project website. Since no packaged version yet exists, you have to download the source code and build it from scratch. The following instructions guide you through the process, assuming that you have a Java Development Kit (JDK), Subversion, and Maven2 installed on your system (as described on the Shindig website):


mkdir ~/shindig
cd ~/shindig
svn co http://svn.apache.org/repos/asf/incubator/shindig/trunk/
cd ~/shinding/java
mvn package

Once the build finishes, you will have a WAR file suitable for deployment in a J2EE application server such as Apache Tomcat. Supposing that you have a working installation of Tomcat in your ~/tomcat folder (if you don't, you can download it from the web and unpack it in your local disk by following this link), start up Tomcat using the following command:


cd ~/tomcat/bin
./startup.sh

Once started, access the Tomcat deployment manager at http://localhost:8080/manager/html and deploy the Shindig container. If you followed the instructions above, the WAR file will be located in ~/shindig/java/server/target/shindig.war. To work properly, the Shindig container must be deployed under the root context path, so be sure to un-deploy any application that may already be deployed under the same path before deploying Shindig. If everything goes accordingly, you should be able to access the URL http://localhost:8080/gadgets/files/samplecontainer/samplecontainer.html and see something similar to Figure 3.

Click to enlarge

Figure 3. The Shindig Container Initial Page: The Shindig OpenSocial container allows you to deploy and test your applications.

The page displayed in Figure 3 is the Shindig OpenSocial container. It allows you to deploy and test your applications, as well as control the application state: changing the number and kind of friends, application data, and activities, or switching the user accessing the application. You can change the application state by providing a properly formatted XML file to the Shindig container (more on this later).




Your First OpenSocial Application
You are now ready to create your first OpenSocial application. To keep it simple, the application will enumerate only the friends currently belonging to the network of the user accessing the application. As previously sated, because OpenSocial is built on top of the Google Gadgets specifications, the first thing to do is to create an XML application specification file like this basic OpenSocial specification file:


<?xml version="1.0" encoding="UTF-8" ?> 
<Module>
  <ModulePrefs title="Opensocial Basic example" >
	<Require feature="opensocial-0.7" />
  </ModulePrefs>
  <Content type="html">
     <![CDATA[
 	 <script src="http://localhost:3000/basic/basic.js" ></script>
     <script>	
       gadgets.util.registerOnLoadHandler(init);
     </script>
     <div id='main'>
       Your friends:
       <div id='friends'></div>
     </div>
     ]]>
  </Content> 
</Module>

Save the above file with the name basic.xml. You'll notice that many things are going in the file. First of all, the XML file that describes the OpenSocial application is just like the one you would use to create a Google Gadget. The ModulePrefs section contains application metadata, such as title and required libraries. Also notice that you request the latest available version of the OpenSocial APIs with the line:


<Require feature="opensocial-0.7" />

Remember to always declare this requirement in your applications; otherwise, you won't be using the OpenSocial APIs.

The actual application contents live within the Content section. Here you include an additional JavaScript file, basic.js, that contains the application logic (see Listing 1). Then you register a handler to fire the init() function (contained in the JavaScript file) at launch time with the gadgets.util.registerOnLoadHandler() function. Finally, you declare an HTML section with the ID friends that will contain a listing of your friends.

All the OpenSocial APIs are built around the concept of asynchronous requests performed by the application toward the container. Therefore, the code in Listing 1 is organized around callback functions.

For your application to access some data from the OpenSocial container, you have to create a DataRequest object using the opensocial.newDataRequest() API call each time.

The DataRequest object acts as a container for querying different entities in a single method call. All the queries share a common format and are created in the same way:

  1. They are created using a specific method that describes the query type and the expected results (a single person or a collection), such as req.newFetchPersonRequest() or req.newFetchPeopleRequest().
  2. The first parameter always specifies the entity (person or group of persons) the request refers to, such as VIEWER of VIEWER_FRIENDS.
  3. The query is added to the DataRequest using the red.add() method, along with a key that will be used later to retrieve the response data, such as 'viewer' or 'viewerFiends' in the previous example.

In OpenSocial terminology, VIEWER represents the user logged into the browser who is using the application to navigate through his social network, while VIEWER_FRIENDS refers to the collection of users that compose the VIEWER social network. Other entities, such as OWNER and OWNER_FRIENDS, differentiate special cases (such as when one user is accessing a profile that is not his own), but they are not relevant in the context of this article. Further information about OpenSocial identifiers is available in the official documentation.

Going back to the example, the loadFriends() method requests two entities, the current viewer and its collection of friends, respectively using the req.newFetchPersonRequest() and req.newFetchPeopleRequest() calls. Finally, it sends the request to the server with the req.send(onLoadFriends) method call. This method accepts a parameter that defines the callback function that will handle the server response. In the example, the onLoadFriends() function is the designated callback. This function extracts the results from the response object (using the keys 'viewer' and 'viewerFriends' declared while constructing the request), iterates through the results, and constructs the HTML contents to be shown to the user.

Click to enlarge

Figure 4. The Basic Application Loaded Within the Shindig Container: Here is the final result when the application is loaded within the Shindig container.

Figure 4 shows the final result when the application is loaded within the Shindig container.




Changing the Application State
But where did the application load its data from? Normally, an application would query its own container (orkut, MySpace, etc.) to access information relative to the user that is accessing the application and his friends.

In the current development setup, Shindig uses an XML file that describes the application state. Here is the state (state-basic.xml) used for the basic application just created:


<?xml version="1.0" encoding="UTF-8"?>
<container>
  <people>
    <person id="john.doe" name="John Doe" gender="M">
      <friend>jane.doe</friend>
      <friend>george.doe</friend>
      <friend>maija.m</friend>
      <friend>riccardo.govoni</friend>
    </person>
    <person id="jane.doe" name="Jane Doe" phone="867-5309" gender="F">
      <friend>john.doe</friend>
    </person>
    <person id="george.doe" name="George Doe" gender="M">
      <friend>john.doe</friend>
    </person>
    <person id="maija.m" name="Maija Meikäläinen" gender="F">
    </person>
    <person id="riccardo.govoni" name="Riccardo G" gender="M" >
    </person>
  </people>
</container>

If you check the parameters used to load the application in Figure 4 again, you will notice that you are instructing the container to use the state-basic.xml file to load application state and that you are impersonating the user john.doe when accessing the application. This explains the source of the data. You can customize the XML file to verify how the application responds to different setups.

Application states can contain much more information than what is shown in state-basic.xml above, including custom data for each user and activities streams. Refer to the Shindig documentation for further info.

More OpenSocial Entities, Persistence, and Activities
So far, you have gotten an overview of the APIs that deal with people and relationships. Two further areas remain to be explored: persistence and activities.

In terms of persistence support, the OpenSocial model allows for custom data to be saved on a per-application, per-user basis. Each OpenSocial application has an associated persistent store (managed by the container) that it can use to write and read custom data. Applications cannot access data associated to different applications, preserving a compartmentalized environment. Applications have write permission only on VIEWER data: they can write data only when associated to the current user. However, they have read permission both on VIEWER data and other entities, such as VIEWER_FRIENDS. This means that applications can collect their data across networks of users--this represents the true value of a social application. For example, the application you will explore shortly allows each user to store his favorite movies, but at the same time collects the same preferences from the cluster of friends using the same application. The result is aggregated movie reports representing the preferences of the entire network of friends.

The following two API functions are used to store and read data:


// assume req is a DataRequest object.
// data store request
req.add(req.newUpdatePersonAppDataRequest(
  'VIEWER', key, value));
// data fetch request
req.add(req.newFetchPersonAppDataRequest(
  'VIEWER_FRIENDS',key),'friendsdata');

The req.newUpdatePersonAppDataRequest() function stores custom data. It accepts only the 'VIEWER' identifier. It then accepts a key and value for the data to be stored. Values can be strings only, so JSON should be used to handle complex objects. The OpenSocial APIs include the gadget.json.parse() and gadgets.json.stringify() utility functions to deal with bidirectional JSON conversion.

After storing data, you can fetch them using req.newFetchPersonAppDataRequest(). This call accepts wider identifiers, such as VIEWER_FRIENDS, the key that points to the data to be retrieved, and the key that will refer to them in the response returned from the data request (friendsdata in the example).

Lastly, OpenSocial applications can deal with activities streams as well. You can publish activities associated to the user and read from activities streams from his network of friends using the following two additional API functions:


// publish activity
var activity = opensocial.newActivity(params);
opensocial.requestCreateActivity(activity, priority, callback);

// read activities
// req is a DataRequest object
req.add(req.newFetchActivitiesRequest(
  'VIEWER_FRIENDS'),'activitiesKey');

The same rules described previously about read and write permissions apply. Further information about activities are available in the OpenSocial documentation.




A Concrete Example: Movie Hotlist and Travel Sharing
Now that you have a complete overview of the OpenSocial APIs, consider a pair of more complex applications that deal with data persistence. The first application stores movie rankings collected from users and provides a view that aggregates such rankings from a network of friends. The second application stores itineraries and places visited by each user and shows an interactive map that displays such itineraries from the whole network of friends. Both are good examples on how a social network can share data (movies, places) across its members. Refer to Figure 1 and Figure 2 to get an idea of the results. The two applications work in similar ways. Refer to the source code attached to this article to access the entire listings.

The first thing to do is initialize the application and read the data to be displayed. The itineraries application uses the initialization code shown in Listing 2.

The code uses a mixture of Google Maps API and OpenSocial API calls. First, it initializes a map, then it prepares the requests for the user and friends data, and finally handles them in the callback function. The renderFriendsListing() function draws the itineraries created by friends as follows:


function renderFriendsListing(friends, friendsData) {
  friends.each(function(person) {
    var data = friendsData[person.getId()];
    if (data) {
      var geodata =
        gadgets.json.parse(
        gadgets.util.unescapeString(data['userdata']));
      addLegendInfo(person);
      addTravelItineraries(
        map, person.getDisplayName(), 
        geodata.homeAddress, geodata.locations);
    }
  });
}

The above code uses the geodata object, as read from the users' stored data. (Refer to the source code for the functions that perform the effective drawing on the map.) Such data are stored using the OpenSocial persistence APIs:


function saveData() {
  userdata = {};
  userdata.homeAddress = 
    document.getElementById('homeId').value; 
  userdata.locations  = 
    document.getElementById('locationId').value.split("\n");
  var stringy = gadgets.json.stringify(userdata);

  var req = opensocial.newDataRequest();
  req.add(
    req.newUpdatePersonAppDataRequest(
    'VIEWER', 'userdata', stringy));
  req.send(onSaveData);
}

function onSaveData(response) {
  Gunload();

  // cleanup and map reset
  markersCounter = 0;
  document.getElementById("legenddata").innerHTML  = "";
  init();
}

Data are read from HTML form fields and passed to the container after converting them into a JSON string. After save, the map is redrawn to show the updated information.

The movie ratings application uses the same functions to deal with data persistence. One difference is it uses the Google AJAX search APIs to look up movie posters, given the titles suggested by the user. In addition, it defines multiple Content sections in its XML descriptor file. This allows for different renderings of the same application, depending on the container placement of the application (in a whole page by itself, or in a small panel of an existing page) as described in the multiple views documentation.

Figure 5 and Figure 6 show how the applications appear in the Shindig container, using some custom application state to provide user persistence data. The downloadable source code attached to the article contains all the details.


Figure 5. The Travel Itineraries Application Loaded Within the Shindig Container: When MMIT is installed the icon to create new mobile projects will show up in the start pane of VS.NET.
 
Figure 6. The Movie Ratings Application Loaded Within the Shindig Container: Designing apps in MMIT will be very familiar to ASP.NET developers.

Deploying Your Open Social Applications
You are now ready to deploy your applications. Every container uses its own process, but since your application is ultimately a Google Gadget, it:

  1. Moves the XML descriptor file and related resources (images, JavaScript files) on to some location on the web, such as your personal web site.
  2. Goes to your container of choice and either adds the application by directly referencing the URL that points to the XML descriptor, or adds it to the gallery of available applications for that container.

For example, if you want to publish your applications on orkut (after enabling application development on your account as described in this article), just access sanbox.orkut.com and follow the "Edit Apps" link to add your application, specifying the URL for the XML descriptor file when requested. Then, it's just about spreading the word to your network of friends and using your creations!

What Have We Learned?
In this article, you have learned what OpenSocial is and gone all the way from a basic example application in a local development environment to a full-featured application deployed in a live container. You can now further explore the OpenSocial APIs for features that were not discussed here, such as permission management and remote requests. Or you can start creating the next killer application and prepare to deploy it to your social network.

Riccardo Govoni has been working since 2003 as a J2EE developer on a variety of applications ranging from financial services to middleware in the IP television field. He currently works for Google as a software engineer. He is a Sun Certified Java Programmer (SCJP).


DevX is a division of Internet.com.
© Copyright 2010 Internet.com. All Rights Reserved. Legal Notices