2013年11月29日金曜日

Yahoo! テキスト解析API キーフレーズ抽出(送信機能作成編)

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在は巷にあるWebAPIの検証を行っています。

リクエスト送信機能

さて、WebAPIを実行するにはリクエスト送信機能が無くてはなりません。

HTTPリクエスト送信には一般に「Getメソッド」と「Postメソッド」があります。

本当はHTTPには「Deleteメソッド」とか「Putメソッド」とか色々と策定されているのですが、HTTPブラウザを初めとして送受信するソフトウェアの方が非対応だったりすることが多く、ほとんど使われていません。
「各メソッドはちゃんと決められたルールに則って使おう」という呼びかけもありますが、それが実現するのはまだ相当先となるでしょう。(永久に来ないかも)

というわけで、今回は「Getメソッド」と「Postメソッド」のみを考察します。

GetとPostの本来の用途は以下です。

  • Get:リソースの取得に使用する。(例えば、テーブルの主キーをGet送信して検索し結果を取得する、など)
  • Post:情報の送信に使用する。(例えば、入力フォームの全情報をPost送信してテーブルに保存する、など)

今回のテキスト解析APIは「テキスト解析結果を取得する」機能ですので、Getを使う方が標準と言えます。

しかし、Getメソッドの場合、Webサーバに最大長制限があります。
(Apacheの場合はデフォルトで「8190バイト」など。)

今回のテキスト解析APIでは、解析するテキストの長さがどれくらいになるか分かりませんので、
「Getで大量データを送信したらエラー」といったケースが想定されます。

その一方、Postにも上限はありますが、こちらはGetよりも大量データを送信出来ます。
(Tomcatの場合はデフォルトで「2メガバイト」など。)

この為、今回はPost送信を使います。

  • テーブルの主キー検索など、リクエスト長の上限が明確に決まっている場合はGetメソッド。
  • 今回のテキスト解析APIのテキスト送信みたいに、リクエスト長が不明 or 大量な場合はPostメソッド。

こういう使い分けにするのが合理的でしょう。

以下に私がJavaで作ったPost送信機能のサンプルソースを記載しておきます。
特に変わった機能は無く、普通に送信して、人間が目で見て分かりやすい形に出力するソースです。

HTTP通信は汎用的なプロトコルですので、JavaScript、PHP、Rubyなど、各言語でも作成できます。
各自の環境で都度、都合の良いように作れば良いでしょう。


public class RequestSender {

 /** logger */
 private Logger logger = Logger
   .getLogger(RequestSender.class);

 /**
  * リクエストをPOST送信する
  *
  * @param url
  * @param postBody
  * @return
  * @throws IOException
  */
 public String sendPost(String url, String postBody) throws IOException {

  //log4j使用
  //送信パラメータをトレースログに出力
  if(logger.isTraceEnabled()){
   logger.trace("送信先URL:" + url);
   logger.trace("リクエストボディ:" + postBody);
  }

  URL sendURL = new URL(url);
  URLConnection con = sendURL.openConnection();

  // POST送信モードを指定
  con.setDoOutput(true);

  // 送信実行
  OutputStreamWriter osw = null;
  BufferedWriter bw = null;
  try {
   osw = new OutputStreamWriter(con.getOutputStream());
   bw = new BufferedWriter(osw);

   // POSTの内容を書き出す
   bw.write(postBody);

  } finally {
   if (bw != null) {
    bw.close();
   }
   if (osw != null) {
    osw.close();
   }
  }

  // 受信
  InputStreamReader isr = null;
  BufferedReader br = null;

  StringBuilder bul = new StringBuilder();

  try {
   isr = new InputStreamReader(con.getInputStream());
   br = new BufferedReader(isr);

   String line;
   while ((line = br.readLine()) != null) {
    //肉眼で見やすいように改行コードを付与
    bul.append(line).append(System.getProperty("line.separator"));
   }

  } finally {
   if (br != null) {
    br.close();
   }
   if (isr != null) {
    isr.close();
   }
  }

  //apachecommons使用
  //最後の改行コード削除
  return StringUtils.chomp(bul.toString());

 }

}


リクエスト発行編へ


文面が長くなってきましたので、今回はここまで。
次回はいよいよ、上記ソースを使ってレスポンスの中身を検証してみます。

2013年11月18日月曜日

Yahoo! Web API 登録編

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

しばらくは世に溢れる「WebAPI」の機能について検証していきたいと思います。

最初はヤフーのWeb APIです。

Yahoo! Web API


YahooはWebAPIをいくつも提供しておりまして、その種類も豊富。
WebAPI界の大御所と言えるでしょう。

しかも良い所は、日本語の説明ドキュメントがある点ですね。
Google、FaceBook、Twitter辺りだと英語しか無いので、大変助かります。

公式サイトは以下です。


さて、早速テキトーにリクエストを投げて……ん?



どうやらリクエスト送信には「アプリケーションID」の取得が必要なようですね。

このようにWebAPIにはIDの取得を求められることが多いです。
WebAPIは使えば使うほど、WebAPI側のネットワークやサーバの負荷が掛かりますので、誰がどれくらい使っているかを管理する為にIDが必要ということですね。

従量課金制になっている所も多く、リクエストが多いIDほど、多くの金が取られるということです。



  • WebAPI業者はIDで使用者を管理している。



逆に言いますと、「IDさえ分かればなりすまし可能」という意味ですよ。

つまり、「JSファイルにIDをベタ書きして、Ajaxでリクエスト発行」とかやるとJSソースを解析されてIDが盗まれますので、
大事なIDはサーバ側で保管しておき、WebAPI発行はサーバ側から行うと良いでしょう。




  • WebAPIのリクエスト発行はクライアントサイドからAjaxでも行えるが、セキュリティを考えるならサーバから発行した方が良い




以上、簡単なことですが大事なことなのでお忘れ無く。


アプリケーションID取得


では、本題のアプリケーションID取得に入りましょう。

YahooJapanにログインしている状態で以下のページにアクセスします。





ここの「新しいアプリケーションを開発」のボタンをクリックします。


すると、以下のような画面が表示されます。
(メアドが表示されていますので、その部分は隠させて頂きました)



これを見ると、「サーバサイド」「クライアントサイド」と、利用目的に応じて違う設定が必要なようです。
クライアントサイドの方に「OAuth 2.0 Implicit」と書いてありますが、これは超巨大なセキュリティホールが出来るという噂の認証方式……。
今回は「サーバサイド」を選択して進んでみようと思います。


そこから先に続くのは「アプリケーション名」や「サイトURL」等ですが、今回は動作検証用ですので、
デフォルト値のままにしておきます。

最後に「同意」を選んで確認ボタンをクリックしますと、確認画面を表示した後に、IDの取得が完了します。

次の画面に進んだ時には、もうIDが発行されています。
(モザイクで見えなくさせて頂いておりますが)



簡単ですね!!

アプリケーションIDは「ハッシュ値」みたいな文字列です。

上記にもありますが、アプリケーションIDは大事な値ですので、推測も出来ないようになっていなければなりません。
更に一意性も必要ですので、「ログインID+シーケンス番号した文字列をハッシュ変換」といった方式で出力しているものと推測されます。

そしてもう一つ、「シークレット」というものが出ています。
これにつきましては、調べたのですが詳細が分かりません。
YahooにはユーザIDがバレてもログイン出来なくする「シークレットID」なる機能もありますが、こちらはそれとは別物の模様。
詳細が分かり次第、記事にしたいと思います。


さて、これでIDの取得は完了です。
もうWebAPIを発行出来る状態になっています。

試しに、画面に表示されているサンプルリクエストを送信してみました。



ちゃんとレスポンスが返ってきていますね。
これで動作確認も取れました。

後は発行するだけでOKです。
実に簡単でした。

次回


次回からは、いよいよ本格的にWebAPIの機能検証に入ります。

2013年11月5日火曜日

WebAPI 導入編

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

今回から「WebAPI」の連載をスタートしたいと思います。

WebAPIとは

連載のテーマであるWebAPIとは、特に厳密な定義があるわけではないのですが、要するにインターネット経由で余所からデータを取ってくる機能のことです。

例を挙げるとすると、ヤフーのニュース記事の下にあるTwitter部分。



これです。
これはヤフーのその記事と関連のあるツイートを表示しているわけですが、これをどうやって取得しているのかと言うと、Twitterが提供しているWebAPIを利用しているのです。


カラクリとしましては、HTTP通信でリクエストを投げると、レスポンスで「XML」か「JSON」かの形式で返ってきますので、それをパースして……。
と難しい話は以降の連載にしましょう。

ようするに、「リクエストを送信すると文字列が戻ってくるので、それを画面に出す」というだけのシンプルな機能です。

もちろん、こういった機能は自前で作ることも、別に難しいことではありません。
自前でWebAPIを作って公開し、使用料を取るというビジネスも普及しています。

WebAPIのニーズ

このWebAPIというサービス形態は昨今……というにはちょっと遅い気もしますが、最近注目のサービスです。
理由としましては、やはりスマートフォンやタブレットといった次世代携帯端末の存在でしょう。

これらの機器は内部にアプリを入れて機能するわけですが、やはり携帯端末ですのでリソースが少なく、そんなに重い機能を実装出来ないのです。
そこで、重い処理はWebAPIを動かしている巨大サーバで行って、必要な情報だけを取得して携帯端末に表示する。
そんなエンドユーザ端末の機器に優しいことがWebAPIの長所です。

WebAPIの現状

とは言え、私はWebAPIを使ったシステム開発は一度しかありません。
注目度の割にはあんまり出番が来ないサービスというイメージがあります。

その理由として、二つの理由を考えてみました。

1.出番が無い


まずはこれでしょう。
「Twitterの情報を取得したところで遊びにしか使えないじゃないか」みたいに、不特定多数のエンドユーザを想定したサービスが多いです。
元からオシャレなスマホアプリ作成を生業としている人ならともかく、私のような企業向け業務システム開発が中心のエンジニアには滅多に使用機会が訪れないのです。

2.お金&余所様のデータであること


もう一つの理由は、これ。
WebAPIはどこまで行っても他社様のデータを貰ってくるサービスですので、契約とか権利とかの理由で、業務用には敬遠されてちまいがち。軽く使いたいだけでも「法務部」とかそんなレベルの話になってしまい、内部調整が非常に大変です。

何より困るのが「仕様変更」ですね。
少し前にTwitterが急に仕様変更したせいで取れていたデータが取れなくなり潰れたサービスがありました。
WebAPI提供業者の都合に振り回されてしまうのも欠点です。

WebAPIの利用価値

このように難点も多いWebAPIですが、一方で凄く便利で高機能なサービスがあるのも確かです。

業務用システムエンジニアである私の立場では、「天気予報取得」「居酒屋の口コミの取得」など永遠に出番が無さそうなサービスも大量にありますが、中には「漢字に読み仮名を降る」「PDF変換」など、もしかしたら使い道もありそうな雰囲気のサービスもちらほら見かけます。
興味が湧いてきましたね。

というわけで、今回の連載では「業務用システムエンジニアから見たWebAPI」というテーマで、調査したWebAPIのご紹介をしていこうと思います。

次回予告

最初はヤフー提供のWebAPI『テキスト解析API』から調査開始です。

2013年10月30日水曜日

最強モックツール JMockit その11 Eclipseプラグイン

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

長く続いた「JMockit」の記事も本日が最終回です。
JMockitは非常に多機能なライブラリなので他にもまだまだ機能はあるのですが、大抵の開発ならば前回までの内容で対応出来ると思います。
何回か使ってみて、『もっとこういう機能が無いかな?』という状況になった時、改めて探してみるのが良いかと思います。

さて、最後はチラッと小ネタをご紹介します。

Eclipseプラグイン


JMockitには、Eclipse上での入力を支援してくれるプラグインがあるようです。


導入すると、「ctr + スペース」で以下のように入力候補が出てくるようになります。


他にも、「書き間違えている場合に赤くエラーを出す機能」「テスト対象になっているメインソースのジャンプする機能」などがついています。

別に導入必須という程の大した機能ではありませんが、こうした「ちょっと便利な機能」も忘れず押さえておくことで、日頃の開発効率を高めていくようにしたいものですね。

これからのJMockit~JMockit2~


何と、Googleの開発サイトでは「JMockit2」の開発が始まっているらしいです。


まだ開発途中ですが、『JMockit1とは違う視点から、もっとシンプルで優れたモックライブラリを作る!!』との触れ込みです。

現時点で十分に優れたライブラリかと思いますが、確かに調べていて少し難しいと感じることもあり、「シンプルさ」にはまだ改善の余地があるのかもしれません。

完成がいつになるかは分かりませんが、Java単体開発者としては耳寄りな状況として要チェックです。

首を長くして完成を待ちたいと思います。

終わりに


これにてJMockitの連載は終了です。

連載を終えるに辺り、JMockitに関する所感を述べるならば、上にもありますが「結構難しい!!」ですね。
そもそも、モックという発想自体が黒魔術ですので、何年もJava開発を行って基本を押さえている技術者ならば兎も角、経験の浅い人が触ったら混乱することになると思います。

また、『チームの全員がJMockitに精通している』という超精鋭チームを用意することも至難でしょう。

というわけで、「せっかく覚えたJMockitだ。ぜひ使いたい!!」という流行る気持ちは押さえて、

  • モックを使わなくてもテスト出来るクラス設計にする。
  • どうしても必要な例外部分だけ、JMockitを使用する。

といった程度の水準で導入するのが一番現実的ではないでしょうか。

例えば「正常系は普通にテストする。異常系はJMockitを使う」など、開発指針のレベルで適切な運用方法を考える所からがJMockitの始まりかと思います。


以上でJMockitの連載を終わります。
ご愛読ありがとうございました。

2013年10月21日月曜日

最強モックツール JMockit その10 コンストラクタ差し替え

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在はモックツール「JMockit」の使い方をご紹介しています。

今回はコンストラクタの差し替えです。

コンストラクタの差し替え

前回は「メソッドを丸ごと差し替え」を行いましたが、
今回はその延長線で「コンストラクタ」の差し替えです。

コンストラクタは普通のメソッドとは違うということか、他のモックツールを見てもコンストラクタには非対応ということが多いようです。
しかしコンストラクタのモック化を必要とするシチュエーションも少なからずあるもの。
例えば、バッチの開発。偶に見るのですが、コンストラクタで環境設定ファイルを読み込む作りになっていることがあるのです。
しかも、前もって用意されている正規の環境設定ファイルは本番実行用で、テストの時はテスト用ファイルを読み込まなければならない、という場合も結構あります。

しすれmそういう現場では必ず以下のような会話で盛り上がります。


「あれ? テストが動かないぞ?? どうなってんの???」⇒「設定ファイルの差し替えを忘れてるんですよ」


これを何回でも繰り返すのが人間というものです。どの現場に行っても100%コレでした。
というわけで、ファイルの差し替えとか設定値の切り替えとか、そういう作業はJMockitを使ってテストソースの中に埋め込んでおく方が楽です。
ぜひ使ってみてください。

では、JMockitにおけるコンストラクタ差し替えの記述方法をご紹介しましょう。
まず、サンプルとして以下のようなコンストラクタを含んだクラスを作成します。

public class ConstructorSample {

 public ConstructorSample() {
  System.out.println("★コンストラクタ処理★");
 }

}

サンプルですのでprintlnのみの処理ですが、本番ではここで色々処理しているという想定です。
これに対し、テストソースの方は以下のように書きます。

public class ConstructorSampleTest {

 @Test
 public void test() {
  new MockUp<ConstructorSample>() {

        @Mock void $init() {
         System.out.println("★コンストラクタ差し替え★");
        }
  };

  new ConstructorSample();
 }

}

コンストラクタの場合はメソッド名の指定が普通には指定できませんので、『$init』という特殊記号を使うわけです。

書き方の要領は前回と全く同じですので、『$init』を使うのだということを知っていれば簡単に使うことが出来るでしょう。


終わりに


JMockitは高機能なライブラリなので連載が長引きましたが、
今日までの記事で殆どのケースに対応可能だと思います。

次回は最終回、JMockit開発を支援するEclipseプラグインをご紹介します。

2013年10月15日火曜日

最強モックツール JMockit その9 メソッド丸替え

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在はモックツール「JMockit」の使い方をご紹介しています。

今回はメソッドの中身の丸ごと差し替えです。

メソッド全体の差し替え

今までご紹介してきたモック機能というのは、『元々のメソッドを実行しないで、仮の値を返す』というものです。

例えば、ログインチェック機能の場合、
本来の機能であれば『ログインIDとパスワードをチェックして、正しい場合はtrue、間違っている場合はfalseを返す』だったとします。
しかし、モック化することによって『いつも固定でtrueにする』とか、そういう感じです。

この場合、元々のメソッドは実行していませんので、DBにアクセスに行っていません。
ただ単に『true』という値が帰ってくるだけです。

このように、『返り値だけあればいい』という状況であれば今までのやり方でOKです。
しかし、そうではなくて、『別の処理をちゃんと実行して欲しい』という場合は、これではダメです。

例えば、以下のような状況です。

  • DBに間違った値が入った時のテストだから、本来の機能はモック化して潰し、代わりに間違った値をインサートさせたい。
  • メール送信機能のテストなんだけど、メール送信処理自体は実際にはメールを送信しなくていいからモック化する。でも、同時に行っている一時ファイル削除処理は行っておく必要がある。

このように、『ダミーの値を返すだけではなくて、違う処理をやりたい』という場合です。
こういう場合は、元々のメソッドをぶっ潰して、違う機能を書いてしまいましょう。

『メール送信後、ファイルを削除する』機能をモック化するというシチュエーションを想定します。
(サンプルなので、printでその処理を行ったという想定とします)

public class MailManager {
 public void sendMail(){
  System.out.println("★メールを送信する。★");
  System.out.println("送信した添付ファイルを削除する。");
 }
}

JUnitは単体テストですが、メール送信はプログラムだけでなくメールサーバも必要とします。
こういう風に違うサーバを必要とする処理のテストは結合テストで行って、単体テストフェーズではモックで済ます、というのは常套手段と言えるでしょう。

しかし、同時に行っている添付ファイル削除処理は実施しなければ都合が悪いということもあるでしょう。
もしくは、『メール送信は成功したけど、ファイル削除は失敗した』という状況を作りたかったりするなど、細かい要望は色々あります。

そういう場合、モックでメソッドを新規作成してしまえば良いのです。

以下がそのやり方です。

@Test
 public void testCreateFile() {
  new MockUp<MailManager>() {
   @Mock
   void sendMail() {
    System.out.println("ファイル削除(差し替え)");
   }
  };
  //メール送信
  MailManager manager = new MailManager();
  manager.sendMail();
 }

JMockitの場合、今回新規登場の『MockUp』というクラスを使うことで実現できます。

使い方も分かりやすいかと。
MockUpクラスの中で同じ名前のメソッドを書いて、@Mockをつければ、それだけで後は自動でモック化されます。

直感的に分かるようによく出来ているライブラリだと感心してしまいます。

終わりに


今回ご紹介したサンプルは、実際のところは回避可能でもあるんですよね。
だって、『メール送信』と『ファイル削除』を別々のメソッドにして、メール送信メソッドだけモック化すれば良いのですから。
しかし、実際の開発だとクラス設計がJUnitのことまで考えられていなくて、こういう作りになっていることもしばしば。
不本意ながらに結構お世話になってしまう機能かもしれません。

もしくは、『ファイル削除失敗』みたいに現実には実現出来ないシチュエーションを作るにも便利です。

代替機能を自分で作る手間はありますが、こんな風に自由に作り込める機能は大変助かりますね。

引き続きJMockitのご紹介をしていきます。

2013年9月30日月曜日

最強モックツール JMockit その8 例外実行

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在はモックツール「JMockit」の使い方をご紹介しています。

今回は例外、『Exception』の出し方についてです。

例外呼び出し


数あるテストの中で悩みがちなのが、「そのテストを実行出来ない」というパターンです。

  • ネットワークエラーのテストをしたい。⇒そのタイミングでネットワークエラーを発生出来ない。
  • 不正なファイルが来た場合に例外を発行するテストをしない。⇒それより前の処理でチェックが済んでいるので、その場所ではエラーを発行出来ない。

こういうのですね。
絶妙なタイミングでLANケーブル抜いたりとか、そうそう上手には出来ません。
そういう時こそ、モックツールの活躍のタイミングです。

JMockitを使って無理矢理例外を発生させてしまいましょう。

そのやり方が以下です。

new NonStrictExpectations() {{
      loginService.isLogin(anyString,anyString); result = new Exception();
  }};
}

ソース全体を見せるよりも、該当部分だけ記載した方が分かり易いでしょう。
resultにExceptionを設定するだけでOKです。

今回はサンプルとして「Exception」の型を使いましたが、IOExceptionとか、自前で作ったExceptionとか、例外クラスならどんなものにも対応出来ます。

特記事項としては、本体ソースがvoid型でも「result = new Exception();」の形は使えるということです。
void型なのに返り値を設定するのは変な気もしますが、そういうものだと理解して下さい。

終わりに


引き続きJMockitのご紹介をしていきます。