こちらのサンプルプログラムは Java 9 以降では動作しません。
Garoon と Google Calendar とを連携させたい場合は、株式会社ノベルワークスのカレンダー連携ソリューション ガル助(有償)の利用をご検討ください。
本サンプルプログラムとの大きな違いは次のとおりです。
・Google Calendar だけでなく、Office 365 とも連携が可能
・双方向連携が可能
・複数ユーザーのスケジュール同期が可能
(著者:サイボウズ 竹内 能彦)
はじめに
Googleカレンダー使っていますか?自分の予定と他の方の予定を並べて表示したり、予定を共有したり出来てとっても便利ですよね。
そこにGaroonの予定を並べて見られたらもっと便利になると思いませんか?
そんな思い付きからGaroonの予定をGoogleカレンダーに表示する連携プログラムを作成しました。事前準備が少し大変ですが、皆さん是非使ってみてください。
概要
連携プログラムは以下の処理をコマンドラインから実行できるサンプルプログラムです。
- Garoonに登録された予定をGoogleカレンダーに登録
- Garoonで更新された予定をGoogleカレンダーに反映
- Garoonから削除された予定をGoogleカレンダーから削除
Googleカレンダーに登録する情報はGaroonの予定の「開始日時」、「終了日時」、「施設」、「メモ」、「コメント」、「参加者」です。
動作環境
- プログラム実行用端末(Java8が動作し、Garoon、Googleカレンダーにネットワーク接続できること)
2018年3月現在、Java9では動作しないことを確認しています。 - Garoon on cybozu、パッケージ版 サイボウズ ガルーン3.0.0以降
- Googleカレンダー
Garoon on cybozu、Googleカレンダーは2018年2月版で確認しています。
事前準備
実行するには連携プログラムの設定だけでなく、GoogleアカウントやGoogleカレンダーの設定が必要になります。
また、GoogleアカウントやGoogleカレンダーの設定内容を連携プログラムの設定に利用するため、メモが必要な項目はその都度注釈を入れてあります。
※現在のGGsyncはOAuth2.0にも対応していますが、本ページではサービスアカウントキー認証を利用します。
1.Googleアカウント作成
下記URLから、Googleアカウントを作成します。Googleアカウントを取得済みの方はログインしてください。
https://accounts.google.com/SignUp
2.Google APIの利用設定
下記URLから、プロジェクトを作成します。
https://console.developers.google.com/project
プロジェクト名には適当な値を入力してください。
プロジェクトの作成完了後、Google Calendar APIを検索し、
Google Calendar APIを有効にします。
認証情報を作成します。
下記画像の通りの内容を選択し、「必要な認証情報」をクリックします。
サービスアカウント名には適当な値を入力し、キーのタイプはP12を選択します。
役割なしで作成します。
自動ダウンロードされたP12キー(以下、秘密鍵(拡張子がp12))は以降の手順で利用しますので任意のフォルダに保存します。
次にサービスアカウント IDを確認します。
画面右の「サービスアカウントの管理」をクリックし、
表示されたサービスアカウント IDをメモします。(以降の手順で利用します)
3.Googleカレンダーの作成
下記URLから、Garoonのスケジュールを連携させるGoogleカレンダーを作成します。
https://www.google.com/calendar
カレンダーの作成完了後、Googleカレンダー設定の「このカレンダーを共有」タブを開きます。先ほどのメールアドレスに予定の変更権限を付与し、保存します。
Googleカレンダー設定の「カレンダー情報」タブを開き、カレンダーIDを確認します。カレンダーIDは以降の手順で利用しますのでメモしてください。
4.連携プログラムの設定
プログラム実行用端末に連携プログラムを動作させるフォルダを作成します。本設定では例として「C:/GGsync」を利用します。
秘密鍵を「C:/GGsync」に移動します。
実行ファイルと設定ファイルをダウンロードしてください。ソースはGitHubで管理しています。(外部サイトが開きます)
実行ファイル「GGsync.jar」と設定ファイル「GGsync.properties」を「C:/GGsync」に移動します。
設定ファイル「GGsync.properties」をテキストエディタで開き、コメントに従い設定します。
Googleカレンダーに登録する予定の色は1から11までの数値を指定できます。下記の色を参考に選択してください。
各カラーIDのカラーコードはこちらのコメントから確認できます。
(tomomo85さん 情報ありがとうございます)
実行手順
プログラム実行用端末でコマンドプロンプトを起動し、以下のコマンドを入力します。
> java -jar C:/GGsync/GGsync.jar C:/GGsync
コマンドの形式は「 java -jar 実行ファイルのパス 設定ファイルが存在するフォルダ」です。
「The sync completed.」と表示されればスケジュール連携に成功しています。
実行結果は設定ファイルが存在するフォルダ配下のGGsync.db(例ではC:/GGsync/GGsync.db)に保存します。GGsync.dbは次回実行時の差分反映に利用します。
プロキシ経由の実行
プロキシを経由する必要がある場合は下記のオプションを追加して実行してください。
> java -Dhttp.proxyHost=ホスト名 -Dhttp.proxyPort=ポート番号 -Dhttps.proxyHost=ホスト名 -Dhttps.proxyPort=ポート番号 -jar C:/GGsync/GGsync.jar C:/GGsync
オプションの詳細はこちら(Oracle社のドキュメントページが開きます)
セキュアアクセス利用時の実行
セキュアアクセスを利用する必要がある場合は、クライアント証明書をGGsync.jarと同じディレクトリに保存し、下記のオプションを追加して実行してください。
> java -Djavax.net.ssl.keyStore=xxxx.pfx -Djavax.net.ssl.keyStorePassword=xxxx -Djavax.net.ssl.keyStoreType=PKCS12 -jar GGsync.jar .
実行例
下記がGaroonのスケジュール、実行結果、予定が反映されたGoogleカレンダーの例になります。
・Garoonのスケジュール
・連携プログラムの実行結果
・Googleカレンダー(プライベートな予定と並べて表示)
Garoonの予定の「メモ」、「コメント」はGoogleカレンダーの「説明」にまとめて登録します。
Garoonの予定が変更された場合は、Googleカレンダーの予定を削除してから再登録します。
下記が変更時の実行例になります。
Garoonの予定が削除された場合は、Googleカレンダーの予定を削除します。
下記が削除時の実行例になります。
定期実行
タスクスケジューラなどを利用することで、定期的にGaroonの予定をGoogleカレンダーに反映できます。
是非試してみてください。
連携プログラムの更新履歴
2015/3/30 繰り返し予定が正常に登録されない不具合を改修しました。
2015/4/24 終了時間未指定の予定がエラーになる不具合を改修しました。
2015/6/18 連携失敗時に詳細なエラーを出力するように修正しました。
2015/9/16 日本語文字のアカウント名に対応しました。
2016/1/14 Googleカレンダーに「参加者」を登録する機能を追加しました。
2016/3/24 ソースコードをGitHubに移しました。
2017/3/21 セキュアアクセス利用時の実行オプションを追記しました。
2017/9/21 ソースコードにライセンス表記を追加しました。
こんにちわ
iOS系の端末を利用する場合、カレンダーとの連携ができないため、このプログラムはとても便利に利用しています。
プログラム利用中に1点だけ問題がありましたので報告します。
サイボウズの予定登録で、以下のように登録すると、javaが「nullpointerexception」のエラーが出てその後の日程の同期ができなくなります。
開始 ○○:○○
終了 (指定なし)
予定を通過すれば問題なく同期できます・・・
取り急ぎは、自分の運用は回避していますが、他人にこのように入れられることもあり、不自由しています。
修正するタイミングがあればあわせて改修いただけると幸甚です。
Akio Haradaさん
返信が遅くなり誠に申し訳ありません。
不具合の報告ありがとうございます。
確認して修正したいと思いますのでもうしばらくお待ちください。
Akio Haradaさん
プログラムを修正し、本文のファイルを更新してあります。
もしよければ最新のGGsync.jarを上書き保存してお試しください。
ご連絡ありがとうございます。
確認しました。
1時間の予定として登録されることを確認しました。
早々な対応ありがとうございました。
竹内様
初めまして。
さっそく、シロウト的なトラブル(質問)で恐縮です。
説明通りにやったつもりなのですが、下記のようにエラーになってしまいます。
何が原因かご教示願えますか?
C:\GGsync>java ?jar C:/GGSync/GGsync.jar C:/GGsync
エラー: メイン・クラス?jarが見つからなかったかロードできませんでした
横槍で申し訳ありません。
バッチファイルで問題なく動作しているので、参考になれば。
起動に関わるバッチファイルの一部ですが、以下のように記述されています。
=-=-=-=-=-=
set INSTALLDIR=C:\hoge\GGsync
set CONFIGDIR="C:/hoge/GGsync"
java -jar "%INSTALLDIR%\GGsync.jar" %CONFIGDIR%
=-=-=-=-=-=
拝見した記述だと、2点変更したほうがよいと思われます。
1."java ?jar"→"java -jar"
→ jarの表記が違うと思います
2."C:/GGSync/GGsync.jar C:/GGsync"→"C:\GGSync\GGsync.jar C:/GGsync"
→ GGsync.jarの場所は\指定が良いと思われます
ご参考になれば。
Akio Harada様
横槍ありがとうございます。
たしかに?jarはまちがいでした。
コピペしたんですが何回かやっているウチに-を?にしてしまったようです。
修正してリトライしたところ、The beginning..と表示されましたので、今実行中です。(/は\にしなくてもOKでした)
お騒がせして申し訳ありませんでした。
たびたび恐れ入ります。
GGsyncを実行し「The sync beginning..」が表示されましたが、次のような結果でした。
c:\GGsync>java -jar C:/GGsync/GGsync.jar C:/GGsync ←14:31頃
INFO 14:35:24 The sync beginning with normal mode.
INFO 14:37:03 [ADD] Title:hoge ←今日のスケジュール名
ERROR 14:37:24 connect timed out
java.net.SocketTimeoutException: connect timed out
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
「The sync beginning..」が表示されるまで4分ほどかかっており、その後タイムアウトしています。
GGsync.propertiesは次のようにしています。
sync.before.days=1
sync.after.days=180
これは私のところのネットワークによるものでしょうか?
ネットワークによるものでしょうか?
Teruo.Abeさん
こちらのエラーですが再発していますか。
1件のスケジュール登録が完了していることから
クライアントとGoogleとの間で通信に問題があることが考えられます。
まずは通信の確認とシンク期間(sync.after.days)を短くして
動作するかご確認いただけますでしょうか。
竹内様
レスありがとうございます。
その後設定をすべてやり直しても同じでした。
また、昨日ご指摘頂いたsync.after.daysを=1にして実行しましたが、結果は同じでした。
c:\GGsync>java -jar C:\GGsync\GGsync.jar C:\GGsync 10:45:??に入力
INFO 10:48:07 The sync beginning with normal mode.
INFO 10:49:09 [ADD] Title:hoge
ERROR 10:49:29 connect timed out
java.net.SocketTimeoutException: connect timed out
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
ハズしているかもしれませんが、気になる点としては
「クライアントID作成後に自動ダウンロードされる秘密鍵(以下、秘密鍵)と... 秘密鍵は任意のフォルダに保存し...」とありますが
クライアントID作成時には”hoge.json"は作成され、"hoge.p12"は作成されませんでしたので,[新しいP12キーを生成]ボタンを
押して取得し、そのファイル名をGGsync.propertiesに記述しました。
Javaのコマンドオプションで、httpsのプロキシーの指定をいれたら、Time outは発生しなくなりました。
-Dhttps.proxyHost=proxy.xxxx.com --Dhttps.proxyPort=9999
一応httpもproxyも指定しました。
-Dhttp.proxyHost=proxy.xxxx.com --Dhttp.proxyPort=9999
NotFoundErrorの件は、カレンダーに権限を与えていなかっただけだったので、解決しました。
お騒がせいたしました。
バッチファイルでjavaコマンドの前に次のコマンドでプロキシを設定していてもダメでしたが
NETSH winhttp import proxy source=ie
RICK DOMさんのコメントの通り試したところ、成功しました。
※javaコマンド投入後、The sync beginning with ...が表示されるまで3分ぐらいかかります。
このメッセージは何でしょうか?
6 09, 2015 11:02:36 午前 org.apache.commons.httpclient.HttpMethodBase readResponseBody
情報: Response content length is not known
こんにちは。
Garoonも初めてならjavaアプリも初めてで、でも連携させたく孤軍奮闘中です。超シロウトです。
GGsync.propertiesの書き方、教えてください。
秘密鍵(サービスアカウントの秘密鍵)の絶対パス
例)C:/GGsync/API Project-xxxxxxxxxxxx.p12
google.oauth.p12key=
仮にダウンロードしたアイル名がhogehoge.p12だったとすると、
google.oauth.p12key=C:/GGsync/API Project-hogehoge.p12
と指定するのだと読み取ったのですが、合ってますでしょうか?
これで指定すると、
INFO 2015/07/07 13:17:59(GGsync:main:75) The sync beginning with normal mode.
ERROR 2015/07/07 13:18:09(GGsync:main:413) C:\GGsync\API Project-hogehoge.p12 (指定されたファイルが見つかりません。)
java.io.FileNotFoundException: C:\GGsync\API Project-hogehoge.p12 (指定されたファイルが見つかりません。)
と言われてしまっております。
ご教示ください。
全ての資源は
c:\GGsync直下に置いてあります。
K-HAYAKAWAさん
ご利用ありがとうございます。
ダウンロードしたファイル名が「hogehoge.p12」の場合は以下を設定してください。
google.oauth.p12key=C:/GGsync/hogehoge.p12
今はファイル名の頭にAPI Project-が付かないのですね・・・
記事は修正したいと思います。
大変便利に使わせていただいています。
garoonの予定参加者もgoogleカレンダーの方で確認できると嬉しいです。
こんにちは、Androidのカレンダーがイマイチなので、設定を一からやり直したところ、OAuth 2.0がP12キーのサポートをやめてしまったようで、ダウンロードするボタンが出てきません。
JSONキーしか無い場合、こちらのアプリの利用は出来ないということでよろしいでしょうか?
Naoki Enomoto様
利用者のユーザーの阿部と申します。
私は、APIと認証-認証情報で上部に表示される[新しいP12キーを生成]でP12キーを取得できました。
今さっきも見たらそのボタンは存在しました。
ハズしていたらごめんなさい。
Teruo.Abe様
コメントありがとうございます。
クライアントIDの作成のところで、間違えておりました(サービスアカウント作成ではなく、0 Auth 2.0作成に行ってました)
失礼致しました。
竹内様
初めまして。
シロウトのユーザーの明と申します。
説明通りに試したが、「ログインできない」エラーが有りました。
いろいろ調査してみると、ガルーンのログインアカウントは漢字(スペースあり)だったすると、上記のエラーとなります。
テストでローマ字のアカウントを新規登録して、やはり成功になりました。
恐縮ですが、GGsync.propertiesの中身で、漢字も認識できるようにしていただくと助かると思っております。
Akira Tokuhei様
アカウント名の日本語文字に対応しました。
アーカイブファイルを再度ダウンロードし、GGsync.jarファイルを上書き更新してお試しください。
よろしくお願いします。
竹内様
ご連絡ありがとうございます。
先ほど日本語文字で試しておりました、完璧に実現できました。
早速なご対応、ありがとうございました。
2015.9.30時点のGGsync.jar (md5sum 3c443dab6d59bddd7c5f798873e8e9f1) ですが、含まれている sqlite-jdbc-3.8.7.jar に問題があり、Linux系ホストだと動作しないようでした。
(Debian GNU/Linux 8.2 Jessie, JDKには https://launchpad.net/~webupd8team/+archive/ubuntu/java の oracle-java8-installer を使っています)
参考
xerial / sqlite-jdbc / 課題 / #152 - 3.8.7 version Linux issue — Bitbucket
https://bitbucket.org/xerial/sqlite-jdbc/issues/152/387-version-linux-issue
sqlite-jdbc作者によって提供されている sqlite-jdbc-3.8.11.1.jar を https://bitbucket.org/xerial/sqlite-jdbc/downloads から入手し、差し替えてjarを再生成すると動作しました。ご参考まで。
便利に使わせて頂いております。
一つ教えていただきたいのですが、過去分の同期対象を設定してると、
毎日設定日数以前の予定が消えていくのは何か設定で回避できますか?
シンク対象を過去3日に設定すると、今日10/5であれば10/2から同期されます。
日付が変わって10/6になると、10/2の予定が消去されてしまいます。
シンク対象過去0日設定でも消えていく様です。
ご確認、ご教授、よろしくお願いします。
Eaurouge Spa様
設定日数以前の予定が消えるのは仕様となります。
1000などの大きい数字を設定することで要件を満たせないかご検討ください。
例えばですが、1000を設定すれば過去1000日分のデータが削除されずに残ります。
竹内様
ご回答ありがとうございます。
大きい数字での運用を検討してみます。
竹内様
一つ教えていただきたいことですが、同期しているカレンダーのタイムゾーンがコントロール出来ないでしょうか。
シンクされたタイムゾーンがGMT+9日本時間ですが、他国に出張すると、GoogleCalendarがロカールタイムゾーンに変更しますが、
毎回にGoogleCalendarで調整要です。
ご教授よろしくお願いします。
最近下記のようなエラーが発生して、その他のスケジュールの更新ができなくなってしまいました。
対応方法はございますでしょうか?
INFO 2015/11/13 16:35:15(GGsync:main:195) [DEL for updated garoon schedule] Title:ガルーンのある繰り返し予定のタイトル
ERROR 2015/11/13 16:35:16(GGsync:main:400) 410 Gone
{
"code" : 410,
"errors" : [ {
"domain" : "global",
"message" : "Resource has been deleted",
"reason" : "deleted"
} ],
"message" : "Resource has been deleted"
}
com.google.api.client.googleapis.json.GoogleJsonResponseException: 410 Gone
{
"code" : 410,
"errors" : [ {
"domain" : "global",
"message" : "Resource has been deleted",
"reason" : "deleted"
} ],
"message" : "Resource has been deleted"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1049)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.cybozu.GoogleCalendar.delSchedule(GoogleCalendar.java:77)
at com.cybozu.GGsync.main(GGsync.java:199)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Sakuori 様
私もSakuori 様と同様のエラーがでておりましたが、グーグルカレンダー側の共有の設定に誤りがあったことと、
設定ファイル「GGsync.properties」の設定に誤りがあったことが原因だったようで、
設定をしなおしたら、うまくいきました。ご参考までに。
Haruki 様
情報ありがとうございます。Haruki様の情報を元に再度「GGsync.properties」の設定を見直したところ、
「メールアドレス(サービスアカウントのメールアドレス)」の設定を間違えておりました。
修正した所、うまくいきました。
ありがとうございました。
GGsync非常に便利で重宝しております。
1つ相談です。
Garoonで登録したスケジュールをGaroon上でコメントが追記された場合も、gcalに対して削除と追加が行われるようですが、 コメントの変更は無視し、スケジュール情報(日時)が変更された場合のみ、追加削除するように対応できないでしょうか。
自分の場合、Garoonで登録したスケジュールをgcalに同期し、gcalで他のgoogleユーザにスケジュール共有しています。
GGsyncによりgcalのスケジュールを削除されたタイミングで、共有していた他のgoogleユーザも削除されますが、 実際にはGaroon上は単にコメント追記されているだけというパターンが多く、この点が改修されるとさらに使い勝手良くなるかなと思います。