JSF2でbootstrapのダイアログとアイコンを使う

 前に作ったJavaEEアプリの画面に機能追加の依頼があったのですが、既存画面に追加するのも新規画面を作るのも微妙な要件だったので、ダイアログ表示でなんとかしたいと考えてました。
 で、ちょうどbootstrapを使っていたので、調べてみるとダイアログ表示はbootstrapで簡単に出来そうです。なおバージョンは2.3を使用しています。
http://bootstrapdocs.com/v2.3.2/docs/javascript.html#modals
JSF2のel式をダイアログに埋め込む為にはh:form内に書けばよいようです。ダイアログにはdatetimepickerをinputを2項目入れ下記のようになりました。

    <div class="modal hide fade" id="modal-timeinput" tabindex="-1">
      <div class="modal-dialog">
        <div class="modal-content">
          <h:form prependId="false">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="modal-label">期間指定</h4>
            </div>
            <div class="modal-body">
             <table>
              <tr>
                <th><h:outputText value="開始日時" class="from-control"/></th>
                <th><h:outputText value="終了日時" class="from-control"/></th>
              </tr>
              <tr>
                <td><h:inputText id="fromlogDate" value="#{LogDl.logStartDate}" class="datetimepicker from-control" /></td>
                <td><h:inputText id="tologDate" value="#{LogDl.logStartDate}" class="datetimepicker from-control" /></td>
              </tr>
             </table>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">閉じる</button>
                <h:commandButton id="getButton" class="btn btn-primary" value="取得" action="#{LogDl.getFile}" >
                </h:commandButton>
            </div>
          </h:form>
        </div>
      </div>
    </div>

呼び出し箇所は下記です。

<li>
  <a data-toggle="modal" data-target="#modal-timeinput" href="#" onclick="return false">
    期間指定</a></li>

これで「期間指定」を押すと下記のようなダイアログが表示されます。
fromto

次にアイコン表示も
http://bootstrapdocs.com/v2.3.2/docs/base-css.html#icons
の通りやってみましたが、なかなか表示されません。なんでかな??と思いながらブラウザの開発ツールを見ていたら、pngファイルは404 Not Foundとの事。ここでやっと気が付き、bootstrap.cssのpngファイル名に「.xhtml」を付け、やっとアイコンが表示されました。

Zend_Dbの微妙な相違にハマる

今、ZendFrameWorkを使ったphpアプリをDB2からOracle接続へ変える対応をしています。
phpは数年前に少し触った程度でしたが、基本的にアプリケーションスペックは何も変えないという前提なので、DB接続部分を変え、DB2独自のSQL部分を変えればそんなに時間は掛からないだろうと思ってました。

接続部分は、
$conn = Zend_Db::factory(“db2”,$params);

$conn = Zend_Db::factory(“Oracle”,$params);

SQL実行部分は
$stmt = new Zend_Db_Statement_DB2($conn, $sqlString);

$stmt = new Zend_Db_Statement_Oracle($conn, $sqlString);
に、その他DB2独自のSQLをOracle向けにSQLを書き換えていく地味な作業です。。

開発環境は、
pleiades 4.6 Neon PHP にしてみました。
php/pearにZendを追加したり、Oracle接続の為にInstantClient12を入れ、
php.iniは、
extension=php_oci8_12c.dllやextension=php_pdo_oci.dllを有効に、
iconv.internal_encoding=UTF-8 でマルチバイト対応とし、
大体開発環境が整いました。

で、DB2のテーブルをOracleDBに作成し、XAMPPを動かして画面を動かしてみると下記のエラーが、
Invalid bind-variable position ‘?’
バインドがインバリッド?何でだろう??
何もまだ変えてない箇所なんだけど。。

でネットで情報収集していくと下記を発見
oci_bind_by_name
Oracle はクエスチョンマークをプレースホルダとして使いません。

との事。。

まったく変更する必要が無い箇所もたくさんあり、いろいろ継承している既存ソースを考慮し、
?を諦め、下記のように:0などに置き換えていこうと決断。

$sqlString = $sqlString . “? = COLUMN_NAME “;
というような箇所を
$cnt = 0;
$sqlString = $sqlString . “:” . $cnt++ . ” = COLUMN_NAME “;
に変えていきます。

変更箇所は当初想定した倍以上になりそうです。
幸い時間があるので、間に合うとは思いますが、参りました。。

weblogic.xmlのprefer-web-inf-classesをtrueにしたらハマった・・

 前に作ったWeblogicのWebアプリで
JAX-RSを使ってみる
weblogicよりもアプリケーションモジュールに入れるライブラリを優先させたい事情があり、weblogic.xmlにprefer-web-inf-classesのtrueを追加してみたところ、これまで問題無かったのが、デプロイ出来ない状態に。。
ログには下記のエラーが出ています。

<2016/07/26 12時58分59秒 JST> <Error> <HTTP> <AUTH-DEV01> <AdminServer> <[ACTIVE] ExecuteThread: '11' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1469505539381> <BEA-101216> <Servlet: "JAX-RS Servlet" failed to preload on startup in Web application: "web-ap".
java.lang.NoClassDefFoundError: Could not initialize class com.sun.proxy.$Proxy121

どうも、JAX-RSに関して何らかの問題が発生しているようなのですが、JAX-RSに関して明示しているライブラリはpom.xmlに書いた下記のみです。

    <dependency>
	  <groupId>com.sun.jersey</groupId>
	  <artifactId>jersey-core</artifactId>
	  <version>1.19</version>
    </dependency>

いろいろ試行錯誤した結果、上記で指定したものよりweblogicライブラリが優先的に使用されていて、1年間問題無かったのが、ライブラリの優先順位を変えた事によって、問題が発生したようなのです。最終的にcom.sun.jerseyについて上記のpomをジャージーのバンドルセットに変える事で解消しました。

    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-bundle</artifactId>
      <version>1.19.1</version>
    </dependency>

いや、びっくりしました。。

UWSCを使ってみた。

前回の続きで、Windows系のサブネットを一括変更するツールを作ろうといろいろ調べてみました。
まずは、コマンドプロンプトなどで、
netsh interface ip show addres
を打ち、その出力から変更対象のネットワーク設定を取得し、それを元に、
netsh interface ip set address “ネットワーク名” static 192.168.1.101 255.255.254.0 192.168.1.1
といったネットワーク変更コマンドを発行するスクリプトを作ります。
 それをリモートから実行するのには、そのスクリプトをリモートマシンに配置して実行するという事なりますが、まずやってみたのがPsExec。net use でスクリプトをリモートマシンへコピーしてPsExecで実行するという内容ですが、2012Serverだとデフォルトではnet useもPsExecもFirewallで弾かれてしまいます。Firewallを無効にするとうまくいくのですが、Firewallとかセキュリティポリシーとか変えなきゃいけないならそれは本末転倒になってしまいます。
 結果、行きついたのが、UWSC。大抵のWindows系サーバはメンテナンスの都合でリモートデスクトップだけは有効になっているので、リモデ経由の作業を自動化するにはと発想を変えてUWSCを見つけました。下記を参考にさせて頂きました。

UWSCによるリモートデスクトップの一括自動操作スクリプト

微妙に2012ServerR2用のGUI操作に変更して使ってみました。
でも、結果的にはコマンドのみで完結しない作業だし、実行結果の証跡確保や確実性を求められる内容なので、やっぱり手作業が必要になってしまいました。ダイアログを出して手作業が終わったらボタンを押すみたいな。。
Windows系OS作業の自動化はインフラ側でそれに合わせた設定が事前にされてないと無理ですね。

TeraTermマクロでvi編集

 マシンが増えたのでサブネットを多数のサーバで一気に変えなきゃという話があり、対象サーバを確認したところ、Windows系もあるけどCentOSの6系が多いとの事。サブネットを変えるにはどうしたらいいのかいろいろ調べたと所、CentOS6だと一時的なのはifconfigで行けるけど、恒久的な変更だとコンフィグファイル更新が必要らしい。ちなみにCentOS7だとまた別のコマンドらしい。windows系は調査中。。。
 という事でリモート端末から一気に複数のサーバを更新するという要件なので、とりあえずはTeraTermマクロを作ってそれを各サーバに繰り返すという形にします。
 下記例はログインや引数処理、該当ネットワーク名の取得等は割愛し、viコマンドによるファイル編集をマクロで実行する箇所をサブルーチンにし、それをコールする内容です。コンフィグファイルは/etc/syscomfigにある該当ネットワークのファイル(下記のCONFFILE)に指定し、検索文字列(下記のSEARCHSTR)はPREFIX=、サブネットをBit24にするとして上書文字列(下記のAPPENDSTR)に24をセットしてサブルーチンをコールしています。

CONFFILE='/etc/sysconfig/network-scripts/ifcfg-eth0'
SEARCHSTR='PREFIX='
APPENDSTR='24'
call CHANGECONF
end

:CHANGECONF
;コンフィグ変更サブルーチン 
; CONFFILE	コンフィグファイル名
; SEARCHSTR	検索文字列
; APPENDSTR	上書文字列

timeout= 3
CMD = 'vi '
strconcat CMD CONFFILE
sendln CMD

;/を送る
send '/'
pause 1
; 検索文字へ移動
sendln SEARCHSTR
pause 1
strlen SEARCHSTR
sendkcode 333 result

; Rで上書き
send 'R'

send APPENDSTR

; エスケープ
send #$1B

send ':'
pause 1
sendln 'wq!'
pause 1
 
; 終了
return

コマンド打った後にwaitlnとかでは出来ないのでpauseを入れてとりあえずは動く形になりましたが、環境によりタイミングは変わるのでエラーハンドリングを追加した方が良さそうです。

JSF2でbootstrapのdatetimepickerを使ってみる

 前回、画面の日付入力にdatepickerを使ってみましたが、
bootstrapのdatepickerを使ってみる
今度は時間の入力も必要な画面を追加する事になり、datetimepickerを使ってみる事にしました。
 使用したのは下記です。日本語も対応されています。
http://www.malot.fr/bootstrap-datetimepicker
 ダウンロードしたJSとCSSをdatepickerの時と同じようにコンテンツディレクトリ配下のresource内に配置。
resource

xhtmlは下記のようになりました。aInfoという管理BeanにdispFromDateとdispEndDateの2つの文字列日付プロパティがあり、ボタン押下でgetListを呼び出し結果をresultListにdataTableで表示するという内容です。

<script type="text/javascript">
$(function() {
	  $('.datetimepicker').datetimepicker({
		  format: 'yyyy/mm/dd hh:ii:ss',
	      autoclose: true,
	      todayBtn: true,
	      pickerPosition: "bottom-left",
		  language: 'ja'
	  });
	});
</script>
・・・中略

<h:inputText id="fromDate" value="#{aInfo.dispFromDate}" class="datetimepicker from-control span2" >
  <f:ajax  execute="@this"/>
</h:inputText>
<h:inputText id="toDate" value="#{aInfo.dispEndDate}" class="datetimepicker from-control span2" >
  <f:ajax  execute="@this"/>
</h:inputText>
・・・中略

<h:commandButton id="listget" action="#{aInfo.getList}" value="表示" class="btn btn-default safebutton">
  <f:ajax execute="fromDate toDate" render="resultList"/>
</h:commandButton>

・・・中略
<h:dataTable id="resultList" var="list" value="#{aInfo.resultList}" class="table table-striped" >
・・・以下略

なお、日付フォーマットは今回の要件的に秒も対象にしていますが、datetimepickerのUI自体は分までが対応範囲なので秒については直入力という整理です。

createQueryとcreateNativeQueryは結構違う

 現在、JavaEEで作っているアプリケーションに画面を追加する事になり、それまではJPAのJPQLを使ってのcreateQueryで済んでいたのですが、今回はGROUP BYとかUNIONとかでSQLを作る必要があり、JPQLでは無理そうなのでcreateNativeQueryで実装する事にしました。
 で、最初はcreateQueryをcreateNativeQueryに置き換えてSQL文を噛ませばいいかなと思っていたのですが、どうやら結構違うらしい。。
 一つ目の違いは、createQueryならテーブル定義に沿って作ったEntityに直接入れる事が出来ますが、ちょっと複雑なSQLだと問い合わせ結果に一致したEntityを作る事自体が難しい。
 二つ目はバインド変数の違い。createQueryならバインド変数は[:PARAM]のように文字として指定して下記のように変数をセットして結果を取得できますが、

List<LoginUser> result = em.createQuery(
  "SELECT c FROM LoginUser c WHERE c.USER_TYPE < '5' AND c.STATUS_FLG < :PARAM ORDER BY c.USER_ID")
  .setParameter("PARAM", "9")
  .getResultList();

createNativeQueryでは[?]でないとダメという解りにくい相違点。。
結果的に下記のようになりました。

String SQL="SELECT KEY,SUBKEY,SUM(AMOUNT) FROM TABLE_A WHERE REGDATE = ? AND (? IS NULL OR SUBKEY = ? ) " +
		"UNION SELECT KEY,SUBKEY,SUM(AMOUNT) FROM TABLE_B WHERE REGDATE = ? AND (? IS NULL OR SUBKEY = ? ) ";

Query q = em.createNativeQuery(SQL);
for (int i = 0 ; i < 6 ; i = i + 3){
	q.setParameter(i+1, StringUtils.remove(StringUtils.remove(getDate(),"/"),":"));
	q.setParameter(i+2, getSubKey());
	q.setParameter(i+3, getSubKey());
}
List<Summary> list = new ArrayList<Summary> ();

List<Object[]> results = q.getResultList();
for (Object[] it : results) {
	Summary sum = new Summary();
	sum.setKey((String)it[0]);
	sum.setSubKey((String)it[1]);
	BigDecimal bd = (BigDecimal)it[2];
	sum.setCount((int)bd.intValue());
	list.add(sum);
}

※上記のSummaryは上記クエリ結果をセットする為だけのクラスです。

なお、数値はBigDecimalで扱うようです。
バインド変数の仕様違いにはちょっとハマりました。。

以外と知られていないが便利なHTA

 Windows用で画面一つだけとかの簡単なツールを作る場合、HTA(HTML Applications)をよく使います。かなり昔からありますが、かなりマイナーな存在のようです。筆者もその存在に気が付いたのは実は3年くらい前です。。小さい規模でしか使う事はまずないので、HTAを使うような開発を外部へ発注するような事がなかったからでしょうか?
 基本的にIE上で動作しているので、MicrosoftがIEを辞めたら終わりかも知れませんが、テキストエディタのみで作れるし、VBScriptとJavaScriptの組み合わせで大抵の事は実現できます。特に助かるのが、企業内で使う端末って勝手にソフトをインストール出来なかったり、会社によっていろんな制約があったりしますが、HTAなら端末環境上の影響がなく、Windows端末でさえあればOKという点です。少数で使うちょっとした画面を作るという前提では結構便利だと思います。

Coherenceと1年付き合ってみた

 OracleのインメモリーグリッドCoherenceを使った開発に携わり1年立ちました。途中の数ヶ月は別の事もやったりで比較的まったりやっていましたが、この辺でちょっと整理。別に筆者が選定した訳ではありませんが、今携わっている仕事でCoherenceを使う事になったのは、Webサービスでミッションクリティカルかつ、応答レスポンスの最小化という要件を満たす為でした。構成はこんな感じです。

構成

 上記のWebLogicにデプロイされているフロントアプリケーションと、別途バックにJavaVMで動作させているプロセスの両方にCoherenceのキャッシュデータが配置されます。フロントは静的かつアクセス頻度が高いマスタ系データをレプリケーションキャッシュとして配置、バック側は主にトランザクション系データを分散キャッシュとして配置することで、分散かつ他のプロセスにバックアップを取ってくれます。コンフィグ次第で他サーバとかにバックアップを取るようにも出来るようです。またバックキャッシュではキャッシュストアといって、キャッシュに無ければDBに取りに行ったり、キャッシュに入ったものをDBへ入れたりする機能が動作します。
 Coherenceに関してコードを書くところは、キャッシュに格納するデータとなるエンティティモデル、上記のキャッシュストア、その他必要に応じてイベント処理やビジネスロジック側の為にDAO的なものを用意するくらいです。

 まず、エンティティモデルとしてPortableObjectを実装します。こんな感じです。

package jp.co.esoro.cache.EDM;

import java.io.IOException;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

/** 取引履歴 */
public class TrnRequest implements PortableObject{

	/** 取引年月日 */
	private String trnDate;
	/** 所属先ID */
	private String companyID;
	/** 取引番号 */
	private String trnID;
	/** 取消フラグ */
	private String canselFlg;
	/** ユーザーID */
	private String userID;
	/** 金額 */
	private long amount;
	/** 取引区分 */
	private String requestType;
	
	public String getTrnDate() {
		return trnDate;
	}
	public void setTrnDate(String trnDate) {
		this.trnDate = trnDate;
	}
	public String getCompanyID() {
		return companyID;
	}
	public void setCompanyID(String companyID) {
		this.companyID = companyID;
	}
	public String getTrnID() {
		return trnID;
	}
	public void setTrnID(String trnID) {
		this.trnID = trnID;
	}
	public String getCanselFlg() {
		return canselFlg;
	}
	public void setCanselFlg(String canselFlg) {
		this.canselFlg = canselFlg;
	}
	public String getUserID() {
		return userID;
	}
	public void setUserID(String userID) {
		this.userID = userID;
	}
	public long getAmount() {
		return amount;
	}
	public void setAmount(long amount) {
		this.amount = amount;
	}
	public String getRequestType() {
		return requestType;
	}
	public void setRequestType(String requestType) {
		this.requestType = requestType;
	}
	public String getId() {
		return trnDate + companyID + trnID;
	}

	@Override
	public void readExternal(PofReader arg0) throws IOException {
		setTrnDate(arg0.readString(1));
		setCompanyID(arg0.readString(2));
		setTrnID(arg0.readString(3));
		setCanselFlg(arg0.readString(4));
		setUserID(arg0.readString(5));
		setAmount(arg0.readLong(6));
		setRequestType(arg0.readString(7));
	}
	@Override
	public void writeExternal(PofWriter arg0) throws IOException {
		arg0.writeString(0, getId());
		arg0.writeString(1, getTrnDate());
		arg0.writeString(2, getCompanyID());
		arg0.writeString(3, getTrnID());
		arg0.writeString(4, getCanselFlg());
		arg0.writeString(5, getUserID());
		arg0.writeLong(6, getAmount());
		arg0.writeString(7, getRequestType());
	}
}

 上記の例ではキー項目が取引年月日と所属先IDと取引番号の3つですが、KeyValueなので1項目のキーとしてgetIdというメソッドを入れてます。
 
 次にバックキャッシュ側で動作するCacheStoreを実装します。こんな感じ。

package jp.co.esoro.cache.Cachestore;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;

import jp.co.esoro.cache.EDM.TrnRequest;

import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.tangosol.net.cache.CacheStore;

/**
 * 履歴テーブルキャッシュストア
 * */
public class ReqCacheStore implements CacheStore {
	protected static Logger logger;
	private Connection con = null;
	PreparedStatement storePs = null;
	PoolDataSource pds;
	
	private static String sql_TrnRequest = "MERGE INTO TrnRequest H "
			+ "USING (SELECT ? trnDate, ? companyID, ? trnID FROM DUAL) U "
			+ "ON (H.trnDate = U.trnDate "
			+ "AND H.companyID = U.companyID "
			+ "AND H.trnID = U.trnID) "
			+ "WHEN MATCHED THEN "
			+ "UPDATE SET canselFlg=? "
			+ "WHEN NOT MATCHED THEN "
			+ "INSERT (trnDate,companyID,trnID,canselFlg,userID,amount,requestType) "
			+ " VALUES (?,?,?,?,?,?,?)";
	
	public ReqCacheStore(String cacheName) {
		super();
		logger = LogManager.getLogger();
		try {
			pds = PoolDataSourceFactory.getPoolDataSource();
			pds.setConnectionPoolName(cacheName);
			pds.setConnectionFactoryClassName(   
			        "oracle.jdbc.pool.OracleDataSource");
			pds.setValidateConnectionOnBorrow(true);

			pds.setURL("****************");
			pds.setUser("user");
			pds.setPassword("password");
			pds.setInitialPoolSize(1);
			pds.setMinPoolSize(1);
			pds.setMaxPoolSize(20);
			
			con = pds.getConnection();
			storePs = con.prepareStatement(sql_TrnRequest);
		} catch (SQLException e) {
			logger.error(e.getMessage());
		}
	}

	@Override
	public Object load(Object arg0) {
		//get時キャッシュに無い場合DB等から読込みが必要な場合記述
		return null;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Map loadAll(Collection arg0) {
		//get時キャッシュに無い場合DB等から読込みが必要な場合記述
		return null;
	}
	
	@Override
	public void erase(Object arg0) {
		//削除が必要な場合記述
	}
	
	@SuppressWarnings("rawtypes")
	@Override
	public void eraseAll(Collection arg0) {
		//削除が必要な場合記述
	}
	
	/**
	 * DB書込み
	 * */
	@Override
	public void store(Object arg0, Object arg1) {
		try {
			TrnRequest trn = (TrnRequest)arg1;
			
			storePs.setString(1, trn.getTrnDate());
			storePs.setString(2, trn.getCompanyID());
			storePs.setString(3, trn.getTrnID());
			storePs.setString(4, trn.getCanselFlg());
			storePs.setString(5, trn.getTrnDate());
			storePs.setString(6, trn.getCompanyID());
			storePs.setString(7, trn.getTrnID());
			storePs.setString(8, trn.getCanselFlg());
			storePs.setString(8, trn.getUserID());
			storePs.setLong(10, trn.getAmount());
			storePs.setString(11, trn.getRequestType());
			
			storePs.executeUpdate();
			
		} catch (SQLException e) {
			logger.error(e.getMessage());
		}
	}

	@SuppressWarnings("rawtypes")
	@Override
	public void storeAll(Map arg0) {		
		for (Object entry :arg0.entrySet()){
			store( (Object)((Entry<?, ?>) entry).getKey(),(Object)((Entry<?, ?>) entry).getValue());
		}
	}
}

上記はDB書き込みのみの実装例です。

 この先はコンフィグを3つ書きます。凝った事をしなければフロント用もバック用も同じものでOKです。これらはJVM起動時オプションで指定します。クラスパス内ならファイル名だけ、外に置いてもフルパスで指定すればOKです。

 まず、キャッシュのクラスタ設定ですが、基本的にクラスタ名だけ書いておけば後は勝手に各プロセスが連携してくれます。
 起動オプションは、-Dtangosol.coherence.override=tangosol-coherence-override.xml

<?xml version="1.0" encoding="UTF-8"?>
<coherence xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config http://xmlns.oracle.com/coherence/coherence-operational-config/1.2/coherence-operational-config.xsd">
    <!--coherence-version:12.1.3-->
    <cluster-config>
        <member-identity>
            <cluster-name system-property="tangosol.coherence.cluster">cohe-cluster1</cluster-name>
        </member-identity>
        <multicast-listener>
          <address system-property="tangosol.coherence.clusteraddress">224.0.0.1</address>  
          <port system-property="tangosol.coherence.clusterport">11131</port>
        </multicast-listener> 
    </cluster-config>
</coherence>

 次にPortableObjectとして実装したものをPOFコンフィグに書いておきます。番号は1000以上で適当に並べます。
 起動オプションは、-Dtangosol.pof.config=pof.xml

<?xml version="1.0"?>
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
    xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config http://xmlns.oracle.com/coherence/coherence-pof-config/1.2/coherence-pof-config.xsd">
	<user-type-list>
	<!-- include all "standard" Coherence POF user types -->
	<include>coherence-pof-config.xml</include>
	<user-type>
		<type-id>1001</type-id>
		<class-name>jp.co.esoro.cache.EDM.MstUser</class-name>
	</user-type>
	<user-type>
		<type-id>1002</type-id>
		<class-name>jp.co.esoro.cache.EDM.TrnRequest</class-name>
	</user-type>
	</user-type-list>
</pof-config>

 最後に各キャッシュ構成として、キャッシュのタイプや構成、作成したキャッシュストア等を書きます。
 起動オプションは、-Dtangosol.coherence.cacheconfig=cache-config.xml

<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config http://xmlns.oracle.com/coherence/coherence-cache-config/1.2/coherence-cache-config.xsd">
  <defaults>
    <serializer>pof</serializer>
    <socket-provider system-property="tangosol.coherence.socketprovider"/>
  </defaults>
  <caching-scheme-mapping>
    <cache-mapping>
      <cache-name>userMst</cache-name>
      <scheme-name>master-scheme</scheme-name>
    </cache-mapping>
    <cache-mapping>
      <cache-name>RequestTrn</cache-name>
      <scheme-name>trn-scheme</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>
  <caching-schemes>
    <replicated-scheme>
      <scheme-name>master-scheme</scheme-name>
      <service-name>master-service</service-name>
      <backing-map-scheme>
      	<local-scheme></local-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </replicated-scheme>
    
    <distributed-scheme>
      <scheme-name>trn-scheme</scheme-name>
      <service-name>trn-service</service-name>
      <thread-count>3</thread-count>
      <backing-map-scheme>
        <read-write-backing-map-scheme>
          <internal-cache-scheme>
      	    <local-scheme>
      	      <eviction-policy>LRU</eviction-policy>
      	      <high-units>1000000</high-units>
      	    </local-scheme>
          </internal-cache-scheme>
          <cachestore-scheme>
            <class-scheme>
              <class-name>jp.co.esoro.cache.Cachestore.ReqCacheStore</class-name>
                 <init-params>
                <init-param>
                  <param-type>java.lang.String</param-type>
                  <param-value>{cache-name}</param-value>
                </init-param>
              </init-params>
            </class-scheme>
          </cachestore-scheme>
          <write-delay>5s</write-delay>
          <write-requeue-threshold>1</write-requeue-threshold>
        </read-write-backing-map-scheme>
      </backing-map-scheme>
      <autostart>true</autostart>
    </distributed-scheme>
    
    <proxy-scheme>
      <scheme-name>proxy-scheme</scheme-name>
      <service-name>proxy-service</service-name>
      <thread-count>10</thread-count>
      <acceptor-config>
        <tcp-acceptor>
          <local-address>
            <address>192.168.111.113</address>
            <port>9099</port>
          </local-address>
        </tcp-acceptor>
      </acceptor-config>
      <proxy-config>
        <cache-service-proxy>
          <enabled>true</enabled>
        </cache-service-proxy>
        <invocation-service-proxy>
          <enabled>true</enabled>
        </invocation-service-proxy>
      </proxy-config>
      <autostart>true</autostart>
    </proxy-scheme>
  </caching-schemes>
</cache-config>

 上記ですとuserMstはレプリケーションキャッシュ、RequestTrnは分散キャッシュでOutOfMemory対策として1プロセス最大100万件まで、処理負荷分散の為にスレッドを3つ、キャッシュストアは応答レスポンスを意識してキャッシュ書き込み5秒後に非同期で動作するという内容です。最後のProxyはクラスタ構成プロセス外からのアクセス(*Extends)がある場合の受信口を用意している形になってます。なお、複数プロセスを動作させる場合は、PORTを個々に指定します。

カテゴリー: Java

JSF2単純リダイレクト

JSF2でコンテンツルートのページから別ページへリダイレクトさせるのに何がいいかなと調べたところ、meta refreshタグを使って飛ばすのが一番簡単そうでした。具体的にはコンテンツルートにログイン画面を置くことが出来ない場合に、ログイン画面に飛ばすという要件への対応になります。

<!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:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<meta http-equiv="refresh" content="0; URL=#{request.contextPath}/login/index.xhtml"/>
</h:head>
</html>
カテゴリー: Java