Goalist Developers Blog

Gradle利用のSeaser2(S2JDBC)をJava8にする

Java7でS2JDBCを使っているプロジェクトをJava8にしたので手順を残します。
プロジェクト自体はGradleで管理されています。
EOLの問題があるけど、諸事情によりS2JDBCをJava8に対応させないといけない場合に役に立てばいいなぁと思います。
やるべきこと(確認ポイント)は以下です。

  • Gradleの設定をJava8でコンパイルするように変更する
  • s2-frameworkのjavassistだけを新しいものに置き換える
  • javax.transaction-apiが必要な場合は入れる
  • MySQLはバージョン5系を使う

1. Gradleの設定をJava8でコンパイルするように変更する

これはそんなに難しくないと思います、build.gradleの対象ヶ所を書き換えます。

sourceCompatibility = 1.8
targetCompatibility = 1.8

2. s2-frameworkのjavassistだけを新しいものに置き換える

今回の作業で一番はまったのはここでした。 dependenciesで以下のように設定しても古いjavassistが含まれてしまいます。

 // https://mvnrepository.com/artifact/org.seasar.container/s2-framework
 compile('org.seasar.container:s2-framework:2.4.44') {
   exclude module: 'javassist' 
 }
 // https://mvnrepository.com/artifact/org.javassist/javassist 
 compile group: 'org.javassist', name: 'javassist', version: '3.20.0-GA'   

 // https://mvnrepository.com/artifact/org.seasar.container/s2-tiger
 compile group: 'org.seasar.container', name: 's2-tiger', version: '2.4.44'   

 // https://mvnrepository.com/artifact/org.seasar.container/s2-extension
 compile group: 'org.seasar.container', name: 's2-extension', version: '2.4.44'

s2-frameworkでexcludeしてもs2-tigerやs2-extensionの部分で古いjavassistを取得してしまいます。
上記の設定からs2-framework以外を省いてgradle dependenciesで確認すると古いjavassistが含まれないので、excludeは機能していることが確認できます。 解決策としては以下のようにexcludeではなく、configurationsで全体から外してやればOKです。

configurations {
    all*.exclude group: 'jboss', module: 'javassist'
}

dependencies {
    // https://mvnrepository.com/artifact/org.seasar.container/s2-framework
    compile group: 'org.seasar.container', name: 's2-framework', version: '2.4.44'
    // https://mvnrepository.com/artifact/org.javassist/javassist 
    compile group: 'org.javassist', name: 'javassist', version: '3.20.0-GA'
    // https://mvnrepository.com/artifact/org.seasar.container/s2-tiger
    compile group: 'org.seasar.container', name: 's2-tiger', version: '2.4.44'
    // https://mvnrepository.com/artifact/org.seasar.container/s2-extension
    compile group: 'org.seasar.container', name: 's2-extension', version: '2.4.44'
    // https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api
    compile group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2'
}

3. javax.transaction-apiが必要な場合は入れる

ここまでを実行して以下のエラーで怒られた場合はjavax.transaction-apiが足らないので入れましょう。

Caused by: java.lang.ClassNotFoundException: javax.transaction.UserTransaction
    // https://mvnrepository.com/artifact/javax.transaction/javax.transaction-api
    compile group: 'javax.transaction', name: 'javax.transaction-api', version: '1.3'

4. MySQLはバージョン5系を使う

Java8に上げるついでにMySQLコネクタのバージョンを6にしてみたのですが、エラーで怒られました。ドライバ名が変わったのが原因だったので、あきらめて5系を使えば大丈夫でした。
たぶんS2JDBCのdialectの設定が新しいドライバ名に対応していません。 ドライバ名について詳しくはこちら。
datameer.zendesk.com

まとめ

今回は既存のバッチプログラムをマルチスレッド化するために、どうしてもJava8が使いたかったのでSeaser2(S2JDBC)をJava8に対応させました。

JSでファイルダウンロードを実行したい場合はどうしたらいい?

一般的に、ファイルダウンロードのために

<a href="https://example.com/my_file.txt" download>click</a>

的なコードで行ってると思いますが、たまにリンクが事前に分からない状態であり、ボタンをクリックした後でリンクを作成してからダウンロードを実行する時もあります。その場合、サーバーが返してくれるリンクのダウンロード実行をjavascriptで行って欲しい時もあるかと思います。

普通のやり方

ほとんどの時、

document.location.assign(url);

window.open(url, '_self');

と書いて、実行できるかと思います。ただし、ファイルの種類によってブラウザーに怒られる可能性もあります。 この間まさに、

f:id:c-pattamada:20180517113207p:plain

と怒られました。 つまり、「本当のファイルがzipなのに、なんでtext扱いしてるの?!」と。 ただのワーニングなのです。でも解決があるかどうか、を調べて見ました。

まずは、

window.open(url, '_blank')

はどうでしょうか?

f:id:c-pattamada:20180517113225p:plain

確かにな、サイトが勝手に何かをダウンロードして欲しくないよね、と思いました。javascriptはそういうことのためにもいっぱい使われてますね。納得。

ですが、一方にあるポップアップブロッカーの存在すら気づいてないお客さんもいるらしい。ダウンロード期待してるのに、何も起こらなくて困ってて問い合わせが頻繁にくるというのが聞きましたので、このままじゃダメだねと思いました。

ということで、ポップアップブロッカーのCMを作りました。 違います。

元のワーニングありの状態に戻すか、別な方法を探すかという二つの選択肢がありました。

リンク作成後->更新してクリック。

まずはhtmlのリンクを作成します。

<a download id="downloadLink" #downloadLink style="display:none;"></a>

‘download’が書いてあるので、ブラウザーがリンクされてるファイルを開こうとせずに、ダウンロードする。

Angularの〇〇.component.tsの中からhtmlをアクセスする方法はこんな感じです:

@ViewChild('downloadLink') downloadLink: ElementRef;

では、このhtmlをどう編集すればいいでしょうか?

this.downloadService.getDownloadUrl(myVariables).subscribe(
       myUrl => { //サーバーからurlをもらって、
                 // 上記のリンクを更新して
        this.downloadLink.nativeElement.href = myUrl; 
        this.downloadLink.nativeElement.click(); 
                  //終わったら、クリックできなくする。
        this.downloadLink.nativeElement.removeAttribute('href');
        }
);

をやって見たら何も文句言わずにダウンロードできました。

結論

こういうものでしょうかな。ワーニング付けの一つめの方法と最後の方法のどっちのほうが好み次第だと思います。 個人的にワーニングをなくそうと頑張ってるつもりながら、2番目の方法は本来ユーザーがするはずのリンククリックをプログラムで実行してるのでちょっとづるいと思ってるところもありました。

JenkinsのPublish Over SSHプラグインでEC2上にjarを配布する

Gradleプロジェクトにしてjarをビルドしてるので
ポチッとな〜するだけでデプロイ作業完了できます

ビルド環境

  • Amazon Linux AMI 2017.09.1.20180307 x86_64 HVM GP2
  • Jenkins ver. 2.111

配布先サーバーもAWS EC2です

やってること

  • Gradleでjarをビルド
  • Jenkinsで配布
  • 場所をチョトダケ動かすヨ

手順

1. Jenkinsで配布先サーバーの登録

Publish Over SSH Plugin - Jenkins - Jenkins Wiki

Jenkinsの管理 > システムの設定 > Publish over SSH

Key
配布先への接続用公開鍵をコピペ

Name
判別しやすい名前をつける

Hostname
配布先のホスト

Username
配布先もec2 linuxなのでec2-userでいく

Remote Directory
なにも指定しなければ↑で指定したユーザーのホームディレクトリ

f:id:y-iio:20180509123510p:plain

Test Configurationで失敗する?
配布先サーバのセキュリティグループで、ビルドサーバからのssh接続を許可するのをお忘れなく

2. Jenkinsジョブの設定

2.1. Gradleでjarをビルドする

Gradle Plugin - Jenkins - Jenkins Wiki

Jenkinsジョブ > ビルド > Invoke Gradle script
Use Gradle Wrapper
Tasks にタスク名を指定

かんたん!

f:id:y-iio:20180509122525p:plain

2.2. 配布する

Jenkinsジョブ > ビルド後の処理 > Send build artifacts over SSH

Name
ドロップダウンでさっき登録したサーバが選べるようになっている

Transfer Sets
Source files
ビルド成果物までのパス

Remove prefix
これ指定しないと配布先にも同様のパスがつくられる

Remote directory
配布先のディレクトリを指定
サーバー設定のRemote Directoryでなにも指定してなければ
↑で指定したユーザーのホームディレクトリからの相対パス

Exec command
上書きして配布することができないので、いったん送りつけた後ファイルの場所を移動している

なんかEither Source files, Exec command or both must be suppliedとかエラーメッセージ出ているが無視

f:id:y-iio:20180509123526p:plain

これで終わり〜

IaC by Terraform ~DAY3: Terraform Commands (2)~

どうも,エンジニアのナカノです.

今や完全に春真っ最中な時期ですが,暑さがまるで夏の様です.

そのため,日中は汗だくで辛いです.これでは夏に耐えられぬ....

さて,今回は前回の記事の内容の続きとなります.

前回はよく使われるTerraformのコマンドに関する内容でした.

今回の内容は,場合によって役立つTerraformのコマンドに関してです.

目 次
  • 場合によって役立つコマンド
    • 出力コマンド
      • graph
      • output
      • show
    • その他
      • console
      • get
      • import
      • providers
  • 最後に

場合によって役立つコマンド

出力コマンド

graph

設定内容或いはplanapplydestroyなどのコマンドの結果を,ビジュアルなものとして出力してくれるコマンドです.

これを実行すると設定間の関連などが視覚的に分かるため,確認作業を行う上では役立つかもしれません.

ただ,設定が多すぎると出力結果がかえって見辛くなるため,使いどころは考える必要があるかなと思います. www.terraform.io

output

ただ単にterraform outputを実行すると,設定された全ての出力値が表示されます.

また,コマンド実行の際に-jsonオプションを使うと,出力結果のフォーマットをJSON形式に変えることが出来ます.

JSON形式での出力が出来るため,例えばjqコマンドと組み合わせて出力値の利用が可能です.

他にも,オプションの利用により,terraform.tfstateの情報やmoduleの設定内容の出力も出来ます.

一見すると重要そうに見えないですがTerraformに慣れてくると有り難みが分かってくる,そんなコマンドです. www.terraform.io

show

このコマンドを実行すると,ファイルの設定内容をhuman-readableなフォーマットで出力してくれます.

outputコマンドは出力設定の内容しか出力しないのに対し,showコマンドは実装した設定の内容を出力します.

そのため,showコマンドはoutputコマンドよりも詳細な情報を画面に表示してくれます. www.terraform.io

その他

console

文字通りで,コンソールを扱うことが出来ます.一見すると役に立たなさそうなコマンドに思えます.

しかし例えば,このコマンドの実行後に,Terraformで使える関数などの挙動を確認することが出来ます.

挙動の確認なしにplanapplyを行うのは怖いため,挙動確認の点で割と重要なコマンドであると言えるでしょう. www.terraform.io

get

moduleと呼ばれるものを使って実装した場合,planapplyの前にこのコマンドを実行する必要があります.

これを実行すると.terraformディレクトリにmoduleに関するファイルが生成されます.

ただ,今のところはgetを使わずにinitplanapplyを行うだけでこと足りる様になっているみたいです.

実際に,私はTerraformを半年ほど使っていますが,このコマンドを実行せざるを得ない状況に遭遇したことがありません. www.terraform.io

import

Terraformで管理されていないインフラリソースを,Terraformの管理対象にすることが出来るコマンドです.

正確には,このコマンドにより「リソースの情報を追記される様にterraform.tfstateが書き換えられる」といった感じです.

もしterraform.tfstateがない場合は生成されますが,このファイルが既に存在する場合は単に書き換えが行われます.

そのため,このコマンドを実行した後は「最新化されたterraform.tfstateをもとに.tfファイルを作成して差分をなくす」作業が必要となります. www.terraform.io

providers

プロバイダーの情報を画面に表示させるコマンドです.表示形式はツリー構造です.

特に様々なプロバイダーを利用している場合であれば,作業ミスの防止のための確認として役立つかもしれません.

ただ,このコマンドは基本的には使われる機会が殆どないのではと思います. www.terraform.io

最後に

如何でしたでしょうか.普段は重要には感じられないが場合によっては非常に役立ちそうなものばかりですね.

次回は「terraform.tfstateに関連するコマンド」をご紹介したいと思います.

それでは,今回はこの辺りで筆を置かせて頂きます.

次回を乞うご期待ください.

10分でWordPressをEC2+CloudFront+ACMでHTTPSにする

「EC2上にあるWordPressをHTTPS化して!」と頼まれることは誰しも一度は経験すると思います。
今回はそんな時に10分で設定を終わらせる手順を残しておきます。
もちろん証明書はAWS Certificate Manager(ACM)を利用します。
CloudFrontの反映に30分とWordPressのDB置換が人によって時間がかかるので、その時間はご飯でも食べに行ってください。
最後の「まとめ」で詳しく書いていますが、ALB(ELB)をCloudFrontとEC2の間に挟まないと見た目上はHTTPSに見えていても、CloudFrontとEC2の間はHTTP通信(初期設定)でインターネットを経由します。

1. ACMで対象ドメインの証明書を作る

ACMのページで基本デフォルトのまま進めていけばできあがります。
注意点としては以下。特にリージョンは嵌りポイントの1つだと思います。

  • リージョンを東京ではなくバージニア北部を選ぶ
  • 確認メールで設定を完了する場合は最後の「検証方法の選択」画面でEメールの検証を選ぶ

CloudFrontはCDNなので特定リージョンではなく、グローバル扱いです。CloudFrontの設定画面でもグローバルになっています。作ったはずの証明書がCloudFrontの設定画面で出てこない!という場合は証明書のリージョンが間違っている場合が100%だと思います。

2. WordPressのあるEC2のパブリックDNSを確認する

f:id:t-moritsugu:20180424191806p:plain

ElasticIPを貼り付けたらパブリックDNSが消えたよ!という場合はサービス一覧からVPCにいき、対象のEC2に紐づいているVPCを選択し、アクションからDNS解決の編集とDNSホスト名の編集を「はい」にすればパブリックDNSは復活します。

f:id:t-moritsugu:20180424193320p:plain

3. CloudFrontを設定する

Create Distribution > WebのほうでGet Started
以下特に記載のないものはデフォルト値です。

Origin Settings

  • Origin Domain Name: EC2のパブリックDNS
  • Origin ID: 自動で入力されるので、変更したければ変える

Default Cache Behavior Settings

  • Viewer Protocol Policy: Redirect HTTP to HTTPS
  • Allowed HTTP Methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
  • Cache Based on Selected Request Headers: All (Whitelistの場合は許可するヘッダを追加)
  • Forward Cookies: All (Whitelistの場合は許可するcookieを追加)
  • Query String Forwarding and Caching: Forward all, cache based on all (Whitelistの場合は許可するパラメータを追加)

Distribution Settings

  • Alternate Domain Names(CNAMEs): WordPressで公開しているサイトのドメイン
  • SSL Certificate: Custom SSL Certificateを選択し、ACMで作成した証明書を選択する

※証明書が出てこない場合は作成の際にリージョンが間違っているか、Eメールでの認証を行っていないために証明書の作成が完了していないかを確認してください。

特に記載のないものはデフォルトでOKなのでCreate Distributionして30分ぐらいまちます。

4. WordPressをHTTPSに対応させる

現行のWordPressはEC2で動いているのでAMIでバックアップを取ります。
DBがRDSなどでEC2上に無い場合、DBのバックアップもとります。
今回は以下のツールを利用してhttp://xxx.comhttps://xxx.comに置換しました。 interconnectit.com

wp-config.phpに以下を追記

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
        $_SERVER['HTTPS'] = 'on';
} elseif (isset( $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO']) && $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'] === 'https') {
        $_SERVER['HTTPS'] ='on';
}

/* That's all, stop editing! Happy blogging.  ←これの前ぐらいに追記*/

CloudFrontはX_FORWARDED_PROTOヘッダをCLOUDFRONT_FORWARDED_PROTOに勝手に変換するので今回はWordPress側でCLOUDFRONT_FORWARDED_PROTOを判定することにしました。
CloudFront側でX_FORWARDED_PROTOをねじ込む方法もあると思います。

5. Route53でドメインをCloudFrontにむける

以下の値で設定します。

  • Name: WordPressで公開しているサイトのドメイン
  • Type: A
  • Alias: Yes
  • Alias Target: CloudFrontのDomainNameの値

まとめ

念のためですが、今回の構成ではCloudFrontとEC2の間はインターネットを通ります。
CloudFront作成後にOriginタブから選択してEditするとOrigin Protocol Policyという設定があり、デフォルトではHTTPです。従ってデフォルトではCloudFrontとEC2の間は全く暗号化されずれにインターネットを通ります。
とりあえずHTTPSになれば良いよ!ということであれば今回の方法でよいですし、そうでない場合でACMしか許されない場合はCloudFrontとEC2の間にALB(ELB)をはさめば良いです。ALBにはACMの証明書が置けるのでCloudFrontとALBの間をHTTPS通信にします。ALBとEC2の間の通信はインターネットに出ないので目的は達成できます。

ngx-datatableでソートしつつ特定の行を固定する!

angularでデータグリッド表示するのにngx-datatable使ってます

github.com

フロント側でのソート機能がついていますが、こんな感じで合計行まで動いてしまうのですよね

f:id:y-iio:20180413180915g:plain

突っ込んだデータの合計行だけは一番下に固定したいという望みを叶えるべく
ゴリラ的な方法でズズイと無理やりやってみました

マルチソートの対応はしない。漢らしい!

<ngx-datatable
        #dataTable
        [rows]="rows"
        [columns]="columns"
        [sorts]="sorts"
        (sort)="onSorted($event)">
</ngx-datatable>
public rows = [];
public columns = [];
public sorts = [];

@ViewChild('dataTable') private dataTable: DatatableComponent;
private ascSortedColumn: string = '';

public onSorted(event): void {
    // ここにくるとき、this.dataTable._internalRowsは常に昇順ソートがかかった状態になっている
    const columnName: string = event['column']['name'];
    // 一度明示的に昇順ソートした後だったら、ここで無理やり降順ソートの設定に書き換える
    if (this.ascSortedColumn === columnName) {
        this.ascSortedColumn = '';
        event['sorts'][0]['dir'] = 'desc';
        this.sorts = [{
            prop: event['sorts'][0]['prop'],
            dir: 'desc'
        }];
        this.rows = [...this.rows]; // 降順ソートを適用
        setTimeout(() => {
            this.moveSumRow(); // ライブラリ側の降順ソート処理が終わった頃合いを見計らう
        }, 100);
    } else {
        this.ascSortedColumn = columnName;
        this.moveSumRow();
    }
}

// ライブラリ側のソート処理が終わってから、合計行をいちばん後ろに移動させる
private moveSumRow(): void {
    const tmpRows = this.dataTable._internalRows.concat();
    const sumRowIndex: number = tmpRows.findIndex((row) => row.hasOwnProperty('x1field') && row['x1field'] === '合計');
    if (sumRowIndex < 0) {
        return;
    }
    const sumRow = tmpRows[sumRowIndex];
    tmpRows.splice(sumRowIndex, 1); // 合計行をいちばん後ろに移動
    tmpRows.push(sumRow);
    this.sorts = []; // テーブルのソートを解除 // ここで解除しておかないと合計行含めてソートし直されてしまう
    this.dataTable.sorts = []; // ほんとうにむりやりテーブルのソートを解除
    this.rows = [...tmpRows]; // 表を再描画
}

こんなかんじで、一瞬ペイッ!ガタッ!と動きます

f:id:y-iio:20180413180948g:plain

すごい力技だ!
現在選ばれているソート条件アイコンを見えなくすることで全てをうやむやにする!

力という名のパワーで全てを解決しました
男にはやらなきゃならねえ""瞬間とき""がある

Javaの未来

こんにちは、ゴーリストのチナパです。去年の9月より、オラクルさんがJavaをよりはやく更新するといい、同じ9月でJava 9がリリースされ、つい最近Java 10もリリースされました。しかも、今までみんなが使ってたJava 8は2019年の1月までしかアップデートされないらしいです。

f:id:c-pattamada:20180406164916j:plain

最近のオラクルのJava Client Roadmap Updateと言う物でもっと詳細が書かれましたのでそれを軽くサマリーしようと思いました。

http://www.oracle.com/technetwork/java/javase/javaclientroadmapupdate2018mar-4414431.pdf (英語です)

スケジュール

一番重要な情報はどんな風に更新が行う予定なのか、とどんな風にサポートが続くのか。故にそこから始めたいと思います。

Java 8は2019年1月まで公式アップデートが行う予定ですが、個人用(つまり、コーポレート用ではない)のためになら2020年までサポートが続くらしいです。

Java 11 (Java 18.9) は2018年の9月でリリースされる予定です、そしてそれは長期的なサポートに入るそうです(9と10は入りません)。

Java SE 11 (18.9) Platform JSR (384)

Java FX がJava 8 で2022年までサポートが残る予定ですが、Java 11からは外されている。swingとawtがJava 11に残るので、せめて2026年まで使えるらしいです。

変更点

では、Java 10の面白い更新に入りましょう。大きく分けると書き方の変化と裏の改善があります。追加機能いっぱいありますが、一番面白いと思った3つを以下にまとめてます。

変数の種類をコンテクストで理解する

var list = new ArrayList<String>();  // ArrayList<String>と理解してくれます

これはちょっとワクワクですね、自分はパイソンもよく使ってるのでちょっとだけでもコードが綺麗になりそう。一方、下手すると分かりにくくなりますね。 すでに存在してるコードの中のvar 変数は影響されないらしいです(つまり[code]int var = 5;[/code] がエラーを出さないです) そして、イニシャライズされない所にvarが使えない。

var x; //うまく行きません
var x, y = 0; //おっけー

裏の改善

スレッドローカルハンドシェーク:

マルティスレッドのセーフポイントの改善の機能です。結果的に現在のグローバルセーフポイント(全スレッドが中止する時)でしかできない活動をこのハンドシェーク機能で行えることによって効率性が高くなるようです。

CDSの改善=> AppCDS

CDSはJDK 5からありまして、ロード時間を減らすために編集しないクラスをarchiveし、そのarchiveされたクラスを高速でロードできるようになるシステムです。今まで、BootstrapClassLoaderしかできなかった事でしたが、この際AppClassLoader(故にAppCDS)もできるようになるためにエンタプライズ系のアプリのロード時間が結構減らせるらしいです。

他もありますので、下にオラクルの記事をリンクします!

オラクル、Java SE 10の一般提供を開始 | Oracle 日本