ラベル SystemDevelop の投稿を表示しています。 すべての投稿を表示
ラベル SystemDevelop の投稿を表示しています。 すべての投稿を表示

2010-07-13

Spring Framework で Oracle Type を利用する

久しぶりに投稿します。

いやー、悩みました。
ようやく解決。

Oracle DB で TYPE AS OBJECT とかを使用したテーブル、ストアドなどを、Spring Framework から利用するための情報です。
ここでは引数(INパラメータ)にTYPEがあるストアドを実行する場合で説明します。
Spring の StoredProcedure を利用します。

まず、実行だけだとこんな感じで実装します。
ストアドの引数が TYPE AS OBJECT の場合


StoredProcedure sp = new StoredProcedure(dataSource, "SCHEMA.STORED_NAME");
sp.declareParameter(new SqlParameter("PARAM_NAME", Types.STRUCT, "ORACLE_TYPE_NAME"));
Map param = new HashMap();
param.put("PARAM_NAME", new OracleStructTypeValue("ORACLE_TYPE_NAME", "aaa", "bbb"));
sp.execute(param);


1行目
 Spring のStoredProcedureクラスのインスタンス化
 コンストラクタの引数は1つ目にDataSource、2つ目は実行するストアド名
2行目
 ストアドの引数の定義
 今回はINパラメータ1つでそれがTYPEだった場合。TYPE は AS OBJECT 、つまり構造体的な場合。
 StoredProcedureクラスのdeclareParameterメソッドに SqlParameter を渡す。
 SqlParameterのコンストラクタの引数は以下のように指定する
 1つ目:引数名(任意の文字列)
 2つ目:java.sql.Types.STRUCTを指定
 3つ目:Oracle 側のTYPEの名前
3行目
 実行時の引数となるMapの作成。
4行目
 ここがポイントかな。実行時引数のキーは2行目で指定したSqlParameterの1番目の引数のモノと同じにして、ポイントは値側。
 通常数値や文字列を渡すところをorg.springframework.jdbc.core.support.AbstractSqlTypeValueを実装したクラスで指定する。
 今回はOracleStructTypeValueというクラスを作成。
 内容は以下のような形。


import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;

import org.apache.commons.lang.StringUtils;
import org.springframework.jdbc.core.support.AbstractSqlTypeValue;

public class OracleStructTypeValue extends AbstractSqlTypeValue {
private String structName;
private Object[] parameterValues;

public OracleStructTypeValue(Object... args) {
parameterValues = args;
}
public OracleStructTypeValue(List args) {
parameterValues = args.toArray();
}
public OracleStructTypeValue(String structName, Object... args) {
this.structName = structName;
parameterValues = args;
}
public OracleStructTypeValue(String structName, List args) {
this.structName = structName;
parameterValues = args.toArray();
}

public void setStructName(String structName) {
this.structName = structName;
}

public void setParameterValue(Object[] parameterValues) {
this.parameterValues = parameterValues;
}

@Override
protected Object createTypeValue(Connection con, int sqlType, String typeName) throws SQLException {
StructDescriptor structDescriptor = StructDescriptor.createDescriptor(
StringUtils.isEmpty(structName) ? typeName : structName, con);
return new STRUCT(structDescriptor, con, parameterValues);
}


XMLからも定義できるようにsetterなども用意しましたが、基本はcreateTypeValueというメソッドを実装すればOK。
createTypeValueの引数の3つ目typeName は、実行時に指定したTYPE名(最初のソースで言う2行目の SqlParameterのコンストラクタ引数の3番目)が渡ってきます。基本はそれをそのままStructDescriptorcreateDescriptorの1番目の引きすに渡せばOKだと思いますが、ここでは別途指定もできるようにしています。
createDescriptorの2番目の引数は実行時にストアドに渡す具体的な値の配列。
Oracle側で定義したTYPEの上から順番に配列にして渡します。(最初のソースでは"aaa"と"bbb"という文字列を渡ています)
これで実行できます。
ただし注意点が。このcreateTypeValueメソッドの引数となっているConnectionOracleConnection型でないとClassCastExceptionが出ます。
なので、DataSourceの設定を以下のようにしてあげる必要があります。


<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" method="close">
<property name="URL" value="jdbc:oracle:thin:@localhost:1521:orcl" />
<property name="user" value="scott" />
<property name="password" value="tiger" />
</bean>



今回はここまで。
TYPE の型が TABLE の場合とか、OUT パラメータの場合は次回以降で。(あるのか?)

2009-08-04

Maven2 依存関係を調べるツール



Maven2を使用してDependencyの設定をしていると、依存関係の依存関係(推移的依存関係というらしい)によって想定外の参照をしているときがあって困っていた。
たとえば、今回Strutsの1.3.8(または1.3.9)とSpringFrameworkを使用していると、起動できない。
javax.servlet.UnavailableException: org.apache.commons.digester.Digester.parse(Ljava/net/URL;)Ljava/lang/Object;
というエラーがでる。
調べると、どうやらStruts1.3.8にはcommons-digesterは1.8が必要とのこと。
確かにMaven2が落としてくるcommons-digesterは1.7になっている。
でもStrutsのpom.xmlをみてもちゃんとcommons-digesterは1.8を参照している。
ということは他のjarが参照しているのが悪さをしているな、ということになるけど、どいつが悪いのかがわからず、探すと「Dependency Analyzer」というツールを発見。
こいつは便利だ。
pom.xmlを読み込ますと、最初はびっくりする画面になるが、「Filter by group id」でcommons-digesterにフィルターをかけると一目瞭然。
原因はspring-modules-validation0.8にあることが判明。
spring-modules-validation0.8のpom.xmlをみると確かにcommons-digesterは1.7を参照している。
なので、自分のpom.xmlにcommons-digester1.8を参照するように変更し、無事解決。
いやぁ、このDependency Analyzerは久々のヒット。

2008-09-17

eclipseのmaven dependenciesでソース参照 (ついでにJavaDocも)

eclipseのプロジェクトでmavenを使って開発をしている際、デバッグなどでどうしてもmavenで持ってきたjarのソースを参照したくなり、でもすでに構築しているのでいまさらmvn eclipse:eclipseをしたくなく(結局したけど)、既存の状態からいかにソースを参照させるかという観点で対応。

簡単にまとめ

m2eclipseを導入
eclipseの設定のmavenでDownload Artifact SourcesとDownload Artifact JavaDocにチェック
pom.xmlに以下を追加

<plugin>
<groupid>org.apache.maven.plugins<⁄groupid>
<artifactid>maven-eclipse-plugin<⁄artifactid>
<version>2.4<⁄version>
<configuration>
<downloadsources>true<⁄downloadsources>
<downloadjavadoc>true<⁄downloadjavadoc>
<⁄configuration>
<⁄plugin>
mvn eclipse:eclipseを実行
.classpathとか.projectファイルが更新されてしまうので元に戻す
そのままではビルドがエラーのままなので、一度maven dependenciesを無効にしてから、もう一度有効にする
でOKななずだったが、
The version cannot be empty.
というエラーでpom.xmlが赤くなる
いろいろ調べて以下のサイトに情報がありました。
org.apache.maven.wagonにversionタグがなかったために出ていた様子
こいつを追加したら無事成功

2008-09-16

Subversion操作メモその2

さっそくその2
今度は
リポジトリにあるディレクトリを別のディレクトリに履歴ありでコピー(または移動)する
というもの
ちょいとてこずりました

基本手順は svnadmin dump → svndumpfilter → dumpファイル編集 → svnadmin load
こいつらはすべてサーバー側で行わないとダメ。
  1. svnadmin dump でリポジトリのダンプをとる
  2. svndumpfilterで特定のディレクトリのみにしたり、特定のディレクトリのみ除外したりする
  3. 出来たdumpファイルをロードしたいリポジトリの構成にあわせ編集
  4. svnadmin loadでロード
まず1と2(面倒くさいのでパイプで処理)
  svnadmin dump /hoge/svn/rep1 | svndumpfilter include hoge > hoge.svndump
この場合/hoge/svn/rep1にあるsvnリポジトリのダンプを取る
「svndumpfilter include hoge」で、その中のhogeというディレクトリのみ対象とする
「指定以外のディレクトリ」としたい場合はexcludeオプションで
指定するパスが複数ある場合はスペースで区切る
新規リポジトリなどに新たに移行するときなどはsvndumpfilterにさらに以下のオプションを指定
  • --drop-empty-revs
    空リビジョンを出力しない
    これをしないと「単に番号が飛ばないようにするための空のリビジョンです。」的なリビジョンが出来る
  • --renumber-revs
    上記オプションだけだとリビジョン番号が飛んでしまうのでこれを指定

次に3
出来たdumpファイルのままだと、元のリポジトリのパス構成のまま新しいリポジトリにコピーされてしまうので、テキストエディタなり、perlなりで「Node-path」の部分を編集
上記dumpだと
Node-path: hoge/subdir
のように出力されているはずなので、ここを編集
ここで指定したNode-pathは、次でloadする際にparent-dirで指定するディレクトリの下に出来るディレクトリになる
ただし、Node-pathで編集したパスの最下層より一つ上までのディレクトリはあらかじめsvn mkdirで作成しておかないとダメ

次に4
  svnadmin load --parent-dir huga /hoge/svn/rep1 <  hoge.svndump
でロード。
できるはずが、ここで問題発生
対象のリポジトリにもよるのであろうが、たとえばファイルを移動(コピーしたあと削除)しているような操作を行っていたリポジトリの場合などはload中に「ファイルが見つかりません」とかいって落ちる様子。

再度dumpファイルを修正
今回の場合は
  Node-path: file1
  Node-action: add
とかなっているあとに
  Node-path: file2
  Node-action: add
  Node-copyfrom-path: file1
となっていて、その後
  Node-path: file1
  Node-action: delete
となっていたので、
最初のエントリのNode-pathをfile2にしてしまい
ほかの2エントリを削除

他には上記の例でNode-path: file2のときに同時に修正している場合
この場合は2つ目のエントリのNode-acitonをchangeにしNode-copyfrom-revとNode-copyfrom-pathという属性を削除し、deleteしているエントリを削除しました

んで、無事完了

参考にさせていただいたサイト



10/28/2008 追記
4の後のdumpファイルの修正がこんなことしなくてもよかった。
3の時点でNode-pathだけでなくNode-copyfrom-pathも新しいパスに変えてしまえばよいようです。

Subversion操作メモその1

仕事でよく使うSubversionで今まで困ったことが起こった際に対応したときのメモを書いておきます。
「その2」以降があるかはわからないけど。

間違ってsvnのリポジトリ内のディレクトリを消してしまい、元に戻す方法svn copyで一つ前のリビジョンをコピーする
プロジェクトで間違ってリポジトリ内のディレクトリを消してしまった奴がいて、あわてて調べて以下のコマンドを実行
結構大きなリポジトリでも瞬殺で完了

  svn copy --revision XXX URL1 URL2

XXXは削除前のリビジョン番号
URL1は削除してしまったディレクトリのURL
URL2は削除してしまったディレクトリの親ディレクトリのURL