09

IM-BISで外部連携のデータソースとしてJAVAの実装を追加する

掲題の件、やり方が分からないと社内で質問されて若干調査したので、その内容をメモ。

といっても基本的には以下の説明に従って実装すれば良い。

IM-BIS で外部連携として利用できるJavaプログラムの仕様(Java連携で呼び出し可能なクラス)

ただ上記の説明は若干理解しにくかった模様。 作成すべきクラスの要件としては

クラスのデフォルトコンストラクタを呼び出すことができること。

多分クラス名から newInstance() か何かでそのままインスタンスを作成するためかな。

クラス内にmainメソッドに該当する呼び出し可能なメソッドを、1つ以上用意してください。

main メソッドに該当というのが何を言いたいのか分からないのだが、単に public なメソッドという事のようだ。別に static でなくていい。というか、試していないけど多分 static ではダメなのではないか。

呼び出し可能なメソッドの引数、および戻り値については、「入出力オブジェクトの仕様」を確認してください。

参照先で述べているのは大体以下のようなこと

  • 引数は Map<String, Object>List<Object> 一つだけ。値の型が決まっているようなら、Objectではなくその型で良いのかもしれない。
  • 戻りは List<Object> のみ。 これも引数と同様。

作成するJavaプログラム内で、intra-martのAPIやサードパーティライブラリを利用して、プログラムを実行することができます。

ま、これはこの通り。

特に何かしらのインタフェースを実装するなどの必要はないので、シンプルなJavaのクラスで、上記のルールを守って書けば良い。作成したらJarにエクスポートして

${imart}/WEB-INF/im_bis/datasource/lib 

に配置。

あと多分、運用環境として構築してると上記のクラスを読み込もうとして失敗してもログとかでないみたいなんで、開発中は単体テスト環境で構築しておくべき。

多分サンプルコードと手順が示されていれば躓かなかったんだろうけど。 今回調査の為に書いた物は以下のようなもの。単純すぎて晒すのもためらうレベルではあるけど。

package test;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Test {

     public List<String> test(Map<String,Object> param){
          List<String> v = new ArrayList<String>();
          v.add("Hello");
          return v;
     }
}

どうしても管理画面で読み込めない場合は、再起動してみたりJarをResinのクラスパスの通っているところに複製してみるなどしてみてもいいかもしれない。が、これはあまり本質的ではないはず。

なお試したバージョンは intra-mart Accel Platform 2013 Winter (Felicia)

正月三ヶ日はPythonと格闘してた

ほんとは社内システムの糞コードと格闘するつもりだったけど、番組を変更してPythonの環境構築との格闘をお送りします。

書いたコードの量としては数十行程度の小さな物なんで大した物ではないんだけど、実装以外でほとんどの時間を消費した。 要件としてシングルページの Webアプリケーションと cron で動かす前提のバッチ処理的なコード数本なんだけど、最初Webページの方をよく知りもしないFlaskで書き始めて、バッチ処理がほとんどかけたところでWebアプリとバッチ処理でデータをDBで共有した方が良いという感じになってきた(もともとは単なるテキストファイルでやってた)。DBはsqliteで十分だとおもうんだけど、そうすると接続情報やなんやかやは双方で共有しておきたいし、モデルデータのハンドリングのコードなんかも共有したい。しかしFlaskは本当に薄いフレームワークでその辺というかDB周りはほとんどサポートしてない。となると、バッチ処理はDjangoでmanage.pyのコマンドを追加する形で実装したほうがきれいになるかもと思ってDjangoに移植した。移植自体はそんなに難しくはないんだけど、試行錯誤して時間を取られた(多分ドキュメントちょっとあっさりすぎる気がする)。 開発環境はPyCharmを使っていたので、開発についてはあまり気にすることはなく開発できたんだけど、とりあえずうちで借りてるサーバにデプロイしてみようと思ったら、まあPythonのバージョンが違ったりするので仮想環境いるよなーとか、Webアプリ配備するのは良いけど依存ライブラリの管理どうやんの?とか全く知らないから調べてたら全然進まない。

  • easy_installとpipとsetuptoolsとdistributeとか基本的なところで同じような役割のツールとかパッケージとかあるんだけど、こっちが新しい、とかこっちに統合された、とか情報が散らばってて結局名に使えば良いの、って感じになる。
    • easy_installでpipをインストールして以後easy_installを使わなければいいの?
    • distributeはsetuptoolsから分化してできたパッケージらしいけどマージされてsetuptoolsに戻ったらしい
  • 仮想環境はvirtualenv使えば良いらしいけどPythonは個別のバージョンごとに自分でインストールしなきゃならない。
    • pyenvにvirtualenvプラグイン入れればこの辺きれいに解決できるっぽい。
      • この場合に予めeasy_installとかpipとか入っている必要はあるんだろうか?
      • pyenv と pyenv-virtualenvが使えれば環境に関しては満足な感じする
  • 依存ライブラリの定義とセットアップに関してはsetup.pyつくってそこに依存先として定義してあればデプロイ先でもインストールしてくれる?

まだテストとか全く書いていないので、CI周りはこれからやってみようかな・・・という感じ。だけど、多分(内部的な制約により)Travisとかは使えないので、代替手段必要。jankinsはセットアップ簡単で良いんだけど重そうなのでちょっと避けたい気がしている。その辺も調査からやる感じかなあ。

そもそも、 ユニットテストもどう書けば良いんだ、と思って調べてみたらなんか色々あってどれ使えば良いの?状態になってはいる。複数あるソリューションから一つを選ぶ場合、「どれが最もコミュニティの活動が活発か」とか「どれが最も息が長そうか」といったことを気にしてしまうんだけど、そしてそんな事いくら気にしても正確な答えなんて出ない訳なんだけど、悩みに悩んで時間を浪費してしまうのがもうつらい。 そう考えるとRoRみたいなフレームワークがあるのって結構いいんだね・・・。

日頃使い慣れていればこの辺全く悩まなくていいんだろうけど、技術的に節操無くSIなんてやっていると、その「慣れ」を作る事ができない。おかげで毎回試行錯誤みたいな感じになるし、そもそも試行錯誤しなきゃいけないのにそこに先進的な取り組みを取り入れるとかするとさらに試行錯誤しなきゃいけなくなって、プロジェクトなんかだとリスクヘッジ考えるとまずやれない。その結果今回みたいに仕事に関係ないところで急に何かしようとすると毎回調査事項が多くなる。何か作りたいと思い立ったところでそもそも効果的な作り方がわかってないので短期間では何つくる力も無い、と、プログラマとしてはどんどん無能になっていくな。

CentOS 6.4 に Python 2.7環境を構築したい。

さくらインターネットでサーバ借りたらCentOSでPythonのバージョンが2.6.6だった。これに2.7の環境を作りたい。

最初virtualenv使えば良いのかなと思ったけど、virtualenvで仮想環境を作るにしても各バージョンのPythonは個別にインストールする必要がある・・・っぽい。で、その辺Python自体のインストールに関するサポートはvirtualenvには無いのかな。よくわからないけど。えー、と思って調べてみるとrbenvやplenvと同じように動くpyenvというのがあるらしいのでこっちを使ってみる事にした。 pyenvを使うと様々なバージョンのPythonのインストールもサポートしてくれるのだけど、単純に pyenv install 2.7.6 とかやってみても何かしらのライブラリが足りないとか言われてインストールできなかった。仕方ないので足りないものを追加する。以下入れたもの

  • yum install readline readline-devl
  • yum install bzip2-devel
  • yum install sqlite-devel

これで Python 2.7.6 をインストールできた。新しいバージョンのPythonをインストールしたら pyenv rehash を実行しておかなければならない。 ただ、これでバージョンの切り替えはできるけど、vitrualenvとは連携していなくて、仮想環境を作れない。探してみると pyenv に pyenv-vertualenv というプラグインがあるのでこれをインストールする。 これで仮想環境を作れるようになった。使い方はドキュメント見るべしな感じ。

Paramikoインストールするのに手間取る

Cent OS 6.4 で Pythonで ssh 接続したかった。 Paramikoというパッケージがいいらしいのでインストールしようとしたけど、うまく行かなかった。

結論から言うと Python-develパッケージが必要というだけ。

Paramiko が使用している PyCrypto というパッケージがあって、これをインストールするためにはPythonのヘッダファイルだかが必要になるらしい。

$ sudo yum install python-devel

こういうのなんか好きじゃないんだよなあ・・・・。

AngularJS お試し中

jQueryを使って書く事に大分慣れてきたのでがしがし書いていたのだけど、ここのところAngularJS が自分の観測範囲内において急に人気が出てきたのでちょっと試してみている。

データバインディングの領域ではAngularJSの前にKnockoutも調べてみたのだけど、Knockoutはなんかあまり好きになれないっぽい。AngularJSは http://rebuild.fm/27 でDIがきもいと言う話を聞いていたので深入りはしたくない感じではあったのだけど、Knockoutが気に入らないせいで調べてみる気になった感じ。

とりあえずドットインストールを見れば大枠は分かるみたい。

もともとjQueryで書いてたアプリを少しずつ書き換える感じで使って見ているのだけど、第一印象はちょっと良い。なぜ良いか?個人的にこういう枠組み系のプロダクトを導入すると理由が分からないエラーにはまって全く前に進まなくなったりする経験がとても多かったのだけど、それが全くなかった。調べて書けばちゃんと動く見たいな。すばらしいと言わざるをえない。すばらしい。

でもちょっとどうかなと思うところもある。jQueryの素晴らしさはDOMの検索や編集をごく少ない手数で実装できる点にあると思うのだけど、AngularJSを使っていると、jQuery.data() によるDOMノードからデータへのマッピングが実はとても重要だった気がしてくる。 AngularJSやKnockoutは双方向データバインディングを主要機能に上げているけれど、基本的に双方向なのはいわゆるフォーム関連のユーザ入力を受け付けるエレメントについてのみ(だと思う)。HTMLとJavascriptを駆使したいわゆるSPA(Single Page Application)ではdivやspanなどもユーザの入力を受け付けるコントロールになり得る。ノードをドラッグアンドドロップで移動させるなんて最近ではWebでも普通のUIだが、何をどこに(何番目の)ノードにドロップしたか、がユーザの編集データとして重要な意味を持っている。 つまりこういったノードに対する操作もイベントリスナでハンドリングするのではなくデータバインディングとして取り扱いたい。これがうまくやれないと結局ビューにイベントハンドラを書いてモデルを直接触るみたいなコードが消えない気がする。どうしたものかな。ディレクティブでうまくやれるんだろうか。

まだ作っている最中&学んでいる最中なので、気付きがあればまた書こうと思う。 今までのところ、コード書くときには以下のような順番でトピックを辿っている。

  • データバインディング
    • {{}}
      • model data -> dom
    • ng-model
      • model data -> form value
      • form value -> model data
  • ディレクティブ
    • ng-repeat
    • ng-click
    • ng-show
  • ディレクティブを作ってみる
    • エレメントの初期化処理みたいな感じで処理が呼ばれるみたい
    • 対象エレメントが渡されるので普通にjQueryを使って $(element).draggable() とかやるとドラッグできるようになる。
    • データバインディングのところで dom -> modeldata が無い事からも分かるように、ドロップされた後にその操作が何を表していたのかは自前でイベントハンドラを書いてモデルデータを変更する必要がありそう。
  • ngResource
    • Ajaxでデータ取ってくるらしい。
    • 細かいところは学習中・・・

ASP.NET デフォルトのレイアウトでハマり

聞いても誰得なハマりを共有するコーナーです

ASP.NET MVC4 (C#) のテンプレート生成して、jQueryとjQuery pluginを読み込んで(もちろんBundleConfigに定義の上)実行してみるんだけどもどうやってもpluginが読み込まれない。書き方はこんな感じ。

<div class=“gridster”>
  ….
</div>

@Scripts.Render(“~/bundles/jquery”);
@Scripts.Render(“~/bundler/jquery.gridster”);

<script text=“javascript”>
$(function(){
  $(“gridster ul”).gridster({ …. } ) // このgridsterでエラーになる
})
</script>

gridterを呼び出そうとするとエラー。Chromeのログなんかを見ても404とかエラーもないし、リソース自体は問題なく読み込まれているように見える。読み込み順序まで確認したりしていたのだけど、とくに問題になりそうな点は無い。

ASP.NET MVC4 (C#) のテンプレート(サンプル?)を生成すると、レイアウトファイルを使用した形の物になっている。レイアウトファイルって言うのは全体的にスタイルやデザインを統一できるようにヘッダとかフッタとなる枠(というかデザインテンプレート)が記述されていて、その枠の中にコンテンツを差し込めるポイントが定義されているもの。コンテンツの実体(つまりView)はこの枠に対して差し込む形で記述する。なのでViewのソースだけ気にしていると分からない点がある・・・・という事を、当初あまりよく理解していなかった。

たまたま生成されたレイアウトファイルを眺めていたらこのフッタ部分に

        @Scripts.Render("~/bundles/jquery")
        @RenderSection("scripts", required: false)

と記述されているのを見つけて、コンテンツの一番最後でjqueryが再読み込み(再初期化)されているらしい、という事に気がついた。おかげで一度読んだプラグインが消えてしまっていた、という事みたい。まさかこんな事になっているとは思っていなかったので全く原因に思い至らず3時間ほど無駄にしてしまった。

この記述に気づいてからコメントアウトしてみたらあっさり動いたのでふざけんなMS、と思ったんだけど、そもそもなんなのこれ、と思って調べたら(まあ何となくレイアウトの仕組みから想像してはいたんだけど)、要するにスクリプトはここ、scriptsセクションで動くようにViewの方を定義しろって事ですね。

Viewの方のスクリプトは以下のように書かないといけない。

@section scripts {
  @Scripts.Render(“~/bundler/jquery.gridster”);

  <script text=“javascript”>
  $(function(){
    $(“gridster ul”).gridster({ …. } )
  })
  </script>
}

これでようやく一歩進めた…。 けどここで使ってるgridster、IE10では動いているけど、なぜかChromeでは動かない。demoサイトではどちらも動いているので、なんか記述がおかしいんだろうけど、ほぼサンプルをコピペしてるだけだというのにこの苦痛・・・。