Google calendarをpython/ruby/goovy/javaを使ってアクセス

出典: Wiki@browncat.org


google calendarをアクセスしようと少しいじってみました。
途中目的が変わってしまい各種LLとjavaとの連携の記録になってしまいました(^^;

目次

[編集] Google Data API/ Google Calendar Data API

googleはgdataというATOM/RSSの拡張?のようなI/FでAPIを公開しており 単純にはwgetなどでURLを指定するとxmlを取り込めます。 またputでデータを書き込めるようです。

googleのページでは仕様だけではなくjavaとc#向けのライブラリが公開されており、 APIへのアクセスやデータの操作が出来るようになっています。 少し探してみたのですが他の言語向け(phpやperlなど)のライブラリは まだあまり整備されていないようです。もう少し調べてみます。

[編集] Jythonで試してみる

javaやc#のような言語は、マジメに作るにはいいと思うのですが とっつきに試行錯誤したり、実験的なソフト作成には今ひとつ向きません。 (少なくとも私には)

スクリプト言語向けのATOM Parserを使ったりもしてみたのですが今ひとつです。 そこでjavaのクラスを取り込めるjythonを使ってみることにしました。

[編集] 簡単にインストールなど

jythonのインストールは簡単です。

  1. 本家から2.1のクラスファイルをダウンロード
  2. コマンドラインから"java jython_21"などとすればOKです

注意としてgoogleのAPIはjava SDKのバージョンが1.5でないとクラスのロード時にエラーが出ます。
複数のjava環境をインストールしている場合はフルパスで1.5のjavaコマンドを指定しても問題ないようです。

googleのAPIを使うにはgoogleのページからgdata.java.zipをダウンロードします。
ファイルを解凍するとgdata/java/libにjarファイルが二つ入っています。
jython起動時にCLASSPATHで両方を指定してやりpythonのスクリプトから

from com.google.gdata.client import Query

などとすれば使えるようです。

[編集] 超簡単なサンプルを動かしてみる

Google Calendar Data APIのページある一番シンプルな例をjythonで動かしてみます。

javaの例(from google)
URL feedUrl =
 new URL("http://www.google.com/calendar/feeds/userID/private-magicCookie/full");
CalendarService myService = new CalendarService("exampleCo-exampleApp-1");

// Send the request and receive the response:
EventFeed myFeed = myService.getFeed(feedUrl, EventFeed.class);

// Print the title of the returned feed:
System.out.println(myFeed.getTitle().getPlainText());
jythonに書き直したもの(import部分も含む)
from com.google.gdata.client import *
from com.google.gdata.client.calendar import *
from com.google.gdata.data import *
from com.google.gdata.data.extensions import *
from com.google.gdata.util import *
from java.net  import URL

feedUrl = URL("http://www.google.com/calendar/feeds/userID/private-magicCookie/full")
myService = CalendarService('Hoge')
myFeed = myService.getFeed(feedUrl, EventFeed);
print myFeed.getTitle().getPlainText()

少し試行錯誤はありましたが、無事動作しました。 しかしこの位ならpythonで書く利点はまだありませんね。

[編集] 超簡単なサンプルを動かしてみる(2)

同じようにgoogleのサンプルからjythonでデータを追加してみます。

myEntry = EventEntry();
myEntry.setTitle(PlainTextConstruct("Tennis with Beth"));
myEntry.setContent(PlainTextConstruct("Meet for a quick lesson."));

author = Person("my name", None, "my@account");
myEntry.getAuthors().add(author);

startTime = DateTime.parseDateTime("2006-09-24T15:00:00-08:00");
endTime = DateTime.parseDateTime("2006-09-24T17:00:00-08:00");
eventTimes = When();
eventTimes.setStartTime(startTime);
eventTimes.setEndTime(endTime);
myEntry.addTime(eventTimes);

post_url = URL('http://www.google.com/calendar/feeds/default/private/full')
myService.setUserCredentials('<my@account>', '<mypassword>')

insertedEntry = myService.insert(post_url, myEntry)

無事エントリが追加されました。認証時(setUserCredentials)にhttpsを要求されます。 またproxyの内側にいる場合の設定は以下の通りです。

System.setProperty('http.proxyHost','<proxy-host>')
System.setProperty('http.proxyPort','<proxy-port>')
System.setProperty('https.proxyHost','<proxy-host>')
System.setProperty('https.proxyPort','<proxy-port>')

[編集] jrubyで試してみる

さて、jythonではなんとかなりそうな感じになってきました。 次はrubyでやってみたいと思います。

rubyは日本で作られたオブジェクト指向色が強いスクリプト言語です。 rubyを使う利点はなんといってもRoRことRuby on Railsとの連携が出来るかに興味があります。 rubyを使うのは久々なので、まずjythonと同じ程度の使い方が出来る位までやってみます。

jrubyはjavaで実装されたrubyの処理系で jythonと同じくjavaのクラスをインポートして使うことが出来ます。 2006/9にコア開発者の2名がsunに雇い入れられたようで、今後の発展が期待されます。

余談ですがIronPythonという.Net環境で動作するpythonをMicrosoftがリリースしています。 pythonはRedHatのインストーラやツールなどにも多く使われており perl, phpに次ぐスクリプト言語として地位を固めつつあるように見えます。 ナショナリズムではありませんが、数少ない日本発の言語なので、 sunがバックアップすることでrubyもがんばって欲しいものです。

[編集] インストール&使い方

特にインストールについては何もないようです。 アーカイブをダウンロードして展開し、パスを通すだけです。 jythonと同じくCLASSPATHをgoogleのjarファイルに通して jrubyコマンドで起動します。

[編集] まずはとにかく使ってみる

javaとの連携においてjrubyはjythonと少し使い勝手が違います。 グローバルにパッケージがインポートされるjythonと異なりjrubyでは基本的にクラス単位となります。 モジュール内であればパッケージ単位でインポートできます。 このあたりはjythonの方がお手軽でjavaとの差が少ないようです。

直接クラス指定して手っ取り早くフィードを取り出す(jruby)
require 'java'

include_class 'com.google.gdata.client.calendar.CalendarService'
include_class 'com.google.gdata.data.extensions.EventFeed'
include_class 'java.net.URL'

url = URL.new('http://www.google.com/calendar/feeds/<my@account>/private-<magic-cookie>/full')
myService = CalendarService.new('Hoge')
myFeed = myService.getFeed(url, EventFeed)
print myFeed.getTitle().getPlainText()

[編集] ざっくり一通り使ってみる

googleのドキュメントを元に 取り出し、新規作成、編集、削除までやってみます。 googleのライブラリにはいくつものクラスがあり一つ一つ書いていては大変です。 jrubyはモジュールへはpackage単位でインポートできるのでこれを使って、 ちょい汚い気もしますが、 テスト用モジュールを作って、必要なものを全部取り込んでアクセスしてみました。

代表的な機能をざっと使うサンプル(jruby)
require 'java'

module Test
 
include_package 'java.net'
include_package 'com.google.gdata.client'
include_package 'com.google.gdata.client.calendar'
include_package 'com.google.gdata.data'
include_package 'com.google.gdata.data.extensions'
include_package 'com.google.gdata.util'

## Login
print "login...\n"
myService = CalendarService.new('Hoge')
url = URL.new('http://www.google.com/calendar/feeds/default/private/full')
myService.setUserCredentials("<my@account>", "<mypassword>")

## Get Feed
print "get feed...\n"
feed = myService.getFeed(url, EventFeed)
print "Calendar: ",feed.getTitle().getPlainText(), "\n"

## Create Entry
print "creating new entry...\n"
myEntry = EventEntry.new()
myEntry.setTitle(PlainTextConstruct.new("Tennis with Beth"))
myEntry.setContent(PlainTextConstruct.new("Meet for a quick lesson."))

author = Person.new("<Name>", nil, "<my@account>")
myEntry.getAuthors().add(author)

startTime = DateTime.parseDateTime("2006-09-24T15:00:00-08:00")
endTime = DateTime.parseDateTime("2006-09-24T17:00:00-08:00")
eventTimes = When.new()
eventTimes.setStartTime(startTime)
eventTimes.setEndTime(endTime)
myEntry.addTime(eventTimes)

### Insert
print "inserting new entry...\n"
insertedEntry = myService.insert(url, myEntry)

## Requesting
print "retrieving last entry...\n"
entryUrl = URL.new(insertedEntry.getSelfLink().getHref())
retrievedEntry = myService.getEntry(entryUrl, EventEntry)

## Updating 
print "edit and updating last entry...\n"
retrievedEntry.setTitle(PlainTextConstruct.new("Important meeting"))
print retrievedEntry.getEditLink().getHref()
editUrl = URL.new(retrievedEntry.getEditLink().getHref())
updatedEntry = myService.update(editUrl, retrievedEntry)

## Deleting
print "deleting last entry...\n"
deleteUrl = URL.new(updatedEntry.getEditLink().getHref())
myService.delete(deleteUrl)

end

[編集] JPype

JPypeはかなりマイナーなようですが、CPythonからjavaのクラスを利用するためのソフトウェアです。pythonのパッケージとして配布されています。 まずはLinuxにインストールしました。

注意としてインストールにはネイティブコードのためにobjcが必要なようです。 またjavaのshared libraryの指定のために setup.pyの変更とsrc/python/jpype/_linux.pyでlibjvm.soのパスが記述してある箇所を書き換えた方がよいようです。
インストールが終わったらexamples/linuxの下のfindjvm.pyを実行してみて正しくlibjvm.soの一つ上の'.so'が入っているディレクトリが示されたら正解です。

スクリプトからのjava classの使用方法ですが、基本はJPackageクラスを使ってトップのクラスをインポート?します。 ただし少し調べた限りではクラスのパス指定を省略するための'*'的インポートの方法がわからず、1つづつ変数に入れて使いました。

jythonと異なりOSに付属のpythonをベースに出来るため、他のスクリプトやモジュールとの組み合わせの問題が出にくそうですし、java以外のスクリプトの速度がかなり高速になるのは大きな利点です。
ただ、もう少し有名になってくれないとプロジェクトが立ち消えになってしまうのが心配です。

サンプルコードですが、上で紹介しているものとほぼ同じです。 当然ながらjythonと互換性が高く、セットアップ以外の部分は全く同じです。(Login以降)

サンプルコード
import os, os.path
from jpype import *

startJVM(getDefaultJVMPath(),
  "-Djava.class.path=gdata-client-1.0.jar:gdata-calendar-1.0.jar")

# setup java classes
URL=java.net.URL
CalendarService = JPackage("com").google.gdata.client.calendar.CalendarService
GDataExtensions = JPackage("com").google.gdata.data.extensions;
EventFeed = GDataExtensions.EventFeed
EventEntry = GDataExtensions.EventEntry
When = GDataExtensions.When
GData = JPackage("com").google.gdata.data
Person = GData.Person
DateTime = GData.DateTime

# Login
myService = CalendarService('Hoge')
myService.setUserCredentials("<username>", "<password>")

url = URL('http://www.google.com/calendar/feeds/default/private/full')

# Get Feed
myFeed = myService.getFeed(url, EventFeed);
print myFeed.getTitle().getPlainText()

[編集] Groovy

javaベースのスクリプト言語でいろいろ試していますが 次はGroovyでやってみます。 この言語は最初からJava環境のために作られた言語で、当然Javaとの親和性が高く、python, rubyやSmalltalkなどの言語の特徴を取り入れて設計されています。
JSRにも入っており、JavaのSE6に取り入れられる噂もありましたがまだのようです。
現在も開発が続いており、数ヶ月に一回くらいのペースでバージョンアップされています。

コードを見る限り、他のスクリプト言語と比べ もっともjavaに近く、イメージとしてはちょっとlazyなjavaって感じです。 perl, rubyのような1 liner上等的な印象は少し薄い気がします。

スクリプトはバイトコード変換されjvmで実行される?らしく、 jythoncのようにgroovycでclassファイルにコンパイルすることも出来ます。 少し試してみたところコンパイルすると結構高速になるようです。

面白いのはRoRと同じようなコンセプトのGRailsというソフトが作られておりVer 0.2が公開されています。

サンプルコード
import java.net.URL

import com.google.gdata.client.*
import com.google.gdata.client.calendar.*
import com.google.gdata.data.*
import com.google.gdata.data.extensions.*
import com.google.gdata.util.*

print "login...\n"

myService = new CalendarService('Hoge')
url = new URL('http://www.google.com/calendar/feeds/default/private/full')
myService.setUserCredentials('<account>', "<password>")

// Get Feed
feed = myService.getFeed(url, EventFeed);
print feed.getTitle().getPlainText()+"\n"

[編集] rjb (Ruby Java Bridge)

rjbはネイティブのrubyからjavaのクラスを利用するためのソフトウェアです。JPypeと同じようにやはり全てのクラスを指定する必要があるようです。

fedora core5にインストールするのに少しつまづきました。 gemパッケージではインストールがうまく出来ず、 zipを展開してsetup.pyを使ってインストールしました。 これは私の環境の設定に問題があるのかもしれません。

さて、サンプルです。jvmの起動とクラスのインポートはJPypeと似ています。 後半はjrubyと同じソースでOKでした。

サンプルコード
## rjb example
require 'rjb'

Rjb::load(classpath='java/gdata-client-1.0.jar:java/gdata-calendar-1.0.jar', jvmargs=[])

URL = Rjb::import('java.net.URL')
CalendarService = Rjb::import('com.google.gdata.client.calendar.CalendarService')
EventFeed = Rjb::import('com.google.gdata.data.extensions.EventFeed')
EventEntry = Rjb::import('com.google.gdata.data.extensions.EventEntry')
When = Rjb::import('com.google.gdata.data.extensions.When')
Person = Rjb::import('com.google.gdata.data.Person')
DateTime = Rjb::import('com.google.gdata.data.DateTime')
PlainTextConstruct = Rjb::import('com.google.gdata.data.PlainTextConstruct')

## Login
print "login...\n"
myService = CalendarService.new('Hoge')
url = URL.new('http://www.google.com/calendar/feeds/default/private/full')
myService.setUserCredentials("<account>", "<password>")

[編集] rjbplus

rjbplusはrjbでimport *相当の機能やinterfaceを書きやすくしたり便利に拡張されているもの。 前置き部分がかなりすっきりするのでこっちの方が良さそうです。 本家にもこの機能は欲しいです。

rjbのサンプルをrjblusで書き直したもの(先頭部分だけ)
## rjbplus sample
require "rjbplus"

Rjb.load('java/gdata-client-1.0.jar:java/gdata-calendar-1.0.jar')

module Test
 rjb_import 'java.net.URL'
 rjb_import 'com.google.gdata.client.*'
 rjb_import 'com.google.gdata.client.calendar.*'
 rjb_import 'com.google.gdata.data.extensions.*'
 rjb_import 'com.google.gdata.data.*'

## Login
print "login...\n"
...

[編集] それぞれの比較

[編集] jythonとjrubyの比較

まだjrubyはそれほど使っていません。ぜひRoR on jrubyを試してみたいのです。 RoR自体初めてなので、これからです。

で、二つの言語システムでほぼ同様のスクリプトを動作させてみたのですが、

  1. どちらも問題なくgoogle calendarへアクセスできました
  2. 双方の考え方の違いは面白い。元言語の性格を表しているような感じです
  3. jythonの方がとっつきはいい感じ
  4. jythonの方が速い。実測でjrubyは10.7秒、jythonは9.4秒でした。10-20%程度高速なようです。
  5. jrubyの方がよりruby的なプログラムが書けそう
  6. jythonは開発が停滞しているっぽい
  7. jrubyは現在も開発が進んでおり、RoR対応がよくなったり開発者をSunが雇い入れるなどいい動きがある

[編集] ブリッジ経由でやるには...

JPypeやrjbもそうですが、こうしたソフトって開発の継続性が問題なんですよね。 作者が飽きたら終わりでは使い続けるのに問題があります。 実際rubyにもpythonにも同様なブリッジのソフトで開発が止まったものが存在します。 (jythonも停止しているようですし)

私はこういうの結構好きなのですが、やはりイロモノ的な感は否めませんし。
javaなどの言語とスクリプトとの同居という意味では非常に意味のあるものだと思いますが、 やはり世間的に見るとマイナーですよね。。。

ちなみにgoogleではサーバサイドはC++, java, 管理ツールなどはPythonがメインの開発言語なようで、他人事とはいえJPypeなどをバックアップしてくれないかなあと思ったりします。 あとsunがrjbとか。

[編集] その他のアイデア

これらを使ってtracやwikiやGTDツール、他のweb serviceとgoogle calendarの融合が出来たら面白そう。

また、当たり前でしょうがjavaを仲介しないで直接google accessライブラリを作った方がいいかも。

ナビゲーション
Ads