Quantcast
Channel: プログラム の個人的なメモ
Viewing all 860 articles
Browse latest View live

【Java】【トラブル】Java で初回の暗号化/複合化処理に時間が掛かる

$
0
0

■ 現象内容

http://blogs.yahoo.co.jp/dk521123/34330480.html
http://blogs.yahoo.co.jp/dk521123/33640872.html
http://blogs.yahoo.co.jp/dk521123/36419973.html
http://blogs.yahoo.co.jp/dk521123/32780473.html
で、Javaの暗号化/複合化処理を実装したが、
以下の「■ サンプル」のように、処理時間を計測してみた。
結果は、以下「出力結果」になるのだが、初回にPCで大体1~1.5秒掛かる。
Raspberry PIやスマホなどの非力なデバイス上で実行した場合、更に掛かってしまう。

■ サンプル

以下の関連記事のサンプルを参考に時間計測のログを張ってみる
http://blogs.yahoo.co.jp/dk521123/34330480.html
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class Main {

  public static void main(String[] args) {
    try {
      String key = "1234567890123456";
      String original = "This is a source of string!!";
      String algorithm = "AES";

      System.out.println("[1]");
      long start = System.currentTimeMillis();
      String encrypedResult = CipherHelper.encrypt(original, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("暗号化文字列:" + encrypedResult);

      System.out.println("[2]");
      start = System.currentTimeMillis();
      String decryptedResult = CipherHelper.decrypt(encrypedResult, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("復号化文字列:" + decryptedResult);

      System.out.println("[3]");
      start = System.currentTimeMillis();
      String encrypedResult2 = CipherHelper.encrypt(original, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("暗号化文字列:" + encrypedResult2);

      System.out.println("[4]");
      start = System.currentTimeMillis();
      String decryptedResult2 = CipherHelper.decrypt(encrypedResult, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("復号化文字列:" + decryptedResult2);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  public static class CipherHelper {
    /**
     * 文字列を16文字の秘密鍵でAES暗号化してBase64した文字列で返す
     */
    public static String encrypt(String originalSource, String secretKey, String algorithm)
        throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException {

      byte[] originalBytes = originalSource.getBytes();
      byte[] encryptBytes = cipher(true, originalBytes, secretKey, algorithm);
      byte[] encryptBytesBase64 = Base64.getEncoder().encode(encryptBytes);
      return new String(encryptBytesBase64);
    }

    /**
     * Base64されたAES暗号化文字列を元の文字列に復元する
     */
    public static String decrypt(String encryptBytesBase64String, String secretKey, String algorithm)
        throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException {

      byte[] encryptBytes = Base64.getDecoder().decode(encryptBytesBase64String);
      byte[] originalBytes = cipher(false, encryptBytes, secretKey, algorithm);
      return new String(originalBytes);
    }

    /**
     * 暗号化/複合化の共通部分
     */
    private static byte[] cipher(boolean isEncrypt, byte[] source, String secretKey, String algorithm)
        throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
        BadPaddingException {
      byte[] secretKeyBytes = secretKey.getBytes();

      SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, algorithm);
      Cipher cipher = Cipher.getInstance(algorithm);
      if (isEncrypt) {
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
      } else {
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
      }

      return cipher.doFinal(source);
    }
  }
}

出力結果

[1]
Time:1478[ms] <=★約1~1.5秒かかる★
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[2]
Time:1[ms] <=☆1ミリ秒☆
復号化文字列:This is a source of string!!
[3]
Time:0[ms] <=☆1ミリ秒未満☆
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[4]
Time:0[ms] <=☆1ミリ秒未満☆
復号化文字列:This is a source of string!!

■ 原因

暗号化・複合化で使用している「Cipher.getInstance()」の初回に時間がかかるため。

# cipher.init()も若干時間がかかっている
計測のため、以下のようにログを打ち込む
・・・
long start = System.currentTimeMillis();
byte[] secretKeyBytes = secretKey.getBytes();
System.out.println("Time for secretKey.getBytes():" + (System.currentTimeMillis() - start) + "[ms]");

start = System.currentTimeMillis();
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, algorithm);
System.out.println("Time for new SecretKeySpec():" + (System.currentTimeMillis() - start) + "[ms]");

start = System.currentTimeMillis();
Cipher cipher = Cipher.getInstance(algorithm);
System.out.println("Time for Cipher.getInstance():" + (System.currentTimeMillis() - start) + "[ms]");

start = System.currentTimeMillis();
if (isEncrypt) {
  cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
} else {
  cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
}
System.out.println("Time for Cipher.init():" + (System.currentTimeMillis() - start) + "[ms]");
・・・
出力結果
[1]
Time for Base64.getEncoder().encode:1[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():3[ms]
Time for Cipher.getInstance():870[ms] <=!!注目!! ★ここに時間が掛かっている★
Time for Cipher.init():78[ms] <=★ここも多少時間が掛かっている★
Time for Cipher.doFinal():1[ms]
Time for Base64.getEncoder().encode:0[ms]
Time:958[ms]
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[2]
Time for Base64.getDecoder().decode:0[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():0[ms]
Time for Cipher.getInstance():0[ms]
Time for Cipher.init():0[ms]
Time for Cipher.doFinal():0[ms]
Time:1[ms]
復号化文字列:This is a source of string!!
[3]
Time for Base64.getEncoder().encode:0[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():0[ms]
Time for Cipher.getInstance():0[ms]
Time for Cipher.init():1[ms]
Time for Cipher.doFinal():0[ms]
Time for Base64.getEncoder().encode:0[ms]
Time:1[ms]
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[4]
Time for Base64.getDecoder().decode:0[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():0[ms]
Time for Cipher.getInstance():0[ms]
Time for Cipher.init():0[ms]
Time for Cipher.doFinal():0[ms]
Time:1[ms]
復号化文字列:This is a source of string!!

■ 対決案

 * システム起動時などにおいて、
   前もって(ダミー文字列でいいから)暗号化又は複合化処理をしておく

関連記事

暗号化/複合化する ~Apache Commonsを使用した場合~

http://blogs.yahoo.co.jp/dk521123/32780473.html

Java で暗号化/複合化する ~Java1.8 標準を使用した場合~

http://blogs.yahoo.co.jp/dk521123/34330480.html

Java で暗号化/複合化する ~Java1.8 標準を使用した場合 / IV使用編~

http://blogs.yahoo.co.jp/dk521123/36419973.html

Java で暗号化/複合化する ~標準ライブラリを使用した場合~

http://blogs.yahoo.co.jp/dk521123/33640872.html

【Linux】バックアップ ~ rsync / pdumpfs ~

$
0
0

■ はじめに

http://blogs.yahoo.co.jp/dk521123/36753771.html
で、ファイルサーバを構築したので、今度はバックアップを考える

バックアップ方法

[1] rsync
[2] pdumpfs

[1] rsync

 * Remote Synchronization(遠隔 同期)
 * 読み方は「アールシンク」?

特徴

 * ファイルを1つ1つコピーする
 * cpコマンドとの違いは、差分コピーが可能な点

構文

rsync [オプション] 【バックアップ元ディレクトリ】 【バックアップ先ディレクトリ】

構築

[1] インストール
[2] 設定ファイルの追加
[3] バックアップ
構築環境
 * OS : CentOS7
 * rsync : version 3.0.9
'構築手順
[1] rsync をインストールする

sudo yum -y install rsync

# 確認としてバージョンを表示する
rsync --version

[2] 設定ファイル「/etc/rsync_exclude.lst」 を追加する

sudo vi /etc/rsync_exclude.lst
~~~~
- /var/logs/* ← 「/var/logs/」のフォルダの中身をすべて(*)バックアップから除外
+ /var/samba/share/*** ← 「/var/samba/share/」のフォルダの中身をすべて(***)バックアップ対象とする
~~~~

[3] バックアップ

sudo rsync -avz  /etc/rsync_exclude.lst
`オプション`説明
`#
`オプション
1 -a --archive アーカイブモード 2 -v --verbose 転送情報を詳しく表示 3 -z --compress 受信ファイルを圧縮compress file data

[2] pdumpfs

特徴

 * ファイルを1つ1つコピーする
 * バックアップ先のディレクトリは日付で構成される


関連記事

【Linux】ファイルサーバの構築 ~ Samba ~

http://blogs.yahoo.co.jp/dk521123/36753771.html

【VMware】VMware vSphere Hypervisor(無償版ESXi) ~ データ移行編 ~

$
0
0

■ はじめに

 * VMware vSphere Hypervisor(無償版ESXi)でのデータ移行を考える

■ 概要

[1] SSHを有効にする
[2] 仮想マシンデータを引き上げ、移行する
[3] データ移行先のVMware ESXiで仮想マシンを登録する

■ 手順詳細

環境
 * 仮想環境 : VMware vSphere Hypervisor v6.5.0
 * 作業PC:Windows10
 * ファイル転送ソフト : WinSCP 5.9.4(※)

※インストールしていない場合は、事前にインストールしておくこと
http://blogs.yahoo.co.jp/dk521123/16726927.html

[1] SSHを有効にする

データ移行元と移行先のVMware ESXiのSSHを有効にする
[1-1] VMware のWeb UI にブラウザで、アクセスする

https://[VMware ESXiのIP]/ui

[1-2] 「ナビゲーター」欄内にある[ホスト]-[管理]-[サービス]-[TSM-SSH]を右クリックし、「起動」を選択
 => SSHが有効になった

[2] 仮想マシンデータを引き上げ、移行する

[2-1] ファイル転送ソフト「WinSCP」を起動する

[2-2] ログイン画面で以下の項目を入力し、「ログイン」ボタン押下
 * 転送プロトコル:SFTP
 * ホスト名:【データ元のVMware ESXiのIP】
 * ポート番号:22
 * ユーザ名:【ユーザ名(例「root」)】
 * パスワード:【ユーザ・パスワード】

[2-3] 右欄にある「/vmfs/volumes/datastoreX(X:1以上の数字)」のようにたどり、
      仮想データのフォルダを引き上げる

 /vmfs/volumes/datastore1/【仮想データのフォルダ】

[2-4] [2-1]~[2-2]のように、今度は、データ移行先のVMware ESXiのIPを入れログインし、
      [2-3]のデータを同等のフォルダ先「/vmfs/volumes/datastoreX(X:1以上の数字)」配下に置く
 => データ移行自体は完了

[3] データ移行先のVMware ESXiで仮想マシンを登録する

[3-1] データ移行先のVMware のWeb UI 上において、「ナビゲーター」欄内にある
      [ストレージ]-[データストア]-[データスト アブラウザ]-[datastoreX(X:1以上の数字)]-[【仮想データのフォルダ】]
      を選択し、「【仮想データ】.vmx」を右クリックし、「仮想マシンの登録」を選択し「閉じる」ボタン押下
 => 仮想マシン登録完了
[3-2] 確認のために、「ナビゲーター」欄内にある[仮想マシン]を選択し、
      移行した仮想マシンがあるか確認する

補足:自動起動について

[1] 「ナビゲーター」欄内にある[仮想マシン]を選択し、移行した仮想マシンを右クリックし、
    [自動起動]-[優先順位を上げる]を選択

【Linux】CentOS で、RAIDを構築するには...

$
0
0

はじめに

http://blogs.yahoo.co.jp/dk521123/36252928.html
で、CentOSをインストールしたが、RAIDを意識してインストールする

RAIDについては、以下の関連記事を参照のこと。
http://blogs.yahoo.co.jp/dk521123/34557792.html

構築例

環境

 * 仮想環境 : VMware vSphere Hypervisor v6.5.0(無償版)
 * 作成するOS : CentOS7
 * 作業PC:Windows10

構成

まず、初めにどのような構成で、どの位容量を割り当てるかを考える
`パーティション`マウントポイント
`#
`サイズ
`ファイルシステム `RAID 1 パーティション1 200Mバイト /boot xfs RAID1 2 パーティション2 512Mバイト スワップ スワップ なし 3 パーティション3 残り / xfs RAID5

構築手順

http://www.orangetakam.com/blog/archives/1000
を一読するといい
[0] 準備 (RAIDを組み練習のための環境設定で、必須の設定ではない)
[0-1] VMware のWeb UI にブラウザで、アクセスする

https://[VMware ESXiのIP]/ui

[0-2] Web UIの「ナビゲーター」欄内にある[仮想マシン]-[仮想マシンの作成/登録]を選択し、
      仮想マシンを作成する(作成した仮想マシンを「vm1」とする)
[0-3] 作成した仮想マシンを選択し、ブラウザ内を右クリックし、
      [設定の編集]-[ハードディスクの追加]-[新規ハードディスク]を選択
     (この手順[0-3]を、再度1回繰り返す)
[0-4] [設定の編集]-[CD/DVD ドライブ 1]で「データストア ISO ファイル」を選択し、
      LinuxのISO(今回の場合、CentOS7「CentOS-7-x86_64-DVD-1511.iso」)を指定する
[0-5] 仮想マシンを「パワーオン」し、Linuxのインストールを行う
[1] インストール
# 下記「トラブル」を一読しておくといい

[1] 言語、キーボードは、「日本語」を選択
[2] [インストール先]を選択し、「完了」ボタン押下
 2-1) 「ローカルの標準ディスク」内のディクスをすべて選択する(チェックが付くはず)
 2-2) [パーティション構成を行いたい]を選択
[3] 「+」押下し、上記の「構成」になるように作成
 * /boot
  + デバイスタイプ : RAID
  + RAIDレベル : RAID1
 * スワップ
  + デバイスタイプ : 標準パーティション
 * /
  + デバイスタイプ : RAID
  + RAIDレベル : RAID5

トラブル

画面で見えない部分がある

http://www.lesstep.jp/step_on_board/centos-7/737/
より

■解決案・手順
[1] CentOS 7のインストール画面において、「Install CentOS 7」選択状態でTABキー押下
# 60秒からカウントダウンされるので、その間に行う事

[2] quit の前に「resolution=1024x768(解像度は自分の環境に合わせる)」を入力して、
    ENTERキー押下

関連記事

Linux(仮想環境) を構築する ~CentOS編~

http://blogs.yahoo.co.jp/dk521123/36252928.html

【ストレージ】 RAID

http://blogs.yahoo.co.jp/dk521123/34557792.html

【Java】【Linux】JavaからLinuxのシステム日付を変更するには...

$
0
0

前準備

Linuxのシステム日付を変更する一つの方法として、dateコマンドを実行する必要があるが、
その場合、ルート権限が必要になる。
Java内でdateコマンドを実行しても、以下「エラー時の出力結果」のように表示されてしまい
日付変更できない。そのため、前準備として設定の変更が必要。

エラー時の出力結果

Result Code : 1
sudo: 端末 (tty) が存在せず、パスワードを尋ねる (askpass) プログラムが指定されていません
Done!

設定変更案

「sudo visudo」で、行末に「【実行ユーザ】 ALL=(ALL) NOPASSWD:ALL」に入れる

サンプル

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
  public static void main(String[] args) {
    execute("sudo", "date","--set","2017-03-14 23:02:15.962");
    System.out.println("Done!");
  }

  private static void execute(String... commands) {
    ProcessBuilder processBuilder = new ProcessBuilder(commands);
    // 標準エラー出力を標準出力にマージする
    processBuilder.redirectErrorStream(true);

    try {
      Process process = processBuilder.start();
      int result = process.waitFor();
      System.out.println("Result Code : " + result);

      try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
        String line;
        while ((line = bufferedReader.readLine()) != null) {
          System.out.println(line);
        }
      }
    } catch (IOException | InterruptedException ex) {
      ex.printStackTrace();
    }
  }
}

出力結果

Result Code : 0
2017年  3月 14日 火曜日 23:02:15 JST
Done!

参考文献

http://stackoverflow.com/questions/18682260/how-can-i-change-the-system-clock-of-a-linux-machine-by-using-java
「端末 (tty) が存在せず、パスワードを尋ねる (askpass) プログラムが指定されていません」関連
http://qiita.com/t_n/items/117d990c273b1d25a3a6

関連記事

【Java】 外部プログラム/コマンドを実行するには ~ ProcessBuilder ~ 修正

http://blogs.yahoo.co.jp/dk521123/34842155.html

【Linux】【Eclipse】Linux上で、Eclipse Neon をインストールする

$
0
0

環境

 * OS : CentOS7
 * Java : openjdk version "1.8.0_121"
 * Eclipse : Eclipse Neon2

手順

[1] 以下のサイトから「eclipse-inst-linux64.tar.gz」をダウンロードする
https://www.eclipse.org/downloads/
[2] 以下のコマンドで、解凍する

tar xavf eclipse-inst-linux64.tar.gz

 => ディレクトリ「eclipse-installer」があるはず。

[3] ディレクトリ「eclipse-installer」内に移動し、「eclipse-inst」をダブルクリックする
[4] インストーラが起動するので、インストールしていくだけ
 => 物凄い簡単にできた!

確認用 Hello World!

public class Main {
  public static void main(String[] args) {
    System.out.println("Hello World!");
  }
}

【Linux】特殊なアクセス権 ~ SUID / SGID / Sticky Bit ~

$
0
0

前提知識

セットID

 * 一時的に切り替えてプログラムを実行できる仕組み

■ SUID

 * SUID : Set User ID
 * 実行ファイルに設定される属性
 * 実行ファイルの所有者の権限で実行(どのユーザがファイルを実行しても、セットされたユーザで実行)

確認の仕方

ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 54192 11月 18  2015 /usr/bin/passwd
   ~
# 「s」になっているとSUIDが設定されていることを意味する

設定方法

sudo chmod u+s 【設定したいファイルのパス】

■ SGID

 * SGID : Set Group ID
 * 実行ファイル/ディレクトリに設定される属性
 * 実行ファイルは所有グループの権限で実行

設定方法

sudo chmod g+s 【設定したいファイルのパス】

# SUIDも付与したいなら...
#
# => sudo chmod ug+s 【設定したいファイルのパス】

■ Sticky Bit

 * スティッキービット
 * アクセス権に関係なくて、所有者とrootユーザのみが名前の変更と削除を行える

【Java】デーモンスレッド (Daemon Thread)

$
0
0

はじめに

スレッドには、以下の2種類ある。

1) デーモンスレッド ★今回、扱う事項★
2) ユーザスレッド ... デフォルト
API仕様
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Thread.html

デーモンスレッドとは?

 * プログラム終了のタイミングで、スレッド処理が破棄される

利点

 * 終了処理(後処理)を意識しないですむ

使用上の注意

 * スレッド内で、後処理が必要な処理(リソース破棄 (データベース接続、一時ファイルなど)
   を行う場合、使用を控える

作成方法

Thread thread = new Thread();
thread.setDaemon(true); // ★setDaemonにtrueをセット★
thread.start();

※ setDaemon()は、start()より先に呼ばないとダメらしい
http://hiratara.hatenadiary.jp/entry/20060725/1153838234

実験

(i) ユーザスレッドの場合

public class Main {

  public static void main(String[] args) {
    Thread thread = new Thread(() -> {
      for (int i = 0; i < 10; i++) {
        try {
          Thread.sleep(10L);
        } catch (InterruptedException ex) {
          ex.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
      }
    });
    //thread.setDaemon(true); // ★ユーザスレッド★
    thread.start();

    System.out.println("Done : " + thread.isAlive());
  }
}
出力結果 (スレッドが実行「Thread-0」されている)
Done : true
Thread-0
Thread-0
Thread-0
Thread-0
Thread-0
Thread-0
Thread-0
Thread-0
Thread-0
Thread-0

(ii) デーモンスレッドの場合

・・・
thread.setDaemon(true); // ★デーモンスレッド(上記のサンプルのコメントを外した)★
・・・
出力結果 (スレッドが実行されない)
Done : true


【Java】【トラブル】Java で初回の暗号化/複合化処理に時間が掛かる

$
0
0

■ 現象内容

http://blogs.yahoo.co.jp/dk521123/34330480.html
http://blogs.yahoo.co.jp/dk521123/33640872.html
http://blogs.yahoo.co.jp/dk521123/36419973.html
http://blogs.yahoo.co.jp/dk521123/32780473.html
で、Javaの暗号化/複合化処理を実装したが、
以下の「■ サンプル」のように、処理時間を計測してみた。
結果は、以下「出力結果」になるのだが、初回にPCで大体1~1.5秒掛かる。
Raspberry PIやスマホなどの非力なデバイス上で実行した場合、更に掛かってしまう。

■ サンプル

以下の関連記事のサンプルを参考に時間計測のログを張ってみる
http://blogs.yahoo.co.jp/dk521123/34330480.html
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class Main {

  public static void main(String[] args) {
    try {
      String key = "1234567890123456";
      String original = "This is a source of string!!";
      String algorithm = "AES";

      System.out.println("[1]");
      long start = System.currentTimeMillis();
      String encrypedResult = CipherHelper.encrypt(original, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("暗号化文字列:" + encrypedResult);

      System.out.println("[2]");
      start = System.currentTimeMillis();
      String decryptedResult = CipherHelper.decrypt(encrypedResult, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("復号化文字列:" + decryptedResult);

      System.out.println("[3]");
      start = System.currentTimeMillis();
      String encrypedResult2 = CipherHelper.encrypt(original, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("暗号化文字列:" + encrypedResult2);

      System.out.println("[4]");
      start = System.currentTimeMillis();
      String decryptedResult2 = CipherHelper.decrypt(encrypedResult, key, algorithm);
      System.out.println("Time:" + (System.currentTimeMillis() - start) + "[ms]");
      System.out.println("復号化文字列:" + decryptedResult2);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  public static class CipherHelper {
    /**
     * 文字列を16文字の秘密鍵でAES暗号化してBase64した文字列で返す
     */
    public static String encrypt(String originalSource, String secretKey, String algorithm)
        throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException {

      byte[] originalBytes = originalSource.getBytes();
      byte[] encryptBytes = cipher(true, originalBytes, secretKey, algorithm);
      byte[] encryptBytesBase64 = Base64.getEncoder().encode(encryptBytes);
      return new String(encryptBytesBase64);
    }

    /**
     * Base64されたAES暗号化文字列を元の文字列に復元する
     */
    public static String decrypt(String encryptBytesBase64String, String secretKey, String algorithm)
        throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException {

      byte[] encryptBytes = Base64.getDecoder().decode(encryptBytesBase64String);
      byte[] originalBytes = cipher(false, encryptBytes, secretKey, algorithm);
      return new String(originalBytes);
    }

    /**
     * 暗号化/複合化の共通部分
     */
    private static byte[] cipher(boolean isEncrypt, byte[] source, String secretKey, String algorithm)
        throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
        BadPaddingException {
      byte[] secretKeyBytes = secretKey.getBytes();

      SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, algorithm);
      Cipher cipher = Cipher.getInstance(algorithm);
      if (isEncrypt) {
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
      } else {
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
      }

      return cipher.doFinal(source);
    }
  }
}

出力結果

[1]
Time:1478[ms] <=★約1~1.5秒かかる★
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[2]
Time:1[ms] <=☆1ミリ秒☆
復号化文字列:This is a source of string!!
[3]
Time:0[ms] <=☆1ミリ秒未満☆
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[4]
Time:0[ms] <=☆1ミリ秒未満☆
復号化文字列:This is a source of string!!

■ 原因

暗号化・複合化で使用している「Cipher.getInstance()」の初回に時間がかかるため。

# cipher.init()も若干時間がかかっている
計測のため、以下のようにログを打ち込む
・・・
long start = System.currentTimeMillis();
byte[] secretKeyBytes = secretKey.getBytes();
System.out.println("Time for secretKey.getBytes():" + (System.currentTimeMillis() - start) + "[ms]");

start = System.currentTimeMillis();
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, algorithm);
System.out.println("Time for new SecretKeySpec():" + (System.currentTimeMillis() - start) + "[ms]");

start = System.currentTimeMillis();
Cipher cipher = Cipher.getInstance(algorithm);
System.out.println("Time for Cipher.getInstance():" + (System.currentTimeMillis() - start) + "[ms]");

start = System.currentTimeMillis();
if (isEncrypt) {
  cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
} else {
  cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
}
System.out.println("Time for Cipher.init():" + (System.currentTimeMillis() - start) + "[ms]");
・・・
出力結果
[1]
Time for Base64.getEncoder().encode:1[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():3[ms]
Time for Cipher.getInstance():870[ms] <=!!注目!! ★ここに時間が掛かっている★
Time for Cipher.init():78[ms] <=★ここも多少時間が掛かっている★
Time for Cipher.doFinal():1[ms]
Time for Base64.getEncoder().encode:0[ms]
Time:958[ms]
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[2]
Time for Base64.getDecoder().decode:0[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():0[ms]
Time for Cipher.getInstance():0[ms]
Time for Cipher.init():0[ms]
Time for Cipher.doFinal():0[ms]
Time:1[ms]
復号化文字列:This is a source of string!!
[3]
Time for Base64.getEncoder().encode:0[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():0[ms]
Time for Cipher.getInstance():0[ms]
Time for Cipher.init():1[ms]
Time for Cipher.doFinal():0[ms]
Time for Base64.getEncoder().encode:0[ms]
Time:1[ms]
暗号化文字列:B/UZj3IF6F6tObxiTAqdDsDLxUKGCBuAYjVTQP1GSnI=
[4]
Time for Base64.getDecoder().decode:0[ms]
Time for secretKey.getBytes():0[ms]
Time for new SecretKeySpec():0[ms]
Time for Cipher.getInstance():0[ms]
Time for Cipher.init():0[ms]
Time for Cipher.doFinal():0[ms]
Time:1[ms]
復号化文字列:This is a source of string!!

■ 対決案

 * システム起動時などにおいて、
   前もって(ダミー文字列でいいから)暗号化又は複合化処理をしておく

関連記事

暗号化/複合化する ~Apache Commonsを使用した場合~

http://blogs.yahoo.co.jp/dk521123/32780473.html

Java で暗号化/複合化する ~Java1.8 標準を使用した場合~

http://blogs.yahoo.co.jp/dk521123/34330480.html

Java で暗号化/複合化する ~Java1.8 標準を使用した場合 / IV使用編~

http://blogs.yahoo.co.jp/dk521123/36419973.html

Java で暗号化/複合化する ~標準ライブラリを使用した場合~

http://blogs.yahoo.co.jp/dk521123/33640872.html

【AWS】人工知能サービス「Amazon AI」 ~ 知識編 ~

$
0
0

Amazon AI

以下は、あくまで、2017/03/29時点では情報
人工知能サービス「Amazon AI」として以下の3つのサービスがある

[1] Amazon Polly : テキスト読み上げ機能
[2] Amazon Rekognition : 画像解析 / 画像認識機能
[3] Amazon Lex : 会話型インタフェース機能

※ 上記のいずれのサービスについて、2017/03/29時点では、東京リージョンでは未サポート

[1] Amazon Polly

 * テキストを音声に変換するサービス
 => テキストを渡すと、MP3のストリームとして音声生成
 * 47の男女バリエーション
 * 日本語対応済 (26言語対応)

音声合成マークアップ言語(SSML)

 * 音声合成マークアップ言語(SSML; Speech Synthesis Markup Language)により、
   テキストを読み上げる際の声量や発音、音の高低、速さをXML形式で制御可能

レキシコン(Lexicon)

 * レキシコン(PLS; Pronunciation Lexicon Specification = 発音辞書仕様)により、
   指定した単語の読み上げをカスタマイズできる

参考文献

https://aws.amazon.com/jp/blogs/news/polly-text-to-speech-in-47-voices-and-24-languages/
https://aws.amazon.com/jp/polly/
http://docs.aws.amazon.com/ja_jp/polly/latest/dg/polly-dg.pdf
一般サイト
https://recipe.kc-cloud.jp/archives/9294
https://recipe.kc-cloud.jp/archives/8971

[2] Amazon Rekognition

 * 画像解析
  => 画像内の「物体識別(例:人、動物、物など)」や「シーン検出(例:夕焼け、ビーチなど)」を特定
 * 顔分析
  => 「性別」「表情」「感情」
 * 顔比較
  => 画像の顔が同一人物かどうか
 * 顔認識機能
  => 大量の画像から似た顔を検出可能

参考文献

https://aws.amazon.com/jp/blogs/news/amazon-rekognition-image-detection-and-recognition-powered-by-deep-learning/
https://aws.amazon.com/jp/rekognition/

[3] Amazon Lex

* 2017/03/29時点では、日本語未対応
 * 対話的なアプリケーション構築が可能

主要コンセプト

飛行機のチケットを例にするとわかりやすい
 * Bot : 会話の全てのコンポーネントを含む bot
 * Intent(意図) : ユーザーがやりたいこと/達成したいゴール (例:飛行機のチケットを買う)
 * Slot : Intentを満たすためにユーザーが提供しなければならないパラメータ(例:都市、州、空港)
 * Utterance(発話) : Intent実現のためのユーザーの発言(入力)文のサンプル (例:飛行機を予約したい)
 * Prompt : ユーザーに変数の提供をうながすための質問文

参考文献

https://aws.amazon.com/jp/blogs/news/amazon-lex-build-conversational-voice-text-interfaces/

【トラブル】【Java】Commons インポートしてるけど、ClassNotFoundExceptionが発生する

$
0
0

■ トラブル内容

 * Commons の RandomStringUtils をラップした自作の共通処理を
   まとめたJavaプロジェクト「CustomCommon」をJARファイル化し、
   そのJARファイルを、Javaプロジェクト「SampleProject」で使用したところ、
   以下の「例外内容」の例外「ClassNotFoundException」が発生した。
   なお、プロジェクト「SampleProject」には「commons-lang3-3.5.jar」をインポートしてある
    => 詳細は、以下の「構成」を参照。
 * Javaプロジェクト「CustomCommon」内で例外が発生したメソッドを使用しても例外が発生しなかった

例外内容

Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang.RandomStringUtils
	at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 2 more

構成

 + Javaプロジェクト「CustomCommon」(JAR化する「CustomCommon.jar」) ★自作の共通処理★
    + src
       + PasswordCustomUtil.java
    + lib
       + velocity-1.7-dep.jar
        など...
 + Javaプロジェクト「SampleProject」 ★使用者側★
    + src
       + Main.java(PasswordCustomUtil.javaを使用)
    + lib
       + CustomCommon.jar
       + commons-lang3-3.5.jar
PasswordCustomUtil.java
import org.apache.commons.lang.RandomStringUtils;

public class PasswordCustomUtil {
  public static String creatNumberInitPassword() {
     return RandomStringUtils.random(4, "0123456789");
  }
}

■ 原因

 自作の共通処理「CustomCommon」で使用していた「RandomStringUtils」は、
  velocity-1.7-dep.jar内に入っているcommons-lang2系「org.apache.commons.lang.RandomStringUtils」を使用している
 
  しかし、使用者側のJavaプロジェクト「SampleProject」では、commons-lang3系のJARファイルをインポートしていたため。

  commons-lang3系だと「org.apache.commons.lang3.RandomStringUtils」で
 「lang3」ってなって、パッケージ名がcommons-lang2系とはそもそも異なる。

補足:velocity-1.7-dep.jarについて

https://blogs.yahoo.co.jp/dk521123/34456704.html
より抜粋

「依存関係のあるツールも含まれたJARファイル」
  => commons-lang2系が含まれている

■ 解決案

 * commons-lang2系「commons-lang-2.X.jar」又は「velocity-1.X-dep.jar」を
   使用者側のJavaプロジェクトにインポートする

関連記事

【Java】 セキュアなランダム文字列生成を考える

https://blogs.yahoo.co.jp/dk521123/36415526.html

【Java】【Velocity】Apache Velocity ~入門編~

https://blogs.yahoo.co.jp/dk521123/34456704.html

【AWS】AWS CLIでAmazon S3を操作する

$
0
0

■ AWS CLIでS3を操作する

 * EC2からAWS コマンドラインインターフェイス (AWS CLI) により、
   Amazon S3にデータ更新、同期を行う
 * Amazon S3について、以下の関連記事を参照のこと。
https://blogs.yahoo.co.jp/dk521123/36747691.html
 * AWS CLIについて、以下の公式サイトを参照のこと。
https://aws.amazon.com/jp/cli/

■ 手順

 * Hello World的なことを行ってみる

概要

[1] S3 バケットの作成
[2] IAMを設定する
[3] EC2に最新の AWS CLIをインストールする
[4] AWS CLI でAmazon S3にファイルをアップロード/同期させる

前提条件

 * EC2(Amazon Linux)が作成されていること(以下の関連記事を参照のこと)
https://blogs.yahoo.co.jp/dk521123/36711839.html

[1] S3 バケットの作成

[1-1] AWSログイン後に [S3]-[バケット作成]を選択
[1-2] 以下を入力し、「作成」ボタン押下
  + バケット名:任意(!!注意!!「グローバルでユニーク」である文字列を入力すること)
  + リージョン:東京

[2] IAMを設定する

AWS Identity and Access Management (IAM) について、以下の関連記事を参照のこと。
https://blogs.yahoo.co.jp/dk521123/36731712.html
[2-1] AWSログイン後に [IAM]-[ユーザ]-[新規ユーザー作成]を選択
[2-2] 任意のユーザー名を入力し、「作成」ボタン押下
[2-3] 「表示」で「アクセスキーID」「シークレットアクセスキー」をコピーしたりして取っておく(後で使う)
[2-4] [IAM]-[ユーザ]で手順[2-2]で作成したユーザー名を選択する
[2-4] [

[3] EC2に最新の AWS CLIをインストールする

[3-1] EC2にTera TarmなどのSSHクライアントでログインアクセスし、
      以下のコマンドを入力し、既存のAWS CLIを一旦アンインストール
~~~~
sudo yum remove -y aws-cli
~~~~

[3-2] 以下のコマンドを入力し、最新のAWS CLIをインストール
~~~~
sudo pip install awscli
~~~~

[3-3] 環境変数 PATH を設定する
~~~~
export PATH=$PATH:/usr/local/bin/
~~~~
環境変数を永続的に行うなら以下のサイトを参照
http://pocketstudio.jp/linux/?%A5%D1%A5%B9(PATH)%A4%CE%B3%CE%C7%A7%A4%C8%C0%DF%C4%EA%CA%FD%CB%A1%A4%CF%A1%A9
http://d.hatena.ne.jp/Akineko/20090825/1251187210
}}}

[3-4] 「aws configure」コマンドで入力し、
手順[2-3]で表示された「アクセスキーID」「シークレットアクセスキー」などを入力する
~~~~
aws configure
AWS Access Key ID [None]: [アクセスキーIDを入力]
AWS Secret Access Key [None]: [シークレットアクセスキーを入力]
Default region name [None]: ap-northeast-1 (東京リージョン)
Default output format [None]: [(何も入力せずに)Enterキー押下]
~~~~
}}}

[4] AWS CLI でAmazon S3にファイルをアップロード/同期させる

[4-1] EC2にTera TarmなどのSSHクライアントでログインアクセスし、
      準備として、以下のコマンドを入力
~~~~
# 作業用ディレクトリ「sample」を作成する
mkdir sample

# 作業用ディレクトリ「sample」に移動
cd sample

# S3にアップロードするファイル「hello.txt」を作成する
echo hello >> hello.txt

# hello.txtがあるか確認する
ls
~~~~

[4-2] aws s3コマンドでAmazon S3を操作する
`コマンド
`#
説明
1aws s3 ls s3://【S3のバケット名】 一覧表示
2aws s3 cp <コピー元> <コピー先> コピー
3aws s3 sync <同期元> <同期先> 同期
その他のコマンドは以下のサイトを参照のこと
http://www.task-notes.com/entry/20150904/1441335600
コピーする(アップロード)
~~~~
# S3内のファイルを一覧表示する(何もないはず)
aws s3 ls s3://【手順[1-2]のS3のバケット名】

# hello.txtをS3内にコピーする(アップロード)
aws s3 cp ./hello.txt s3://【手順[1-2]のS3のバケット名】

# S3内のファイルを一覧表示する(「hello.txt」が表示されるはず)
aws s3 ls s3://【手順[1-2]のS3のバケット名】
~~~~
同期
~~~~
# hello.txtに「World」を追記
echo World >> hello.txt

# hello.txtの内容を表示する
less hello.txt
------
hello
World
------

# 同期する(同期後、S3内の「hello.txt」を確認してみると「hello<改行>World」)
aws s3 sync ./ s3://【手順[1-2]のS3のバケット名】

# hello.txtを削除する
rm ./hello.txt

# 同期する
aws s3 sync --delete ./ s3://【手順[1-2]のS3のバケット名】

# S3内のファイルを一覧表示する(何もないはず)
aws s3 ls s3://【手順[1-2]のS3のバケット名】
~~~~

関連記事

AWS(Amazon Web Services) ~ 入門編 / S3 ~

https://blogs.yahoo.co.jp/dk521123/36747691.html

AWS(Amazon Web Services) ~ 入門編 / EC2作成 ~

https://blogs.yahoo.co.jp/dk521123/36711839.html

IAM (Identity and Access Management)

https://blogs.yahoo.co.jp/dk521123/36731712.html

【AWS】AWSで自動デプロイを考える

$
0
0

■ デプロイ自動かで考えたい事項

 * 誰にでもできること(手数が少なく、誰でも行うことが理想)
 * ロールバックできること
 * 開発環境/ステージング環境/本番環境(プロダクション環境)の切り替えが容易に行える
etc

■ 利用できそうなサービス

[1] AWS CodeDeploy
[2] AWS Elastic Beanstalk
[3] AWS OpsWorks
etc

[1] AWS CodeDeploy

 * Amazon EC2 インスタンスへのコードのデプロイを自動化するサービス

公式サイト

https://aws.amazon.com/jp/codedeploy/
https://aws.amazon.com/jp/codedeploy/getting-started/

[2] AWS Elastic Beanstalk

 * コードをアップロードするだけで、プロビジョニング、ロードバランシング、Auto Scaling から
   アプリケーションの状態モニタリングまで、デプロイを自動処理する

公式サイト

https://aws.amazon.com/jp/elasticbeanstalk/



関連記事

AWSクラウドデザインパターン (CDP)

以下が関連
 * Stampパターン(サーバの複製)
 * Bootstrapパターン(起動設定の自動取得
https://blogs.yahoo.co.jp/dk521123/36747769.html

【AWS】Amazon S3 ~ バージョニング編 ~

$
0
0

はじめに

https://blogs.yahoo.co.jp/dk521123/36799017.html
の続き。
ファイルのバージョン管理できるようにする

バージョニングについて

http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/Versioning.html

■ 手順

前提条件

 * 以下の関連記事で行ったAWS CLIを行っていること
https://blogs.yahoo.co.jp/dk521123/36799017.html

[1] S3 バケットにバージョニングを設定する

[1-1] AWSログイン後に [S3]を選択し、対象のバケットを選択する
[1-2] [プロパティ]-[Versioning]-[バージョニングの有効化]を選択し、「保存」ボタン押下

[2] ファイルの追加と同期

# hellos3.txtを追記
echo HelloS3 > hellos3.txt

# hellos3.txtをS3内にコピーする(アップロード)
aws s3 cp ./hellos3.txt s3://【対象S3のバケット名】

# 追記
echo HelloVerisoning >> hellos3.txt

# 同期する
aws s3 sync ./ s3://【対象S3のバケット名】

⇒ S3のバケットを確認すると、ファイルのバージョン管理できている

■ ライフスタイルを設定する

[1] AWSログイン後に [S3]を選択し、対象のバケットを選択する
[2] [管理]-[ライフサイクルルールの追加]を選択
[3] 「ライフサイクル」において、以下のように入力し「次へ」ボタン押下
 + ルール名を入力する:任意の文字列
 + フィルタを追加してプレフィックス/タグのみを対象する:.txt
[4] 以下のように入力し「次へ」ボタン押下し、「保存」ボタン押下
 + 「以前のバージョン」にチェック
 + 「前のバージョンを完全削除」にチェック
 + 次の後:「1」日間以前のバージョンになってからの日数

関連記事

AWS(Amazon Web Services) ~ 入門編 / S3 ~

https://blogs.yahoo.co.jp/dk521123/36747691.html

AWS CLIでAmazon S3を操作する

https://blogs.yahoo.co.jp/dk521123/36799017.html

【分散リポジトリ】【HG】【Linux】 Mercurial(HG) ~リポジトリ作成編~

$
0
0

■ コマンド

hg init 【リポジトリ対象のパス】

前提条件

 * 以下の関連記事でHG環境を構築してあること
http://blogs.yahoo.co.jp/dk521123/36290337.html
【環境】
 * OS          : CentOS 7.2.1511
 * HTTP Server : Apache HTTP Server 2.4.6
 * Mercurial   : Mercurial 2.6.2
【構成】
usr/local
 + hg
   + htdocs ... ディレクトリ(この配下にリポジトリを管理)

■ 手順

【1】プロジェクトを作成する
# 1-1) プロジェクト名「SampleProject」を作成する
sudo mkdir /usr/local/hg/htdocs/SampleProject

# 1-2) プロジェクト名「SampleProject」の所有者を「apache」に変更
sudo chown -R apache:apache /usr/local/hg/htdocs/SampleProject
【2】リポジトリを作成する
sudo -u apache hg init /usr/local/hg/htdocs/SampleProject

関連記事

Mercurial(HG) ~入門編~

http://blogs.yahoo.co.jp/dk521123/36067390.html

Mercurial(HG) ~環境構築編~

http://blogs.yahoo.co.jp/dk521123/36290337.html

【AWS】サーバレス アーキテクチャ / Lambda ~ 知識編 ~

$
0
0

■ サーバレス アーキテクチャ(Serverless Architecture)

 * ユーザは、サーバを意識せずに、利用可能なサービスを活用できるアーキテクチャ
  => サーバを必要としないわけではないらしい

主なサービス名

 * AWS Lambda(アマゾン)
 * Azure Functions(マイクロソフト)
 * Google Cloud Functions(グーグル)
 * OpenWhisk(IBM)

■ 関連用語

PaaS(Platform as a Service)

 * リクエストリプライ方式(リクエストごとにアプリケーション全体を起動・終了)

FaaS(Function as a Service)

AWS Lambdaが該当
 * イベントドリンブン方式(必要なサービス毎に起動・終了)

■ AWS Lambda

 * Lambda:ラムダ

利点

 * サーバー/インフラ管理が不要
 * スケールについて、運用者が考える必要がない

料金体系

 * プログラムを実行した「時間(100ミリ秒単位)」×「回数」で課金
  => 使わなかったら、お金は掛からない(使った分だけ払えばいい)

公式サイト

http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html

【Eclipse】Eclipse/Antで、SSHを使ってファイル転送/実行を行う

$
0
0

使用するAntタスク

scpタスク

 * scpコマンド(※)を利用して、ファイル転送する

 ※ sshを利用してリモートマシン間でファイルコピーするコマンド
構文
<scp todir="【ユーザ】:【パスワード】@【ホスト/IP】:【パス】" port="【実行するポート】"
  trust="true" file="【ファイル転送するファイルパス】" />

sshexecタスク

 * ssh経由でコマンド実行する
構文
<sshexec username="【ユーザ】" password="【パスワード】" host="【ホスト/IP】" port="【実行するポート】"
 trust="yes" command="【実行コマンド1】; 【実行コマンド2】;・・・ 【実行コマンドX】;" />

設定手順

 * Eclipseでの設定を行う

前提条件

 * Eclipse をインストールしてある

手順

[1] 以下のサイトから 最新の jsch をダウンロードする(今回は「jsch-0.1.54.jar」)
http://mvnrepository.com/artifact/com.jcraft/jsch
[2] Eclipseを起動し、[Window]-[Preferences]-[Ant]-[Runtime]-[Classpath]-[Ant Home Entities(Default)]
    -[Add External JARS]を選択し、[1]でダウンロードしたJARファイルを指定する

サンプル

設定環境

 * OS : Windows10
 * Java : Java1.8
 * Eclipse : Eclipse Nano1
 * jsch : jsch-0.1.54.jar
 * デプロイ先のOS : CentOS7

build.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?><project basedir="." default="helloworld" name="Demo"><!-- HOST --><property name="connect.host" value="XXX.XXX.XXX.XXX" /><!-- User --><property name="connect.user" value="root" /><!-- Password --><property name="connect.pwd" value="password" /><!-- SSH Port --><property name="connect.port" value="22" /><property name="shell.path" location="${basedir}/etc/helloworld.sh" /><!--  --><target name="helloworld"><!-- SCP送信 --><echo message="path = ${shell.path}" /><scp todir="${connect.user}:${connect.pwd}@${connect.host}:/root/" port="${connect.port}"
      trust="true" file="${shell.path}" /><!-- SSH実行 --><sshexec username="${connect.user}" password="${connect.pwd}" host="${connect.host}"
      port="${connect.port}" trust="yes" command="chmod +x ~/helloworld.sh; ~/helloworld.sh" /></target></project>

helloworld.sh

echo "Hello World!"

出力結果

Antを実行するために、「build.xml」を右クリックし、[Run]で実行する
Buildfile: C:\workspace\Demo\build.xml
helloworld:
     [echo] path = C:\workspace\Demo\etc\helloworld.sh
      [scp] Connecting to XXX.XXX.XXX.XXX:22
      [scp] done.
  [sshexec] Connecting to XXX.XXX.XXX.XXX:22
  [sshexec] cmd : chmod +x ~/helloworld.sh; ~/helloworld.sh
  [sshexec] Hello World!
BUILD SUCCESSFUL
Total time: 6 seconds

トラブルシューティング

Antを実行後に、エラーが表示する

エラー内容
Variable references non-existent resource : ${workspace_loc:/Tomcat/build.xml}.
解決案
 * Eclipseを起動し、[Window]-[Preferences]-[Ant]-[Runtime]-[Classpath]-[Ant Home Entities(Default)]
   で「${workspace_loc:/Tomcat/build.xml」があるので、選択した状態で「Remove」ボタン押下し
  「OK」ボタン押下

【Java】【Swing】 jLabel の折り返しを考える [1]

$
0
0

jLabel の折り返しを考える

jLabelのデフォルトだと表示領域を超えると「ああ...」ってなってしまうので、折り返しを考える
1) <br>を入れる
2) 独自で実装する

1) <br>を入れる

お手軽にできる
JLabel jLabel = new JLabel("<html>改行前<br>改行後<html>");

2) 独自で実装する

 * paintComponent() をオーバーライドして計算して折り返しを実装する

サンプル

http://ateraimemo.com/Swing/GlyphVector.html
を参考に実装(ただし、気になる点あり)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.border.LineBorder;

public class WrappedLabel extends JLabel {

  private static final long serialVersionUID = 1L;

  public static void main(String[] args) {
    JFrame frame = new JFrame("WrappedLabel Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Box box = Box.createVerticalBox();

    String text = "あいう。1234567890123456789012345678901234567890";

    JLabel jLabel = new JLabel(text);
    jLabel.setBorder(new LineBorder(Color.BLACK, 2));
    jLabel.setPreferredSize(new Dimension(50, 100));
    box.add(jLabel);
    box.add(Box.createVerticalGlue());

    String text2 = "あいう。1234567890123456789012345678901234567890";

    WrappedLabel wrappedLabel = new WrappedLabel(text2);
    wrappedLabel.setBorder(new LineBorder(Color.BLACK, 2));
    wrappedLabel.setPreferredSize(new Dimension(50, 100));
    box.add(wrappedLabel);

    frame.add(box);
    frame.setBounds(100, 200, 400, 400);
    frame.setVisible(true);
  }

  public WrappedLabel(String text) {
    super(text);
  }

  @Override
  protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setPaint(this.getForeground());
    Insets insets = this.getInsets();
    float x = insets.left;
    float y = insets.top;
    int width = this.getWidth() - insets.left - insets.right;
    AttributedString attributedString = new AttributedString(this.getText());
    attributedString.addAttribute(TextAttribute.FONT, this.getFont());
    AttributedCharacterIterator attributedCharacterIterator = attributedString.getIterator();
    FontRenderContext fontRenderContext = g2.getFontRenderContext();
    LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator, fontRenderContext);
    while (lineBreakMeasurer.getPosition() < attributedCharacterIterator.getEndIndex()) {
      TextLayout textLayout = lineBreakMeasurer.nextLayout(width);
      textLayout.draw(g2, x, y + textLayout.getAscent());
      y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
    }
    g2.dispose();
  }
}

サンプルで気になる点

「あいう。」の後に自動的に改行されてしまう
以下の関連記事で解決をはかる
https://blogs.yahoo.co.jp/dk521123/36833885.html

関連記事

文字列を描画するための情報を取得するには... ~ FontMetrics ~

https://blogs.yahoo.co.jp/dk521123/36673357.html

独自のグラフィックを表示させる [1]

https://blogs.yahoo.co.jp/dk521123/36666467.html

jLabel の折り返しを考える [2]

https://blogs.yahoo.co.jp/dk521123/36833885.html

【Java】【Swing】 jLabel の折り返しを考える [2]

$
0
0

■ はじめに

https://blogs.yahoo.co.jp/dk521123/36831910.html
の「2) 独自で実装する」でうまくいかないケース(『「あいう。」の後に自動的に改行されてしまう』)があったので
別の実装方法を考える。

■ 原因

 * LineBreakMeasurerで、折り返し方法を定義するBreakIteratorが、
   文字単位で分割されるように指定していなかったため。
LineBreakMeasurerのAPI
http://e-class.center.yuge.ac.jp/jdk_docs/ja/api/java/awt/font/LineBreakMeasurer.html
http://e-class.center.yuge.ac.jp/jdk_docs/ja/api/java/awt/font/LineBreakMeasurer.html#LineBreakMeasurer(java.text.AttributedCharacterIterator, java.text.BreakIterator, java.awt.font.FontRenderContext)
public LineBreakMeasurer(AttributedCharacterIterator text,
                         BreakIterator breakIter, // ★ここ : breakIter - 改行を定義する BreakIterator★
                         FontRenderContext frc)

■ 解決案

 * BreakIteratorで文字で分割するようにする。

修正前

AttributedCharacterIterator attributedCharacterIterator = attributedString.getIterator();
FontRenderContext fontRenderContext = g2.getFontRenderContext();
LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator, fontRenderContext);

修正後

AttributedCharacterIterator attributedCharacterIterator = attributedString.getIterator();
BreakIterator characterBreakIterator = BreakIterator.getCharacterInstance();// ★ここ★
FontRenderContext fontRenderContext = g2.getFontRenderContext();
LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator, characterBreakIterator,
    fontRenderContext);

■ サンプル

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.BreakIterator;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.border.LineBorder;

public class WrappedLabel extends JLabel {

  private static final long serialVersionUID = 1L;

  public static void main(String[] args) {
    JFrame frame = new JFrame("WrappedLabel Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Box box = Box.createVerticalBox();

    String text = "あいう。1234567890123456789012345678901234567890";

    JLabel jLabel = new JLabel(text);
    jLabel.setBorder(new LineBorder(Color.BLACK, 2));
    jLabel.setPreferredSize(new Dimension(50, 100));
    box.add(jLabel);
    box.add(Box.createVerticalGlue());

    String text2 = "あいう。1234567890123456789012345678901234567890";

    WrappedLabel wrappedLabel = new WrappedLabel(text2);
    wrappedLabel.setBorder(new LineBorder(Color.BLACK, 2));
    wrappedLabel.setPreferredSize(new Dimension(50, 100));
    box.add(wrappedLabel);

    frame.add(box);
    frame.setBounds(100, 200, 400, 400);
    frame.setVisible(true);
  }

  public WrappedLabel(String text) {
    super(text);
  }

  @Override
  protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setPaint(this.getForeground());
    Insets insets = this.getInsets();
    float x = insets.left;
    float y = insets.top;
    int width = this.getWidth() - insets.left - insets.right;
    AttributedString attributedString = new AttributedString(this.getText());
    attributedString.addAttribute(TextAttribute.FONT, this.getFont());
    AttributedCharacterIterator attributedCharacterIterator = attributedString.getIterator();
    BreakIterator characterBreakIterator = BreakIterator.getCharacterInstance();
    FontRenderContext fontRenderContext = g2.getFontRenderContext();
    LineBreakMeasurer lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator, characterBreakIterator,
        fontRenderContext);
    while (lineBreakMeasurer.getPosition() < attributedCharacterIterator.getEndIndex()) {
      TextLayout textLayout = lineBreakMeasurer.nextLayout(width);
      textLayout.draw(g2, x, y + textLayout.getAscent());
      y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
    }

    g2.dispose();
  }
}

余談

 * 上記「■ 解決案」を気づく前に、以下の「別解サンプル」で解決しようと思った。。。

別解サンプル

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.border.LineBorder;

public class WrappedLabel extends JLabel {

  private static final long serialVersionUID = 1L;

  public static void main(String[] args) {
    JFrame frame = new JFrame("WrappedLabel Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Box box = Box.createVerticalBox();

    String text = "あいう。1234567890123456789012345678901234567890";

    JLabel jLabel = new JLabel(text);
    jLabel.setBorder(new LineBorder(Color.BLACK, 2));
    jLabel.setPreferredSize(new Dimension(50, 100));
    box.add(jLabel);
    box.add(Box.createVerticalGlue());

    String text2 = "あいう。1234567890123456789012345678901234567890";

    WrappedLabel wrappedLabel = new WrappedLabel(text2);
    wrappedLabel.setBorder(new LineBorder(Color.BLACK, 2));
    wrappedLabel.setPreferredSize(new Dimension(50, 100));
    box.add(wrappedLabel);

    frame.add(box);
    frame.setBounds(100, 200, 400, 400);
    frame.setVisible(true);
  }

  public WrappedLabel(String text) {
    super(text);
  }

  @Override
  protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setPaint(this.getForeground());
    Insets insets = this.getInsets();
    float x = insets.left;
    float y = insets.top;
    int width = this.getWidth() - insets.left - insets.right;

    FontMetrics fontMetrics = g.getFontMetrics();
    FontRenderContext fontRenderContext = g2.getFontRenderContext();
    String text = this.getText();

    if (text == null || text.isEmpty() || text.length() == 1) {
      return;
    }

    int start = 0;
    int end = 1;
    while (true) {
      int targetWidth = fontMetrics.stringWidth(text.substring(start, end));
      if (width < targetWidth) {
        TextLayout textLayout = new TextLayout(text.substring(start, end - 1), this.getFont(), fontRenderContext);
        textLayout.draw(g2, x, y + textLayout.getAscent());
        y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
        start = end;
      } else if (text.length() == end) {
        TextLayout textLayout = new TextLayout(text.substring(start, end), this.getFont(), fontRenderContext);
        textLayout.draw(g2, x, y + textLayout.getAscent());
        break;
      }
      end++;
    }

    g2.dispose();
  }
}

関連記事

jLabel の折り返しを考える [1]

https://blogs.yahoo.co.jp/dk521123/36831910.html

The Twelve-Factor App ~ クラウドアプリケーション開発・運用のための方法論 ~

$
0
0

■ The Twelve-Factor App とは?

クラウドアプリケーション開発・運用のための方法論(ベストプラクティス)
 * 米ヘロク(Heroku)の創設者の一人であるアダム・ウィギンス氏が作成
 * Heroku上でクラウドアプリケーションを開発・運用する際に培ってきたノウハウから、
   12要素(Twelve factor)を抽出したもの


■ The Twelve Factors / 12要素

[01] Codebase            / コードベース
[02] Dependencies        / 依存関係
[03] Config              / 設定
[04] Backing services    / バックエンドサービス
[05] Build, release, run / ビルド、リリース、実行
[06] Processes           / プロセス
[07] Port binding        / ポートバインディング
[08] Concurrency         / 並行性
[09] Disposability       / 廃棄容易性
[10] Dev/prod parity     / 開発/本番一致
[11] Logs                / ログ
[12] Admin processes     / 管理プロセス

■ 詳細

[01] コードベース

バージョン管理されている1つのコードベースと複数のデプロイ
 * コードをバージョン管理システム(ex. git, subversion)で管理する
 * コードベースとアプリケーションは、常に1対1
https://12factor.net/ja/codebase
http://itpro.nikkeibp.co.jp/atcl/column/14/110900092/110900003/?itp_leaf_index

[02] 依存関係

依存関係を明示的に宣言し分離する
https://12factor.net/ja/dependencies
http://itpro.nikkeibp.co.jp/atcl/column/14/110900092/110900004/?itp_leaf_index

[03] 設定

設定を環境変数に格納する
https://12factor.net/ja/config
http://itpro.nikkeibp.co.jp/atcl/column/14/110900092/111700006/

[04] バックエンドサービス(連携サービス)

バックエンドサービスをアタッチされたリソースとして扱う
https://12factor.net/ja/backing-services
http://itpro.nikkeibp.co.jp/atcl/column/14/110900092/111700007/?itp_leaf_index

[05] ビルド、リリース、実行

ビルド、リリース、実行の3つのステージを厳密に分離する
https://12factor.net/ja/build-release-run

[06] プロセス

アプリケーションを1つもしくは複数のステートレスなプロセスとして実行する
https://12factor.net/ja/processes

[07] ポートバインディング

ポートバインディングを通してサービスを公開する
https://12factor.net/ja/port-binding
http://itpro.nikkeibp.co.jp/atcl/column/14/110900092/111700009/

[08] 並行性

プロセスモデルによってスケールアウトする
https://12factor.net/ja/concurrency

[09] 廃棄容易性

高速な起動とグレースフルシャットダウンで堅牢性を最大化する
 * 即座に起動・終了できること
 * 「クラッシュオンリー設計」
  => トラブルがあった際に、アプリケーションプロセス自体をクラッシュさせ、
     再起動によってリカバーするという考え方(そのためにも「即座に起動・終了」が必要)
https://12factor.net/ja/disposability
http://itpro.nikkeibp.co.jp/atcl/column/14/110900092/111700010/?itp_leaf_index

[10] 開発/本番一致

開発、ステージング、本番環境をできるだけ一致させた状態を保つ
https://12factor.net/ja/dev-prod-parity
http://itpro.nikkeibp.co.jp/atcl/column/14/110900092/110900002/

[11] ログ

ログをイベントストリームとして扱う
https://12factor.net/ja/logs

[12] 管理プロセス

管理タスクを1回限りのプロセスとして実行する
https://12factor.net/ja/admin-processes

Viewing all 860 articles
Browse latest View live