jjs

jjsを使う

先日まで、java7サーバで作業していたため、jrunscriptを利用していたけれども、
これから使うサーバはjava8。なのでjjsを利用する。

jjsでは新たなメソッドが定義されている。
なお、下記のメソッドを利用するためには、jjsをscriptingモードで実行する必要がある。
scriptingモードで実行するためには、2つの方法がある。

jjsの引数に-scriptingを指定する。

下記の通りスクリプトを呼び出す。

1
$ jjs -scrpting my-script.js

スクリプトファイルの先頭にShebangを書く。

上記のmy-script.jsの先頭行にShebangを書く。

1
2
3
4
#!/usr/bin/env jjs

print('my script start!');
//

Shebangが書かれているスクリプトは、jjsの引数に-scriptingを指定しなくても、
自動的にscriptingモードで実行される。
Windowsでjjsを動かす場合も、特に気にせずShebangを書けば良い。
しかし、WindowsではShebangは利用されないので、1行目に#のみ書いておけば良い。

scriptingモードでの便利機能

  • ヒア・ドキュメント
  • グローバルオブジェクト
  • コマンド実行
  • readFully()

ヒア・ドキュメント

scriptingモードではヒアドキュメントを利用できる。
sqlを格納したいときなど便利。

1
2
3
4
5
6
var sql = <<"SQL";
SELECT
    *
FROM
    TAB
SQL

グローバルオブジェクト

$ARG配列を参照することで、スクリプトの引数を参照できる。
なお、argumentsからでも同様に取得することができる。

$ENVオブジェクトを利用することで、環境変数を取得することができる。

1
2
print($ENV.ORACLE_HOME);
print($ENV['ORACLE_HOME']);

コマンド実行

$EXEC(‘ls -l’)を利用することで、ls -lを実行できる。
なお、出力される標準出力は$OUTに入っている。戻り値にも標準出力に入っている。エラー出力は$ERRに入る。
終了コードは$EXITに入る。
なお、コマンド呼び出しに失敗すると例外が飛ぶ。
コマンドを呼び出し、$EXITや$OUTを解析することで、ジョブ実行判定などができる。

readFully()

テキストファイルを読み込んで、変数に収めることができる。

1
2
var text = readFully('my-data.txt');
print(text);

テキスト読み込みが簡単にできる。当然、java.ioやjava.nioを利用して読み込んでも良い。

java8からnashornなので

java7のRhinoでは、Listをfor eachしても、Listオブジェクトのメソッドが取得できるだけだった。
java8のNashornでは、Listの中身でeachする。

1
2
3
4
5
6
7
8
9
10
11
var list = new java.util.ArrayList();
list.add('apple');
list.add('banana');
for (var i in list) {
    print(list[i]);
}
// listの中身が欲しいとき
var ite = list.iterator();
while (ite.hasNext()) {
    print(ite.next());
};

上記のスクリプトをjava7のjrunscriptで実行すると、forループではArrayListのメソッドリストが出力され、whileループでapple,bananaが出力される。
java8のjjs(jrunscript)では、forループもwhileループもapple,bananaが出力される。

無駄にイテレーターを作らなくても良いので、本来の実装のみに力を注ぐ事ができる。

注意

Nashornになり、importPackage()とimportClass()が廃止されている。
今後は、Java.type()を利用することになる。

1
2
3
4
var ArrayList = Java.type('java.util.ArrayList');
var list = new ArrayList();
list.add('Apple');
list.add('Banana');

JavaImporterは従来通り利用できる。
どうしてもimportPackage()、importClass()を利用したい場合は、組み込み互換性スクリプトをロードする。

1
2
3
4
5
load('nashorn:mozilla_compat.js');
importClass(java.util.ArrayList);
var list = new ArrayList();
list.add('Apple');
list.add('Banana');
同じタグの記事
同じカテゴリの記事

jrunscript

jrunscript

今更ながらjavaの組み込みjavascriptを試す。

javaのクラス(パッケージは)簡単に呼び出せる。

java標準のクラスは、特に気にすること無く、普通に呼び出せる。

1
2
java.lang.System.out.println('test message');
java.swing.JOptionPane.showMessageDialog(null, 'Test Message');

Java標準以外のクラスは、Packagesから始めて呼び出す必要がある。

1
2
var log = Packages.org.apache.commons.logging.LogFactory.getLog('my-script.js');
log.info('message');

上の例では、commons-loggingを利用しているので、jrunscript引数の-cpまたは-classpathで、commons-logging.jarとロガーを指定する必要がある。
クラスパスの指定で、jarを*でディレクトリごと指定することはできない。個別に.jarを羅列する。

Java標準クラスをPackagesから辿ることもできる。

1
2
java.lang.String.format('Test. %04.3f', 12.3);
Packages.java.lang.String.format('Test. %04.0f', 13);

なお、Javaでは何もしなくてもインポートされているjava.langは、jrunscriptではインポートされていない。
Object,Boolean,Stringなどがjavascriptとjavaで当たってしまうためらしい。

jrunscriptでもimportを行えば、クラス名だけでクラスを指定することができる。

1
2
importClass(java.util.ArrayList);
importPackage(javax.swing);

クラス毎のimportと、パッケージ単位のimportができる。
このimport方法だとスクリプト内のすべてで有効になってしまうため、不都合があるかもしれない。
そんなときは、JavaImporterを利用することで、狭い範囲のインポート宣言を行える。

1
2
3
4
5
6
7
var mylib = new JavaImporter(
    java.lang,
    javax.swing
);
with (mylib) {
    JOptionPane.showMessageDialog(null, String.format('Test. %s', 'NN'));
}

度々、String.formatのサンプルで書いているが、javascriptの数値はjavaのDoubleとして変換される。
したがって、String.formatでjavascriptの数値を変換するときはfを利用する。

jrunscriptでは、外部のjavascriptファイルを簡単に呼び出すことができる。

1
load('myCommon.js');

面倒な処理があるばあいは、共通処理として出しておければ良いと思う。
内部処理的には、ファイルを開いてevalしているらしい。

注意すべきところ

javaのメソッドを呼び出して返ってきたStringはあくまでもjava.lang.String。
したがって、javascriptの文字列との比較でアンマッチになることがある。
if (a == b) は、問題なく比較できる。
Arrayにpushし、indexOfで存在確認すると、アンマッチになった。

まとめ

結構、普通に使えた。
ただ、Java7に付属するRhinoでは、javaのリストのイテレートがが面倒。
Java8からのNashornになると、イテレートがfor inでできるようになるので使い易いと思う。

Javaクラスを呼び出せばなんでもできてしまうが、javascriptそのものが非力なため、ファイルの一覧を処理するような場合は、jythonを使ったほうがずっと手軽にできた。

ただ、まったく新しい言語を覚えなくても、公用語とも言えるjavascriptでjavaのAPIを自由に使えるのはとても良いと思った。

同じタグの記事
同じカテゴリの記事

All-in-One Media Keyboard

マイクロソフト All-in-One Media Keyboard

マイクロソフトのオールインワンのキーボード。
通常のキーボードのテンキー部分にタッチバッドがついている。
簡易なインターフェースとして、とても優れている。
テレビに挿してあるスティックPC用に購入した。

キーボード全体を大きくしたくなかったのか、キーの1つ1つが小さい。
タッチバッドは普通に動作する。しかし、タッチパッドはmacのようにガラス製ではなく、プラスチック製なのでチープ。

良いところ

  • 1つのUSBポートで、キーボードとポインティングデバイスが両方使える。
  • 無線なので、色々邪魔にならない。

残念なところ

  • 全体に小さい。
  • 全体にチープ。

まとめ

結局、スティックPCごと処分してしまった。

同じタグの記事
同じカテゴリの記事

High Sierraに更新したらgitコマンドが使えなくなった

High Sierraに更新したらgitコマンドが使えなくなった。

久々に、個人サイトの更新をしようと思い、git pullすると、エラーになった。

1
2
MacBookAir:program user$ git pull
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

atomのgitも動かない。

どうやら、Command Line Toolsが正常に動作しなくなったようだ。

次のコマンドを実行し、Command Line Toolsをインストールしたら、今まで通り動くようになった。

1
2
MacBookAir:program user$ xcode-select --install
xcode-select: note: install requested for command line developer Tools

なお、Command Line Toolsをインストールしたら、すぐにCommand Line Toolsのアップデートが来た。

同じタグの記事
  • ありません。
同じカテゴリの記事

macでスクリーンショットを撮る

macでスクリーンショットを撮る

macでもスクリーンショット(画面のハードコピー)を取得したい。

画面全体のスクリーションショット

control + command + 3

選択範囲のスクリーンショット

control + command + 4

選択したウィンドウのスクリーンショット

control + command + 4 からの Space

マウスカーソルがカメラに変わるので、スクリーンショットを取得したいウィンドウをクリックする。

同じタグの記事
  • ありません。
同じカテゴリの記事

サントリー登美の丘ワイナリー

サントリー登美の丘ワイナリーに行きました

とても良い天気

雲が幻想的

こっちの雲は清清しい

こっちの雲も悪くない

しかし雲のない空は美しい

同じタグの記事
  • ありません。
同じカテゴリの記事

花壇

花壇

黄色い花

白い花

紫の花

名前も知らない花だけど、これだけ並んでいると綺麗。

同じタグの記事
同じカテゴリの記事

たまには写真(夜)

たまには写真(夜)

縦位置で電車を狙う

横位置で電車がいなくなった後を、不思議な色の空と共に

夜は夜で色々美しい

5年以上前のカメラだけど、美しい写真を残せた。

同じタグの記事
同じカテゴリの記事

EclipseLinkでJPA

EclipseLinkでJPA

EclipseLinkを利用し、JPAでデータベース更新をしようと考えた。
サンプルを作成し、動かしてみたが下記のような課題が検出された。

実装について

  • データ登録(INSERT)

事前に作成しておいたEntityクラスのインスタンスを作成し、そのプロパティをセット→EntityManager.persist(entity)で
レコードの登録ができる。お手軽。
EntityTransaction.commit()を実行しないとデータ更新はされない。

  • データ更新(UPDATE)

更新対象レコードのEntityをEntitiManager.find(Entity.class, pk)で取得し、取得できたEntityのプロパティを更新するだけで、
レコードの更新ができる。お手軽。
更新はEntityManager.persistする必要もない。
EntityTransaction.commit()を実行すればよい。
登録のアクションが必要ないのは不安に思われることもあるかもしれないが、
エラー時はEntityManager.rollback()すれば更新されないので、更新忘れがなくて良い仕様だと思う。

  • データ削除(DELETE)

これもとても簡単。EntityManager.find()で取得したentityをEntityManager.remove(entity)するだけ。

  • データ取得(SELECT)

キーで取得するのは簡単。EntityManager.find(Entity.class, pk)で取得できる。簡単。
リストで取るときは、多少癖がある。
また、いくつか異なるアクセス方法がある。

1.SQLを使う方法
2.JPQLを使う方法
3.CriteriaQueryを使う方法

1.はコンパイラ警告が出るので使わないほうが良いかと思う。(SuppressWarningsして使ってもいいけど)
2.の方法がとっつきやすい気がする。
3.CriteriaQuery、Root、などなど、よくわからないクラスを使う。サンプルを見ながらでも、どのクラスがどの役割なのかわかりにくい。

  • Entity作成にあたって

Entityクラスを生成するのは結構面倒。
特に複合主キーの場合。キーのみをクラス(内部クラスでも可)として定義する必要がある。
JPAでは主キーを単一項目にすることが推奨されているらしい。
すでに複合キーのテーブルで検証したため、なかなか面倒だった。

1
2
3
4
5
6
7
CREATE TABLE T01 (
    C01 CHAR(10) NOT NULL,
    C02 CHAR(2) NOT NULL,
    C03 VARCHAR2(100),
    C04 VARCHAR2(100),
    PRIMARY KEY (C01, C02)
)

上記のテーブルの場合、Entityは下記のようになる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package entity;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

@Entity(name = "T01")
public class T01 {

    @EmbeddedId
    public PK pk;

    @Embeddable
    public static class PK {
        @Column(name = "C01", nullable = false)
        public String c01;

        @Column(name = "C02", nullable = false)
        public String c02;

        public boolean equals(Object obj) {
            PK tgt = (PK) obj;
            return c01.equals(tgt.c01) && c02.equals(tgt.c02);
        }

        public int hashCode() {
            return (c01 + c02).hashCode();
        }
    }

    @Column(name = "C03", nullable = false)
    public String c03;

    @Column(name = "C04", nullable = false)
    public String c04;
}

実行環境について

  • EclipseLinkのバージョン

最新バージョンは2.7.0。これはjava8以降で動作する。
あえてjava7で利用したい場合は、2.6.4を利用する。

  • Entityをjarファイルにまとめている場合

Entityクラスがjarファイルに入っている場合は、persistence.xmlに設定が必要。
classファイルのまま、クラスパスにおいてある場合は、@Entityのクラスを自動的に読んでくれる。

jarファイルに入っている場合は、

1.Entityクラスをとして宣言しておく。
これはすべてのクラスをここに書かなくてはならないので、追加・変更時のメンテンナンスがなかなか大変。

2.Entityクラスが入っているjarファイルをに宣言しておく。
これであれば、jarファイル内の@EntityのクラスをEntityとして自動的に読んでくれる。

ただし、jarファイルを参照するパスが独特なので注意する必要がある。
絶対パスで指定する場合は、あまり気にしなくてよいが、通常はディレクトリ構成に左右されないように相対パスで指定すると思う。

カレントディレクトリはクラスパスで最初に見つかったMETA-INF/persistence.xmlが存在するディレクトリとなる。
たとえば、top_dir/conf_dir/META-INF/persistence.xmlの様にpersistence.xmlが存在する場合、top_dir/conf_dirがカレントディレクトリとなる。
したがって、top_dir/libにエンティティが収められたjarが保存されていた場合、persistence.xmlには下記のように書く。
../lib/my_entities.jar
ここに宣言されたjarファイルはクラスパスを追って読むわけではないので注意が必要。

同じタグの記事
同じカテゴリの記事