Challenge Engineer Life !

エンジニア人生を楽しみたい!仕事や趣味で学んだ技術的なことを書いていくブログです。

Integrating PrimeFaces Terminal sample with Twitter4J.

I'm glad Mr.Cagatay Civici who is lead of PrimeFaces picked up my blog entry yesterday.

But it's just only Japanese. So, I try to rewrite the entry in English.

What is Terminal of PrimeFaces ?

Terminal component is similar to Unix/Linux terminal.
Here is showcase link of Terminal component.
http://www.primefaces.org/showcase/ui/terminal.jsf

You can input two command in the PrimeFaces showcase sample.

  • greet
  • date

If you input 'greet' command, then terminal responses 'Hello Stranger'.
If you add your name after greet command, for example 'greet kikutaro', then terminal responses 'Hello kikutaro'.
Finally, you input 'date' command, then it returns now date.

f:id:kikutaro777:20130805230220j:plain

Make Twitter4sh

I thought what is good usage of PrimeFaces terminal.
Finally I tried to make collaboration between PF terminal and Twitter4j.

Twitter4j is great library for tweet by using Java.
Here is a English site link of Twitter4j.
http://twitter4j.org/en/index.html

I named this collaboration sample 'Twitter4sh' :)

My code is very simple, if you are interested in this, please enhance!

Twitter4sh has only two command.

  • user : command for user information
  • tweet : command for tweet

That's all.

User command has '-i' option and target.

  • user -i name : show Twitter account name
  • user -i follow : show total count of follow
  • user -i follower : show total count of follower

Environment

I made on this environment.

OS :Windows 7 Professional
Java version :JDK 7
IDE :NetBeans 7.3
Framework :Java EE 6
Application Server :GlassFish 3.1.2
Library:Twitter4j,PrimeFaces 3.5

Result

I inputed each command.
f:id:kikutaro777:20130806201417j:plain

Check my tweet.

Success!

Code

Creating view is very easy.
Only set terminal component of PrimeFaces.

I set 'prompt' attribute, it means head of prompt message in each line.
Also set 'welcomeMessage' attribute, it's first message of showing the page.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h:form>
            <p:terminal commandHandler="#{terminalBean.handleCommand}" 
                        prompt="Twitter4sh"
                        welcomeMessage="Welcome to Twitter4sh!"/>
        </h:form>
    </h:body>
</html>

JSF Managed Bean is here.

package com.mycompany.primefacesterminal;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;

@ManagedBean
@ViewScoped
public class TerminalBean implements Serializable{
    private Twitter twitter;
    
    @PostConstruct
    public void init(){
        twitter = new TwitterFactory().getInstance();
    }

    public String handleCommand(String command, String[] params) {
        try {
            if(command == null){
                return "Please input twitter4sh command";
            }else switch(command){
                case "user":
                    User user = twitter.verifyCredentials();
                    
                    if(params.length == 2){
                        if(params[0].equals("-i")){
                            switch(params[1]){
                                case "name":
                                    return user.getName();
                                case "follow":
                                    return Integer.toString(user.getFriendsCount());
                                case "follower":
                                    return Integer.toString(user.getFollowersCount());
                            }
                        }else{
                            return "You only use -i option.";
                        }
                    }else{
                        return "Usage:user -i name/follow/follower";
                    }
                    
                case "tweet":
                    if(params.length > 0){
                        String myTweet = "";
                        for(int i = 0; i < params.length; i++){
                            myTweet = (i==0) ? myTweet + params[i] : myTweet + " " + params[i];
                        }
                        twitter.updateStatus(myTweet);
                        return "Your tweet'" + myTweet + "'" + "is success.";
                    }else{
                        return "Usage:tweet 'message'.";
                    }
                default:      
                    return "There are only two command user or tweet.";
            }
        } catch (TwitterException ex) {
            return "Error" + ex.getErrorMessage();
        }
    }
}

This is useful for tweeting by command line!
I can make this code in 10 minutes, thanks to PrimeFaces and Twitter4j :)

PrimeFacesのTerminalとTwitter4jをコラボしてみる

August 6 2013 EDIT
I rewrite this entry in English.

Integrating PrimeFaces Terminal sample with Twitter4j.
http://kikutaro777.hatenablog.com/entry/2013/08/06/202431

仕事でしばらくC#(しかも2.0のまま…VS2005…VSS…ぬぅ…)に戻るのでネタがないです(-_-;

そんなわけで、昨日TwitterでPrimeFacesのTerminalを利用されている方がいらっしゃったので、自分も使ってみたくなって遊んでみました(^^;

Terminalコンポとは?

TerminalはいわゆるUnixLinuxのターミナルを模したWebコンポです。
以下ショーケースで動くものがあります。
http://www.primefaces.org/showcase/ui/terminal.jsf

上記のショーケースでは、コードをみるとわかりますが以下のコマンドを打てます。

  • greet
  • date

greetは引数もとれて名前を入れると挨拶してくれます。以下試した画像。

f:id:kikutaro777:20130805230220j:plain

Twitter4shを作ってみる

普通にコマンド作ってもなぁ…と思って、少し前に遊んでいたTwitter4jを思い出し、Terminalとコラボしてみました(^^;

名付けてTwitter4sh

なんちゃって…完全に遊びレベルです。すみません。

コマンドは

  • user :ユーザ情報に関するコマンド
  • tweet:ツイートするコマンド

の2つ

userコマンドは「-i」で詳細情報を指定できて

  • user -i name  :ユーザ名を表示
  • user -i follow :フォロー数を表示
  • user -i follower:フォロワー数を表示

みたいな(^^;テキトーです。

実行結果

起動すると

f:id:kikutaro777:20130805230607j:plain

それぞれコマンド打つと

f:id:kikutaro777:20130805230742j:plain

で、Twitterみると

それっぽく動く(^^)/

コード

すごくしょぼいです。JSFのビューは以下だけ。Terminal置いただけですね;

promptが各行の先頭にでるプロンプトのしるしです。
welcomeMessageは起動時に表示される文言ですね。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h:form>
            <p:terminal commandHandler="#{terminalBean.handleCommand}" 
                        prompt="Twitter4sh"
                        welcomeMessage="Welcome to Twitter4sh!"/>
        </h:form>
    </h:body>
</html>

JSF管理対象は以下。ここはCDI管理対象で作るほうが今やベターですが手抜きしました;

package com.mycompany.primefacesterminal;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;

@ManagedBean
@ViewScoped
public class TerminalBean implements Serializable{
    
    private Twitter twitter;
    
    @PostConstruct
    public void init(){
        twitter = new TwitterFactory().getInstance();
    }

    public String handleCommand(String command, String[] params) {
        try {
            if(command == null){
                return "コマンド入力してください";
            }else switch(command){
                case "user":
                    User user = twitter.verifyCredentials();
                    
                    if(params.length == 2){
                        if(params[0].equals("-i")){
                            switch(params[1]){
                                case "name":
                                    return user.getName();
                                case "follow":
                                    return Integer.toString(user.getFriendsCount());
                                case "follower":
                                    return Integer.toString(user.getFollowersCount());
                            }
                        }else{
                            return "詳細情報は「-i」で指定してください";
                        }
                    }else{
                        return "使い方:user -i name/follow/follower";
                    }
                    
                case "tweet":
                    if(params.length == 1){
                        twitter.updateStatus(params[0]);
                        return "「" + params[0] + "」" + "とツイートしました。";
                    }else{
                        return "使い方:tweet ツイート文言";
                    }
                default:      
                    return "userコマンドまたはtweetコマンドを入力してください";
            }
        } catch (TwitterException ex) {
            return "エラーです" + ex.getErrorMessage();
        }
    }
}

多分もっとシンプルで綺麗にかけると思いますが…(^^;

こんなサンプルが10分くらいで作れました。そう、Java EEJSFならね!

とか言ってみたり。

MacのGrowlみたいなメッセージコンポーネントを試してみる

HTML5を少し触ってみて、今後PrimeFacesとかRichFacesとかのリッチコンポーネントとの棲み分け・共存がどうなっていくんだろう?と気になる今日この頃(^^;

ただ業務系のWebシステムだと普通にIE7や8が指定されたりするので、HTML5を使う日が来るのか…とも思ったり。まあ仕事関係なく触ればいいんですが。

さて、今日はそんな業務系からのちょっとしたネタです。

PrimeFacesにはGrowlコンポーネントというものがあり、実際にシステムで利用したわけではないのですが、検討の1つになったので、将来的には何らか使うケースもあるのかなぁ、と。

……

業務系に限った話ではないですが、バリデーションによるエラーメッセージの表示などはお客さんが非常に気にされる点の1つかと思います。
メッセージの表示場所、表示タイミング、消えるタイミング、メッセージ内容……。

コンポーネントのそばに表示する

以下は例え話ですが、バリデーションエラーを以下のように出したりしたとします。

問題のテキストの横に出るからわかりやすいよね。と。

f:id:kikutaro777:20130729215032j:plain

ちなみに上記サンプルはPrimeFacesを使って

<h:panelGrid columns="2">
    <p:inputText id="txt" validatorMessage="必須です" />
    <p:message id="message" for="frm:txt" showDetail="true" />
</h:panelGrid>

と定義するだけです。

メッセージエリアを設けて表示する

でもテキスト入力にあまり関係ないような場合、メッセージ表示エリアみたいなのが望まれたりもあるんじゃないかと。

f:id:kikutaro777:20130729220030j:plain

PrimeFacesではメッセージ表示したい場所にmessagesコンポを置くだけ。

<p:messages id="messages" showDetail="false" />

あとはツールチップで出す、とかもあるかもしれませんが、大体の選択肢はこんな感じなのかなぁと。

でも画面によってはなんか縦が長いものもあったりして(画面内のスクロールとはなくて)、メッセージエリアが見えない、なんてことを言われるケースもあったりなかったり…。

以下はDataTableみたいなもので行が長いパターンですが、もうメッセージエリアとかみえない(^^;

f:id:kikutaro777:20130729215345j:plain

で、こんなときの手段の1つとして考えてもいいのかなと思ったのがGrowlです。

Growlによるメッセージ

私はあまりMacユーザではないのでわからないのですがMacにGrowlという通知システムがあって、それをPrimeFacesが模したコンポーネントです。

ASCII OS X必携ツール「Growl」の知って得する使い方
http://ascii.jp/elem/000/000/562/562062/

こいつを使うと画面に重ね合わせた感じでメッセージが表示されて

f:id:kikutaro777:20130729220221j:plain

スクロールで移動してもついてきます(sticky属性をtrueにしないと消えますが)。

f:id:kikutaro777:20130729220303j:plain

コンポーネントの配置は簡単でmessagesとほぼ同じ扱いです。

<p:growl id="growlMessage" showDetail="false" sticky="true"/>

formの中において、あとはボタンでupdateとかすれば表示されます。

便利で簡単に使えるコンポの1つかなぁと(^^)

とあるJava EE 6開発を終えて

はやいもので6月も終わりですね。

5月末時点で開発は終えていて、以降、試験チームによるテストが続けられています。

自動テストやCIの効果があったのか、直接の結びつきはわからないですが、Java EE担当範囲でバグは数件に収まる感じです(連携系は除いて)。

テスト部隊のテストが甘くて少ない、というよりは、やはり色々と自動化したことで無駄な時間が省かれて、実装メンバでのテスト時間を増やすことができたんじゃないかなぁと。なので、そのくらいに抑える自信もあったり(`・ω・´)キリッ

とはいえ、本当の始まりは運用が始まってからなので、これからが勝負なのですが。
それでも一旦、開発という大きなフェーズを終えて一安心しているところです(^^;ほっ

お上の鶴の一声で始まったJava EE開発ですが、終わってみれば自分にとって良い経験になりました。

今まで保守改造案件ばかりで、新しいことを学ぶ機会や自分がそれを駆動する立場になったことがなかったので(-_-;

そんなこんなで、感想をまとめてみます。

※なお、今回はJavaを使う前提という少し特殊な(個人では外しにくい)制約がありました。なので、Java EEが最高なんだぜ!という趣旨ではなく、本来であれば、現在世の中にある様々な技術から、各組織にあったベストなチョイスをするのが良い、と思っています(^^;

続きを読む

JMeterでJSFの負荷試験にチャレンジ

少し前に「JenkinsとJava EE6で取り組んだ初めてのCI」というエントリを書きましたが、図の負荷試験の所は「これから」となってます(^^;

本来は画面開発中でも負荷試験を交えながら作るべきなのだと思うのですが、自分自身、開発にかなり時間を割く必要もあって、そういう状況にできませんでした(-_-;言い訳に過ぎないのですが、CIの仕組み入れるのもやっとだった環境なんで…。

が、まだ時間はある!ということでGWを使ってJMeterを触ってみます。

ちなみに自分の負荷試験の記憶は

「みんなー集まってー。いくよー、いっせーのー、せっ」

だったり…(^^;マジです。

数年前で、WebじゃなくWindows Formでしたが…。
今のVisualStudioだとフォームの自動テストもずいぶん簡単にできるようなので、もうそんなことはしないはず。。そしてWeb開発ならばなおさら。。

JMeter関連の参考情報

JMeterに関しては詳しい情報が日本語でも揃ってますので、ここでの説明はJMeter+JSFに絞りたいと思います。
ちなみに参考にさせて頂いたサイトをまとめておきます。

本家のサイトです。User Manualなど、情報は豊富ですね。もちろん英語ですが(^^;

Web系の負荷試験=JMeter、というイメージしかなかったのですが、コマンドラインツール含めて色々あるんですね。
今回はJMeterを選びましたが、色々トライしてみたい!
なお、上記サイトはJMeterのインストール手順と設定手順も詳しいので参考になりました(^^)

先のサイトにもリンクがありますが、JMeterの詳しい使い方はこの資料を読むのが良さそうです。自分もこれから読んでいきます!※PDF直リンです。すいません。

最初のサイトにも紹介がありますが、JMeterって画面の操作記録を取って使うことができるんですね…(^^;実は知らなかったのです。このサイトを立ち上げた直後ぐらいに初めてJMeterを少し触ったのですが、それを知らなかったのでえらく苦戦しました。この機能を知ってる、知らない、で負荷テスト工数に大きく差がでそうです。

JSFJMeterで参考にさせて頂いたサイト。
JSFを使ったページの場合、ViewStateの関係で少し工夫がいるんですね。それを知らなかったので最初苦戦しました(^^;

最後に、上記サイト内からもリンクがありますが、JMeterJSFのviewStateを設定する方法に関してはApacheのMyFacesのこのページが参考になりました。

えーっと、もう自分の記述は不要な気も(^^;
するけど、ここからは自分が実際に設定した内容を備忘メモしておきます。
興味がある方は以下「続きを読む」でどうぞ~。

続きを読む

JenkinsとJava EE6で取り組んだ初めてのCI

前の開発では、それなりに大規模な開発だったにもかかわらず、構成管理や試験が全て人間ベースで行われていました。

従って当然のようにミスは起きるし、終いには

「あの人がいないとビルドできない!」

とか

「ここの試験はあの人にお願いしないと」

みたいな状況が続きました(実は今も…)

運用が安定すると人も減らさなければならなくなり「引継ぎ」というマジカルワードの嵐が起き、メタメタなコードもドンドンと任されます。

でも自動テストもないので、引き継いだ立場の人間は改造で苦労の連続…自分自身、デグレスパイラルを何度も経験しました(-_-;

で問題が発生すれば、当然、担当した自分がお客様から色々言われるわけです。
過去に設計した人や開発した人達はどこへやら…。

そんなプロジェクトが自分自身の初参加プロジェクトだったのですが、この経験から運用系システムにおける品質の重要性を身を持って学んだ気がします。

運用システムは開発自体も大変ですが、いかんせん動いてからが始まりで、安定するのもつかの間、多々発生する改造への迅速な適応が求められます。

なので心の底から

全てを手でやるのは本当にありえない!

というわけで、去年Java EE6を始めて触るのを機に+自分がアーキテクチャを任せて頂ける機会を得て、世間一般で行われている自動化の取り組みを少しずつ入れていき、現状は以下のようになりました。

  • Jenkinsを中心にビルドやモジュール管理を自動化
  • Jenkinsでリグレッション的に自動試験を日々実行
    • 単体試験は主にJUnit(+Mockito)
    • 単体では難しい試験はArquillian
    • DBも伴った試験はArquillian Persistence Extension
  • 自動ビルドで生成されたモジュールを自動で試験環境へデプロイ
  • 自動ビルド結果は関係者へ自動メールでリターン

f:id:kikutaro777:20130426220741j:plain

今のプロジェクトがこの状態なのですが、やはり安心感が違う気がします。

なんで前の大規模プロジェクトでこういうことを最初に考える人がいなかったのか…今思うと不思議です。

こういう取り組みをしたことがどこで伝わったかわかりませんが、社内の全く関係のない部署の方からJenkinsについて教えて欲しい、などの問い合わせがきたりもして、少しずつ社内に浸透すれば嬉しいなぁと思う今日この頃。

でも世間ではもっともっとすごいことをやっている人だらけなので、勉強を続けていかねば。
まずは第一歩進めたかなぁ、という感じです。

そんなこんなでJenkinsとJavaには、色々とありがとうございます、という気持ちが大きいです。

Java EE 6のDIで理解していなかったこと

今の開発では、メモリの懸念などもあり、なるべくSessionScopeなBackingBeanを利用しないようにしています。かといって完全に取り除けるものでもないので、一部は当然使っていますが。

で、今日はこのSessionScopeで、基礎的な所をちゃんと理解していなかったなぁ…と結構ショックに思うことがあったので備忘としてまとめようかと…。

いかにも素人ちっくな恥ずかしい内容、かつ、まだ色々理解できていないんじゃないか…という不安もあるので「違うよ!」「おかしいよ!」とか突っ込みあればお願いします(^^;

まず、結論から書くと

SessionScopeの(今回はCDI)管理対象BeanをInjectしたとき、同一セッション下であれば、以降のInjectでは同じインスタンスが注入される

ことをわかっていませんでした。なんか上手く説明できていないので、具体例を書くと。

以下のようなSessionScopedのBackingBeanを定義して

package jp.co.hoge.cdiconfirmation;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named(value = "sessionScoped")
@SessionScoped
public class SessionScopedData implements Serializable{
    
    private String test;

    @PostConstruct
    public void init(){
        test = "キープしてる?";
    }

    //testのsetter getterを省略
}

さらにこいつを別のBackingBeanでInjectします。こっちはRequestScoped。

package jp.co.hoge.cdiconfirmation;

import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;

@Named(value = "indexBean")
@RequestScoped
public class IndexBean {

    @Inject
    private SessionScopedData data1;
    
    @Inject
    private SessionScopedData data2;
    
    private String output;

    @PostConstruct
    public void init(){
        System.out.println(data1.getTest());
        System.out.println(data2.getTest());
        
        data1.setTest("どうなる?");
        
        System.out.println(data1.getTest());
        System.out.println(data2.getTest());
    }

    // outputのsetter getterは省略
    // outputはBackingBeanを起動するためにViewが参照してる変数
}

自分は今まで、Inject=明示しないnewのようなもの、と理解していたので、上記定義だとdata1とdata2のインスタンスは別ものになるものと思っていました。

上記を実行すると

f:id:kikutaro777:20130416225408j:plain

となります。data1のインスタンスにだけ「どうなる?」をセットしたのですが、data2にも反映されています。というわけで、data1、data2の変数ともに参照先のインスタンスは同じです。

知らなかった… orz

で、1行だけ加えて

package jp.co.hoge.cdiconfirmation;

import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;

@Named(value = "indexBean")
@RequestScoped
public class IndexBean {

    @Inject
    private SessionScopedData data1;
    
    @Inject
    private SessionScopedData data2;
    
    private String output;

    @PostConstruct
    public void init(){
        System.out.println(data1.getTest());
        System.out.println(data2.getTest());
        
        // data2 を明示的にnewする
        data2 = new SessionScopedData();

        data1.setTest("どうなる?");
        
        System.out.println(data1.getTest());
        System.out.println(data2.getTest());
    }

    // outputのsetter getterは省略
    // outputはBackingBeanを起動するためにViewが参照してる変数
}

として、data2を明示的にnewして実行すると

f:id:kikutaro777:20130416225500j:plain

となりました。data2の参照先が別のインスタンスとなったようです。
nullになってるのも「ほぉ」という感じ(InjectじゃなくnewしたのでPostConstructは実行されないってことかなと)

Inject = 自動でやってくれるnew

とか思っていましたが、SessionScopeなインスタンスをInjectする際は違うのですね。。

詳しい方々からすると「何をあたりまえなことを…」という感じかも…ですが、自分のようにJava EE初心者だとこういう基礎的な所で考え違いをしていたり…。精進あるのみ。

今のJava EE 6開発での利用技術をまとめてみた

最近絶賛ネタ切れ中です…。開発でつまづく所がだいぶ減ってきたのと、開発が忙しくなってきてインプットがないからですね…土日で吸収していきたい所です。

というわけで、今日は仕事上でも整理する必要があったため、現在のJava EE 6開発で利用している技術(というか基盤とかライブラリとか)を整理してみました。

Javaの世界へ足を踏み入れてから約8ヶ月。初めてなことだらけで結構しんどかったけれど、開発の観点という意味でも色々なことを学べたし、今後も学んでいきたいと思う今日この頃です。

種類 利用技術
開発プラットフォーム Java EE 6
JDK JDK 7
IDE NetBeans 7.3
アプリケーションサーバ GlassFish 3.1.2
プロジェクト管理とビルド Maven 3
ソース管理 Subversion
プロジェクト情報共有と障害管理 Trac
構成管理 Jenkins
自動試験(単体) JUnit 4.11
Hamcrest
自動試験(結合) Arquillian
自動試験(画面) Selenium
O/Rマッパー EclipseLink 2.3.2
画面コンポーネント PrimeFaces 3.5
PrimeFaces Extensions 0.6.3
ロギング SLF4j
Logback
Util系 Apache Commons Lang
Google Guava
Joda-Time

ちなみに前までは

種類 利用技術
開発プラットフォーム .NET C# 2.0 Windows Form
IDE Visual Studio 2005
ソース管理 VSS
構成管理 人間
自動試験 なし 人間
O/Rマッパー 作りこみ
ロギング log4net

みたいな(^^;C#は外部ライブラリなくても良いのは嬉しい所ですね。
自分は2.0止まりなので、今だともっともっと楽しそうなんですが;

開発で自分が主体になることはなかったので、色々環境を変えることも難しかったです。

構成管理やビルドはほぼ職人まかせだったし、管理が人手だからリリースミスもあったり。いかんせん自動テストがないものだから、引き継ぎした時とか泣きそうだったし、リグレッションとかも悲惨でした。
デフレスパイラルならぬデグレスパイラルを何度も味わいました。

そういった経験があったからこそ、開発で主体になれる今、自動化できるところはしたかったし、運用保守での苦労を少しでも減らせるように自動テストをしっかり入れたり、と意識しながら、まずはできる範囲で改善をしている感じです(^^)

まあ運用システムはリリースしてからが本番なので、そういった効果がどれだけ得られるかはもう少し先になりますが。。。

JavaScript内でJSFのEL式が使えることを初めて知りました ~画面表示時にダイアログ表示する挙動を例に~

Java EEを初めて触るようになって8ヶ月くらい経ちました。
EEはもちろんのこと、Java SEに関してもゼロスタートだったので、日々学習が必要で未だにてんてこ舞いです。
そして最近すっかり.NETの世界を忘れています(-_-;

今は実開発に入ってるので、ゆっくり学習する余裕も既になく、かつ周囲に聞ける人がいない状況は結構辛かったりもしますが、壁にぶつかって一緒に調べたり相談し合えるメンバが一緒なだけ幸いです。

前置きが長くなりましたが…

昨日、とある画面を作っていて

画面表示時にDBのあるフラグをみて、フラグに応じて警告ダイアログを出す

みたいなのがありました。遷移する前に出せよって感じですが、まあその辺の仕様は置いておいて(^^;

Windows Formだとごくごく簡単なことですが、自分のようなWeb開発初心者にとっては「何を使うのがbestなの…」って感じだったりします。

バッキングビーンのPostConstructでFacesContextにDialogのコンポーネントぶっこむ?と考えたり、preRenderViewとか使うのか、とかあれこれ思いつつ、色々とググっていくとJavaScriptにwindow.onLoadなるものがあると知りました。

JavaScriptかぁー、でもフラグはバッキングビーンみないとねぇ…どーすんのよ」

と頭の固い自分達は「うーん」となったわけですが、一緒に調べてた人が「あれー、これできるよ」と以下stackoverflowで見つけてきました。

Mixing JSF EL in a Javascript file

なんというか、みると「あ、できるんだ(^^;」と思うし、よくよく考えれば「そりゃできるわな」って感じなのですが、頭の中が「JSFの世界」「JavaScriptの世界」みたいに何故か分けて考えてしまってたので、気づかなかった感じです。

てか、これできるなら、今まで作った所で、もう少し簡単な実装に変えられる部分もあるなぁ…と気づいて、今後リファクタとか必要になりそうです。

とりあえず、簡易サンプルを書いて検証しました。以下のようなものです。

JSFのビュー(xhtml)
<h:body>
    <script type="text/javascript">
        window.onload = function() {
            if(#{onLoadConfirm.hasOpenError()}){
                dlg.show();
            }
        };
    </script>
    
    <p:confirmDialog id="dlgId" widgetVar="dlg" message="ダイアログですー"/>
</h:body>
バッキングビーン(CDI管理対象Bean)
package jp.co.hoge.primefacessandbox;

import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;

@Named(value = "onLoadConfirm")
@RequestScoped
public class OnLoadConfirm {
    
    private boolean hasOpenError;

    @PostConstruct
    public void init(){
        hasOpenError = true; //false
    }

    //getter,setterは省略
}

フラグ値を直接書いてるアホなサンプルコードですが…(^^;

hasOpenError=falseの場合

f:id:kikutaro777:20130403201302j:plain

ページ表示しても何も表示されません。

hasOpenError=trueの場合

f:id:kikutaro777:20130403201244j:plain

ページ表示するとダイアログが出ます。動いたー!

補足

Twitterで@aoetkさんから「やり過ぎるとソースがカオスになるので注意です」とコメント頂きました。
確かに上記のような簡易サンプルはいいですが、複雑になった場合には、フロントのJavaScriptとバッキングビーンを追いかけるのが大変そうな感じがします(^^;

ということで、そういった辺りは注意しつつ、恩恵を受ける所は上手く使っていきたいと思います。

てか、これまた毎度ですが、有識者の方々的には「当たり前だがなー」って感じなんだろうなぁ、と思いつつ、意外とこういうところで詰まってる自分に力のなさを感じたりします。。Challengeあるのみ(^^;

Java EE6の開発でよく悩むこと ~ コールバックを例に ~

Java EE6の開発をしていて、「自分がやっていることは正しいのか…」と悩み、迷うことがあります。
わかりやすく自分が実際に迷った道を書いてみます。

例題がJava SEで書かれている時

Javaでコールバックを実装したいなー、と思って以下のサイト情報を見つけました。

Java コールバック関数

わかりやすい(^^)

ちなみに、いきなり脱線ですがJavaのコールバックの情報
やはり上記サイトのようにインタフェース利用するのがメジャーなんですかね。

アノテーション使う例もあるようです。

で、本題ですが、先のサイトではMain関数があって、Java SEでのサンプルコードとなっています。

じゃあ、Java EEになると…?と一瞬止まりますが、まあここは何とかなります。

サイトのソースをそのままに、Mainクラスだけを書き換えると多分こんな感じかと↓

package jp.co.hoge.bean;

import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import jp.co.hoge.callback.A;
import jp.co.hoge.callback.B;
import jp.co.hoge.callback.MyInterface;

@Named(value = "main")
@RequestScoped
public class MainBean implements Serializable{
    
    @Inject
    A a;
    
    @Inject
    B b;
    
    public MainBean(){
        
    }
    
    public void btnClick(){
        testCallback(a);
        testCallback(b);
    }
    
    private void testCallback(MyInterface myinterface){
        myinterface.doit();
    }
}

上記はCDI管理対象Beanを利用してます。
ここで既に違ってたら恥ずかしい…ですが…。

で、main関数の代わりに、ボタンが押されたらコールバック処理を各々呼ぶ、みたいな記述にしてます。

Java EEだと…

上記の単純な例は普通に書けるのがわかりました。

でも実際には、クラスAやクラスBの中身では、EJBを呼び出したりとか、色々したいわけです。

例えば以下のような単純なEJBを用意します。

package jp.co.hoge.business;

import javax.ejb.Stateless;

@Stateless
public class SomethingEjb {

    public String callEjb(){
        return "EJBの実装だよ";
    }

}

現実的にはDB処理とかになりますが、例を簡単にするために上記の定義とします。

POJOからEJBを呼ぶ…?

で、自分の場合、ここら辺で「ふにゃ?」となります。

以下のようなことを書いちゃったりします。
(Bクラスを書き換え例にします)

package jp.co.hoge.callback;

import javax.inject.Inject;
import jp.co.hoge.business.SomethingEjb;

public class B implements MyInterface{
    
    @Inject
    SomethingEjb ejb;

    @Override
    public void doit() {
        System.out.println("クラスBの実装");
        ejb.callEjb();
    }
}

「Injectすればいいんじゃないの、動くんじゃね」と悪魔がささやいたり…。

でも、ふと我に返って「それってCDI管理対象Beanの話でしょ!」と天使君がささやきます。

実際に上記を実行すると、落ちたりはしませんが、EJBとして機能しないためか

情報: クラスBの実装

としか出ませんでした。(Java EE6 + GlassFish 3.1.2.2)

CDI管理対象BeanからEJBを呼ぶ

というわけで次のように書きます。
(Aクラスを書き換え例にします)

package jp.co.hoge.callback;

import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import jp.co.hoge.business.SomethingEjb;

@Named
@SessionScoped
public class A implements MyInterface, Serializable{

    @Inject
    SomethingEjb ejb;
    
    @Override
    public void doit() {
        System.out.println("クラスAの実装");
        System.out.println(ejb.callEjb());
    }
    
}

実行すると

情報: クラスAの実装
情報: EJBの実装だよ

おー出た出た。大丈夫だ。

正しい道に進んでいるのかな…

なんか変に悩んでしまうのは、

Java SEの例だったPOJOをCDI管理対象Beanとかにしていいの?

とか変に悩んだりします。

なんかこういうことやってると実は後々メモリの問題とかやばいよ、みたいなことだったりするのか
そういう辺りが全然わからなくて…(^^;
普通はこういう風に書くんだぜ、という例もあまり見なくて…うーんって悩んだり。

同じような悩みをされる人はいるのでしょうか。。。

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村