ITエンジニアの技術メモ

神奈川在住のITエンジニアの備忘録です。主にプログラミング(Perl, Java など)やネットワーク技術について、仕事などを通じて学んだことを自分の中で整理するためにゆるゆると書いています。ちゃんと検証できていない部分もあるのでご参考程度となりますが、誰かのお役に立てれば幸いです。

Windows10環境における「コマンドウィンドウをここで開く」

Windows7環境で良く使っていた、

エクスプローラー ⇒ シフト+右クリック ⇒ コマンドウィンドウをここで開く

がWindows10ではなくなっているので、ちょっと不便だなあと思って調べたところ、以下の記事を見つけた。

https://www.softantenna.com/wp/tips/windows-10-command-prompt-here/

 

これによると、エクスプローラーのロケーションバーに「cmd」と入力すれば同等のことができる。(試したところできた。)

また、レジストリを編集して、「コマンドウィンドウをここで開く」メニューを復活することもできるらしい。

JBossのjbm_* テーブル

JavaアプリケーションのアプリケーションサーバとしてJBossを使用している場合、JBossと連携するDBに jbm_* という名前のテーブルができる場合がある。これが何者なのか調べてみた。

この jbm_* テーブルは、JBoss上のアプリケーションが JMS (Java Messaging Service) を利用してメッセージの非同期通信をする際に、JBossがメッセージの情報を格納するために使用されるものらしい。

 

[参考]

https://stackoverflow.com/questions/3107767/purpose-of-jboss-tables

https://www.vanrish.com/blog/2013/10/08/jboss-messaging-configuration/

Javascriptのpromiseパターン

先日、JavaScript の promise パターンで書かれたコードに遭遇した。promise パターンについては、以下のページに詳しく書かれている。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises

https://blogs.msdn.microsoft.com/ie_jp/2011/10/04/promise-javascript/

 

このパターンを使うと、Javascriptで非同期処理を書くときにコードがシンプルになる。仕組みをざっくり説明すると、非同期処理を行う関数を発行した際、その関数から受け取った戻り値(promise)に対して、任意のタイミングで then(成功時のコールバック関数, 失敗時のコールバック関数) 関数を実行し、その時点で非同期処理が終わっていればコールバック関数が実行され、終わっていなければそこでwaitするというもの。

 

非同期処理発行時の戻り値をあとでチェックするという方式は、JavaのFutureパターンに似ているなあ、と思った。

https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/Future.html

以下は、参考として、以前JavaのFutureパターンを使って書いたサンプルプログラム。

https://akrad.hatenablog.com/entry/2018/04/25/220836

完全コンストラクタパターン

オブジェクト指向の勉強をしていて、「完全コンストラクタパターン」というものが出てきた。これは、オブジェクト生成時にコンストラクタに必要な情報を全て渡して、後からそのオブジェクトの状態(フィールド変数)を変更しない設計方式。つまり、オブジェクトのもととなるクラスについては、setter は持たず、フィールド変数の定義に final が付くことになる。

このパターンのメリットは、オブジェクト生成時点からオブジェクトの状態が変更されない、つまりイミュータブルなオブジェクトになるので、どこかでそのオブジェクトが変更されている可能性を気にする必要がなくなるし、意図せずオブジェクトの状態が変更されているということも起きなくなる。

オブジェクト生成時点で必要な情報が全て揃う場合に有用だと思う。

xcopyコマンドが実行できない。

先日、Windowsxcopyコマンドが実行できない環境に遭遇した。具体的には、xcopy コマンドを実行すると、以下が表示される。

'xcopy' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

 

このメッセージからは、xcopyコマンドへのパスが通っていないように見えて、「xcopy なんて基本的なコマンドへのパスが通っていないことなんてあるんだろうか・・?」と思って調べてみたら、以下の記事を見つけた。

http://d.hatena.ne.jp/dooluka/20101214/1292333925

どうやら、OS初期設定時のアカウント作成の方法次第では、xcopyコマンドがあるフォルダ (C:\windows\system32) が PATH 環境変数に入らない(パスが通らない)ことがある模様。

もしくは、ユーザが PATH 環境変数を編集する際、間違って PATH 環境変数から 「C:\windows\system32」を削除した可能性も考えられたが、結局どうして PATH環境変数がそのようになったのか、原因は分からなかった。

JavaのInetAddressクラスのメソッドで名前解決(逆引き)する時は正引きも行われている。

JavaのInetAddressクラスのgetHostName()やgetCanonicalHostName()で、IPアドレスからホスト名への名前解決(逆引き)を実行すると、裏で正引き(ホスト名⇒IPアドレス)も行われるようだ。詳細は以下の通り。

InetAddressクラスのソースを確認すると、getHostName()とgetCanonicalHostName()は、その延長でInetAddress#getHostFromNameService()をコールする。このgetHostFromNameService()の実装は以下になっている。

    private static String getHostFromNameService(InetAddress addr, boolean check) {
        String host = null;
        for (NameService nameService : nameServices) {
            try {
                // first lookup the hostname
                host = nameService.getHostByAddr(addr.getAddress());

                /* check to see if calling code is allowed to know
                 * the hostname for this IP address, ie, connect to the host
                 */
                if (check) {
                    SecurityManager sec = System.getSecurityManager();
                    if (sec != null) {
                        sec.checkConnect(host, -1);
                    }
                }

                // ★★
                /* now get all the IP addresses for this hostname,
                 * and make sure one of them matches the original IP
                 * address. We do this to try and prevent spoofing.
                 */

                InetAddress[] arr = InetAddress.getAllByName0(host, check);
                boolean ok = false;

                if(arr != null) {
                    for(int i = 0; !ok && i < arr.length; i++) {
                        ok = addr.equals(arr[i]);
                    }
                }
                // ★★

                //XXX: if it looks a spoof just return the address?
                if (!ok) {
                    host = addr.getHostAddress();
                    return host;
                }

                break;

            } catch (SecurityException e) {
                host = addr.getHostAddress();
                break;
            } catch (UnknownHostException e) {
                host = addr.getHostAddress();
                // let next provider resolve the hostname
            }
        }

        return host;
    }

(JDK 1.8 のInetAddressクラスのソースから抜粋)


上記の ★★ で囲んだ部分で、(名前解決の結果得た)ホスト名からIPアドレス群を取得し、取得したIPアドレス群の中に問い合わせの元となったIPアドレスが存在するか確認している。この処理は、ソースのコメントにもある通り、DNS spoofing対策のために入れらている。
つまり、Javaにおいて名前解決(逆引き)を行う時は正引きも実施され、逆引き・正引きの結果が不整合だと、名前解決に失敗するということになる。

JavaのURLの名前解決で、DNSの逆引きが発生しています。DNSの逆引きを抑止することはできますか?
という記事もあるし、Javaで名前解決処理を含むアプリケーションを動かす場合、正引きと逆引きの結果が一致する環境にした方がアプリケーションの動きは安定しそうな気がする。(まあ、Javaのアプリケーションに限らず、正引きと逆引きは一致させた方が予想外の挙動に悩まされなくて済みそう。)

J2EEのEntity Manager経由でDBから取得したオブジェクト

J2EEのEntity Manager経由でDBから取得したオブジェクトを、そのオブジェクトがEntity Managerの管理下にある状態の時に変更すると、それがDBに反映されるので注意が必要である。
例えば、

User user = entityManager.find(User.class, id);

として取得した user オブジェクトに対して、

user.setName("Taro");

とすると、この変更はトランザクション終了時などに自動的にDBに反映される。DBに反映されるタイミングについては、以下のページが分かりやすかった。
http://enterprisegeeks.hatenablog.com/entry/2015/01/19/142730
http://itref.fc2web.com/java/jpa/


上述のことを意識しておかないと、メモリ上のオブジェクトの情報を変更しただけのつもりで、実際にはその変更はDBにも反映されて「あれ?DBのデータは変更した覚えがないけど・・・」とかなってしまう。