『オブジェクトデザイン』第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(インターネットプロトコル)ネットワーク経由で配信する動画コンテンツを指す
AWS Summit Tokyo 2015 2日目【Day2 キーノート】
AWS Summit Tokyo 2015の2日目に参加した。
いくつかセミナーに参加したので、まとめ・感想文を書いておく。
※正確な情報・見解は後日公開される(であろう)公式資料や資料作成者のスライド等を参照のこと。
※長くなったので基調講演のまとめを前に置いた。
Day2 キーノート【同時通訳】
セッションスケジュール - AWS Summit Tokyo 2015 - クラウドで、未来を「今」に。- 2015年6月2~3日 グランドプリンスホテル新高輪にて開催
【基調講演まとめ】
1.AWSはモバイル分野・エンタープライズ分野に注力する。
→AWSが言うエンタープライズ分野への注力、というのはIaaS、PaaSレイヤの提供・運用だけでなく、
VDI環境のフルマネージメントサポート*1や、ファイル共有サービスとメールやカレンダーアプリを業務利用できるレベルでの提供、といったDaaS(※Desktop as a Service)、SaaSなどの上位レイヤのサービスも提供・運用することを指す。
2.AWSの各マネージドサービスは「世界で使用されているサービス」という実績がある。
→AWSとしての顧客は全世界・多業種にわたる。その顧客ごとのユースケースに対して、AWSは各マネージドサービスを適用してきた実績がある。
そのため、十分な適用・運用実績を持って顧客にアプローチをかけることが可能となっている。
【基調講演内容】
1.AWSの歴史
[内容]
・2006年からサービス開始。
・サービスの数が飛躍的に増えた。またサポートできるレイヤも増えた。
→2006年:24 2015年:516
・現在、一ヶ月におけるアクティブユーザが100万ユーザに達している。
→ここでいうアクティブユーザというのは、AWSのサービスを実運用しているレベルのユーザの数を指すらしい。
2.AWSのモバイルサービス
[概要]
・AWSはモバイルデベロッパー向けのサービスに注力する。
→モバイルビジネスのモデルに沿うようなサービスを提供する、ということ。
→インフラ*2の抽象化等。本来モバイルデベロッパーが時間をかけるべき箇所はアプリ開発であるので、その他の部分をAWSがサービスとして提供する。
[内容]
・AWS LambdaとAmazon Cognitoが6/3より東京リージョンで使用可能となった。(※途中で発表された。)
・AWSが提供するモバイルサービスについて、4つの観点から紹介していた。
(1)ユーザ管理
・BtoB, BtoC, MtoMなどの認証情報を扱う認証基盤として、「Amazon Cognito」を紹介した。
→「Amazon Cognito」はID認証およびデータ同期、セキュリティに関する機能を提供する認証基盤サービス。
・イベント(データ)駆動が可能となっており、データ同期を契機としてAWS Lambdaのサービスを実行する、といった使い方ができる。また、他デバイスでの認証状況をCognitoにて参照できるため、デバイス毎のアプリの使用状況の把握が可能となる。
[利用事例]
ATARI Inc. : フィットネスアプリの認証基盤
(2)ユーザ行動分析
・「Amazon Mobile Analytics」を紹介した。
→デバイスから送られるデータをAnalyticsで受け取り、Amazon S3(データストレージ)とAmazon Redshift(分析基盤サービス)を使用し、過去分のデータとマージした結果をAnalyticsのコンソールに表示するという使い方ができる。
[利用事例]
(※企業名は失念した) : メッセージのプッシュ基盤と組み合わせ、メッセージにおけるデバイス毎のA-Bテストに使用
(3)SNS Push
・Amazon Simple Notification Service (Amazon SNS) を紹介した。
→メッセージのプッシュ基盤サービス。データ駆動が可能となっており、AWS Lambdaと組み合わせることができる。
[利用事例]
Path Inc. : 1日5億件のメッセージを送信するプッシュ基盤サービスを構築
(4)AWS Lambda
・「AWS Lambda」では、ステートレスなイベント駆動型の処理を作成することができる。
→イベント駆動型のバックエンドサービスを作成することができるため、「インフラの抽象化」が可能となる。
・Javaでの記述に対応予定。
3.Deep Dive DynamoDB
[概要]
AWSの川本さんの発表。Amazon DynamoDB紹介
[内容]
・Amazon DynamoDBはAmazonが社内利用するために作ったNoSQLデータベースシステム。
・AWSのIaaSレイヤのサービスを扱いやすいように作られている。
・DynamoDB内に格納したデータを「DynamoDB Streams」として取り出すことができ、StreamデータをAWS Lambdaに読み込ませ、Redshift、Amazon Machine Learning(機械学習サービス)等に出力することで、サーバレスで目的のデータを取り出すことが可能となっている。
4.デベロッパ(コミュニティ)向けサービス
[概要]
AWS Community Heroes 横田さんのマネージドサービスの利用事例紹介。
[内容]
(1)スシロー
予約用モバイルアプリから待ち時間情報を収集・加工し、Amazon Machine Learningへ連携するという事例。他にも回転寿司の皿にセンサーをつけて、売れ方や廃棄を管理しているらしい。*3
(2)ガリバーインターナショナル
ユーザ認証毎?のイベント駆動でモバイルアプリにメッセージをプッシュ配信するという事例
[まとめ]
・両サービスの特徴としては、全てAWSのマネージドサービスで構築されており、EC2を一切使っていないこと。
→プログラミングが不要となる、とのこと。*4
・開発および運用をスピーディーに実行することができる。
→1ヶ月かかっていた作業が3日で完了するようになった。
Oracle Certified Expert, Java Platform, EE 6 Web Component Developerうかった
Oracle Certified Expert, Java Platform, EE 6 Web Component Developer(OCJ-WC)に合格した。
受験動機としては、生のサーブレットを触ったり、アプリケーションサーバにデプロイする資産構成をまとめたりする機会があり、体系的な知識を得るために勉強しておきたかった為。
【試験名】
Java EE 6 Web Component Developer Certified Expert Exam
Java EE 6 Web Component Developer Certified Expert | Oracle Certification Exam
【勉強方法】
JavaEE6の資格に対応した日本語の問題集がないので、英語の問題集をメインに使用し、その他書籍やWeb上の情報を使いながら勉強した。
問題集を1~2周する中で、都度JavaDocを確認したり、サンプルアプリを作ったりし、問題集の各単元ごとに出てくるコードや設定を確認する、という学習方法をとった。
また不安に感じた部分は検証し、ブログの記事として書いた。
http-method-omissionを試す - ITお絵かき修行
サーブレット3.0のセキュリティ系アノテーションを試す - ITお絵かき修行
【使用した教材 書籍】
1.『Ocejwcd Study Companion: Certified Expert Java Ee 6 Web Component Developer (Oracle Exam 1z0-899)』
Ocejwcd Study Companion: Certified Expert Java Ee 6 Web Component Developer (Oracle Exam 1z0-899)
- 作者: Charles Lyons
- 出版社/メーカー: Garner Press
- 発売日: 2012/08/15
- メディア: ペーパーバック
- この商品を含むブログを見る
■使用感
ゴツくて重い。確実に筋力がつく*1
全22章、666ページあるので1周するのが非常にしんどい。
ただこの1冊を理解できたらサーブレット3.0の仕様はマスターした、といっても過言ではないと思う。そのくらい仕様を細かく解説している。
問題の精度はそこそこ。若干細かすぎる感がある。レベル感は少し難しめ(と感じた)。
章ごとの構成は「解説+問題」というオーソドックスな構成。自分は問題のみ使用して、解説は都度読んだ。
誤植が少なからず存在するので、詰まったときは早めに回答を見たほうが精神衛生上良い。
■総評
後で紹介するSJC-WC用の紫本のほうがオススメ。ただし、万全を期したいのであれば買ったほうがいいかも。
自分はこの機会に英語の問題文に慣れる、という気持ち込みで買った。今となっては買ってよかったと思っている。
2.『SUN教科書 Webコンポーネントディベロッパ(SJC-WC) 試験番号:310-083』
SUN教科書 Webコンポーネントディベロッパ(SJC-WC) 試験番号:310-083
- 作者: 山本道子
- 出版社/メーカー: 翔泳社
- 発売日: 2010/06/29
- メディア: 単行本(ソフトカバー)
- 購入: 4人 クリック: 23回
- この商品を含むブログ (9件) を見る
JavaGoldの紫本より少し薄く、少し重い。
内容自体はJavaEE5時代の試験に対応した内容だが、十分対応できる。
ただしサーブレット2.5と3.0とで仕様が変わってる部分がたくさんあるので、サーブレット3.0に関する情報は別途自分で集めなければならない。
本番の試験でも「ここ紫本でやったところだ…!」的な問題が少なからずあった。レベル感は本番の試験と似ている。(問題によっては若干易しいかも)
■総評
合格したいなら絶対に買うべき。書籍はこれ一冊でもいいかも。
3.『Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava (Programmer’s SELECTION)』
Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava (Programmer’s SELECTION)
- 作者: Antonio Goncalves,日本オラクル株式会社,株式会社プロシステムエルオーシー
- 出版社/メーカー: 翔泳社
- 発売日: 2012/03/09
- メディア: 大型本
- 購入: 5人 クリック: 147回
- この商品を含むブログ (28件) を見る
重い。詰まってる感がある。1.の問題集と同時に持ち運ぶのはかなり厳しい。
■総評
試験勉強ではほとんど使わなかった。ただしRESTful Webサービスに関する説明は参考になった。
【使用した教材 Web】
1.サーブレット仕様書、第 3.0 最終版
http://www.cresc.co.jp/tech/java/Servlet_Specifications/Servlet_Specification_3_0_Japanese.pdf
2.Java EE | TECHSCORE(テックスコア)
Java EE | TECHSCORE(テックスコア)
3.サーブレット3.0の新機能(1/5):CodeZine
サーブレット3.0の新機能 (1/5):CodeZine
4.Servlet 3.0 の新機能概要 | 寺田 佳央 - Yoshio Terada
Servlet 3.0 の新機能概要 | 寺田 佳央 - Yoshio Terada
1.2.は初めて勉強する際に一通り目を通した。
3.4.は都度確認する際に使用した。受験直前までお世話になった。
【試験の感想】
・JavaSEの試験のようにコードを追いかけていく試験ではなく、基本的に暗記モノの試験なので時間が足りないと感じることは無かった。
・JSP、カスタムタグ、JSTL、EL式、デプロイメント記述子(web.xml)のタグ情報や組み合わせ、設定可能な属性を執拗に聞かれる。なので、その他の部分の割とわかりやすい部分(「Java サーブレットの概要」など)で点を落とさないようにするべき。
・合格ライン61%に対して、正解率71%だった。自分はセキュリティに関するアノテーションが苦手だった。
RedmineのREST APIを使ってチケット登録・参照
RedmineにはRESTのAPIが用意されており、HTTPボディ部にJSON or xml形式のデータを指定してリクエストを送信することで、チケットに対するCRUD操作ができる。
今回はRedmine公式が配布している「Redmine Java API library」*1というライブラリを使ってチケット登録してみた。
【すること】
・RedmineのREST APIを使ってチケット登録・参照
→登録は1件単位で、参照は1件単位およびプロジェクトに含まれる全てのチケット情報単位で実行できるようにする。
【環境】
●OS
Windows7 64bit
●Redmine系
- Redmine 2.6.2
- Apache 2.4.12
- MySQL 5.5.42
- Ruby 2.0.0-p594-i386-mingw32
- Rails 4.2.0
- RubyGems 1.8.12
Redmine Cloud Hosting, Redmine Hosting - Installers and VM
※インストールが面倒だったので上記のオールインワンパッケージを入れた。
※ソースコード管理は別立てのGitで行うので入れなかった。
●Redmine操作用ライブラリ
Redmine Java API library 2.1.0
taskadapter/redmine-java-api · GitHub
●Java
jdk1.8.0_25
【Redmine Java API libraryのコンパイルに必要なライブラリ】
ソースをGithubから取得するため、依存関係にあるライブラリは別途取得する必要がある。
Gradleのビルドスクリプトが同梱されているので、実行することで実行資産を作成可能(のはず)。
# Gradleの使い方がわからなかったので、スクリプトを読んでググって人力で集めたorz
1.HttpClient
httpclient-4.4.jar
httpcore-4.4.jar
2.CommonsCodec
commons-codec-1.10.jar
3.fest ※テスティングフレームワーク
fest-assert-1.4.jar
4.SLF4J
slf4j-api-1.6.6.jar
slf4j-log4j12-1.6.6.jar
6.org-json-java ※jsonパーサ
org.json-20120521.jar
【事前準備】
1.Redmine側で、管理 → 設定 → 認証 の順で設定ページを表示した後、
[REST による Web サービスを有効にする] にチェックを入れる必要がある。
2.自分のユーザのアクセスキー(APIキー)を確認する。
⇒ 個人設定 ページの右側(デフォルトテーマの場合)に表示されている。
【処理】
1.TicketClient クラス
⇒チケット発行&取得する。
⇒チケット発行においては「題名」が重複する場合はチケットを発行しない仕様としている。発行が目的なので・・・
package sample.redmine; import java.util.List; import java.util.Optional; import com.taskadapter.redmineapi.IssueManager; import com.taskadapter.redmineapi.RedmineException; import com.taskadapter.redmineapi.RedmineManager; import com.taskadapter.redmineapi.RedmineManagerFactory; import com.taskadapter.redmineapi.bean.Issue; import com.taskadapter.redmineapi.bean.IssueFactory; import com.taskadapter.redmineapi.bean.Project; import com.taskadapter.redmineapi.bean.ProjectFactory; import com.taskadapter.redmineapi.bean.Tracker; import com.taskadapter.redmineapi.bean.TrackerFactory; import com.taskadapter.redmineapi.bean.User; public class TicketClient { private static final String BUG = "バグ"; private static final String FUNCTION = "機能"; private static final String SUPPORT = "サポート"; private RedmineManager redmineMgr = null; private IssueManager issueMgr = null; private List<User> userList = null; private boolean flg = false; public void setup(String url, String apiAccessKey) throws Throwable { System.out.println("【接続先】" + url); redmineMgr = RedmineManagerFactory.createWithApiKey(url, apiAccessKey); issueMgr = redmineMgr.getIssueManager(); userList = redmineMgr.getUserManager().getUsers(); flg = true; } private void flgChk() { if (!flg) { System.err.println("TicketClient#setup(String, String)を先に実行してください。"); System.exit(1); } } public void putIssue(String projectKey, String trackerName, String subject, String description) throws RedmineException { flgChk(); System.out.println("■■■チケットを1件登録します。■■■"); // チケット名重複チェック if(chkSubject(projectKey, subject)){ System.out.println("題名が重複する場合、チケットは発行しません。題名 :" + subject); }else { // Issue(1チケット)生成 Issue issue = IssueFactory.create(null); // プロジェクト setProjectInfo(issue, projectKey); // 題名 issue.setSubject(subject); // 説明 issue.setDescription(description); // トラッカー setTrackerInfo(issue, trackerName); // 1チケット登録 Issue newIssue = issueMgr.createIssue(issue); issueMgr.update(newIssue); System.out.println("チケットを登録しました。題名 :" + subject); } } private void setProjectInfo(Issue issue, String projectKey) throws RedmineException { int intProjectKey = redmineMgr.getProjectManager().getProjectByKey(projectKey).getId(); Project project = ProjectFactory.create(intProjectKey); issue.setProject(project); } private void setTrackerInfo(Issue issue, String trackerName) { int trackerId = getTrackerId(trackerName); Tracker tracker = TrackerFactory.create(trackerId, null); // 第二引数はなくてもよい issue.setTracker(tracker); } private boolean chkSubject(String projectKey, String subject) throws RedmineException { List<Issue> issues = issueMgr.getIssues(projectKey, null); // 第二引数はなくてもよい? boolean contains = issues.stream().anyMatch(a -> { if(subject.equals(a.getSubject())){ return true; } return false; }); return contains; } private int getTrackerId(String trackerName) { switch (trackerName) { case BUG: return 1; case FUNCTION: return 2; case SUPPORT: return 3; default: return 1; } } public List<Issue> getAllIssues(String projectKey) throws RedmineException { flgChk(); System.out.println("■■■チケットを全件取得します。■■■"); List<Issue> issues = issueMgr.getIssues(projectKey, null); // 第二引数はなくてもよい? System.out.println("チケットの件数 : " + issues.size()); issues.stream().forEach(is -> { System.out.println("【題名】" + is.getSubject()); }); return issues; } public Issue getOneIssue(String projectKey, String subject) throws RedmineException { flgChk(); System.out.println("■■■チケットを1件取得します。■■■"); List<Issue> issues = issueMgr.getIssues(projectKey, null); // 第二引数はなくてもよい? // チケットの探索(無かったらnull) Optional<Issue> is = issues.stream().filter(i ->(i.getSubject().equals(subject))).findAny(); if(is.isPresent()){ System.out.println("【題名】" + is.get().getSubject()); return is.get(); } System.out.println("チケットは取得できませんでした。" ); return null; } }
2.TicketClientTest クラス
⇒TicketClientクラスの各操作メソッドを実行する。
package sample.redmine; import java.util.List; import com.taskadapter.redmineapi.RedmineException; import com.taskadapter.redmineapi.bean.Issue; public class TicketClientTest { /** * mainメソッド * * @param args */ public static void main(String[] args) { TicketClient client = new TicketClient(); try { client.setup("(RedmineのトップページURL)", "(アクセスキー)"); // 全件取得 List<Issue> allIssues = client.getAllIssues("(プロジェクトの識別名)"); // 1件登録 client.putIssue("(プロジェクトの識別名)", "バグ", "題名題名題名題名題名題名", "説明説明説明説明説明説明説明説明説明説明"); // 1件取得 Issue issue = client.getOneIssue("(プロジェクトの識別名)", "題名題名題名題名題名題名"); } catch (RedmineException e) { e.printStackTrace(); } catch (Throwable th) { th.printStackTrace(); } } }
【実行結果】
●実行前
※実行前に「前もってきっておいたチケット」というチケットを作成済。
●実行後
【実行ログ ※標準出力】
【接続先】(RedmineのトップページURL) ■■■チケットを全件取得します。■■■ チケットの件数 : 1 【題名】前もってきっておいたチケット ■■■チケットを1件登録します。■■■ チケットを登録しました。題名 :題名題名題名題名題名題名 ■■■チケットを1件取得します。■■■ 【題名】題名題名題名題名題名題名
【感想】
・Redmine Java API libraryはJSON or XMLデータの取り回しやHttp通信時の例外処理を隠蔽し、1チケット分の情報を取り回すBeanと操作メソッドを用意しているため、かゆいところにだいたい手が届くライブラリだった。
⇒カスタムフィールドの操作も簡単だった。履歴情報が操作できるかは要検証。
※JSON or XMLデータをいじって実装していたときは、名前空間やタグに関するドキュメントが少なくよく迷ったので、かなり楽になった。
・チケットを削除する場合はIssueManager#deleteIssueを実行する。
・今回作ったクラスでは、操作側にRedmine Java API libraryのクラスが見えてるので、見えないようにする必要がある。
【参考文献】
Rest api - Redmine
Rest api with java - Redmine
いぬこいのこや Redmineのチケット登録をRedmine REST APIを使ってやってみる
RedmineのREST APIを使ってみる | 世界はどこまでもシンプルである
Redmine(オールインワンパッケージ)のWindowsへの導入メモ - Qiita
Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築
- 作者: 綿引琢磨,須江信洋,林政利,今井勝信
- 出版社/メーカー: 翔泳社
- 発売日: 2014/11/07
- メディア: Kindle版
- この商品を含むブログ (1件) を見る