Home > Seasar

Seasar Archive

Seasar Conference 2008 Autumn


9月6日(土)にSeasar Conference 2008 Autumnが開催されます。まだ一般募集は始まってませんがサイトは立ちあがっています。サイトデザインは前回に続いてsugaさんの手によるものです。2匹のシーサーがお行儀よくお月様を眺める後ろ姿が可愛らしくてGood!です。左右の花瓶にも向きの違う尻尾マークが入ってたりしてほんと上手いです。いつもデザインありがとうございます。

今回は、スピーカーをSeasarのコミッタに限らず一般募集していますので、他のオープンソースコミュニティ、開発者コミュニティなどの「話したくてうずうずしている皆さん」、スピーカーとして是非ご参加ください。応募方法は、イベントサイトに詳細書いてありますのでどうぞご確認ください。

また、一般来場参加はセッションが決まってからの募集になりますので、もうしばらくお待ちください。

OpenLDAPのスキーマをOpenDSに追加する時の7つのポイント


OpenDSはSunが中心にオープンソースで開発しているJavaで書かれたディレクトリサーバです。詳細についてはOpenDSのサイトを見てもらえば判りますが、個人的に興味を引かれた特徴は次の点です。

  • Javaで書かれているので組み込みで動かせる
    • テストも兼ねて実際にコード書いてみましたが良い感じ
    • Java 5以上必要
  • マルチマスタ構成が可能
    • もちろんschmeaやconfig系も込みで
  • 将来的にSun Java System Directory Server Enterprise Editionの中身はOpenDSになるらしい

さて、では実際に使おうとするといろいろスキーマを追加したくなります。早速、広く使われているOpenLDAP用のスキーマを追加しようとしたところいくつか変更する必要がありました。

先に良く使うスキーマの変更済みスキーマを提示しておきます。動作確認はちょっとバージョンが古いですが、Mavenで手に入るOpenDS 1.0.0 build 005でしました。

これらを作るにあたって判ったスキーマファイルの変更ポイントは次の7つです。

  • 1. スキーマファイルは $OPENDS_HOME/config/schema 以下に XX-hoge.ldif というファイル名で配置

XXの部分には任意の数字を入れます。数字が若い順に読み込まれるので標準で入っているスキーマより大きい数字を指定します。上で挙げたスキーマでは、適当に10としています。

  • 2. 定義を開始する部分に次を追加
dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema

ファイルの先頭のコメント部分はそのままで構いません。

  • 3. attributetype ( … ) を attributeTypes: ( … ) に置換

変更前: openssh-lpk.schemaより

attributetype ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey'
        DESC 'MANDATORY: OpenSSH Public key'
        EQUALITY octetStringMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

変更後: openssh-lpk.schemaより

attributeTypes: ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey'
        DESC 'MANDATORY: OpenSSH Public key'
        EQUALITY octetStringMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
  • 4. objectclass ( … ) を objectClasses: ( … ) に置換

変更前: openssh-lpk.schemaより

objectclass ( 1.3.6.1.4.1.22054.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
        DESC 'MANDATORY: OpenSSH LPK objectclass'
        MUST ( sshPublicKey $ uid )
        )

変更後: openssh-lpk.schemaより

objectClasses: ( 1.3.6.1.4.1.22054.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
        DESC 'MANDATORY: OpenSSH LPK objectclass'
        MUST ( sshPublicKey $ uid )
        )
  • 5. attributeTypes ( … ) の ) 前には必ずスペースが1つ必要

NG: qmail-ldap.schemaより

attributeTypes: ( 1.3.6.1.4.1.7914.1.2.1.6 NAME 'mailHost'
        ... 省略 ...
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE)

OK: qmail-ldap.schemaより

attributeTypes: ( 1.3.6.1.4.1.7914.1.2.1.6 NAME 'mailHost'
        ... 省略 ...
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )

objectClassesはスペースが無くても大丈夫です。

  • 6. 定義途中で改行した場合、先頭にスペースを2つ以上入れてから続きを記述する

NG: openssh-lpk.schemaより

attributetype ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey'
 DESC 'MANDATORY: OpenSSH Public key'
 EQUALITY octetStringMatch
 SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

OK: openssh-lpk.schemaより

attributetype ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey'
  DESC 'MANDATORY: OpenSSH Public key'
  EQUALITY octetStringMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

TabもNGです。

  • 7. 定義と定義の間に空行を作ってはいけない、コメントアウト行を入れるのはOK

NG: openssh-lpk.schemaより

dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema

# octetString SYNTAX
attributeTypes: ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey'
  DESC 'MANDATORY: OpenSSH Public key'
  EQUALITY octetStringMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

# printableString SYNTAX yes|no
objectClasses: ( 1.3.6.1.4.1.22054.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
  DESC 'MANDATORY: OpenSSH LPK objectclass'
  MUST ( sshPublicKey $ uid )
  )

OK: openssh-lpk.schemaより

dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema
# octetString SYNTAX
attributeTypes: ( 1.3.6.1.4.1.22054.500.1.1.1.13 NAME 'sshPublicKey'
  DESC 'MANDATORY: OpenSSH Public key'
  EQUALITY octetStringMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
# printableString SYNTAX yes|no
objectClasses: ( 1.3.6.1.4.1.22054.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
  DESC 'MANDATORY: OpenSSH LPK objectclass'
  MUST ( sshPublicKey $ uid )
  )

以上の7つに注意すればOpenLDAPのスキーマをOpenDSでも使うことができます。OpenLDAPとOpenDSの標準で提供されているスキーマのいくつかは、オブジェクトクラスの構造クラスと補助クラス定義が異なるのがありますが、基本的にはほぼ同じようなのでそれほど戸惑うこともないと思います。

そして最後に、S2Directoryで問題無くOpenDSのエントリを扱えることも確認済みです。

[18:50追記] S2DirectoryでSMD5, SSHAを使用してパスワードを保存した時に保存したパスワードでOpenDSのSASL認証が上手くいきませんでした。原因はsaltの長さがS2Directoryは4バイトを、OpenDSは8バイトを想定しているためでした。とりあえずDIRECTORY-25で対応して、S2Directory 0.7-SNAPSHOTをデプロイしときました。

Seasar Conference 2008 Spring 終わり


講演者の皆様、スタッフの皆様、お疲れ様でした。今回も無事終えました。当日資料は順次掲載していきます。

また、事後アンケート へのご協力よろしくお願いします。

それにしてもITProの仕事速いな。もう記事になってる。【Seasar Conference】「世界への普及目指す」—ひがやすを氏が新フレームワーク「Slim」を発表:ITpro

場所の名前が入ってると報告しやすいんだけどまぁいいや。

JIRAのライセンス更新


気付いたら今年も更新の時期でした。メールで特にお知らせは来てなかったのでログインしてみたら、WEBから数クリックで更新できました。Atlassianありがとー。

次回の期限は2009/05/27です。

Seasar Conference 2008 Spring


ちょうど1ヵ月後の5/24(土)にSeasar Conference 2008 Springが開催されます。

Seasarプロジェクトの従来の技術から始まり、ちょっと違った視点のプロダクト、現時点の最新事情、そして、近未来にむけてのロードマップをこのイベントで見ることが出来ます。

Seasarに関して興味をお持ちの方、ぜひご参加ください。

app02/03の作り直し案: 落ちてもリモートですぐに復旧できる仕組み


明日は無理だけど近日中にこうしようかと思っている案。

落ちてもリモートですぐに復旧できる仕組み

落ちてもリモートですぐに復旧できる仕組み

IPMIが使えない&RAIDカードが認識できないという制限を考慮してこんな感じ。

app03.seasar.org 障害発生中 3回目


帰ってきたらまた死んでた。もうダメなので、明日は朝から入れるので行ったら新サーバ最速で作ります。

  • [02/17 9:08] ML仮復旧済み
  • [02/17 9:45] JIRA別サーバ移行完了
    • SVNリポジトリのインデックスはそのうち反映されます
  • [02/17 12:18] RAIDカードが使えないのでLinux mdで代用、sync待ち中。2時間ぐらい。。。
  • [02/17 17:11] とりあえず見た目的には完了、ログ関係とかまだ移植し終えてないのがちょっとアリ
    • MLデータとかの移植に時間掛って全然最速じゃなかった
      • 次に一から作り直す時、冗長化されたストレージはやっぱ用意した方が良いかも
      • [02/17 18:45] 帰りの車の中で気付いた。DRBDで一応冗長化されるんだった。でも、Xenホスト部分がダメだからその部分だけLinux mdすれば良さそう。ちょうどHDD2に100GB空いてるし。RAIDカードが使えなくてちょっと無理やりに考えた構成だったけど、ものすごく良い案に思えてきた。

app03.seasar.org 障害発生中 2回目


現在app03.seasar.orgが接続出来なくなっています。このためこのサーバで動いてる下記のサービスが現在使えない状況になっています。

  • Wiki
  • ML
  • Tracking

前回同様、入試期間中なため復旧可能なのが、16日(土) 17:00以降になってしまいます。関係者の皆さん申し訳ありません。

http://www.seasar.org/ に障害のお知らせを書いておきました。

代替パーツの調達が来週になるため、しばらくご迷惑をお掛けするかもしれません。

またapp02と03に関して、この2サーバは特に重要な機能を持っているため、マシン丸ごと冗長構成を取ることを考えています。今でもメールなどはプライマリ・セカンダリという構成になってますが、落ちている間キューを受け取っているだけでサービス的にはマシンを物理的に起動し直さないと復活しません。

冗長構成用の新マシンとパーツは来週以降揃うため、早ければ2月中に移行させたいと思います。

いろいろ後手後手になってすいません。

MLが復旧したら検討している構成をサーバチームのMLに流します。

app03.seasar.org 障害発生中


現在app03.seasar.orgが接続出来なくなっています。このためこのサーバで動いてる下記のサービスが現在使えない状況になっています。障害の原因はまだ不明です。

  • Wiki
  • ML
  • Tracking

タイミングが悪いことに現在大学が入試期間中で復旧可能なのが、12日(火) 16:30以降になってしまいます。関係者の皆さん申し訳ありません。。

http://www.seasar.org/ に障害のお知らせを書いておきました。

[17:28追記] 16:33に復旧しました。ログには何も残ってなかったのでハード的に死んだっぽいです。

Cubbyの良いところ


先日Cubbyで作った2個目の簡単なアプリを予定通り動かし始めました。今のとこ大きなトラブルもないようです。というわけで、Cubbyの良いところを書きたいと思います。ちなみにほとんど同じことがSAStrutsにも言えます。

  • Examplesが実用的で簡単

Cubbyに興味を持ったらとりあえずサンプルwarを動かし、Todoサンプルアプリケーションを見てみてください。一覧表示・詳細・追加・編集・確認・保存に加えて、ログインとログイン状態確認(AuthActionInterceptor)もついています。そして、それぞれの機能に対応するTodoListAction、TodoAction、LoginActionを見ると、とてもコードが少なく、これならすぐに似たようなアプリが作れる気がします(実際すぐに作れました)。

さらにコードを良くみると、フォーム=アクション自身になっています。これは僕の中でかなり革新的でした。今までフォーム用にPOJO(Entityを継承したりして)を用意してたけど、結局僕のように小さなアプリしか作らない場合、POJOを使いまわすなんてことは無く、それだったらアクション自身にあった方が見通しが全然良いんです。なお、別に分けたい場合は@Formで別途指定できるので、フォーム=アクション自身に絶対する必要があるというわけでもありません。

他にもCubbyのExampleは小さなテクニックがいろいろ散りばめられています。例えば、エラー時の画面装飾。effects.jsでちょっと目に付いて親切な装飾がされています。もちろんこれはCubbyでしかできないことではないですがこういったちょっと「良いな」っと思えるサンプルがいろいろあります。そんなわけでますますCubbyを使ってみたいと思ってしまうわけです。

また、今のExampleの例では、S2DxoとS2Daoを使っていますがここをBeansとS2JDBCにしたって問題ありません。僕はそうしています。

  • URIが綺麗

やはりURIは、名は体を表す如く美しくあるべきだと思います。以前、無設定S2Struts用にSplitUpperActionPathNamingRuleというのを取り入れていただきましたが、それでも自由自在というところまではいきませんでした。Cubbyでは@Pathにより、URIの一部分をリクエストパラメータにするなど思い通りにURIを表現できます。この仕組みは、RequestRoutingFilterというフィルタにより、実体のアクションクラスへフォワードすることで実現されています。この仕組みも最初見たときそんな手があったかーっと驚きました。

また、通常認証確認処理はURI単位で設定したいので今まではオリジナルのフィルタで書いていました。StrutsなどでInterceptorを使ってやろうとすると、アクションに引っ掛けることになるので、.jspなどのページに直接アクセスされると認証処理が掛けられないので困ってしまいます。でも、Cubbyを使ったアプリでユーザがアクセスするのはすべて綺麗なURIにすることができ、実体のページにアクセスさせないようにしやすいです。なのでExampleのAuthActionInterceptorのようにInterceptorでも抜けのない認証確認が出来ます。ちなみにこのInterceptorはcustomizer.diconでLoginAction以外のアクションに適用するように設定されています。サンプルのAuthActionInterceptorをちょっと拡張すれば、URIごとにアクセス権限を分けるといったことも簡単に実現できます。

public Object invoke(MethodInvocation invocation) throws Throwable {
    // 実行しようとしているアクションを取得
    final Action action = (Action)invocation.getThis();
    // リクエストされたURLを取得
    final String url =
        (String)request.getAttribute("javax.servlet.forward.servlet_path");

    // 非ログインページ
    if (url.startsWith("/index")) {
        return invocation.proceed();
    }
    ...
    // ログインページ
    // ログイン状態の確認
    final PosixAccount user = (PosixAccount)sessionScope.get("user");
    if (user == null) {
        action.getFlash().put("notice", "ログインしていません。");
        return new Redirect("/login/");
    }
    ...
    // 各ページへのアクセス権限の確認
    Object group;
    // admin
    group = sessionScope.get("group_admin");
    if (url.startsWith("/admin/") && group == null) {
        return new Redirect("/");
    }
    ...
    return invocation.proceed();
}
  • @Pathによる制約

「URIが綺麗」に関係しますが、@Pathで指定する値には正規表現で制約を付けることができます。簡単な例だと次のとおりです。

public class TodoAction extends Action {
    public Integer id;
    @Path("{id,[0-9]+}")
    public ActionResult show() {
        Todo todo = todoDao.selectById(this.id);
        todoDxo.convert(todo, this);
        return new Forward("show.jsp");
    }
}

これだと、/todo/1 にアクセスすれば、idに1が自動的に入った状態でshow()が実行されます。/todo/aa の時はshow()は実行されません。この例はアクションメソッドに@Pathを付けていますが、クラス自身に@Pathを付けることもできます。

僕が使った複雑な例としては、こんな感じです。

@Path("admin/{thesisTypeName,abstract|full}/{userId}")
public class AdminThesisAction extends ThesisAction {
    ...
    @Validation(rules = "submitValidation", errorPage = "/admin/index.html")
    public ActionResult submit() {
        super.submit();
        return new Forward("/admin/submit.html");
    }
    ...
    public ActionResult download() {
        File file = new File(saveDir, thesis.getFileName());
        if (!file.exists()) {
            flash.put("notice", "ファイルが見つかりません: " + file.getName());
            return new Redirect("/admin/");
        }
        return super.download(file);
    }
}
public class ThesisAction extends DownloadAction {
    public String thesisTypeName;
    public String userId;
    ...
    public ActionResult submit() {
        if (thesis != null) {
            Beans.copy(thesis, this).excludesNull().execute();
        }
        return new Forward("submit.html");
    }
    ...
}
public class DownloadAction extends Action {
    public HttpServletResponse response;
    protected ActionResult download(File file) {
        ...
    }
}

この例だと、/admin/abstract/user001/submitや/admin/abstract/user099/downloadなどがAdminThesisActionですべて処理されます。extends ThesisActionとしているのは同じようなことをユーザごとや特定の権限を持った人も同じ機能を使いたかったからです。実際に@Path("student/{thesisTypeName,abstract|full}")を持つStudentThesisActionと@Path("faculty/{thesisTypeName,abstract|full}/{userId}")を持つFacultyThesisActionを作りました。権限ごとに項目が多少違うので、validationはそれぞれの権限に応じたものをそれぞれの実装クラスで定義しました。

  • Validationが柔軟

CubbyではValidationはValidationRuleをValidationRulesでひとまとめにして定義し、それぞれのアクションメソッドにそれぞれ適用できます。つまり、アクションメソッドごとに違うValidationを適用できます。アクションのコードが少ないのはここでも役に立ちます。ExampleのLoginActionを見れば判りますが、アクション内にオリジナルのValidationRuleがあります。ここでも僕のように小さなアプリで使いまわすことがないなら同じアクション内の方が見通しが良いです。しかも同じアクション内にあることでアクションにあるパラメータもそのまま使えます。

@Binding(bindingType = BindingType.NONE)
public ValidationRules confirmValidation = new DefaultValidationRules() {
    @Override
    public void initialize() {
        add("token", new TokenValidator());
        add("enTitle", new RequiredValidator());
        add("enTitle", new RegexpValidator("\\p{ASCII}+"));
        add("jaTitle", new RequiredValidator());
        add("pageSize", new RequiredValidator());
        add("file", new RequiredValidator());
        add("file", new FileRegexpValidator(".+\\.pdf"));
    }
};

Cubbyが提供するカスタムタグは親切な設計になっています。特にお気に入りなのが、tokenです。ページのform内に <t:token /> と書いて、ValidatgionRulesに add("token", new TokenValidator()); するだけで、2重サブミット・CSRF対策が出来てしまいます。また、カスタムファンクションのoddもテーブルなどで色分けが簡単に出来るようになっていて親切です。

  • プレゼンテーションがJSPである = Mayaaが使える

個人的にフレームワークを選ぶ基準の一つにMayaaが使えるかどうかというのがあります。Mayaaは「プログラマとデザイナの作業分担を強く意識したWEBフロントサービスエンジン」という説明がありますが、一人で作る場合でも有効です。主な理由は2つです。1つ目はそのページの機能が一目瞭然になること。2つ目はコンポーネントによる機能分割が可能なことです。

1つ目は、僕の記憶力が良くないことに関係します。たいてい1日経たずしてそのページが何の機能を持ってたか綺麗に忘れます。そんな時、まず.mayaaを見ます。.mayaaにはそのページで実現される「機能」しか書かれていません。それもたいていたいした量はありません。そんなわけで、一目瞭然にそのページの機能が判ります。そして機能を把握したら、頭をデザイナモードにして.htmlを編集するか、プログラマモードにしてアクションを編集します。記憶力が良い方でもおそらく1年も経てばすっかり忘れてしまうと思います。そんな時、.mayaaはきっと役に立つはずです。

2つ目は、1つ目にも関係しますが、まとまった機能・使いまわす機能はコンポーネントにして、<m:insert>を使えば、複雑なページでも.mayaaが簡潔になります。簡潔になれば、1つ目のように機能を確認する時にすぐに把握できます。先程の@Pathのとこで出てきた複雑な例は、ThesisActionを継承したクラスが3つありました。フォームの項目に1つか2つの違いはありますが基本的に同じです。そんなわけでそれらに対応したフォーム部分は共通のコンポーネントに切り出してしまいます。

他にも、m:extendsでページデザインを楽に出来たり、やろうと思えば.mayaa単体でアクション相当のことが出来てしまうなどMayaaは超強力です。そんなわけで、フレームワークを選択する時、僕はMayaaが使えるかどうかは重要な判断基準になります。

  • 何はともかくS2ContainerのHOT deploy, publicフィールド, Beans, S2JDBCなどなど

CubbyとMayaaの良いところを書きましたが、忘れちゃいけないのがS2Containerです。アクションのコードを小さく書けるのは、Cubbyだけでなく、S2Containerの多くの機能があるおかげです。S2ContainerというとDI・AOPと想像される方もいるかもしれませんが、S2Containerのすごいとこは、DI・AOPと同じかそれ以上にその周辺の様々な強力な機能群があることだと思います。Cubbyの内部でもリクエストパラメータを処理するのにS2Dxoが使われていたり、CubbyやSAStruts利用者がアクションメソッドを小さく書くのに、publicフィールド, Beans, S2JDBCは必須機能です。これらはきちんと型を理解して処理してくれるのも大きな魅力です。また、サクサク開発するのにHOT deployは欠かせません。

というわけで、長々書きましたが、今現在僕には、Cubby + S2ContainerのHot deploy, publicフィールド, Beans, S2JDBC + Mayaaがちょうど良いのです。

他にも書いてない良いとこもあると思いますがとりあえずこんな感じです。Cubbyの代わりにほぼ同様のことのできるSAStrutsを選択するのも良いと思います。CubbyとSAStruts、まだ触ってない方は是非触ってみてください。

ホーム > Seasar

検索
フィード
メタ情報

Return to page top