BPMN 2.0

BPMN といえばビジネスプロセスの記法であるが、それ自身が直ちに実行可能な形式ではない。BPM ベンダーの製品では BPMN で記述されたプロセスモデルを実行可能なものはあるが、それは内部的に BPEL 等に変換していたり、そのた独自の方法によって実行していたりする。BPMN と BPEL の相互変換についてはある程度のパターンは示されているものの、すべての表現が完全にマッピングできるわけでもなく、また変換したものを逆変換して同じものが得られるとも限らない。

そんな中、「BPMN で実行可能なプロセスモデル設計をできるようにしよう」というのが BPMN 2.0 のひとつ大きなモチベーションであったと思う。ほんまにそんなことできるんやろか、ということでちょっと BPMN 2.0 仕様を読み解いていく。現時点で最新のものは 2009 年 8 月にリリースされた beta 1 である。

ひさしぶり

最近全然はてなダイアリー使ってないや。気分転換にタイトルとテーマを変えてみた。またすぐに変えてしまうかもしれません。

ふと思い立ったので、ゆるゆると再開していきます。お仕事の関係などもありますので、これからしばらく BPM (Business Process Management) 関連の情報をまとめていくつもりです。ちょっと技術寄りになると思いますが。

[Linux][Apache] SELinux 上での mod_proxy_ajp

SELinux の有効になっているサーバ上で Apache 2.2 + Tomcat 6 の連携をやろうとしてちょっとはまった。

普通に proxy_ajp.conf を設定したのだが、

LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
ProxyPass /webapp/ ajp://127.0.0.1:8009/webapp/


error_log に以下のようなエラーがでて接続できない。

[error] (13)Permission denied: proxy: AJP: attempt to connect to 127.0.0.1:8009 (127.0.0.1) failed
[error] ap_proxy_connect_backend disabling worker for (127.0.0.1)
[error] proxy: AJP: failed to make connection to backend: 127.0.0.1
[error] proxy: AJP: disabled connection for (127.0.0.1)


/var/log/messages を見てみると、以下のエラーが出ていた(*** は実際には16進らしき数字)。

setroubleshoot: SELinux is preventing the http daemon from connecting to network port 8009 For complete SELinux messages. run sealert -l ********-****-****-****-************


で、messages に記載されている sealert コマンドを実行すると、以下の出力を得た。

Summary:

SELinux is preventing the http daemon from connecting to network port 8009

Detailed Description:

SELinux has denied the http daemon from connecting to 8009. An httpd script is
trying to do a network connect to a remote port. If you did not setup httpd to
network connections, this could signal a intrusion attempt.

Allowing Access:

If you want httpd to connect to network ports you need to turn on the
httpd_can_network_network_connect boolean: "setsebool -P
httpd_can_network_connect=1"

The following command will allow this access:

setsebool -P httpd_can_network_connect=1

Additional Information:

Source Context                user_u:system_r:httpd_t
Target Context                system_u:object_r:port_t
Target Objects                None [ tcp_socket ]
Source                        httpd
Source Path                   /usr/sbin/httpd
Port                          8009
Host                          *******.********.**.**
Source RPM Packages           httpd-2.2.3-22.el5
Target RPM Packages           
Policy RPM                    selinux-policy-2.4.6-203.el5
Selinux Enabled               True
Policy Type                   targeted
MLS Enabled                   True
Enforcing Mode                Enforcing
Plugin Name                   httpd_can_network_connect
Host Name                     *******.********.**.**
Platform                      Linux *******.********.**.**
                              2.6.18-128.1.1.el5xen #1 SMP Mon Jan 26 14:19:09
                              EST 2009 x86_64 x86_64
Alert Count                   6
First Seen                    Thu Apr 16 11:43:17 2009
Last Seen                     Thu Apr 16 11:55:37 2009
Local ID                      ********-****-****-****-************
....


どうも SELinuxhttpd_can_network_connect という設定で、httpd プロセスからのネットワーク接続を制限しているらしい。setsebool コマンドで設定を変更できるとかいてあるので、その通りやってみたら問題が解決した。getsebool コマンドで設定値を確認できる。

# getsebool httpd_can_network_connect
httpd_can_network_connect --> off
# setsebool -P httpd_can_network_connect 1
# getsebool httpd_can_network_connect
httpd_can_network_connect --> on


しかし、SELinux ってどれだけ普及してるんやろうね。難解すぎて結局あまり普及してない気がする。

[Spring] TestContext Framework で WebApplicationContext を使う

Direct Web Remoting (DWR) を Spring 統合含めて導入したら、これが WebApplicationContext でしか利用できないスコープを利用しているみたいで、ユニットテストで ApplicationContext の生成ができなくなってしまった。

この問題は認識されているようで JIRA に要求が上がっているのだが、対応されるのは Spring 3.0 ということで、いつになることやら。そこで、このチケットのコメントにも記載されている方法を参考に、現状の Spring 2.5 の TestContext Framework で WebApplicationContext を利用できるようにしてみた。

TestContext Framework では、@ContextConfiguration アノテーションで ApplicationContextLoader を指定できるので、まず WebApplicationContext を生成する独自の ApplicationContextLoader を作成する。

public class XmlWebApplicationContextLoader extends AbstractContextLoader {

    /** ロガー */
    private static final Logger log = LoggerFactory.getLogger(XmlWebApplicationContextLoader.class);

    @Override
    protected String getResourceSuffix() {
        return "-context.xml";
    }

    @Override
    public final ConfigurableApplicationContext loadContext(String... locations)
            throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Loading ApplicationContext for locations ["
                    + StringUtils.arrayToCommaDelimitedString(locations) + "].");
        }
        
        GenericWebApplicationContext context = new GenericWebApplicationContext();
        context.setServletContext(new MockServletContext());
        prepareContext(context);
        customizeBeanFactory(context.getDefaultListableBeanFactory());
        createBeanDefinitionReader(context).loadBeanDefinitions(locations);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
        customizeContext(context);
        context.refresh();
        context.registerShutdownHook();
        
        return context;
    }

    /**
     * prepareContext
     * @param context
     */
    protected void prepareContext(GenericApplicationContext context) {}

    /**
     * costomizeBeanFactory
     * @param beanFactory
     */
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {}

    /**
     * createBeanDefinitionReader
     * @param context
     * @return BeanDefinitionReader
     */
    protected BeanDefinitionReader createBeanDefinitionReader(
                                                              final GenericApplicationContext context) {
        return new XmlBeanDefinitionReader(context);
    }

    /**
     * customizeContext
     * @param context
     */
    protected void customizeContext(GenericApplicationContext context) {}
    
}

ApplicationContext として GenericWebApplicationContext を利用し、そこに MockServletContext をインジェクトしている。それ以外は XmlWebApplicationContextLoader と同じ。

あとはテストの基底クラスで、この ApplicationContextLoader を使うように設定するだけ。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/applicationContext.xml"}, loader = XmlWebApplicationContextLoader.class)
public abstract class AbstractTestCase {
  ....

データベースを使っているなら、さらにトランザクション関係の設定もアノテーションで記述しておく。

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/applicationContext.xml"}, loader = XmlWebApplicationContextLoader.class)
public abstract class AbstractTransactionalTestCase {
  ....

これで、無事ユニットテストが動作するようになった(WebApplicationContext 固有のスコープがちゃんと機能しているかは確認していないが)。

SLF4J + Logback への完全移行

以前SLF4J に依存したライブラリの追加により SLF4J を導入したが、今回そこからさらに進めて完全に SLF4J + LogBack に移行し、Commons Logging と Log4J への依存を完全になくした。

以前の対応では、以下の2つの構成が混在していた。

  • Commons Logging - Log4J
  • SLF4J(slf4j-api.jar) - (slf4j-log4j12) - Log4J


ここからまず Commons Logging 実装を排除したいが、当然 Commons Logging API を利用しているライブラリは残っているので、Commons Logging API から SLF4J に変換するライブラリ(jcl-over-slf4j.jar)を導入する。これを導入するには commons-logging.jar は削除しなければいけない。maven を使っていると依存ライブラリとして勝手に読み込まれてしまうので、以下のように明示的に除外する必要がある。

		
			commons-httpclient
			commons-httpclient
			3.1
			
				
					commons-logging
					commons-logging
				
			
		

次にログ実装の置き換え。LogBack本体 (logback-core.jar) と LogBack 用のブリッジ (logback-classic.jar) を導入し、前回導入した Log4J ブリッジは削除した。maven なら、logback-classic だけ追加すれば勝手に logback-core も読み込まれる。

あとは Logback の設定ファイル(logback.xml)の準備。Log4J からの移行であれば、ウェブ上で設定ファイルの変換ができる。いたれりつくせりだ。

これで完全に移行ができ、以下の構成になった。


なお、SLF4J には紛らわしい名前のライブラリがあるので注意が必要だ。

  • jcl-over-slf4j.jar Commons Logging API を用いて SLF4J を利用するためのもの
  • slf4j-jcl.jar SLF4J から呼び出されるログ実装として、処理をさらに Commons Logging に移譲するもの


Log4J にも同じようなものがある。

  • log4j-over-slf4j.jar Log4J API を用いて SLF4J を利用するためもの
  • slf4j-log4j12.jar SLF4J から呼び出されるログ実装として Log4J を利用するためのもの

[freemarker] Map のデータでループを回す

Freemarker で Map のデータの一覧を表示させようとしたのだが、Java で EntrySet を利用するような感じで実現する方法はわからなかった。

Java なら以下のようなコードを書くのだが。

  for( Map.Entry entry : map.entrySet ) {
    System.out.println(entry.key() + " = " + entry.value());
  }

で、結局どうしたかというと、キーのリストでループを回せば実現できた。?keys を利用することで Map のキー集合を取得することができる。ちなみに ?values で値集合も取得できる。

<#assign map = {"aaa":"111", "ccc":"333", "bbb":"222"}>
<#list map?keys as key>
 ${key} = ${map[key]}
</#list>
 aaa = 111
 ccc = 333
 bbb = 222

Java で書くとこんな感じ。こっちの方がシンプルだった・・・

  for( Object key : map.keySet() ) {
    System.out.println(key + " = " + map.get(key));
  }

あと freemarker では ?sort によってコレクションをソートできることを知った。

<#assign map = {"aaa":"111", "ccc":"333", "bbb":"222"}>
<#list map?keys?sort as key>
 ${key} = ${map[key]}
</#list>
 aaa = 111
 bbb = 222
 ccc = 333

なんてことはないが、今日は ?keys ?values ?sort を覚えた。

Mac 版 Firefox の Flash Player で日本語入力できるようになった!

以前から、MacFirefoxFlash Player で日本語入力ができないという問題があった。

Mac版Firefox 3正式版に、日本人ユーザにとって結構致命的な問題が残ってしまいそうな件について

私の環境ではなぜか日本語どころか半角英数も入力できなくて、まったく使い物にならなかった(ATOK を使っていることが関係しているんだろうか?)。3.0.2 や 3.0.3 で直ったという情報も見かけるんだけど、私の 3.0.5 ではいまだに入力できない。

3.0.2 のリリースノートにも以下の記述があるんだけど。

以下の Mac 固有の問題が修正されました。
* 日本語、韓国語、中国語、インド語の文字を Flash オブジェクト上のテキスト欄に (IME を使って) 入力できない (bug 357670)

http://mozilla.jp/firefox/3.0.2/releasenotes/

で、3.1 では直っているといいなあと思って 3.1 beta 2 を試したところ、ちゃんと入力できるようになっていた。すばらしい!

対応してくれた開発者に感謝。正式リリースが待ち遠しいです。