ExCellaを使ってJavaアプリケーションからExcel出力

※この投稿は、丸太式 Advent Calendar 2014の4日目です

ExCellaとは

JavaのプログラムからExcelファイルを操作するライブラリとしては、Apache POIが有名ですが、決まったテンプレートに値を設定して出力するような使い方をする場合に必要なコード量が多いと思います。
また、出力する項目は変えずに値を設定するセルをかえるだけでもプログラムを書き換える必要があり、とても扱いやすいとは言えません。
ExCellaは、そんな扱いづらいPOIのラッパーとして利用できるOSSのライブラリです。

ExCellaのコンポーネント

ExCellaは3つのコンポーネントで構成されており、それぞれのJarと、一緒にダウンロードできる依存ライブラリのJarをクラスパスに追加することで利用できます。
※現状Mavenで管理することはできませんが、GitHubのリポジトリを見る限りでは今後対応する方針のようです。
* ExCella Core
ExCellaのコアとなるコンポーネント。
他のコンポーネントから共通で利用される。
* ExCella Trans
データ移行の為のコンポーネント。
ExcelファイルやCSVファイルからSQLやJavaオブジェクトを生成できる。
* ExCella Reports
Excelの帳票を出力する際に用いるコンポーネント。
テンプレートに埋め込まれたタグを置換して、ファイルに出力できる。

Excel帳票出力のサンプルコード

ExCella Reportsを使った帳票出力のサンプルコードです。
単純にタグと値を一対一で置換する場合、これだけのコードで出力できます。

String templatePath; // テンプレートファイルのパス
String outputPath; // 出力先のファイルパス
 
// 1. ExCellaのReportBookオブジェクト(Excelのワークブックに相当)を生成する
ReportBook reportBook = new ReportBook( templatePath, outputPath, ExcelExporter.FORMAT_TYPE);
// 2. ExCellaのReportSheetオブジェクト(Excelのシートに相当)を生成する
ReportSheet reportSheet = new ReportSheet( "シート名");
// 3. テンプレートのタグを置換する値を設定する
// この例では、テンプレート中の ${tagName} を tagValue に置換します
reportSheet.addParam( SingleParamParser.DEFAULT_TAG, "tagName", "tagValue"); 
// 4. ReportBookにReportSheetを追加する
reportBook.addReportSheet( reportSheet);
// 5. 帳票出力処理を行う
ReportProcessor processor = new ReportProcessor();
processor.process( reportBook);

ExCella Reportsは単純な1対1の置換だけでなく、指定範囲の繰り返し置換にも対応しています。
詳しくは、公式のドキュメントをご覧ください。

最後に

ExCellaはOSSのプロダクトとしてはコミュニティがあまり活発ではありませんが、帳票文化が根付いている日本ではかなり便利に使えると思います。

参考リンク

Oracleのリストの最大数を考慮したHibernate Criteria

※この投稿は、丸太式 Advent Calendar 2014の2日目です

DBMSのOracleには、IN句等に渡せるリストの最大長に制限があることは皆さんご存じだと思います。
ご存じ無い方のために例を示しますと、以下の二つのSQLでは、前者は成功し、後者は失敗します。

SELECT * FROM AnyTable WHERE AnyColumn IN (1, 2, 3, (), 1000);
SELECT * FROM AnyTable WHERE AnyColumn IN (1, 2, 3, (), 1000, 1001);
-- →ORA-01795: リストに指定できる式の最大数は1000です。

そもそもこんなSQLが発行されているのが大きな間違いですが、保守開発などどうしても大きく変更できないときは、このようにしてお茶を濁すことになります。

SELECT *FROM AnyTable WHERE AnyColumn IN (0から1000) OR AnyColumn IN (1001以降);

単純ですね。IN句を1000要素毎に分割してORでつないだだけです。

さて、ここでJavaからHibernateのCriteriaを使う場合に、Collectionの要素が1000件を超えるとやはりエラーとなってしまいます。
OracleのDialectでは対応出来ていないため、Criteriaに条件を指定する際には以下のように工夫する必要があります。

Collection<T> theCollection; // 要素数が1000を超えるかもしれないコレクション
Criteria criteria = session.createCriteria(AnyTable.class);
// criteria.add(Restrictions.in("AnyColumn", theCollection)); //←これではtheCollection.size() > 1000の場合にエラー
List<T> tmpList = new ArrayList<>(theCollection);
Junction disjunction = Restrictions.disjunction();
while (tmpList.size() > 1000) {
  List<T> subList = tmpList.subList(0, 1000);
  disjunction.add(Restrictions.in("AnyColumn", subList));
  tmpList = tmpList.subList(1000, tmpList.size());
}
if (!tmpList.isEmpty()) {
  disjunction.add(Restrictions.in("AnyColumn", tmpList));
}
criteria.add(disjunction);

面倒ですね。
コレクションを渡してdisjunctionを返すユーティリティメソッドを作っておくと多少は楽になるかもしれません。

まとめ

こんな事をするくらいなら、はじめからサブクエリを使いましょう。

今年も無謀な挑戦を始めます[Advent Calendar 2014]

※この投稿は、丸太式 Advent Calendar 2014の1日目です

無謀な挑戦=一人でAdvent Calendarを埋める

無謀ですね。
海外ではクリスマスまでのカウントダウンのために、Advent Calendarというカレンダーがあるそうです。
近年、日本のIT系技術者の間ではあるテーマに基づい12月1日から25日まで、日替わりでブログ等のエントリを書く催しがはやっています。

目的

一人でアドベントカレンダーを埋めることで、単純にアウトプットを増やすだけでなく、継続してアウトプットするきっかけにしたいと考えています。
挫折したら挫折したで、また来年がんばろうとは思いますが、去年も挫折しているので今年は毎日何かしら書きたいです。

今年のアドベントカレンダーは、「丸太式 Advent Calendar 2014」にまとめているので、気が向いたらご覧ください。

※去年の挫折した結果はこちら→http://www.adventar.org/calendars/256

GitLabにPushしたときに”Could not find rake-10.3.2 in any of the sources”が発生した場合の対処

このバグ踏みましたorz
Could not find rake-10.3.2 in any of the sources · Issue #7230 · gitlabhq/gitlabhq

詳しくはチケットのほうを見ていただければわかると思いますが、
とりあえず解消するには

sudo apt-get purge ruby1.9.1 libruby1.9.1

を実行すればOKです。

apt-getで追加したrubyと共存したいときはどうすればいいんでしょうね・・・(あまり調べてない

HipChat+HubotでChatOps【とりあえずHipChatにHubot参加編】

久しぶりの投稿です。今週は珍しく成果が出たので、きちんとアウトプットします。

HipChat

HipChat(http://hipchat.com)とは、Atlassianが提供するグループチャットサービスです。
以前は無料で使えるのが最大で5人だったそうですが、現在は無料でもユーザ数無制限になっています。

Hubot

Hubot(https://github.com/github/hubot)は、GitHubが使っているBotフレームワークです。
Adapterを追加することで、様々なグループチャットやWebサービスと相互に接続することが出来ます。
Node.js上で動作し、AdapterやスクリプトはCoffeeScriptで記述できます。

heroku

Ruby, Java, Node.js等のPaaSのサービスです。
今回はHubotを動作させるために利用しました。Hubotを使う位であれば無料で利用できます。

ChatOps

チャットを使ってサービスを運用しようとする最近のはやりです。DevOpsのツールとの相性も良さそうです。
HipChatやCampfire等のグループチャットにHubot等のBotを接続して、Botを使ったオペレーションを行います。

・・・で、何したの?

今日はHubotの設定とHipChatに参加させただけです。(つまりほとんど何もしていない)
特にハマった点はないので、記事の最後に参考にしたリンクを載せるくらいにしておきます。

(Redmine|GitLab) + HipChat

ついでにRedmineとGitLabをHipChatに連携して、月次で処理しているスクリプトの処理結果をHipChatに表示するように設定しました。
Redmineはプラグインを追加しただけですし、GitLabに至っては標準機能として連携出来るので、こちらもリンクを載せておきます。

これからの目標

NginxのアクセスログとエラーログをFluentdで収集して簡単な解析をしてみようと思っています。
Hubotは解析のトリガーにするか、特定時点の解析結果を取得するのに使うか検討中です。

ところで

このブログを置かせてもらっているConoHaで、オブジェクトストレージ機能の提供が始まりましたが、1年間の無料モニターに当選しました。
オブジェクトストレージも触るのは初めてですが、アウトプットできる何かを作ろうと思います。


Photo By: i k oCC BY-NC-SA 2.0

XOOPS CubeのProfileモジュールをServiceManagerに登録する

XOOPS Cubeのコアに同梱されているProfileモジュールは、ユーザー情報の項目を自由に追加できるモジュールです。
XOOPS CubeのServiceManagerは、モジュール間の連携を実現するXCube_Serviceを管理するコンポーネントです。
コア同梱のモジュールは基本的にServiceManagerにサービスを登録していますが、なぜかProfileモジュールだけは登録されていません。
そこで、登録するためのモジュールプリロードとパッチ(後述)を作りました。

コード

とりあえずコードはGistにあげておきました。

ちょっと解説

Definitions.class.php.patchはご覧の通りパッチファイルです。
メソッドを追加しただけですが、これがないとFATALになります。
呼び出し元を改変することも考えましたが、サービスの機能を減らす修正となってしまうのでこうなりました。
特に怪しい挙動もないので問題なく動作するとは思いますが、自己責任でお願いします。

RegisterService.class.phpはモジュールプリロードです。
このプリロードがServiceManagerへの登録を行います。
こちらのファイルはXOOPS_ROOT_PATH/modules/profile/preloadに配置してください。

まとめ

Profileモジュールのサービスは戻り型にXCube_Objectを継承したクラスを定義していますが、実際に帰ってくるのが配列だったりするので注意が必要っぽいです。
XOOPS Cubeのモジュール開発やカスタマイズに関するドキュメントが少ない印象があるので、こういうネタはもっと拡充したいですね。

参考

PHP – XOOPS Cube ServiceManager – Qiita


Photo By: Robert SchroederCC BY-NC-SA 2.0

[XOOPS Cube] Protectorモジュールに初Pull Requestした話

XOOPS Cubeの定番モジュールである「Protector」に、これまた定番のALTSYSがインストールされていないときにメニューの「一般設定」リンクがXOOPS2のSystemモジュールを指してしまうバグを見つけたので、修正してPull Request、すぐにマージされました。
管理メニューのリンクは正しく生成されているので、管理メニューから移動している限り見つけにくいバグです。

コードについてはhttps://github.com/xoopscube/protector/pull/3をご覧ください。

発生条件

ALTSYSがインストールされていないという1点だけです。
ALTSYSがインストールされている場合、Protector自身のadmin/index.phpを指すようにリンクが生成されます。
しかしALTSYSがインストールされていない場合、Systemモジュールのadmin.phpを指すリンクとなります。
Protector自身はALTSYSのインストールが必須ではないので、これではXOOPS CubeでALTSYSを使わずにProtectorを使いにくくなってしまいます。

修正

ALTSYSの有無を判定している部分で、ALTSYSがインストールされていない場合にlegacyモジュールの有無を判定し、インストールされていればlegacy/admin/index.phpを指すリンクを生成するようにしました。

蛇足

今回Pull Requestを出したのはXOOPS Cubeのリポジトリでしたが、よく見たらXoopsXのProtectorにも同様のバグがありました。
XoopsXは確かALTSYSが必須になっていたような気がするので、ほとんど気づけないですね。
最近のXOOPS Cubeコミュニティは、XoopsXとXOOPS Cubeで別のリポジトリを持ってしまっているせいで外から構造がよくわからなくなっている気がします。


Image By: Barbara DieuCC BY-NC-SA 2.0

[CentOS 7] MariaDB Serverのインストールとsystemdによる操作

RHEL7からMySQLの代わりにMariaDBが提供されるようになりましたね。
MySQLと互換性があるようなので、これからはMariaDBの時代が来るのでしょうか。
また、SysV Initに代わってsystemdが新しいinitプロセスとして採用されました。
操作方法が微妙に異なるので、ここで簡単にまとめておきます。

インストール

mysql, mysql-serverパッケージの代わりにmariadb, mariadb-serverパッケージが提供されています。

# yum install mariadb  # クライアント
# yum install mariadb-server  # サーバー

コマンドやUNIXソケットはMySQLと同じですが、バージョン情報を見るとちゃんとMariaDBになっています。

$ mysql --version
mysql  Ver 15.1 Distrib 5.5.37-MariaDB, for Linux (x86_64) using readline 5.1
$ mysqladmin -u root -p version
Enter password:
mysqladmin  Ver 9.0 Distrib 5.5.37-MariaDB, for Linux on x86_64
Copyright (c) 2000, 2014, Oracle, Monty Program Ab and others.
 
Server version          5.5.37-MariaDB
Protocol version        10
Connection              Localhost via UNIX socket
UNIX socket             /var/lib/mysql/mysql.sock
Uptime:                 2 min 49 sec

systemdの操作

RHEL7ではSysV initがsystemdで置き換えられました。基本的な操作はコマンドと引数の順番が違うだけなので覚えやすいと思います。
systemdではサービスやデバイスをUnitと言う単位で管理します。systemctlコマンドではこのUnitの名前を操作対象として指定します。
MariaDBのUnit名はmariadb.serviceです。

# systemctl アクション Unit名で基本的な操作ができます。
# ここで示したほかにもアクションがあるので、詳しくはsystemctl(1)のManページを見ましょう。
systemctl [enable|disable|start|stop|restart] mariadb.service

MariaDB Serverをインストールした後は、MySQLと同じように初期設定を行います。

# systemctl start mariadb.service
# mysql_secure_installation
()

システム起動時にMariaDB Serverが立ち上がるように設定します。

# systemctl enable mariadb.service

Image By: Giuseppe MoscatoCC BY-NC-SA 2.0

GitLab環境のUbuntuを13.10->14.04にアップデートしたときにはまった話

GitLabを手動でインストールしていたUbuntuを13.10から14.04にアップデートした後、GitLabが立ち上がっていないことに気づいたので解決方法を記載します。

たぶんこの問題で一番厄介なのは、service gitlab startコマンド自体は正常に終了するってところです。
ブートログを見ても特に問題が見つからず、いつの間にかGitLabだけが落ちているように見えてしまいます。

環境

  • GitLab 6.6.5
  • Ubuntu 13.10 -> 14.04

原因

実はかなり単純な問題で、charlock_holmesというgemに必要なlibicuパッケージが更新されたことが原因です。
unicornのエラーログを見てみると、/home/git/gitlab/vendor/bundle/ruby/2.0.0/gems/activesupport-4.0.3/lib/active_support/dependencies.rb:229:in `require': libicui18n.so.48: cannot open shared object file: No such file or directory - /home/git/gitlab/vendor/bundle/ruby/2.0.0/gems/charlock_holmes-0.6.9.4/lib/charlock_holmes/charlock_holmes.so (LoadError)とあります。
ここに出てくるlibicui18n.so.48は、Ubuntu 13.10のlibicu48パッケージでインストールされたファイルですが14.04ではlibicu52となっており、そもそもこのファイルは存在しません。

解決法

charlock_holmes gemを再インストールする必要があります。
このgemはNative extensionが要るのでビルド時にlibicui18n.soのバージョンが固定されてしまいます。
若干面倒ではありますが、GitLabのインストールパス/vendor/bundle以下のcharlock_holmes関連ファイルを削除し、bundle installを再実行することで新しいバージョンのlibicui18n.soを参照するようになります。

まとめ

GitLabのUbuntu 14.04向けパッケージが提供されると幸せになれそうですね。
PPAでも良いけど。

#qpstudy 2014.04 〜俺の屍を超えて行け、でも踏まないで〜 に参加した話

4月19日(土)に開催された、qpstudy 2014.04に参加してきました。
過去にも何度か参加したりUstで眺めてたりしていましたが、新入社員であることに間違いは無いので新人枠での参加です。

qpstudyについてはこちら→https://sites.google.com/site/qpstudy/
qpstudy 2014.04についてはこちら→http://www.zusaar.com/event/4897007
Twitterのハッシュタグ「#qpstudy」を、@wasaistさんがまとめています。いつもありがとうございます→http://togetter.com/li/657194


就職先はインフラ屋さんじゃないので業務に直結する話ではないのですが、以前から個人的興味があったのとアプリより下のレイヤーの話も知っておいて損はないと思っています。
qpstudyは「初心者に優しい」勉強会なので、アプリ屋さんも積極的に参加してみてはいかがでしょうか。

今回の発表内容についてはTogetterのまとめと登壇された方のスライドに任せるとして、参加した感想を幾つか。

  • 相変わらずの人気。新人枠はそれほどでもなかった(とはいえ補欠20人くらい居たけど)が、告知翌日には一般枠はほぼ埋まって多様な気がする。
  • 今回はUstではなくニコ生で中継していたため、リモート参加者のツイートがあまり流れていなかった感じがする。
  • もっと前に座ればよかった。(座席表→http://seats.nekoruri.jp/36新人さん同士の絡みが出来なかったのが最大の後悔ポイント。
  • コミュ障改善してもっとつながりを増やしたい。

他にも今後の課題が幾つか出てきたので、頭の片隅にしまっておきます。とりあえず今は新人研修がんばろう!

登壇者の皆さんのスライドを貼って、この記事を締めさせていただきます。
会場を提供してくださったドワンゴ様、スタッフの皆様、参加者の皆さん、お疲れ様でした。そして、これからお世話になる(かも?)と思うので、よろしくお願いします!

第1セッション インフラエンジニアとは、なんだ by しょっさん(@sho7650)

第2セッション インフラアーキテクチャ設計の勘所 by せちろー(@sechiro)さん

第3セッション ハードウェア設計の勘所 by はせがわ(@hasegaw)さん

第4セッション OSとネットワーク設計の勘所 by おおむら(@yktko)さん

第5セッション ミドルウェア設計の勘所 by nekoruriさん

第6セッション 今後のインフラエンジニアとは by ばば(@netmarkjp)さん ※スライド非公開