Java で開発した Facebook アプリケーションを Google App Engine にデプロイする

Facebook アプリケーションを作成し、Java で実装し、Google App Engine にデプロイする

Facebook Platform には Java のネイティブ・サポートがないからといって、それが必ずしもサードパーティーの Facebook アプリケーションを Java 言語で作成する上で障害になるとは限りません。この記事では、Facebook アプリケーションを作成し、Java で実装し、Google の App Engine サービスにデプロイする方法について説明します。

Mr Joseph P. McCarthy, Developer, Dun & Bradstreet

Photo of Joseph McCarthyJoseph McCarthy はダブリンにある Dun & Bradstreet の Java 開発者です。彼はコンピューター・システムの学士号、コンピューター・エンジニアリングの準修士号で University of Limerick を卒業後、カスタム Ant タスクの開発や (Twitter、Facebook、GetGlue など) さまざまな公開 APIを扱いながら、10 年間にわたって幅広く Java 技術を扱ってきました。



2012年 7月 19日

2004年 2月にサービスの提供を開始した Facebook は、世界最大のソーシャル・ネットワークであり、9 億人を超えるユーザーが Facebook のサイトを使用し、そのユーザーとつながりを持つ友人達とコンテンツを共有しています。2007年 5月には、サードパーティーが Facebook との統合アプリケーションを作成できるようにする Facebook Platform の提供が開始されました。Facebook Platform は当初、(Java を含む) さまざまな種類のプログラミング言語をサポートしていましたが、現在提供しているのは JavaScript 用および PHP 用のネイティブ SDK (そして iOS 機器と Android 機器用のアプリケーションのサポート) のみです。しかし Facebook が Java API を提供しなくなった後、オープンソースの RestFB プロジェクトが Java API の保守を行っています (「参考文献」を参照)。

GAE (Google App Engine) は PaaS (Platform as a Service) であるため、GAE に登録した開発者は自分が Python、Java、Go などで作成したアプリケーションを Google のインフラストラクチャー上で実行することができます。この記事では、Facebook アプリケーションを登録する方法、そのアプリケーションを Java で開発する方法、そしてそのアプリケーションを無料で GAE にデプロイし、Facebook にログインしたユーザーであれば誰でもそのアプリケーションを利用できるようにする方法について説明します (Google では、GAE にデプロイされた各アプリケーションが 1 日に使用できるリソースに関して制限を設けていることに注意してください)。

この記事で作成するのは、Facebook ユーザーの友達全員の ID とプロフィールの写真を、かつてユーザーのプロフィールにあった「友達」ページと同じようなルック・アンド・フィールで一覧表示する単純なアプリケーションで、そのためには以下のものが必要です。

  • Facebook アカウント
  • Google アカウント
  • GAE プラグインをインストールした Eclipse IDE (「参考文献」を参照)
  • Eclipse の使い方を理解していること

このアプリケーションのサンプル・コードは「ダウンロード」から入手することもできます。

アプリケーションを登録する

最初のステップは、Facebook と GAE の両方にアプリケーションを登録することです。それぞれに登録するために入力した情報が、必要に応じて確実に対応するように、両方のプラットフォームで同時にアプリケーションを作成することがプラクティスとして適切です。

アプリケーションを Facebook に登録する

Facebook にログインし、https://developers.Facebook.com/apps で開発者アプリケーションを起動します (初めてアプリケーションを起動する場合には、皆さんのプロフィールへのアクセスをアプリケーションに許可し、その先に進めるようにします)。

「Apps (アプリ)」ページの右上で「Create New App (新しいアプリを作成)」をクリックし、「Create New App (新しいアプリを作成)」ダイアログを表示します (図 1)。

図 1. Facebook の「Create New App (新しいアプリを作成)」ダイアログ・ボックス
Facebook の「Create New App (新しいアプリを作成)」ダイアログのスクリーン・ショット

アプリケーションに対する有効な名前と、利用可能な名前空間を入力します。名前空間は 1 つの単語による一意の識別子であり、Facebook アプリケーションの URL に使われます (図 1 では、アプリケーションの名前として「My Old Friends」を、名前空間として「myoldfriends」を入力しました)。Heroku が提供する無料のホスティングのオプションにはチェックを入れずに、「Continue (続行)」をクリックします。次のダイアログで CAPTCHA コードを入力して「Submit (送信)」ボタンをクリックすると、新しいアプリケーションの基本設定のためのダイアログが表示されます (図 2)。

図 2. Facebook アプリケーションの基本設定のダイアログ
Facebook アプリケーションの基本設定のダイアログのスクリーン・ショット

画面最上部にある 2 つの鍵「App ID (アプリ ID)」と「App Secret (アプリのシークレットキー)」に注意してください (図 2 では隠してあります)。Facebook では、この 2 つの鍵を使用してアプリケーションを識別します。これらの鍵を他の人に見せないように、また他の開発者に使わせないようにしてください。他の開発者が皆さんの知らないうちに鍵を悪用する可能性があるからです。

App Domains (アプリのドメイン)」フィールドにアプリケーションのドメインを入力します。このドメインは GAE の開発者サイトにアプリケーションを登録するための GAE のドメインでなければなりません。そのため、このドメインは「.appspot.com」で終わる必要があります。例えば図 2 では、「myoldfacebookfriends.appspot.com」と入力しています。このドメインはもう他の人が使用することはできないので、皆さんは別のドメインを使用する必要があります。GAE アプリケーションを登録する際に使用するアプリケーションの ID とそのドメインが必ず対応するように注意してください。

「Select how your app integrates with Facebook (アプリを Facebook に結合する方法を選択してください)」の下にある「Website with Facebook Login (ウェブサイト)」を選択し、http:// の後には「App Domains (アプリのドメイン)」フィールドに入力した GAE ドメインを含むサイトの URL を入力します。(図 2 では「http://myoldfacebookfriends.appspot.com」と入力しています。)

「Canvas URL (キャンバス URL)」

アプリケーションの基本設定で「Canvas URL (キャンバス URL)」を指定すると、キャンバスページに入力するページ・コードをどこで取得するのかを Facebook に指示することができます (キャンバスページは Facebook 内にある空白のキャンバスであり、そこでアプリケーションが実行されます)。ユーザーがキャンバスページを要求すると、Facebook は「Canvas URL (キャンバス URL)」で指定される URL のコンテンツをそのページの <iframe> の中にロードします。

App on Facebook (Facebook 上のアプリ)」を選択し、アプリケーションを実行するサーブレットの「Canvas URL (キャンバス URL)」を入力します。このアプリケーションの場合、「Canvas URL (キャンバス URL)」は疑問符で終わっており、このアプリケーションのパラメーターはアプリケーションに送信されるリクエスト URL を通じて渡されることを示しています。「Secure Canvas URL (セキュリティで保護されたキャンバスの URL)」は「Canvas URL (キャンバス URL)」と同じですが、http の代わりに https が使われている点が異なります。この場合も URL の最後にある疑問符が重要です。(私のアプリケーションのサーブレットの URL は http://myoldfacebookfriends.appspot.com/myoldfacebookfriends なので、図 2 では「Canvas URL (キャンバス URL)」に「http://myoldfacebookfriends.appspot.com/myoldfacebookfriends?」と入力し、「Secure Canvas URL (セキュリティで保護されたキャンバスの URL)」には「https://myoldfacebookfriends.appspot.com/myoldfacebookfriends?」と入力しています。)

Facebook でアプリケーションを設定するために必要なことは以上ですが、アプリケーションのアイコンやカテゴリーなど、他のいくつかの設定も構成することで、ユーザーに対してどのようにアプリケーションが表示されるのか、その方法を変更しておいてもよいかもしれません。

アプリケーションを GAE に登録する

これでアプリケーションを Facebook に登録できたので、次はアプリケーションを GAE に登録します。

GAE のアプリケーション・ページ (https://appengine.google.com/) にサイン・インし、「Create Application (アプリケーションを作成)」をクリックします。「Application Identifier (アプリケーションID)」の下に、Facebook でアプリケーションの基本設定に使用したものと同じドメイン名を入力します。(「appspot.com」は最初から表示されています。) アプリケーションのタイトル (登録したアプリケーションを検索する際に使用します) は自由に指定することができます。他のオプションはデフォルトのままにしておきます。

図 3. GAE の「Create Application (アプリケーションを作成)」ダイアログ
GAE の「Create Application (アプリケーションを作成)」ダイアログのスクリーン・ショット

Create Application (アプリケーションを作成)」をクリックし、GAE への登録プロセスを終了します。


アプリケーションを開発する

Eclipse で「File (ファイル)」 > 「New (新規)」 > (「Other (その他)」 > 「Google」 >) 「Web Application Project (Web アプリケーション・プロジェクト)」の順にクリックするか、「Google Services and Deployment Tools (Google サービスおよびデプロイメント・ツール)」メニューの下にある「New Web Application Project (新規 Web アプリケーション・プロジェクト)」ボタンをクリックして、新規の GAE プロジェクトを作成します。プロジェクト名とパッケージ名を入力し、「Use Google Web Toolkit (Google Web ツールキットを使用)」の選択を解除します。RestFB の JAR ファイルをダウンロードし (「参考文献」を参照)、新規プロジェクトの WEB-INF/lib フォルダーに追加します。

アプリケーションのサーブレットの定義を、このプロジェクトの web.xml ファイルに追加します。リスト 1 は私が使用した定義です。

リスト 1. サーブレットの定義
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>myoldFacebookfriendsServlet</servlet-name>
<servlet-class>com.Facebook.friends.MyOldFacebookFriendsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myoldFacebookfriendsServlet</servlet-name>
<url-pattern>/myoldFacebookfriends</url-pattern>
</servlet-mapping>
</web-app>

<url-pattern> は Facebook アプリケーションの基本設定ダイアログの「Canvas URL (キャンバス URL)」で指定した URL の末尾と (疑問符がないこと以外は) 同じです。

2011年 10月から、Facebook アプリケーションは SSL (Secure Sockets Layer) を有効にすることが必要になりました。GAE ではデフォルトで SSL が無効になっています。SSL を有効にするためには appengine-web.xml に以下の行を追加します。

<ssl-enabled>true</ssl-enabled>

Facebook の署名付きリクエスト

Facebook は HTTP の POST メソッドを使用して署名付きリクエストをアプリケーションのサーブレットに送信し、アプリケーションのコンテンツを作成します。このリクエストには 64 ビットでエンコードされたペイロードが含まれており、このペイロードには特に注目すべきメタデータとして、現在のユーザーのアプリケーションの OAuth トークンが含まれています。この OAuth トークンがリクエストのペイロードに含まれるのは、ユーザーがプロフィールに対するアクセスをアプリケーションに許可した場合のみです。アプリケーションが OAuth トークンを使用できるように、OAuth トークンを Java オブジェクトに変換する必要があります。

リスト 2 は署名付きリクエストの Java オブジェクトのソースを示しています。わかりやすくするために、該当する GET メソッドと SET メソッドはすべて省略しました。「ダウンロード」セクションから入手できるソース・コードにはどちらのメソッドも含まれています。

リスト 2. 署名付きリクエストのオブジェクト
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.map.ObjectMapper;

public class FacebookSignedRequest {

   private String algorithm;
   private Long expires;
   private Long issued_at;
   private String oauth_token;
   private Long user_id;
   private FacebookSignedRequestUser user;

   public static class FacebookSignedRequestUser {

      private String country;
      private String locale;
      private FacebookSignedRequestUserAge age;

      public static class FacebookSignedRequestUserAge {
         private int min;
         private int max;

      }
      
   }
   
}

このペイロードは、Apache Commons Codec ライブラリーの Base64 を使用してデコードすることができます。デコードされたペイロードは JSON (JavaScript Object Notation) フォーマットであり、Jackson JSON プロセッサーを使用して Java オブジェクトに変換することができます。これらの JAR ファイルをダウンロードしてプロジェクトに追加します (「参考文献」を参照)。リスト 3 の静的なヘルパー・メソッドを FacebookSignedRequest クラスに追加して Java オブジェクトを作成します。

リスト 3. ペイロードをエンコードおよびデコードするためのヘルパー・メソッド
public static FacebookSignedRequest getSignedRequest(String signedRequest) 
      throws Exception {
   
   String payload = signedRequest.split("[.]", 2)[1];
   payload = payload.replace("-", "+").replace("_", "/").trim();
   String jsonString = new String(Base64.decodeBase64(payload.getBytes()));
   return new ObjectMapper().readValue(jsonString, 
                              FacebookSignedRequest.class);
   
}

サーブレットを作成する

これで、サーブレットで実行するアプリケーションのコーディングを開始することができます。web.xml で <servlet-class> を定義した場合と同じシグニチャーを使用して新しいクラスを作成します。まず、SignedRequest クラスを使用してペイロードから OAuth トークンを抽出する必要があります (リスト 4)。

リスト 4. OAuth トークンを抽出する
String signedRequest = (String) request.getParameter("signed_request");
FacebookSignedRequest FacebookSR = null;
try {
   FacebookSR = FacebookSignedRequest.getSignedRequest(signedRequest);
} catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
}
String oauthToken = FacebookSR.getOauth_token();

oauthToken オブジェクトがヌルの場合には、ユーザーがアプリケーションに対してアクセスを許可していないということなので、認証 URL にリダイレクトする必要があります。認証 URL はすべてのアプリケーションに共通であり、以下のフォーマットになっています。

https://www.Facebook.com/dialog/oauth?client_id=API KEY&redirect_uri=
   https://apps.Facebook.com/Application Namespace/&scope=Permissions

認証 URL に含まれる「API KEY」と「Application Namespace」は、アプリケーションに対する Facebook の基本設定ダイアログに表示された「API Key (API キー)」と「Application Namespace (アプリの名前空間)」です。「Permissions」はアプリケーションに必要なアクセス許可のリストです。すべてのアプリケーションはデフォルトで基本的なアクセス許可を持っており、この記事の場合には他のアクセス許可を追加する必要はありません (利用可能なアクセス許可の完全なリストについては「参考文献」のリンクを参照)。

このページのルック・アンド・フィールは、Facebook 開発者アプリケーションから「Settings (設定)」 > 「Auth Dialog (認証ダイアログ)」の順にクリックして表示されるページでカスタマイズすることができます。通常はサーブレットの HttpServletRequest.sendRedirect() メソッドを使用しますが、このアプリケーションは apps.Facebook.com ドメインの <iframe> 内で実行されるため、簡単な JavaScript スニペット (リスト 5) により、ブラウザーのウィンドウの場所をアプリケーションの URL に変更します。

リスト 5. アプリケーションの URL にリダイレクトするための JavaScript コード
PrintWriter writer = response.getWriter();
if(oauthToken == null) {
   
     response.setContentType("text/html");
     String authURL = "https://www.Facebook.com/dialog/oauth?client_id="
       + API_KEY
       + "&redirect_uri=https://apps.Facebook.com/myoldfriends/&scope=";
     writer.print("<script> top.location.href='" + authURL + "'</script>");
     writer.close();

}

Facebook の Graph API

Graph API を利用すると、Facebook のソーシャル・グラフのプロパティーや接続を読み取ることができます。また、特定のフィールドを読み取ることや、任意のオブジェクトの写真を取得すること、オブジェクトにイントロスペクションを行ってメタデータを取得すること、そして変更をリアルタイムで更新することもできます。

有効な OAuth トークンがあると、RestFB ライブラリーから DefaultFacebookClient を作成すること、そしてその DefaultFacebookClient と fetchConnection() 呼び出しを使用して Facebook の Graph API からデータを取得することもできます。https://developers.Facebook.com/tools/explorer で Facebook の Graph APIエクスプローラにアクセスしてください。右上のドロップダウン・ボックスから作成中のアプリケーションを選択して「Get access token (アクセストークンを取得)」をクリックし、アクセスを許可します。「Connections (つながり)」という見出しの下にあるさまざまなリンクをクリックし、その結果を調べてみてください。

ユーザーの友達を取得するためには、「friends (友達)」リンクをクリックすると、友達の一覧が表示されます。エクスプローラの URL の値が user id/friends であることに注意してください。関数呼び出しの connection パラメーターには、通常は Graph API エクスプローラの値と同じ値を使用します。しかしこのアプリケーションはログインしたユーザーのデータを使用するため、ユーザー ID を me で置き換え、値を me/friends にします。これで関数を呼び出すと Connection 型がそのまま返されます。クラスの型は User であるため、その User 型をパラメーターとして追加する必要があります。最終的な呼び出しは以下のようになります。

Connection<User> myFriends = FacebookClient.fetchConnection("me/friends", User.class);

fetchConnection() メソッドを呼び出した結果は List オブジェクトの List として Connection クラスに保持されます。Connection クラスは Iterable インターフェースを実装しているため、以下の拡張 for ループを使用することにより、List の中の各 List オブジェクトを取得することができます。

for (List<User> myFriendsList : myFriends)

ループの繰り返しごとに、myFriendsList オブジェクトには返されたデータ・ページの最新のユーザー・リストが追加されます。このリストの各 User オブジェクトを使用することで、サーブレットが作成するユーザー・テーブルの中に行が 1 行作成されます。ユーザー ID とユーザーの名前は User オブジェクトから取得できますが、プロフィールの写真を取得することはできません。しかし Facebook には、任意のユーザーのプロフィールの写真を取得するための URL (https://graph.facebook.com/User ID/picture) が用意されています。そのため、この URL の User ID を User オブジェクトから取得したユーザー ID で置き換えることで、プロフィールの写真の URL を作成することができます。先ほどと同じ PrintWriter オブジェクトを使用することで、ヘッダー行を持つテーブルをキャンバスに作成します。

writer.print("<table><tr><th>Photo</th><th>Name</th><th>Id</th></tr>");

今説明したように User オブジェクトの List に対して繰り返し処理を行い、続いて各 User オブジェクトのインスタンス変数を使用して、このテーブルに新しい行を作成します。

for (List<User> myFriendsList : myFriends) {

   for(User user: myFriendsList)
      writer.print("<tr><td>" + 
         "<img src=\"https://graph.facebook.com/" + user.getId() + "/picture\"/>" +
         "</td><td>" + user.getName() +"</td><td>" + user.getId() + "</td></tr>");

}

最後に、<table> タグを閉じ、PrintWriter オブジェクトを閉じてサーブレットを完成させます。

writer.print("</table>");
writer.close();

リスト 7 は最終的に完成したサーブレットの doPost() メソッドです。

リスト 7. doPost() メソッド
public void doPost(HttpServletRequest request, HttpServletResponse response) 
  throws ServletException, IOException {
  
  String signedRequest = (String) request.getParameter("signed_request");
  FacebookSignedRequest facebookSR = null;
  try {
    facebookSR = FacebookSignedRequest.getSignedRequest(signedRequest);
  } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
  String oauthToken = facebookSR.getOauth_token();
  PrintWriter writer = response.getWriter();
  if(oauthToken == null) {
    
    response.setContentType("text/html");
    String authURL = "https://www.facebook.com/dialog/oauth?client_id="
      + Constants.API_KEY + 
      "&redirect_uri=https://apps.facebook.com/myoldfriends/&scope=";
    writer.print("<script> top.location.href='"  + authURL + "'</script>");
    writer.close();

  }
  else {
    
    FacebookClient facebookClient = new DefaultFacebookClient(oauthToken);
    Connection<User> myFriends = facebookClient.fetchConnection("me/friends", 
                                                User.class);
    writer.print("<table><tr><th>Photo</th><th>Name</th><th>Id</th></tr>");
    for (List<User> myFriendsList : myFriends) {

      for(User user: myFriendsList)
        writer.print("<tr><td><img src=\"https://graph.facebook.com/" + 
                 user.getId() + "/picture\"/></td><td>" + user.getName() +
                 "</td><td>" + user.getId() + "</td></tr>");

    }
    writer.print("</table>");
    writer.close();
    
  }

}

アプリケーションをデプロイする

サーブレットを作成できたので、アプリケーションをデプロイする準備が整いました。Eclipse で Google のアイコン「Deploy to App Engine (App Engine プロジェクトのデプロイ)」をクリックします。これにより、アプリケーションがコンパイルされてサーバーにアップロードされると、皆さんは (そして Facebook ユーザーは誰でも) このアプリケーションを Facebook の http://apps.facebook.com/APP ID/ にインストールすることができ、その結果を確認することができます。


まとめ

この記事では、Java で開発した Facebook アプリケーションを登録、実装、デプロイし、Google App Engine サービスでホストする方法について説明しました。これで基本事項を理解できたので、皆さんも少しバリエーションを試してみることをお勧めします。

コンテンツの HTML をページに直接書き込む代わりに、標準的な RequestDispatcher.forward() 呼び出しを使用して JSP (JavaServer Pages) ページへと転送する従来の MVC (Model-View-Controller) 手法を実装することもできます。

Graph API によって得られるデータに対するアクセス許可をいくつか追加で使用するアプリケーションを作成することもできます。その場合には、1 つひとつのアクセス許可を scope リクエスト・パラメーターに追加することで、アプリケーションが必要とするアクセス許可のリストを認証 URL に渡します。RestFB には、このリストを適切に作成するためのヘルパー・メソッド (StringUtils.join()) があります。このメソッドは 1 つの String 配列を引数に取り、その配列の各エントリーがアクセス許可の名前になっています。

最後に、Facebook API の別の実装として、RestFB の代わりに Google Code プロジェクトの Facebook-java-api (「参考文献」を参照) を使用してサンプル・アプリケーションを作成することもできます。


ダウンロード

内容ファイル名サイズ
Sample code for this articlej-fb-gaecode.zip5KB

参考文献

学ぶために

製品や技術を入手するために

  • RestFB: RestFB をダウンロードしてください。
  • Eclipse: Eclipse IDE をダウンロードしてください。
  • Apache Commons Codec: Commons Codec をダウンロードしてください。
  • Jackson: JSON プロセッサーをダウンロードしてください。
  • IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2、Lotus、Rational、Tivoli、WebSphere などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=825818
ArticleTitle=Java で開発した Facebook アプリケーションを Google App Engine にデプロイする
publish-date=07192012