Upgrade Java SE 7 to Java SE 8 OCP Programmer(1Z0-810)対策 第一章 ラムダ式(2)
(1)に引き続き、ラムダ式の章を進める。
■注意
全文が超意訳です。正確な情報は下記リンクを参照してください。
■試験対策ページ
java.boot.by
■試験
Upgrade Java SE 7 to Java SE 8 OCP Programmer | Oracle Certification Exam
1.2. 関数型インタフェースクラスの実装
関数型インタフェースクラスはラムダ式とメソッド参照のための型を提供する。
各関数型インタフェースクラスは関数メソッドと呼ばれる単一の抽象メソッド(single abstract method (SAM))を持ち、ラムダ式のパラメータと戻り値に対応あるいは合致する。
JDK8において、既に存在するRunnabl、Callable、 Comparator、ActionListenerのような、単一のメソッドを持つインタフェースクラスは、現在の関数型インタフェースとラムダ式となる。これらは単一の抽象メソッドが使われているインタフェースクラスにて使用することができる。
@FunctionalInterface アノテーション
Java8では@FunctionalInterfaceという新しいアノテーションを関数型インタフェースに付与するよう紹介している。関数型インタフェースであるという意図の伝達とコンパイラにいくつかの追加のチェックを許可するためである。
※WARNING※
@FunctionalInterfaceはオプションである。Javaコンパイラに対するヒント句である。
例えば下記のインタフェースはコンパイルに成功する。
public interface MyInterface { }
しかし関数型インタフェースであることを示した場合(コンパイルに失敗する)
// Java 8 compiler fails @FunctionalInterface public interface MyInterface { }
抽象メソッドが無かった場合、コンパイラは"MyInterface is not a functional interface" や "no abstract method was found"といったエラーを発生させる。
2つ目のメソッドを追加した場合もエラーを発生させる。
// Java 8 compiler fails ! @FunctionalInterface public interface MyInterface { void doIt(); void doItNow(); }
インタフェースにおけるデフォルトメソッド
Java8のインタフェースクラスではデフォルトメソッドとstaticメソッドをサポートする。
デフォルトメソッドはインスタンスメソッドの先頭に「default」キーワードを付けて定義する。またデフォルトメソッドはコードの本文を提供する。
デフォルトメソッドを含むインタフェースの具象クラスは、デフォルトメソッドとその他のメソッドをオーバーライドすることができる。
関数型インタフェースクラスは単一の抽象メソッドを必要とする。下記のコードはコンパイルに失敗する、無効な関数型インタフェースクラスである。
// Java 8 compiler fails ! @FunctionalInterface public interface MyDefInterface { default void doIt() { /* cool implementation */ } }
しかし下記の関数型インタフェースクラスはコンパイルに成功する。
@FunctionalInterface public interface MyDefInterface { default void doIt() { /* cool implementation */ } void doItNow(); // Single Abstract Method (SAM) }
インタフェースにおけるstaticメソッド
staticメソッドは定義したクラスと結びついている、というよりもクラスのどのオブジェクトでも使用できる。
各クラスのインスタンスは、クラス内でstaticメソッドを共有している。
Java8ではインタフェースに定義したstaticメソッドをデフォルトメソッドで補足することができる。
staticメソッドのようにインタフェースにstaticメソッドを定義したい時はメソッドのシグネチャの先頭に「static」を付与する。
インタフェースクラスの全てのメソッド宣言は「public」となるので「public」キーワードは省略することができる。
staticメソッドを含むインタフェースクラスを実装したい時、staticメソッドはまだインタフェースクラスの一部であり、実装クラスの一部ではない。
理由はクラス名をメソッドの接頭辞に付加できないため。staticメソッドの呼び出し時はインタフェースクラス名を付記する必要がある。
関数型インタフェースは単一の抽象メソッドを定義する必要がある。下記のコードはコンパイルに失敗する、無効な関数型インタフェースである。
// Java 8 compiler fails ! @FunctionalInterface public interface MyStatInterface { static void doIt() { /* cool implementation */ } }
しかし下記の関数型インタフェースはコンパイルに成功する。
@FunctionalInterface public interface MyStatInterface { static void doIt() { /* cool implementation */ } void doItNow(); }
java.lang.Objectクラスの関数型インタフェース
インタフェースクラスがjava.lang.Objectクラスの抽象メソッドのひとつをオーバーライドした場合、関数型インタフェースの抽象メソッドとしてカウントしない。
例えば java.util.Comparatorは関数型インタフェースであるが、2つの抽象メソッドを有している。
package java.util; @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); ... }
(関数型インタフェースである)理由は、equals() メソッドはjava.lang.Objectクラスの持つpublicメソッドのシグネチャと一致するため。
【参考】
Java関数型インターフェースメモ(Hishidama's Java8 Functional Interface Memo)
Upgrade Java SE 7 to Java SE 8 OCP Programmer(1Z0-810)対策 第一章 ラムダ式(1)
Upgrade Java SE 7 to Java SE 8 OCP Programmer(1Z0-810)を受けるための勉強メモ。
下記サイトが詳しそうな雰囲気だったので訳しながら追ってゆく。
■注意
全文が超意訳です。正確な情報は下記リンクより一次情報を参照してください。
■お世話になる試験対策っぽいページ
java.boot.by
※githubにも別の対策サイトがあったので紹介
rahulsh1.github.io
■試験
Upgrade Java SE 7 to Java SE 8 OCP Programmer | Oracle Certification Exam
1.1. ネストしたクラス、静的クラス、ローカル・クラス、無名クラスなど、Javaの内部クラスを使用する
Javaでは4種類の内部クラスを実装することができる。下記に名称と実装例を示す。
staticな内部クラス ※コンパイルが通るよう修正済
public class Outer { static class Inner { void doIt() { System.out.print("Static nested class reference is: " + this); } } public static void main(String[] args) { Outer.Inner n = new Outer.Inner(); n.doIt(); } }
●標準出力
Static nested class reference is: chap1.stat.Outer$Inner@2a139a55
内部クラスと似ているが、静的クラスとして宣言している。
エンクロージングクラスのインスタンスに依存しない。エンクロージングクラスのインスタンスのstaticメソッドとフィールドへのみアクセスすることができる。
「利用シーン」
・エンクロージングクラスのインスタンスと分離したい場合
・エンクロージングクラスのインスタンスより生存期間が長い場合
内部クラス(インナークラス)
内部クラスは明示的なインスタンスとして生成する。(メンバ変数として外部のクラス内で宣言される。)
内部クラスはエンクロージングクラスと内部クラスの全てのメソッド、フィールド、エンクロージングインスタンスのthisによる参照にアクセスすることができる。
public class Outer { private int secretVar = 1; public void makeInner() { Inner in = new Inner(); in.seeOuter(); } class Inner { public void seeOuter() { System.out.println("Outer 'secretVar' is " + secretVar); System.out.println("Inner class reference is " + this); System.out.print("Outer class reference is " + Outer.this); } } public static void main(String... args) { Inner i = new Outer().new Inner(); i.seeOuter(); } }
●標準出力
Outer 'secretVar' is 1 Inner class reference is chap1.inner.Outer$Inner@2a139a55 Outer class reference is chap1.inner.Outer@15db9742
内部クラスはエンクロージングクラスとは別のスコープで定義される。
無名クラスであることがある。(次のセクションを参照)
外部・内部クラスはお互いのメソッドを直接参照することが可能(※private宣言されてる場合でも)
OuterクラスのメソッドはInnerクラスのインスタンスを生成することでInnerクラスを使用する。
内部クラスのインスタンスはエンクロージングクラスのインスタンスとは分離されている。
内部クラスのインスタンスはエンクロージングクラスのインスタンスよりインスタンス化する必要がある。
内部クラスはエンクロージングインスタンスの生成タイミングに縛られる。(※変更不可)
ローカル内部クラス(ローカルインナークラス)
ローカル内部クラスはブロック内で定義される。ブロックは0以上の要素で構成され互いに関係する。
「インスタンスメソッドにおけるローカル内部クラス」
public class Outer { private String x = "outer"; public void doStuff() { class MyInner { public void seeOuter() { System.out.println("x is " + x); } } MyInner i = new MyInner(); i.seeOuter(); } public static void main(String[] args) { Outer o = new Outer(); o.doStuff(); } }
●標準出力
x is outer
「staticメソッドにおけるローカル内部クラス」
public class Outer { private static String x = "static outer"; public static void doStuff() { class MyInner { public void seeOuter() { System.out.println("x is " + x); } } MyInner i = new MyInner(); i.seeOuter(); } public static void main(String[] args) { Outer.doStuff(); } }
●標準出力
x is static outer
内部クラスはエンクロージングクラスに対するアクセスを持つ。
加えて、内部クラスはエンクロージングクラス内の変数に対するアクセスを持つ。
JavaSE7以前のバージョンでは、内部クラスはエンクロージングクラスの「定数」に対するアクセスを持っている。
内部クラスがエンクロージングクラスの変数、パラメータへアクセスする時は他の変数やパラメータで保持する。
// Java SE 7 syntax ... public void validatePhoneNumber(String phoneNumber) { final int numberLength = 10; class PhoneNumber { PhoneNumber(String phoneNumber) { if (phoneNumber.length() > numberLength) { ... } } } } ...
※WARNING※
Java8からは、内部クラスがエンクロージングクラスの定数または"事実上の定数"へアクセスできる。
初期化後に一度も変更されていない変数、パラメータを"事実上の定数"とする。
// Java SE 8 - successfully compiles and runs; // Java SE 7 - compilation failure ... public void validatePhoneNumber(String phoneNumber) { int numberLength = 10; // no mandatory 'final' anymore, as long as variable not modified class PhoneNumber { PhoneNumber(String phoneNumber) { if (phoneNumber.length() > numberLength) { ... } } } } ...
※WARNING※
下記の例はエンクロージングクラスの変数(numberLength)の代入文が内部クラス(PhoneNumberクラス)にある場合。
変数numberLengthは定数ではないため、Javaのコンパイラは「Local variables referenced from an inner class must be final or effectively final」というエラーメッセージを生成する。
// Java SE 8 - compilation failure ... public void validatePhoneNumber(String phoneNumber) { int numberLength = 10; class PhoneNumber { numberLength = 12; PhoneNumber(String phoneNumber) { if (phoneNumber.length() > numberLength) { ... } } } } ...
匿名インナークラス
GUIアプリにおけるウィジェットに対するActionリスナーを追加するときによく利用する。
public class Outer { public void init() { JButton button = new JButton(); JLabel comp = new JLabel(); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { comp.setText("Button has been clicked"); } }); } }
内部クラスは匿名クラスであり、エンクロージングクラスのインスタンスの一部となる。
内部クラスの一部の箇所でインスタンス化して使用したいときによく使用される。
SomeType x = new SomeType() { // unnamed (i.e. anonymous) inner class // body of class goes here };
・SomeTypeは存在するクラスまたはインタフェースでなければならない。
・SomeTypeがクラスの場合:提供されたクラスの拡張クラス
・SomeTypeがインタフェースの場合:提供されたインタフェースの実装クラス
シャドーイング
変数やパラメータ等の箇所にて宣言した型が独特なスコープ(内部クラスやメソッドの宣言部)にて、エンクロージングクラスのスコープ内の別の宣言と同じ名前があると、
エンクロージングクラスのスコープの宣言を隠蔽する。
覆い隠された宣言部へ対して、宣言の名前単独で参照することはできない。
public class Shadow { public int x = 0; class FirstLevel { public int x = 1; void methodInFirstLevel(int x) { System.out.println("x = " + x); System.out.println("this.x = " + this.x); System.out.println("Shadow.this.x = " + Shadow.this.x); } } public static void main(String... args) { Shadow s = new Shadow(); Shadow.FirstLevel fl = s.new FirstLevel(); fl.methodInFirstLevel(2); } }
●標準出力
x = 2 this.x = 1 Shadow.this.x = 0
この例では3つのxという変数が定義されている。Shadowクラスのメンバ変数、内部クラスのFirstLevelのメンバ変数、methodInFirstLevelメソッドのパラメータである。
内部クラスのFirstLevelのメンバ変数xは、methodInFirstLevelメソッドのパラメータの変数を隠蔽する。
その結果、methodInFirstLevelメソッドのパラメータの変数を使用したい時は、メソッドのパラメータを参照するようにする。
内部クラスのFirstLevelのメンバ変数を参照するには、エンクロージングクラスのインスタンスのスコープを表すthisキーワードを使用する。
System.out.println("this.x = " + this.x);
参照するメンバ変数は、所属するクラスよりもより大きなスコープに属している。
例えば、下記の代入文はmethodInFirstLevelメソッドからShadowクラスのメンバ変数へアクセスする。
System.out.println("Shadow.this.x = " + Shadow.this.x);
■参考
四種類の内部クラス - にょきにょきブログ
【改訂版】Eclipseではじめるプログラミング(17):あなたの知らない、4つのマニアックなJava文法 (1/3) - @IT
裏Javaメモ(Hishidama's Java Memo)
jol(Java Object Layout)を使ったオブジェクトのサイズ取得
jol(Java Object Layout)というOpenJDKに含まれるツールを使用して、オブジェクトのメモリサイズが取得できるらしいので試してみる。
■環境
・Windows7 Home Premium 64bit
・JDK 1.8.0_60-b27
・Eclipse Luna SR1 (4.4.1)
・jol (0.4) (※jol-cli-0.4-full.jar)
■すること
jolを使用して何ができるのかを調べる。
主目的は、1処理におけるメモリ量の取得とする。
よって割とメイン所(と思われる)の機能のみ追いかける。
■クラス紹介
1.ClassLayoutクラス
jolを使用する上で基本となるクラス。クラス・クラスインスタンスのメモリ情報を取り扱う。
●処理対象特定系
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | ○ | ClassLayout | parseInstance | Object | インスタンスのメモリ情報を取得する。 |
2 | ○ | ClassLayout | parseInstance | Object, Layouter | インスタンスのメモリ情報を取得する。第二引数のLayouterで読み込み時の動作変更が可能 |
3 | ○ | ClassLayout | parseClass | Object | クラスのメモリ情報を取得する。 |
4 | ○ | ClassLayout | parseClass | Object, Layouter | クラスのメモリ情報を取得する。第二引数のLayouterで読み込み時の動作変更が可能 |
●サイズ取得系
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
5 | SortedSet< FieldLayout> | fields | - | インスタンス内に含まれるフィールドのメモリ情報を取得する。 | |
6 | int | headerSize | - | インスタンスのヘッダサイズ(int値)を取得する。 | |
7 | int | instanceSize | - | インスタンスのサイズ(int値)を取得する。 | |
8 | String | toPrintable | - | インスタンスのメモリ情報を整形して詳細情報を出力する。 | |
9 | String | toString | - | インスタンスのメモリ情報を整形して出力する。 |
2.FieldLayoutクラス
フィールドのメモリ情報を取り扱う。
●サイズ取得系
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | String | name | - | フィールド名を取得する。 | |
2 | String | offset | - | インスタンスが占めるサイズの先頭からのメモリ量を取得する。 | |
3 | int | size | - | フィールドのサイズを取得する。 | |
4 | String | typeClass | - | フィールドの型を取得する。 | |
5 | String | toString | - | フィールドの詳細を取得する。 |
3.VMSupportクラス
JVMのメモリに関連する情報を取得する。
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | ○ | String | vmDetails | - | JVMのメモリ情報を出力する。 |
4.GraphLayoutクラス
インスタンス生成からGraphLayout#parseInstanceした時点までにおける、指定したインスタンスに対するメモリの状態を可視化する。
通番 | static | 戻り値の型 | メソッド名 | 引数 | メソッド概要 |
---|---|---|---|---|---|
1 | ○ | GraphLayout | parseInstance | Object | インスタンスのメモリ情報を取得する。 |
2 | ○ | - | toImage | String | 引数で指定したファイル名(~.png等)でグラフを生成する。 |
●HelloWorld的なやつ
package com.hhhhhskw.jol; import java.util.SortedSet; import org.openjdk.jol.info.ClassLayout; import org.openjdk.jol.info.FieldLayout; import org.openjdk.jol.util.VMSupport; public class HelloJol { private String HELLO_JOL_HOGE = "HOGEEEEEEEEEEEEEEEEE"; private String HELLO_JOL_FUGA = "FUGAAAAAAAAAAAAAAAAA"; public static void main(String[] args) { HelloJol hj = new HelloJol(); System.out.println("■JVM情報■"); System.out.println(VMSupport.vmDetails()); System.out.println("■クラスインスタンスのメモリ情報■"); System.out.println(ClassLayout.parseInstance(hj).instanceSize()); System.out.println(ClassLayout.parseInstance(hj)); System.out.println(ClassLayout.parseInstance(hj).toPrintable()); SortedSet<FieldLayout> flSet = ClassLayout.parseInstance(hj).fields(); flSet.stream().forEachOrdered(fl -> { System.out.println("■フィールドのメモリ情報■"); System.out.println(fl.name()); System.out.println(fl.size()); System.out.println(fl.typeClass()); System.out.println(fl); }); System.out.println(flSet); } }
●実行結果*1
■JVM情報■ WARNING: Unable to attach Serviceability Agent. You can try again with super-user privileges. Use -Djol.tryWithSudo=true to try with sudo. WARNING: VM details, e.g. object alignment, reference size, compressed references info will be guessed. Running 64-bit HotSpot VM. Using compressed oop with 3-bit shift. Using compressed klass with 3-bit shift. Objects are 8 bytes aligned. Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] ■クラスインスタンスのメモリ情報■ 24 HelloJol.HELLO_JOL_HOGE@12(4) HelloJol.HELLO_JOL_FUGA@16(4) size = 24 com.hhhhhskw.jol.HelloJol object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0) 8 4 (object header) 05 c0 00 f8 (00000101 11000000 00000000 11111000) (-134168571) 12 4 String HelloJol.HELLO_JOL_HOGE (object) 16 4 String HelloJol.HELLO_JOL_FUGA (object) 20 4 (loss due to the next object alignment) Instance size: 24 bytes (estimated, add this JAR via -javaagent: to get accurate result) Space losses: 0 bytes internal + 4 bytes external = 4 bytes total ■フィールドのメモリ情報■ HELLO_JOL_HOGE 4 String HelloJol.HELLO_JOL_HOGE@12(4) ■フィールドのメモリ情報■ HELLO_JOL_FUGA 4 String HelloJol.HELLO_JOL_FUGA@16(4) [HelloJol.HELLO_JOL_HOGE@12(4), HelloJol.HELLO_JOL_FUGA@16(4)]
【感想】
・継承関係にあるクラスのフィールドの中身までさかのぼってサイズ取得してくれるので便利。
・アプリケーション単位で特定の箇所でメモリサイズを取得する場合、インスタンスを適当に決めると、重複してサイズ取得する恐れがあるので、取得対象とするインスタンスは慎重に選ぶべき。
・VMSupport、GraphLayoutクラスを使用したサンプルは下記のソースを参照。
code-tools/jol: 4443d2696dcf /jol-samples/src/main/java/org/openjdk/jol/samples/
【参考】
[Java]オブジェクトの使用メモリを測る - Qiita
『オブジェクトデザイン』第2章 DoubleDispatchパターン実装
下記エントリに影響を受けて、『オブジェクトデザイン』を読み始めている。kymmt90.hatenablog.com
『オブジェクトデザイン』の第2章において、DoubleDispatchパターンの実装が紹介されているが、
要点が書かれているだけで全体の実装が書かれていなかったので、実装してみた。
DoubleDispatchパターン自体は、GoFのVisitorパターンとほとんど同じものらしい。
【要件】
じゃんけん(Scissors,Paper,Stone)*1を実装する。
オブジェクト自身にオブジェクトが他のオブジェクトを負かすかどうかを判定する処理を書いておく。
→3種類のオブジェクトにじゃんけんの処理を記述するため、9通りの結果が生じることになる。
【書籍からの変更点】
『オブジェクトデザイン』の例では、「あいこ」の場合が考慮されていなかったので、
「あいこ」を表現するために、booleanからintで数値を返却するよう変更した。
変更に伴い、他のオブジェクトを負かすかどうかの判定処理を抽象クラス(※新規作成)に追い出して共通化した。
【シーケンス図】※だいぶ適当
【実装】github.com
■実行結果の例 (※標準出力)
自分の手 : パー 相手の手 : グー 勝敗 : 勝ち
【感想】
「操作するデータの型」「データごとの操作」に対する判定処理が消えたことで、各クラスの関心事を細かく分断することができた。
ただしインタフェースクラスに定義するメソッドの数、シグネチャが変動する可能性があるので、初期設計が難しそう。
【参考】
ダブル・ディスパッチ~ 典型的なオブジェクト指向プログラミング・イディオム ~
オブジェクトデザイン (Object Oriented SELECTION)
- 作者: レベッカ・ワーフスブラック,アラン・マクキーン,株式会社オージス総研藤井拓,辻博靖,井藤晶子,山口雅之,林直樹
- 出版社/メーカー: 翔泳社
- 発売日: 2007/09/13
- メディア: 大型本
- 購入: 3人 クリック: 52回
- この商品を含むブログ (41件) を見る
*1:グーはRockではなくてStoneで習った気がしたので…
PowerShellを使ってOracleJDKサイレントインストール
OracleJDKをサイレントインストールする。
【概要】
・OTNサイト(US)から取得したJDK8u45(64bit)のインストーラを使用しサイレントインストールする。*1
・ダウンロードしたインストーラは「C:\\tmp」に置く。
・環境変数も設定する。
→ユーザ環境変数の「JAVA_HOME」と「PATH」にJDK実行に必要なパスを設定する。
・インストーラが出力するログは「C:\tmp\JDKsetup.log」に格納する。
【実行環境】
・Windows7 Home Premium 64bit
・PowerShell 4.0 (※新しい関数は使っていないので、おそらくPowerShell2.0以降であれば動作する)
【スクリプト】
Function Download{ $serverSourceURL = "http://download.oracle.com/otn/java/jdk/8u45-b15/jdk-8u45-windows-x64.exe" $localSourceURL = "C:\\tmp\\jdk-8u45-windows-x64.exe" Write-Host ("■インストーラ取得先URL : " + $remoteFileLocation) Write-Host ("■インストーラ保存先パス : " + $downloadToPath) $client = new-object System.Net.WebClient # ライセンスに同意する $cookie = "oraclelicense=accept-securebackup-cookie" $client.Headers.Add([System.Net.HttpRequestHeader]::Cookie, $cookie) Write-Host "★ダウンロード開始(しばらくお待ちください…)" $client.downloadFile($serverSourceURL, $localSourceURL) Write-Host "★ダウンロード終了" return } Function Install{ Write-Host "★インストール開始(しばらくお待ちください…)" # インストーラ実行(※同期実行) cmd /c "start C:\tmp\jdk-8u45-windows-x64.exe /s /lang=1041 INSTALLDIR=C:\java\jdk1.8.45\ /L C:\tmp\JDKsetup.log" Write-Host "★インストール終了" # ユーザー環境変数設定 # PATHは末尾に付加する $user_path = [Environment]::GetEnvironmentVariable('PATH', 'User') $user_path += ';' + "C:\java\jdk1.8.45\bin\" [Environment]::SetEnvironmentVariable('PATH', $user_path, 'User') # JAVA_HOMEは更新する #$user_java_home = [Environment]::GetEnvironmentVariable('JAVE_HOME', 'User') $user_java_home = "C:\java\jdk1.8.45\" [Environment]::SetEnvironmentVariable('JAVA_HOME', $user_java_home, 'User') Write-Host ("■現在のユーザー環境変数 PATH : " + $user_path) Write-Host ("■現在のユーザー環境変数 JAVA_HOME : " + $user_java_home) return } # 処理開始 Write-Host "★★★Oracle JDKのダウンロード・インストール開始" Download Install Write-Host "★★★Oracle JDKのダウンロード・インストール終了" # 処理終了
■実行結果
PS C:\Windows\system32> (ファイルパス).ps1 ★★★Oracle JDKのダウンロード・インストール開始 ■インストーラ取得先URL : http://download.oracle.com/otn/java/jdk/8u45-b15/jdk-8u45-windows-x64.exe ■インストーラ保存先パス : C:\tmp\jdk-8u45-windows-x64.exe ★ダウンロード開始(しばらくお待ちください…) ★ダウンロード終了 ★インストール開始(しばらくお待ちください…) ★インストール終了 ■現在のユーザー環境変数 PATH : (既存のPATH設定値);C:\java\jdk1.8.45\bin\ ■現在のユーザー環境変数 JAVA_HOME : C:\java\jdk1.8.45\ ★★★Oracle JDKのダウンロード・インストール終了
■結果確認
C:\>java -version java version "1.8.0_45" Java(TM) SE Runtime Environment (build 1.8.0_45-b15) Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode) C:\>
【備考】
・インストーラを毎回取りに行くので、インストーラの有無チェックが必要。
・インストールを毎回実行するので、プログラム一覧をなめてOracle Javaの存在チェックする処理が必要。*2
【参考】
java - Downloading jdk using powershell - Stack Overflow
Microsoft WindowsのJDKのインストール
【改訂新版】 Windows PowerShell ポケットリファレンス
- 作者: 牟田口大介
- 出版社/メーカー: 技術評論社
- 発売日: 2013/02/23
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
*1:PowerShellの関数のみで実行したかったが、リクエストに載せるCookieの設定方法がわからなかったので、.NETのクラスを使った。
*2:要は冪等性を作りこむ必要がある。現状のコードのまま2回実行すると、インストーラを再ダウンロードし、再インストールを実行する。
JavaでTelnetクライアント作成・RHELにTelnetサーバ導入
JavaのSocketクラスを使ってTelnet接続してみる。
ついでにTelnetサーバを立てる手順も備忘録として残す。
【すること】
・Telnet接続する。
※セッションモードで端末に接続し、コマンドが打てるところまで確認する。
NVTとしての仕様は網羅しない。
【環境】
●OS
クライアント側:Windows7 64bit
サーバ側 :Red Hat Enterprise Linux Server release 7.1 (Maipo)
●Java
1.8.0_60-b27
【Telnetサーバ導入】
0.はじめに
・23番ポートを空ける。
・Telnetを実行するユーザはスーパーユーザである必要があるため、rootユーザで接続確認する。
Telnetプロトコルで使用するユーザ名とパスワードは平文で流れるので注意する。
[参考] ITエンジニアの「やってはいけない」 - [セキュリティ編]運用管理にtelnetを使ってはいけない:ITpro
・スーパーサーバであるxinetdを利用してTelnetサーバを管理する。
[参考] xinetd - Wikipedia
1.インストール(※rootユーザで行う)
yum update yum install telnet -y yum install telnet-server -y yum install xinetd -y ※RHELには入ってないので入れておく
2.xinetdよりTelnetサーバ有効化
vi /etc/xinetd.d/telnet
●/etc/xinetd.d/telnet
service telnet { flags = REUSE socket_type = stream wait = no user = root server = /usr/sbin/in.telnetd log_on_failure += USERID disable = no ←「yes」から「no」へ変更し、有効化 }
3.xinetd起動および自動起動の設定
(※xinetdを起動することによりTelnetサーバも起動する)
service xinetd start chkconfig --add xinetd chkconfig xinetd on
インストール手順はここまで。
package hhhhhskw.com; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * Telnet接続用クラス */ public class TelnetConnector { private final static int DEFAULT_TELNET_PORT = 23; private final static byte IAC = (byte) 255; private final static byte DONT = (byte) 254; private final static byte DO = (byte) 253; private final static byte WONT = (byte) 252; private final static byte WILL = (byte) 251; /** * NVTとしてのネゴシエーションを行う * @param os * @param is * @throws IOException */ private void negotiation(OutputStream os, BufferedInputStream is) throws IOException { byte[] buff = new byte[3]; while (true) { is.mark(buff.length); if (is.available() >= buff.length) { is.read(buff); // ネゴシエーション完了 if (buff[0] != IAC) { is.reset(); return; // DOコマンドに対してWONTで返答する } else if (buff[1] == DO) { buff[1] = WONT; os.write(buff); } } } } /** * 実行メソッド * @param host * @param port */ public void execute(String host, int port) { Socket socket = null; OutputStream os = null; BufferedInputStream is = null; try { socket = new Socket(host, port); os = socket.getOutputStream(); is = new BufferedInputStream(socket.getInputStream()); // 23番ポートへの接続の場合ネゴシエーションを行う if (port == DEFAULT_TELNET_PORT) { negotiation(os, is); } StreamConnector stdinToSocket = new StreamConnector(System.in, os); StreamConnector socketToStdout = new StreamConnector(is, System.out); Thread input = new Thread(stdinToSocket); Thread output = new Thread(socketToStdout); input.start(); output.start(); } catch (IOException e) { e.printStackTrace(System.out); System.err.println("接続中に例外が発生しました"); System.exit(1); // コネクションはクローズしない // } finally { // try { // socket.close(); // os.close(); // is.close(); // } catch (IOException e) { // } } } /** * ストリームの読み書きクラス */ class StreamConnector implements Runnable { private InputStream is = null; private OutputStream os = null; public StreamConnector(InputStream in, OutputStream out) { this.is = in; this.os = out; } @Override public void run() { byte[] buff = new byte[1024]; try { while (true) { int n = is.read(buff); if (n > 0) { os.write(buff, 0, n); } } } catch (IOException e) { e.printStackTrace(System.out); System.out.println("入出力の書き込み中に例外が発生しました"); System.exit(1); } } } }
● 実行クラス
package hhhhhskw.com; public class TelnetMain { /** * mainメソッド * @param args 第一引数:ホスト名 第二引数:ポート番号 */ public static void main(String[] args) { String host = args[0]; int port = Integer.parseInt(args[1]); TelnetConnector tc = new TelnetConnector(); tc.execute(host, port); } }
●実行方法
第一引数にサーバのホスト名(IPアドレス)、第二引数にポート番号を指定し、実行する。
java hhhhhskw.com.TelnetMain (ホスト名orIPアドレス) 23
●実行結果
Kernel 3.10.0-229.el7.x86_64 on an x86_64 (サーバ名) login: root root Password: (パスワード) Last login: Sat Sep 5 07:17:35 on pts/2 [root@ip-xxx-xxx-xxx-xxx ~]# ls -al total 104 dr-xr-x---. 4 root root 4096 Aug 31 04:23 . dr-xr-xr-x. 18 root root 4096 Aug 30 07:59 .. -rw-------. 1 root root 9813 Feb 25 2015 anaconda-ks.cfg -rw-------. 1 root root 1974 Aug 31 05:34 .bash_history -rw-r--r--. 1 root root 18 Dec 28 2013 .bash_logout -rw-r--r--. 1 root root 176 Dec 28 2013 .bash_profile -rw-r--r--. 1 root root 176 Dec 28 2013 .bashrc -rw-r--r--. 1 root root 100 Dec 28 2013 .cshrc -rw------- 1 root root 45711 Sep 5 07:18 nohup.out drwxr----- 3 root root 18 Aug 30 08:00 .pki -rw-r--r-- 1 root root 7154 Aug 31 02:27 ps.txt drwx------. 2 root root 28 Aug 30 07:55 .ssh -rw-r--r--. 1 root root 129 Dec 28 2013 .tcshrc -rw------- 1 root root 759 Aug 31 04:23 .viminfo [root@ip-xxx-xxx-xxx-xxx ~]#
【参考URL】
http://www.kg-group.com/JavaContent/Menu/TreeView5150_16/reference/j-network/Telnet.java
Telnetプログラム IT EngineerによるIT生活/ウェブリブログ
CentOSでtelnetできるようにするまでの手順(クライアント・サーバ) | Futurismo
UJP - 技術情報(dotforward.jp)
AWS Summit Tokyo 2015 2日目【EA-08】
AWS Summit Tokyo 2015の2日目に参加した。
下記セミナーに参加したので、まとめ・感想文を書いておく。
※正確な情報・見解は後日公開される(であろう)公式資料や資料作成者のスライド等を参照のこと。
[EA-08: Enterprise Advance]AWS と NGN(フレッツ・キャスト)によるハイブリット・ネットワークのメリット ~高速映像配信・教育 PF 事例~
http://www.awssummit.tokyo/session.html#EA-08
【講演概要】
AWS上のサービスをNGN(フレッツ・キャスト)という専用線を使用し、インターネットを介さずに利用するサービスの内容紹介および事例紹介
※6/5付けでサービス試用開始されている。
「プレスリリース」
「フレッツ・キャスト」経由のAWSダイレクト接続検証環境の提供開始について〜パブリッククラウドとの連携強化に向けた取り組み〜 | お知らせ・報道発表 | 企業情報 | NTT東日本
【講演内容】
1.何故、AWSを選んだのか
・新サービス立ち上げにあたって、重視したのは「コスト」「サービス」「フレキシビリティ」の3点
→以前は「サーバ設備」や「ネットワーク」という点を重視していた。
・増え続ける動画トラフィックに柔軟に対応したい、という思いがあった。
インターネットに占める動画トラフィック量は、2013年~2018年で倍になる、と予測されている。
動画トラフィックの大部分はIPビデオ*1が占めており、今後もこの傾向は続くとみられる。
・AWSに限らず、パブリッククラウドの選定に当たって最も重要視したのは「セキュリティ」だった。
→NTT東のお客様と社内の双方から求められた為。結果としては各種AWSのサービスの組み合わせにより担保できた。
2.フレッツ・キャストの紹介
・ISPを介さずに、AWSのNWからNTT東日本のNWを通って利用者がサービスを利用することを可能とする。
・全FTTHユーザのうち、7割がNTT西・東を利用している。
・以下の3点を売りとして挙げていた。
①速度 :通信キャリアのVPNより安価で高速
②セキュリティ:回線認証(※IPSecでない)
③品質 :クローズドなNW。24時間365日対応可能。
・4KのVoDが可能となる。
→「ひかりTV 4K」等
3.サービス事例
・サービス適用例として「映像配信」「ICT教育」を挙げていた。
①映像配信
・会場と配信サーバをNGNで結び、配信はNGNかインターネット経由で行う。
→現在は映像データをバイク便で運んでいるが、回線に置き換えられる。
・課題:IPv6
AmazonVPC内ではインターナルでIPv6のアドレスを割り当てることができない点が課題。
→リバプロを立てることで解決したとのこと。IPv6のアドレスの割り当て先としてELBを使用しなかった理由としては、セキュリティ面の都合??
[参考]http://srad.jp/~ozuma/journal/591374/
http://d.hatena.ne.jp/rx7/20130925/p1
②ICT教育
・ICTパッケージとして提供する。学校・学習塾がターゲット。
→インフラから学習アプリの導入~運用まで提供する。
「反転学習」*2にも使用できるとのこと。
・公教育の分野のため、個人情報の取り扱いに対する要望が強い。
●苦労した点
・有識者が少なかったこと
→書籍の情報や「ドコモ・クラウドパッケージ」を活用した。
●良かった点
・IaaS部のセキュリティは外部に協力を仰いだ。(ex.スカイアーチ社)
・サーバ構成を頻繁に変更することができた。
→50~60?回は構成を変更したとのこと。
*1:IP(インターネットプロトコル)ネットワーク経由で配信する動画コンテンツを指す