20190403のJavaに関する記事は8件です。

JSPのformのパス

サーブレット・JSP formのパス

formのactionのパスについて

eclipseにて開発中ですが
formのパスで悩んだので記録

test.jsp
から
サーブレットクラスの 
RetweetBot2.java
foo.java
にパラメータを送信したい時のパス

RetweetBot2.javafoo.javaの修飾名は下記のものです。
/sample/src/pkg/foo.java

↓のコードだと404エラー

test.jsp
<form action="/sample/src/pkg/foo" method="post">
    <p>送信したいテキストを入力して下さい:
      <input type="text" name="hoge"></p>
      <input type="submit" value="送信">
</form>

。。。。

↓のコードだと送信成功しました。

test.jsp
<form action="/sample/foo" method="post">
    <p>送信したいテキストを入力して下さい:
      <input type="text" name="hoge"></p>
      <input type="submit" value="送信">
</form>

理由は勉強中です。まだ不明です。

理解できたら追記予定です。

・2019/04/06 修正
サーブレットクラス名に誤りがあった為
(誤)RetweetBot2.java → (正)foo.java
に修正しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ifとswitchどっちがいいのか問題

はじめに

  • みなさんコーディングをしてきて、今までに何回ifを書いてきましたか?笑
  • 何万回と書いていても、たまにswitchを使うかifを使うか悩みますよね??(僕は悩むことがあります)

今の僕の選択基準

  • if文を選ぶとき:&&とか||したいとき
  • switchするとき:選択肢がいっぱいあるとき
  • switchするまでもないとき:三項演算子
  • あとは悩んだら感覚
  • てな感じで選んでたわけなんですが、ある日僕は思いました

どっちでもかけるときってどっちがパフォーマンス出るんだろう?

  • 気になったら計測すればいいんじゃね?と思い立ちます
  • いざ、実行!

用意したもの

  • Java1.8
  • IntelliJ IDEA

目次(目次を書いてる時点でやる想定のもの)

  • 100回くらいのループで分岐を走らせる
  • 100回で性能差が出なかったら、桁数を1つずつ増やしていく
  • ある程度満足したら、条件を増やしていく
  • 条件増やすのにも満足したら、文字列と数字のパターンをやる
  • こんな感じでやります

実践

100回くらいのループで分岐を走らせる

  • 実行したコードは下記
CheckPerformance.java
import java.util.stream.IntStream;

public class CheckPerformance {

    public static void main(String[] args) {
        Long start = System.currentTimeMillis();
        // if実行分
        IntStream.rangeClosed(0, 100).forEach(i -> {
            if (i % 2 == 0) {
                System.out.println("偶数です");
            } else if (i % 2 == 1) {
                System.out.println("奇数です");
            } else {
                System.out.println("その他です");
            }
        });

        // switch実行分
        IntStream.rangeClosed(0, 100).forEach(i -> {
            switch (i % 2) {
                case 0:
                    System.out.println("偶数です");
                    break;
                case 1:
                    System.out.println("奇数です");
                    break;
                default:
                    System.out.println("その他です");
                    break;
            }
        });
        Long end = System.currentTimeMillis();
        System.out.println(end - start + "ms");
    }
}
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 7ms 12ms
2回目 15ms 10ms
3回目 13ms 12ms
4回目 8ms 15ms
5回目 10ms 10ms

検証

  • 他にも何回か実行したが、運ゲーみたいになったので100回では性能差を検証するのは難しいと判断
  • 要するに誤差でしかない

1,000回のループで分岐を走らせる

  • ソースは省略
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 36ms 39ms
2回目 33ms 35ms
3回目 31ms 28ms
4回目 38ms 39ms
5回目 38ms 34ms

検証

  • うーん、1,000回でも性能差を検証するのは微妙
  • ここでもまだ、誤差の範疇な気がする

10,000回のループで分岐を走らせる

  • ソースは(ry
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 133ms 119ms
2回目 147ms 136ms
3回目 116ms 121ms
4回目 135ms 130ms
5回目 128ms 136ms

検証

  • うーん、10,000回でも...(ry

100,000回のループで分岐を走らせる

  • ソースは(ry
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 903ms 917ms
2回目 947ms 885ms
3回目 1012ms 964ms
4回目 1109ms 947ms
5回目 943ms 884ms

検証

  • 100,000回でちょっとだけ性能差がでた気がします
  • switchが1秒超えたのが0回だったのに対して、ifは2回ありますね。
  • とはいえ、誤差っちゃ誤差なのかもしれないし、平均値だけみるとswitchの方が早いのかも?って仮説はたちました
  • でも、ちょっと不安なのでもう1桁だけ増やして実行しておきます

1,000,000回のループで分岐を走らせる

  • s..(ry
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 6366ms 6339ms
2回目 6410ms 6396ms
3回目 6794ms 6298ms
4回目 6730ms 6248ms
5回目 6823ms 6495ms

検証

  • 1,000,000回での性能差はご覧の通りです
  • switchの方が速度にばらつきが無かった気がするのと、やっぱり若干ですが早いという結果に
  • とはいえ、100万件やってようやくこれだけしか性能差が出ないんで、普段使いで性能差を意識することはなかなかなさそうですかね

分岐を増やしていく

  • では、ある程度満足したので分岐を増やしていきます
  • ここからは100件でやってもあまり意味がないことがわかったので100万件で実施していきます

まずは分岐を3つにする

  • ソースは省略します
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 6348ms 6476ms
2回目 6751ms 6354ms
3回目 6461ms 6324ms
4回目 6500ms 6411ms
5回目 6537ms 6646ms

検証

  • 分岐3回での性能差はご覧の通りです
  • 平均値でみたときにはswitchの方が、やっぱり若干ですが早いですかね
  • とはいえ、誤差なのかもしれないので分岐を増やします

分岐を5つにする

  • 5つにしたのは計算の都合上と気分です
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 6528ms 6279ms
2回目 6452ms 6507ms
3回目 6661ms 6599ms
4回目 6501ms 6589ms
5回目 6608ms 6322ms

検証

  • 分岐5回での性能差はご覧の通りです
  • うーん誤差の範囲内ですかね。

結論

ifとswitchは性能差はほとんどない!

  • タイトルで釣っておいてあれなんですが、僕なりの結論です
  • 100万件しか実行してないのですが、もっと増えれば変わる可能性はあるかもなのは重々承知してます
  • とはいえ、分岐の数や処理件数でifとswitchでパフォーマンスが顕著に変わることはないっぽいので、その時々に合わせて読みやすくなる実装を選択するという判断が正しい気がします
  • 何かおかしいだろとか、もっとこんな検証した方がいい等々あればコメントでも編集リクエストでもください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】インスタンスメソッド、インスタンスフィールド、クラスメソッド、クラスフィールド、コンストラクタまとめ

Javaを学んでいく中で結構混乱した部分をまとめます。
参考にしているのはProgateです。

1.インスタンスメソッド

インスタンスメソッドはインスタンスが持つ・インスタンスに持たせる「振る舞い」。

メソッドの定義の仕方

public <戻り値の型> <メソッド名>(){
 <メソッドの中身>
}

のように書く。

メソッドの呼び出し方

/* Personクラスのインスタンス、person1を作成 */
Person person1 = new Person();

/* helloメソッドの呼び出し */
person1.hello();

のように呼び出す。

2.インスタンスフィールド

インスタンスフィールドはインスタンスが持つ情報を格納する変数。

インスタンスフィールドの定義の仕方

class Person {
  /* 変数なので型を宣言する */
  public String name;
}

インスタンスフィールドのアクセス方法

/* インスタンスを生成 */
Person person1 = new Person();
/* nameに値をセット */
person1.name = "Suzuki";

/* nameの値を取得 */
System.out.println(person1.name);

このようにアクセスできる。

3.クラスメソッド

クラスに属するメソッド。

クラスメソッドの定義の仕方

class Person {
  public static <戻り値の型> <メソッド名>() {
    <メソッドの中身>
  }
}

※インスタンスメソッドと異なり、static をつけることに注意。

クラスメソッドの呼び出し方

<クラス名>.<メソッド名>();

このように呼び出す。
親の顔ほど見たpublic static void <メソッド>(){ } は実はクラスメソッドのこと。

4.クラスフィールド

クラスに属するフィールド。
クラスに持たせる情報を格納する変数。

クラスフィールドの定義の仕方

class Person {
  public static <データ型> <変数名>;
}

※インスタンスフィールドと異なり、static をつける

クラスフィールドへのアクセス方法

Main.java
class Main {
  public static void main(String[] args) {
    System.out.println("合計" + Person.count + "人です");
    Person person1 = new Person( ... );
    System.out.println("合計" + Person.count + "人です");
  }
}
Person.java
class Person {
  /* countという変数に人数という情報を格納していく */
  public static int count = 0;
  .........
  Person(String firstName, ...) {
    Person.count ++;
  }
}
> 合計0人です
> 合計1人です

※インスタンス生成のたびにcountに1ずつ足していっている

5.コンストラクタ

newでインスタンスを生成後自動で呼び出されるメソッド。
定義方法が決まっているので注意

コンストラクタの定義方法

class Person {
  public String name;
  Person() {
    /* インスタンス生成時行いたい処理 */
  }
}

インスタンス生成時に、インスタンスフィールドにセットしたい値をコンストラクタの引数に渡す

Person.java
class Person {
  public String name;
  Person(String name) {
    this.name = name;
  }
}

コンストラクタの呼び出し方

Main.java
Person person = new Person("Suzuki");
System.out.println(person.name);

6.まとめ

修飾子 static データ型 メソッド名orフィールドの変数名 メソッド名
インスタンスメソッド public - データ型 メソッド名
インスタンスフィールド public - データ型 フィールドの変数名
クラスメソッド public static データ型 メソッド名
クラスフィールド public static データ型 フィールドの変数名
コンストラクタ public - データ型 変数名 クラス名

混乱しやすいですね!
以上です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Authleteを使った認可サーバの構築手順(CIBA対応版)

OAuth/OpenID Connect の CIBA (Client Initiated Backchannel Authentication)ってなに

3/28(木)に開催された「OAuth & OIDC 勉強会(FAPI & CIBA 特集!) 」へ行ってきました。

主催はAuthlete社という、OAuthやOpenID Connect(以下OIDC)の認可サーバを構築できるBaasを提供する企業です。そのAuthlete社のクラウドサービスが、OAuth/OIDCの新仕様である CIBAに対応したということで、そのクラウドサービスの紹介もかねた勉強会でした。

わたくしOAuthはともかく、CIBAは初見だったので、むちゃくちゃ勉強になりました。勉強会を主催されたAuthlete社の方々、ありがとうございました。

今回はFAPI(Financial-grade API) とCIBA(Client Initiated Backchannel Authentication) についてだったのですが、FAPIに関しては「金融業界などのよりセキュリティ要件が高いところでOAuth/OIDCを使うときの制約事項」が仕様化されたモノと考えればよさそう。わかりやすい例だと、トークンを取るときのOAuth Clientのクライアントの認証はBasic認証はダメでX.509の証明書を用意してね、などなど。。

またCIBAとは、OpenID Connect Client Initiated Backchannel Authentication Flow - Core 1.0 のことで、いままでのOAuth/OIDC(いわゆるRFC 6749)が WEBブラウザのリダイレクトを用いる前提の処理シーケンスだったのに対し1、CIBAではバックチャネル認証エンドポイントに認証リクエストを送ると、事前に登録していたユーザの認証デバイスに「同意する?」って通知がとぶという処理シーケンスになってるのが特徴です。。

これによってたとえば、

  • Alexaに「xxxを買うから¥3,000払っといて!」というと、Alexaアプリが認可サーバに認証リクエストを送り
  • 認可サーバは「許可する?」って通知を認証デバイスに(スマホアプリ)に通知して
  • ユーザがスマホでOKを押せば、決済が完了する

なんていう、ブラウザのリダイレクトが不要な処理シーケンスが実現できるというわけです。うーん、なるほど便利です。

具体的な処理シーケンスは、だいたいこんな感じになりそうですね。。

image.png

イントロ

さて以前、とある開発案件でAuthleteサービスをさわれる機会がありまして、そのときの構築手順をHelloWorld程度ですがQiita に投稿しました。

今回はラッキーにもCIBA対応したAuthleteサービスをさわる機会をいただきましたので、備忘として構築手順を記録しておきます。(感謝です!)

前提知識

下記の構築手順を読む上での前提知識ですが、ある程度OAuth/OIDC とCIBAをしってる前提で話を進めます。たとえば、Authorization Code Grant Flow やCIBA Flowの処理シーケンスをだいたい知ってる、などです。

さて下記は、Authorization Code Grant Flow いわゆる OAuth Danceな処理シーケンスです。Authleteの位置づけも一緒に書いています。

  • Authorization Code Grant Flow の処理シーケンス

image.png

今回はCIBA対応されたAuthleteをさわるってことで、下記のような(さきほど載せた) CIBA Flowの処理シーケンスを実装してアクセストークンを取得するところまでをやってみます。認証デバイスについては、認証デバイスのシミュレータサイトがあるので、そのサイトを使用します。

  • CIBA Flowの処理シーケンス

image.png

また「ユーザが認証デバイスでオペした結果(認可・拒否・タイムアウトetc.)」をOAuth Clientが知る方法としてpoll,pingもしくはpushという3つのモードがあるのですが、今回は「poll」を使います。このモードはOAuth Clientが認可サーバへポーリングすることで、ユーザのオペ結果を知るという方法です。ping,pushはまだ試してないのですが、pingの場合は認可サーバから「取りに来てイイよ」っていうHTTPSでの通知が来る、pushはそのままアクセストークンが送られてくるようですね。(参考: 9. Client Notification Endpoint )

前提環境

今回構築する環境まわりは以下の通りです。

$ sw_vers
ProductName:    Mac OS X
ProductVersion:    10.14.4
BuildVersion:    18E226
$ java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
$ mvn --version
Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-25T03:41:47+09:00)
$
$ curl --version
curl 7.54.0 (x86_64-apple-darwin18.0) libcurl/7.54.0 LibreSSL/2.6.5 zlib/1.2.11 nghttp2/1.24.1
$
$ jq --version
jq-1.6
$

上記でやってますが、mavenとcurl, jq (とgit)が動けば、OS含めなんでもOKだと思います。

準備

また、各種サーバなど登場人物ですが、前回記事では

用途 サーバ名 URL
認可サーバ。ユーザIDごとの認可情報を管理するサーバ。 java-oauth-server http://oauth.example.com:8080/
リソースサーバ。ユーザIDごとのデータや機能をもったサーバ。 java-resource-server http://resource.example.com:8081/
Webアプリケーション。リソースサーバのリソースを使用するWebアプリ java-oauth-client http://client.example.com:8082/

としていたのですが、今回は、アクセストークン(やid_token)を取得するまでの記事にしているので、リソースサーバは省略、またOAuth Clientとしてcurlコマンドを使用します。従って、下記のようなシンプルな構成になります。

用途 サーバ名 URL
認可サーバ。ユーザIDごとの認可情報を管理するサーバ。 java-oauth-server http://localhost:8080/
リソースサーバ。ユーザIDごとのデータや機能をもったサーバ。 省略 -
OAuth Client。リソースサーバのリソースを使用するアプリ。 今回はcurl -

おおまかな流れ

おおまかな流れについても、基本的にいままでのAuthleteの使用方法と変わらず、

  1. Authleteへのサインアップ
  2. 認可サーバの登録・クライアントの登録
  3. 認可サーバの構築、リソースサーバの構築(省略)
  4. Webアプリケーションからの疎通(アクセストークン取るまで)

となるのですが、Authlete を使って CIBA 対応の認可サーバーを作る (中のヒトかな)の記事にあるように、アカウントのサインアップはAuthlete社の方に問い合わせる必要がありそうです。

したがって今回の記事では、アカウントのサインアップが済んでいて、CIBA対応のAuthleteのサイト(通常だと https://so.authlete.com/ だけどCIBA対応版は別URL )で下記の情報は取得済、という前提で話を進めます。

  • そのアカウントにひもづく認可サーバの、API キー/API シークレット
API キー API シークレット
116xxxxxxxx sZUkxxxxxxxxxxxxxxxxxxx
  • その認可サーバに登録されたOAuth Clientの クライアント ID/クライアントシークレット
クライアント ID クライアントシークレット
249xxxxxxx WUItxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

ちなみに、認可サーバのAPI キー/API シークレット は、下記の サービス一覧 >> サービス詳細より 確認できます。
image.png

また、認可サーバに登録されたOAuth Clientの クライアント ID/クライアントシークレット は、クライアントアプリ開発者コンソール の、アプリ一覧 >> アプリ詳細より 確認できます。
image.png

環境設定

さて、AuthleteのWEBサイトでCIBAを使用可能にするための環境設定をいくつか。

認可サーバ側の設定

さきほどの、認可サーバ側の API キー/API シークレット を確認したサイト(サービス管理者コンソール)
にて「サービス一覧 >> サービス詳細 >> CIBA」タブに遷移し、

項目
サポートするトークンデリバリーモード POLL,PING,PUSH
ユーザーコードのサポート サポートする

を選択します。

image.png

OAuth Client側の設定

OAuth Clientの クライアント ID/クライアントシークレット を確認したサイト(クライアントアプリ開発者コンソール)にて「アプリ一覧 >> アプリ詳細」に遷移。

「基本情報」タブにて

項目
クライアントタイプ CONFIDENTIAL

を選択します。

image.png

「認可」タブにて

項目
クライアント認証方式 CLIENT_SECRET_BASIC

を選択します。

image.png

「CIBA」タブにて

項目
トークンデリバリーモード POLL
ユーザーコードの要求 要求する

を選択します。

image.png

以上で、POLLモードで動かすときの認可サーバ、OAuth Clientの環境設定は完了です。

動かしてみる

認可サーバを構築

まずは、認可サーバを構築します。GitHubのリポジトリをcloneしてきて、設定ファイル(authlete.properties)に API キー、API シークレット、base_urlを設定すればOKです。

$ git clone https://github.com/authlete/java-oauth-server.git
$ cd java-oauth-server
$ cat authlete.properties
service.api_key = 116xxxxxxxx   ← 正しい API キー に変更してください
service.api_secret = sZUkxxxxxxxxxxxxxxxxxxx   ← 正しい API シークレット に変更してください
base_url = https://api.authlete.com   ← CIBA 対応のURLに変更してください(値はAuthlete社さんに要問い合わせ)

起動します。

$ mvn clean jetty:run  -Dauthlete.ad.workspace=masatomix/testProject ← 引数は後ででてくるシミュレータで設定する値

以上で、認可サーバの構築は完了です。

認証デバイスの準備

バックチャネル認証リクエストを受信した認可サーバは、認証デバイスに対して「許可してよい?」という通知を送りますが、cloneしてきた認可サーバのコードはデフォルトでAuthlete CIBA Simulator へ通知を送るようになっています。なのでシミュレータのセットアップをおこないます。

https://cibasim.authlete.com/ へアクセスし、さきほどの引数に設定した、

Namespace Project
masatomix testProject

を指定し「Create」をクリック。(下記画面キャプチャは作成した後のもので「Open」になってますが。。)

image.png

すると、Authentication Device(AD)のシミュレータ画面に遷移します。Authleteさん提供の認可サーバはダミーのユーザ認証がコーディングされていて、

User ID User Code
1001 675325

でログイン可能となっています。従って、キャプチャにあるとおり「1001」というUser IDを指定して「Launch AD simulator」をクリック。

image.png

シミュレータが待ち状態になりました。この画面でOAuthの認証/認可を行うので、画面は閉じずに出しておいてください(認可サーバがバックチャネル認証リクエストを受信したときにここにWebSocketでプッシュ通知がくるっぽい)。

image.png

ちなみに、この画面をスマホとかで開いておくと、わりと臨場感がでます。全然関係ないPC上のcurlから認証リクエストを送ると、スマホに通知が来るようなイメージです。
image.png

バックチャネル認証リクエストを送信

さてさっそく認可サーバへ、認証リクエストを送ってみます。

$ clientId=249xxxxxxx  ← クライアント ID
$ clientSecret=WUItxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  ← クライアントシークレット
$ curl http://localhost:8080/api/backchannel/authentication -X POST \
--user ${clientId}:${clientSecret} \
-d 'login_hint=1001' \
-d 'user_code=675325' \
-d 'scope=openid' 
{
  "auth_req_id": "Xe250q9AoSdUL_xohrPm8txYNUo8VlddhLv1ENUY6SM",
  "interval": 5,
  "expires_in": 600
}
$

auth_req_id (認証リクエストID)が得られました。後でつかうので記録しておいてください。

認証デバイスで、認証処理

認証リクエストを送信すると、さきのほどのシミュレータにOAuthでおなじみの認可画面が表示されていると思います。今回は「Allow」を選択。
image.png

トークンリクエストを送信

ユーザの認可が得られたので、さきほどの auth_req_id が使用可能になっています。トークンを取得する準備が出来ていますので、トークンリクエストを送信します。

$ clientId=249xxxxxxx  ← クライアント ID
$ clientSecret=WUItxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  ← クライアントシークレット
$ curl http://localhost:8080/api/token -X POST \
--user ${clientId}:${clientSecret} \
-H 'Content-type: application/x-www-form-urlencoded' \
-d 'auth_req_id=Xe250q9AoSdUL_xohrPm8txYNUo8VlddhLv1ENUY6SM' \
-d 'grant_type=urn:openid:params:grant-type:ciba'

{
"access_token":"ldofpBo8hO67CNr4sE_Cibt1FYZ8RpQCIPVlUaeokks",
"refresh_token":"U0JyhKdXh-h3h6hDLiu3eart9RpEwnSClMtgGjAFu5o",
"scope":"openid",
"id_token":
"eyJhbGciOiJIUzI1NiJ9.eyJhdF9oYXNoIjoiRkxwdFBEaWlMbUcwdkVLWFZndjBUZyIsInN1YiI6IjEwMDEiLCJhdWQiOiIyNDkzOTMxNjU5OTciLCJhdXRoX3RpbWUiOjE1NTM4NTE3MjQsImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTUzOTM4MTM0LCJpYXQiOjE1NTM4NTE3MzR9.7G_VfqlSlDd0cOSjZaRorSrbcH3PoKneM_YalCpFHig","token_type":"Bearer","expires_in":86400
}

アクセストークンが取得できましたね!今回はscopeを openid にしているのでid_tokenも得られています。

$ echo eyJhdF9oYXNoIjoiRkxwdFBEaWlMbUcwdkVLWFZndjBUZyIsInN1YiI6IjEwMDEiLCJhdWQiOiIyNDkzOTMxNjU5OTciLCJhdXRoX3RpbWUiOjE1NTM4NTE3MjQsImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTUzOTM4MTM0LCJpYXQiOjE1NTM4NTE3MzR9 | base64 -D | jq
{
  "at_hash": "FLptPDiiLmG0vEKXVgv0Tg",
  "sub": "1001",
  "aud": "249393165997",
  "auth_time": 1553851724,
  "iss": "https://authlete.com",
  "exp": 1553938134,
  "iat": 1553851734
}

実際はポーリングする

今回の処理は push,ping,poll のモードのうちpollでやっているので、認証リクエストがOKされたかどうかの通知は来ません。なので実際は、認証リクエストを送信してからアプリがポーリングする必要がありそうです。

たとえば下記のようなシェルを実行してみます。

$ cat ciba_request.sh
#!/bin/bash

clientId=249xxxxxxx  ← クライアント ID
clientSecret=WUItxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  ← クライアントシークレット

login_hint=1001
user_code=675325

backchannelReq=`cat << EOS
curl http://localhost:8080/api/backchannel/authentication -X POST \
--user ${clientId}:${clientSecret} \
-d 'login_hint=${login_hint}' \
-d 'user_code=${user_code}'  \
-d 'scope=openid' -s | jq .auth_req_id -r
EOS
`

auth_req_id=`eval "${backchannelReq}"`
echo ${auth_req_id}

for i in {0..3}; do
    sleep 3
    tokenReq=`cat << EOS
curl http://localhost:8080/api/token -X POST \
--user ${clientId}:${clientSecret}  \
-H 'Content-type: application/x-www-form-urlencoded' \
-d 'auth_req_id=${auth_req_id}' \
-d 'grant_type=urn:openid:params:grant-type:ciba' -s
EOS
`
    token=`eval "${tokenReq}"`
    error=`echo ${token} | jq 'select(.error_description==null)'`

    echo ${token} | jq
    if [ -n "$error" ]; then
        break;
    fi
done
$ ./ciba_request.sh
lrHy0QdUalqpL7K2MRMfV_uhCLuvolCk5hS70LEb7R8
{
  "error_description": "[A200308] The end-user has not been authenticated yet.",
  "error": "authorization_pending",
  "error_uri": "https://www.authlete.com/documents/apis/result_codes#A200308"
}
{
  "error_description": "[A200308] The end-user has not been authenticated yet.",
  "error": "authorization_pending",
  "error_uri": "https://www.authlete.com/documents/apis/result_codes#A200308"
}

// ココでシミュレータでAllowを押下したら。。
{
  "access_token": "RexqI1mrrCpVI9fiYJWhxuJMSSOfD6j1ijNXs-cXOts",
  "refresh_token": "x0CuGD-CPK1q2b8WzuU5WYBeCoIxdkBg5aaenLCeeWQ",
  "scope": "openid",
  "id_token": "eyJhbGciOiJIUzI1NiJ9.eyJhdF9oYXNoIjoidVBRWVVnT1BmenVaQ1Jab0E1b21XUSIsInN1YiI6IjEwMDEiLCJhdWQiOiIyNDkzOTMxNjU5OTciLCJhdXRoX3RpbWUiOjE1NTQyNTc4NzksImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU0MzQ0MjgxLCJpYXQiOjE1NTQyNTc4ODF9.1mdVZ2hub3GzwGNNxaL1HxlQHdIioSvLyp0UJfdMDog",
  "token_type": "Bearer",
  "expires_in": 86400
}
$

よさそうですね。。

まとめ

今回はAuthleteサービスを用いて、CIBA対応の認可サーバ(pollモード)を構築してみました。
まだまださわりを構築しただけで、全体感の理解とはほぼ遠いのですが、Authleteを用いることで容易に認可サーバを立ち上げることが出来ました。

おつかれさまでした。

関連リンク


  1. 登壇されていた方が この処理シーケンスのことをOAuth Dance と説明されてたのが印象的 :-) 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java でコールバック簡単なサンプルPart2 無名クラスの例

public interface myCallback {
    void onSuccess();
    void onError(String err);
}



public class App {

    public static void main(String[] args) {
        // call your method 無名クラス利用
        doSomething("list your Params", new myCallback(){  
            @Override
            public void onSuccess() {
                // no errors
                System.out.println("Done");
            }

            @Override
            public void onError(String err) {
                // error happen
                System.out.println(err);
            }
        });
    }

    private void doSomething(String param, // some params..
                             myCallback callback) {
        // now call onSuccess whenever you want if results are ready
        if(results_success)
            callback.onSuccess();
        else
            callback.onError(someError);
    }

}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Stanford NER Taggerを自分のデータで訓練

NERとは、Named Entity Recognitionの略で、固有表現認識という自然言語処理のタスクの一つです。Stanford NER Taggerは、このタスクを解くためのツールです。今回は、これを自分で訓練します。

事前準備

まず、訓練データの例をダウンロードします。
https://github.com/synalp/NER/blob/master/corpus/CoNLL-2003/eng.train

次に、Stanford NER Taggerをダウンロードします。
https://nlp.stanford.edu/software/CRF-NER.shtml#Download

そして、jdkをインストールします。

apt install default-jdk

訓練データの準備

ダウンロードしたeng.trainを整形します。

out = []
with open("eng.train", "r") as f:
    for line in f:
        line = line.split()
        if len(line) > 2:
            out.append(str(line[0])+"\t"+str(line[-1]).replace("I-","").replace("B-","")+"\n")
        else:
            out.append("\n")

with open("train.tsv") as f:
    f.write(''.join(out))

訓練

訓練準備

  1. stanford ner taggerをunzipして、展開後のディレクトリに入ってください。
  2. そのディレクトリ内に、train.tsvを入れてください。

プロパティファイルの作成

train.prop
trainFile = train.tsv
serializeTo = ner-model.ser.gz
map = word=0,answer=1

useClassFeature=true
useWord=true
useNGrams=true
noMidNGrams=true
maxNGramLeng=6
usePrev=true
useNext=true
useSequences=true
usePrevSequences=true
maxLeft=1
useTypeSeqs=true
useTypeSeqs2=true
useTypeySequences=true
wordShape=chris2useLC
useDisjunctive=true

これを、train.propというファイル名で保存してください。

訓練の実行

java -cp stanford-ner.jar edu.stanford.nlp.ie.crf.CRFClassifier -prop train.prop

すると、ner-model.ser.gzという名のファイルとしてモデルが出来上がります。

モデルをpythonから使う

nltkのStanford NER Taggerのラッパーを使えば、モデルをpythonから使えます。

import nltk
from nltk.tag.stanford import StanfordNERTagger
sent = "Balack Obama kills people by AK47"
model = "./ner-model.ser.gz"
jar = "./stanford-ner.jar"
tagger = StanfordNERTagger(model, jar, encoding='utf-8')
print(tagger.tag(sent.split()))

[出力]

[('Balack', 'PER'),
 ('Obama', 'PER'),
 ('kills', 'O'),
 ('people', 'O'),
 ('by', 'O'),
 ('AK47', 'O')]

参考

[0] https://nlp.stanford.edu/software/crf-faq.html#a
[1] https://blog.sicara.com/train-ner-model-with-nltk-stanford-tagger-english-french-german-6d90573a9486

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ScalaのTry的なやつをJavaでやりたい!!

はじめに

ScalaのTry関数とは,例外ベースのAPIをOptionベースのAPIに変換するための汎用関数です.この記事では,Javaで例外ベースのAPIをOptionalベースのAPIに変換する方法について述べます.

この記事の対象読者は次のような人です.

  • Scalaを習得している人
  • Javaに馴染みがない人

例外ベースのAPIをOptionalベースのAPIに変換する方法

メソッドの中ででtry-catchを隠蔽し,クライアントに対してOptionalベースのインタフェースを提供します.

    // 時間をWebAPIから取得するメソッド
    public static Optional<String> getTime() {
        try {
            // 接続先URLや接続方法を設定する.
            URL url = new URL("http://api.aoikujira.com/time/get.php");
            ......
            ......
            return Optional.of(time.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return Optional.empty();
    }

サンプルプログラム

現在時刻をWebAPIから取得し,表示するプログラムを次の2通りの方法で実装しました.

  • 例外ベース
  • Optionalベース

例外ベースのプログラム

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {
    public static void main(String[] args) {
        System.out.println(getTime());
    }

    // 時間をWebAPIから取得するメソッド
    private static String getTime() {
        try {
            // 接続先URLや接続方法を設定する.
            URL url = new URL("http://api.aoikujira.com/time/get.php");
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            http.setRequestMethod("GET");
            http.connect();

            // 接続先から文字列を読み込む.
            BufferedReader reader = new BufferedReader(new InputStreamReader(http.getInputStream()));
            StringBuilder time = new StringBuilder();
            String line = "";
            while((line = reader.readLine()) != null)
                time.append(line);
            reader.close();

            return time.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "";
    }
}

Optionalベースのプログラム

getTime()メソッドがOptional型を返すように書き換えました.メインルーチン(mainメソッド)からすると,getTime()メソッドはOptionalベースのインタフェースに見えます.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Optional;

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

    // 時間をWebAPIから取得するメソッド
    private static Optional<String> getTime() {
        try {
            // 接続先URLや接続方法を設定する.
            URL url = new URL("http://api.aoikujira.com/time/get.php");
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            http.setRequestMethod("GET");
            http.connect();

            // 接続先から文字列を読み込む.
            BufferedReader reader = new BufferedReader(new InputStreamReader(http.getInputStream()));
            StringBuilder time = new StringBuilder();
            String line = "";
            while((line = reader.readLine()) != null)
                time.append(line);
            reader.close();

            return Optional.of(time.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return Optional.empty();
    }
}

おわりに

もっとスマートなやり方あったら,コメントお願いします.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのtry-catchをOptionalで書き直す

はじめに

例外処理を行う際,try-catch構文が利用可能ですが,scala.util.Tryを利用すると関数型っぽい実装をすることができます.

Javaでは,Tryクラスは利用できませんが,例外内容に関心がない場合,Optionalクラスを利用することが可能です.そこで,この記事では,Javaで例外ベースのAPIをOptionalベースのAPIに変換する方法について述べます.

この記事の対象読者は次のような人です.

  • Scalaを習得している人
  • Javaに馴染みがない人

例外ベースのAPIをOptionalベースのAPIに変換する方法

メソッドの中ででtry-catchを隠蔽し,クライアントに対してOptionalベースのインタフェースを提供します.

    // 時間をWebAPIから取得するメソッド
    public static Optional<String> getTime() {
        try {
            // 接続先URLや接続方法を設定する.
            URL url = new URL("http://api.aoikujira.com/time/get.php");
            ......
            ......
            return Optional.of(time.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return Optional.empty();
    }

サンプルプログラム

現在時刻をWebAPIから取得し,表示するプログラムを次の2通りの方法で実装しました.

  • 例外ベース
  • Optionalベース

例外ベースのプログラム

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {
    public static void main(String[] args) {
        System.out.println(getTime());
    }

    // 時間をWebAPIから取得するメソッド
    private static String getTime() {
        try {
            // 接続先URLや接続方法を設定する.
            URL url = new URL("http://api.aoikujira.com/time/get.php");
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            http.setRequestMethod("GET");
            http.connect();

            // 接続先から文字列を読み込む.
            BufferedReader reader = new BufferedReader(new InputStreamReader(http.getInputStream()));
            StringBuilder time = new StringBuilder();
            String line = "";
            while((line = reader.readLine()) != null)
                time.append(line);

            return time.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            reader.close();
        }

        return "";
    }
}

Optionalベースのプログラム

getTime()メソッドがOptional型を返すように書き換えました.メインルーチン(mainメソッド)からすると,getTime()メソッドはOptionalベースのインタフェースに見えます.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Optional;

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

    // 時間をWebAPIから取得するメソッド
    private static Optional<String> getTime() {
        try {
            // 接続先URLや接続方法を設定する.
            URL url = new URL("http://api.aoikujira.com/time/get.php");
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            http.setRequestMethod("GET");
            http.connect();

            // 接続先から文字列を読み込む.
            BufferedReader reader = new BufferedReader(new InputStreamReader(http.getInputStream()));
            StringBuilder time = new StringBuilder();
            String line = "";
            while((line = reader.readLine()) != null)
                time.append(line);
            reader.close();

            return Optional.of(time.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            reader.close();
        }

        return Optional.empty();
    }
}

おわりに

もっとスマートなやり方あったら,コメントお願いします.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む