Kohei Nozaki's blog 

BeanShell recipies


Posted on Sunday Jan 24, 2016 at 04:00PM in Technology


BeanShell is a handy lightweight scripting language for Java. In this entry, I’ll introduce you some useful snippets powered by BeanShell, and some recipies about it.

Setup and hello world

Grab a copy of bsh-2.0b4.jar from http://www.beanshell.org and put following shell script named bsh into your PATH:

#!/bin/sh
BEANSHELL_JAR=$HOME/Downloads/bsh-2.0b4.jar # replace path to suit your environment
java -cp $BEANSHELL_JAR bsh.Interpreter $@

Then fire up bsh from your console then just put print("hello, world!"); to confirm it works.

$ bsh
BeanShell 2.0b4 - by Pat Niemeyer (pat@pat.net)
bsh % print("hello, world!");
hello, world!

Hit Ctrl+D to exit interpreter.

You can launch your BeanShell script in a file as follows:

$ echo 'print("hello, world!");' > hello.bsh
$ bsh hello.bsh
hello, world!

Stdin

Text filtering script can be written as follows:

Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
  String line = scanner.nextLine();
  System.out.println(line.toUpperCase());
}

Save this script as toUpperCase.bsh . The script can be executed as follows:

$ echo foo | bsh toUpperCase.bsh
FOO

Command line arguments

Command line arguments can be used as follows:

sb = new StringBuilder();
for (arg : bsh.args) {
    sb.append(arg);
}
print(sb);

Save this script as args.bsh. The script can be executed as follows:

$ bsh args.bsh foo bar
foobar

Use of external jar

Any external jar can be added via addClassPath clause dynamically. For example, a SQL beautifier script powered by a Hibernate class can be written as follows:

addClassPath("/path/to/hibernate-core-4.3.7.Final.jar"); // replace path to suit your environment
import org.hibernate.engine.jdbc.internal.BasicFormatterImpl;

scanner = new Scanner(System.in);
sb = new StringBuilder();
while (scanner.hasNextLine()) {
  sb.append(scanner.nextLine()).append('\n');
}

beautifized = new BasicFormatterImpl().format(sb.toString());
print(beautifized);

Save this script as sql-beautifier.bsh then execute following command:

$ SQL="SELECT t0.content AS a2, t0.contenttype AS a3, t0.email AS a4 FROM roller_comment t0, weblogentry t1 WHERE ((t1.websiteid = 'f0588427-f2ca-4843-ac87-bbb31aa6013c') AND (t1.id = t0.entryid)) ORDER BY t0.posttime DESC LIMIT 31 OFFSET 0;"
$ echo $SQL | bsh sql-beautifier.bsh

This yields nicely formatted SQL:

SELECT
    t0.content AS a2,
    t0.contenttype AS a3,
    t0.email AS a4
FROM
    roller_comment t0,
    weblogentry t1
WHERE
    (
        (
            t1.websiteid = 'f0588427-f2ca-4843-ac87-bbb31aa6013c'
        )
        AND (
            t1.id = t0.entryid
        )
    )
ORDER BY
    t0.posttime DESC LIMIT 31 OFFSET 0;

Maven plugin

If you have Maven installed, you can execute any BeanShell script without obtaining bsh-2.0b4.jar by hand. Maven and the beanshell-maven-plugin takes care of it instead of you:

$ mvn com.github.genthaler:beanshell-maven-plugin:1.0:run -Dbsh.file="hello.bsh"
...
[INFO] --- beanshell-maven-plugin:1.0:run (default-cli) @ standalone-pom ---
[INFO] Executing Script
[INFO] file class java.lang.String
[INFO] script class java.lang.Object
[INFO] interpreting file hello.bsh
hello, world!

Note that you don’t need to create pom.xml to execute a simple BeanShell script.

For managing complex dependencies, you can leave that duty to Maven with pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>sql-beautifier</groupId>
    <artifactId>sql-beautifier</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>com.github.genthaler</groupId>
                <artifactId>beanshell-maven-plugin</artifactId>
                <version>1.0</version>
                <configuration>
                    <script><![CDATA[
                    import java.nio.charset.Charset;
                    import org.apache.commons.io.FileUtils;
                    import org.hibernate.engine.jdbc.internal.BasicFormatterImpl;

                    file = new File(System.getProperty("sql"));
                    sql = FileUtils.readFileToString(file, Charset.defaultCharset());
                    result = new BasicFormatterImpl().format(sql);

                    print(result);
         ]]></script>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-core</artifactId>
                        <version>4.3.7.Final</version>
                    </dependency>
                    <dependency>
                        <groupId>commons-io</groupId>
                        <artifactId>commons-io</artifactId>
                        <version>2.4</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

Save the SQL you want to beautify as original.sql and executing following command yields similar result:

$ mvn bsh:run -Dsql=original.sql

jEdit integration

jEdit has pretty nice integration with BeanShell. You can integrate that SQL beautifier as a jEdit macro. Put following snippet as ~/Library/jEdit/macros/FormatSQL.bsh (for OS X) or create it with Macros → New Macro from jEdit menu bar:

addClassPath("/path/to/hibernate-core-4.3.7.Final.jar"); // replace path to suit your environment
import org.hibernate.engine.jdbc.internal.BasicFormatterImpl;

sql = textArea.getSelectedText();
beautifized = new BasicFormatterImpl().format(sql);
textArea.setSelectedText(beautifized);

Paste SQL to any jEdit buffer, and select SQL statement and execute the macro with Macros → FormatSQL to trigger formatting.


Testing guice-persist nested @Transactional behavior


Posted on Wednesday Dec 23, 2015 at 01:41PM in Technology


There is no mention of nested use of @Transactional in the Transactions page of official Guice Wiki so I’ve done some testing about how transactions will be treated in nested use.

As it turns out, Guice seems ignore any of nested @Transactional and any of its rollbackOn attributes. It’s all up to the parent invoker.

For testing, I created two classes as following UML diagram:

b03b90cb 0b01 4601 9dac 755d79f2347e

EnclosingService holds a reference to EnclosedService and invokes a method of it from every method of EnclosingService. Each name of methods state that what exception will be thrown from the method. For example, EnclosedService#runtimeException() throws RuntimeException while EnclosedService#noException() won’t throw any of Exception. EnclosedService#ioExceptionWithRollbackOn() throws IOException and annotated as @Transactional(rollbackOn = IOException.class). And names of methods of EnclosingService states same but the part of after _ means that what method of EnclosedService will be invoked.

All of methods in both services save a Entity with em.persist() then invoke em.flush() so that every changes will be flushed immediately. i.e. EnclosingService#noException_noException() saves two entities that one in the method itself and another one in the enclosing invocation of EnclosedService#noException().

Then I created a test case which has 16 test methods that covers all of methods defined in EnclosingService and found that any of @Transactional annotation or rollbackOn attribute in EnclosedService are being ignored. I summarized the result in a table:

0f595e00 fad6 4df1 b0d6 442024eca778

I can see all of operations are atomic and any Exception thrown in methods of EnclosedService doesn’t affect the result if the transaction will be committed or rolled back. When Guice detects that it’s a RuntimeException or a checked exception that defined as rollbackOn in the first method which annotated as @Transactional then rollback happen.

All resources that used in this test can be obtained from my GitHub repository. It used in-memory database of Apache Derby so that everyone can execute the testcase without any annoying preparation. Also EclipseLink 2.5.1, Guice 3.0 and log4jdbc are used so that I can see how transaction is going such as commit / rollback.


Java EE ブログエンジン Apache Roller のご紹介


Posted on Thursday Dec 03, 2015 at 08:00AM in Technology


このエントリは Java EE Advent Calendar 2015 の3日目(12月3日)の記事です.

自己紹介

業務ではJPA, JAX-RSなどを使っているソフトウェアエンジニアです.趣味ではWildFly, JBatch, JSFなどを使っていろいろ作ったり,Java/Java EE関連OSSの不具合を見つけてパッチやPull Requestを送ったりしています.

今回紹介する Apache Roller のコミッタをやっているのですが,日本ではあまり知名度がないので,少しでも日本の方に興味を持ってもらえればと思い,紹介記事を書くことにしました.

Apache Rollerとは?

Apache Rollerは,Javaサーブレットコンテナ向けのオープンソースブログエンジンで,WordPressやMovable Typeとほぼ同じジャンルのソフトウェアです.元Sun Microsystemsのエンジニア David M. Johnsonさんによって2002年に作られ,blogs.sun.com(現 blogs.oracle.com )などで利用されてきました.

現在の最新バーションは,2015年3月にリリースされた5.1.2です.

誰が使っているの?

Rollerはさまざまな組織や個人によって使われています.組織での使用例としては,Javaエンジニアにはおなじみの Oracle blogs や, IBM developerworks blogApache Foundationのブログなどがあります.他にも世界中のさまざまな企業,官公庁などで使われています.

個人では,Java EEを追っかけている人にはおなじみの Adam Bienさん ,Javaの父 James Goslingさんなどが,Rollerを使ってブログを書いています. コミッタもそれぞれ自分でRollerのブログを持っています.

その他多数のユーザについては オフィシャルのWikiページにまとめられています.

使われている技術

DIコンテナとしてはGuiceが使われていて,パーシステンス層ではEclipseLink,ビュー・コントローラ層はStruts2 + JSP + Servlet,ブログのデザインなどはVelocityテンプレートで書けるようになっています.認証まわりではSpring Security,全文検索エンジンとしてはLuceneが使われています.

ServletとJSPのコードが多く,今となってはちょっと時代遅れな感は否めませんが,ソースは全て公開されているので,Javaで書かれていてリアルに運用されているWebシステムのサンプルとして一つの参考になるかもしれません.

特徴

マルチユーザー・マルチブログに対応

1つのインストレーションで複数のブログ,ユーザを作ることができます.

各ユーザーには3種類の権限のうちいずれかを割り当てることができ,具体的には,エントリの下書きだけができるユーザ(Limited),エントリの投稿などはできるがブログやシステムの設定変更はできないユーザ(Author),全ての操作ができるユーザ(Admin)のうちいずれかをユーザごとに割り当てることができます.組織用ブログなどで,日常的にレビュープロセスを取り入れているようなケースで便利に使うことができます. LDAP認証に対応しているのも組織で使いやすいポイントです.

個人で使う場合でも,複数のブログをかんたんに作れるので,たとえば技術系エントリはこのブログ,趣味の旅行の話題はまた別のブログ,といった感じで使い分けることができます.もちろん,それぞれのブログのデザインやテンプレートはべつべつに管理できます.

さまざまなDB・アプリケーションサーバに対応

DBスキーマ生成用スクリプトとして,MySQL,PostgreSQL,Oracle,DB2,SQL Server,Derby,HSQLDB用のものが用意されています.ほとんどのユーザおよび開発メンバが使っているのはMySQLなので,特に理由がなければMySQL 5.6.x以降をおすすめします(次のリリースからは5.6.xより前のサポートがなくなる予定なので).個人的にはPostgreSQLを使っていて,このブログもPostgreSQLで動いています.

いわゆるサーブレットコンテナ向けに作られているので,TomcatやJettyをはじめ,JBoss(WildFly),GlassFishなどのJava EEコンテナにもデプロイできます.ほとんどのユーザはTomcatを使っているようですが,個人的にはWildFly(このブログ)やJBoss EWSにデプロイして使っています.

Javaでプラグインが書ける

最近のブログサービスでは,冗長なHTMLだけではなくMarkdownや「はてな記法」のような簡潔なシンタックスを使ってエントリを書けるものが多くでてきています.Rollerがデフォルトでサポートしているのは標準的なHTMLだけですが,プラグインを使うことで,そういったシンタックスを使ってブログエントリを書けるようになります.

個人的には, Asciidoctorjプラグインというものを作り AsciiDoc シンタックスを使って日常的にエントリを書いています(このエントリもそうです).他にも MarkdownJSPWiki プラグインなど,いくつかのプラグインが公開されており,別途インストールすることで利用できるようになります.

プラグインを書くのはとても簡単で,適用するプラグインはエントリごとにべつべつに設定できます.今後またなんらかの新たな記法が登場してそれを使いたくなったら,HTMLへの変換エンジンとRollerをつなぐ部分だけをプラグインとして書いてやれば,既存のエントリはそのままに新しい記法を使うことができるようになります.ブログエントリの記法の他にも,コメントの記法,コメント認証などもプラグインとして独自に追加することができるようになっています.

インストール

いわゆるオンプレミス環境へのインストール方法については,英語になりますが Wiki および オフィシャルのインストレーションガイド を参照してください.また OpenShift で運用することもできます(無料枠でも可能).詳細は,こちらも英語になりますが, このブログエントリを参照してください.

メンテナンスなど

まずバックアップですが,個人的にはPostgreSQLデータベースとRollerのデータファイル用ディレクトリをssh経由でバックアップするためのAntスクリプトを書いて,定期的にcronで実行しています.スクリプトは GitHubで公開しています.

他のブログエンジンからのデータ移行については,残念ながら確立されたやり方はまだ存在していませんが,WordPressのブログエクスポート形式であるWXR形式のファイルを取り込むためのツールを作っています.詳細は こちらをご確認ください.

また,SVNからのソース取得,ビルド,プラグインのインストール,自家製パッチ適用などを自動化するためのAntスクリプトを GitHub に置いてあります.

その他,運用ノウハウなどは このブログエントリ によくまとまっています.

最後に

日本語情報は少なめですが,最新リリースでは,実用上は日本語依存の問題というのは特にありません.

ただ,日本語ブログで使うと表示上の違和感があるところがいくつかあったり,メッセージの誤訳や不足,モバイル用テーマ・一部の利用者が少ないDBでのみ生じる細かいバグが残っています(詳細は JIRA を参照).SVN上の最新版では,そのうちのいくつかは修正ずみですので,可能な方はぜひ 開発中の最新版のソース をSVNからチェックアウトしてビルドしてみてください.mvn clean package でWARファイルが生成されます. 前述のAntスクリプト も併用されると便利かもしれません.

バグレポート・パッチはもちろん大歓迎です.なにか日本語まわりで質問などあれば,このエントリにコメントをつけていただいても結構です.Javaエンジニアで,自分のブログを持ちたいとお考えの方,ぜひRollerを試してみてください!

リファレンスなど

宣伝:求人のご案内

現在,私の勤務先 株式会社 L is B ではエンジニア・デザイナーを募集しています.主に direct というインスタントメッセージングサービスの開発と運用を行っている会社です.

会社所在地は東京(+徳島県に開発拠点があります)ですが,一部リモートワークも認められています.少しでも興味を持たれた方,ぜひ応募してみてください!


Adding indexes to tables of Apache James 3


Posted on Sunday Nov 15, 2015 at 05:06PM in Technology


I’m using Apache James (3.0-beta5-SNAPSHOT) as the mail server for my domain. It’s running with JPA backend on PostgreSQL.

Today I’ve found that some slow queries are logged as the number of emails has been grown through the days. The slowest two are following:

  • SELECT t0.property_id, t0.property_line_number, t0.property_local_name, t0.property_name_space, t0.property_value FROM public.JAMES_MAIL_PROPERTY t0 WHERE t0.mailbox_id = $1 AND t0.mail_uid = $2 ORDER BY t0.property_line_number ASC

  • SELECT t0.userflag_id, t0.userflag_name FROM public.JAMES_MAIL_USERFLAG t0 WHERE t0.mailbox_id = $1 AND t0.mail_uid = $2 ORDER BY t0.userflag_id ASC

These queries are used sequential scan. It’s terrible for thousands of rows so I’ve created a couple of indexes to avoid sequential scan as follows:

  • create index on james_mail_property (mailbox_id, mail_uid);

  • create index on james_mail_userflag (mailbox_id, mail_uid);

They seems work expectedly as I’ve confirmed that now these queries are using index scan instead.


Notes about using UPSERT on RDBMS


Posted on Saturday Nov 07, 2015 at 12:15PM in Technology


Recently I’ve investigated some ways to implement UPSERT which gets the following job done without problems of race conditions:

  • INSERT a row if there’s no duplicate one with same ID

  • UPDATE a row otherwise

Also another slightly differ requirement:

  • INSERT a row if there’s no duplicate one with same ID

  • Do nothing otherwise

  • Application needs to know whether the query has inserted a row because one is not exist

The above two requirements are needed to implement an application that works with an Amazon SQS which is configured as the destination of Amazon SES notification.

Table to use for experimentation

CREATE TABLE mytable (id INTEGER PRIMARY KEY, cnt INTEGER);

Solution for MySQL (5.6.x)

There’s an easy solution that uses a MySQL specific clause INSERT INTO …​ ON DUPLICATE KEY UPDATE …​. For detail check http://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html

With the mytable, I’ve done some experimentation (on MySQL 5.6.27) as follows:

  1. Launch two instances of mysql

  2. Execute begin; on both so let a transaction begin for each instances

  3. Execute INSERT INTO mytable (id, cnt) VALUES (1, 1) ON DUPLICATE KEY UPDATE cnt=cnt+1; on both. Note that the following execution will be blocked due to the preceding transaction is about to insert a row which has same ID

  4. Execute commit; on the instance which executes the statement first

  5. Execute commit; on the another instance which has been blocked

Then execute select * from mytable; you will see the desired result:

+----+------+
| id | cnt  |
+----+------+
|  1 |    2 |
+----+------+
1 row in set (0.00 sec)

If you don’t want to update any values if duplicated one already exists, Use following SQL instead:

INSERT INTO mytable (id, cnt) VALUES (1, 1) ON DUPLICATE KEY UPDATE id=id;

Also note that if you’re using JDBC to communicate with MySQL, You need to add useAffectedRows=true parameter to the JDBC URL so that executeUpdate() method will return the number of affected rows instead of found rows. For detail check https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html

Another solution

I found an interesting attempt that seems to work with generic SQL:

And I’ve confirmed it works as I expected. I’ve done the following experiment on MySQL 5.6.x:

  1. Launch two instances of mysql

  2. Execute begin; on both so let a transaction begin for each instances

  3. Execute INSERT INTO mytable (id, cnt) SELECT 1, 0 FROM (select 0 as i) mutex LEFT JOIN mytable ON id = 1 WHERE i = 0 AND id IS NULL;. Note that the following execution will be blocked as well

  4. Execute UPDATE mytable SET cnt = cnt + 1 WHERE id = 1; on the instance which executes the statement first, if incrementation is needed

  5. Execute commit; on the instance which executes the statement first

  6. Execute UPDATE mytable SET cnt = cnt + 1 WHERE id = 1; on the instance which executes the statement second as well

  7. Execute commit; on the another instance

Note that I’ve tried the experimentation for PostgreSQL 9.3.4 as well but doesn’t work. It blocks the following query but produces ERROR: duplicate key value violates unique constraint "mytable_pkey" after issuing commit of the preceding transaction.

I have no idea why it doesn’t work for PostgreSQL (To be honest, I don’t exactly know why it does work for MySQL). If you know why, Let me know via posting a comment to this entry that would be greatly appreciated.

UPSERT functionality will be in the PostgreSQL 9.5 release (citation from https://wiki.postgresql.org/wiki/SQL_MERGE).