覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

PostgreSQL - テーブルとindexのサイズを確認する

PostgreSQLでテーブルのレコード数ではなく容量(サイズ)を知りたい場合があります。
その場合には以下のSQLを実行することで各テーブルと各indexのサイズを確認できます。

select
  objectname,
  to_char(pg_relation_size(objectname::regclass), '999,999,999,999') as bytes 
from (
  select 
   tablename as objectname 
  from pg_tables 
  where schemaname = 'public'

  UNION

  select 
   indexname as objectname 
  from pg_indexes
  where schemaname = 'public'
) as objectlist

order by bytes desc;


■実行結果サンプル

       objectname       |      bytes       
------------------------+------------------
 auditlog               |       99,589,824
 sampletbl1             |          294,912
 sampletbl1_col1_idx    |          172,032
 sampletbl1_seq_idx     |           73,728
 sampletbl1_pkey        |           65,536
 master1_pkey           |           16,384
 master2_pkey           |           16,384
 sampletbl2_seq_idx     |            8,192
 sampletbl2s_pkey       |            8,192
 master1                |            8,192
 master2                |            8,192
 sampletbl2             |                0


とても便利



関連エントリ

Class#newInstanceは非推奨になるようなので気を付けよう

Javaでリフレクションによるデフォルトコンストラクタ呼び出しでインスタンス生成する方法としてClass#newInstanceが挙げられると思います。

ただし、Class#newInstanceはJava9で非推奨(Deprecated)になるようです。(さらに以降のバージョンでAPI自体が削除になるんですかね・・・)

Class#newInstanceは、シグニチャ上に無いチェック例外がスローできてしまうため、それが問題で非推奨となったようです。
その辺の動きについて今回のエントリで確認してみます。


インスタンス化対象のクラス

今回は以下クラスのインスタンス化を行って動きを確認します。
このクラスは、デフォルトコンストラクタを実行するとFileNotFoundException(チェック例外)をスローするようになっています。

import java.io.FileNotFoundException;

public class SampleObject {

    public SampleObject() throws FileNotFoundException {
        throw new FileNotFoundException("target file not found.");
    }
}


Class#newInstanceでコード上に無い例外をスローしてみる

SampleObjectClass#newInstanceでインスタンス化するコードを書いて実行してみます。


■実行用のサンプルコード

public class ClazzNewInstanceTrial {

    public static void main(String[] args) {
        try {
            SampleObject obj = createSampleObject();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    private static SampleObject createSampleObject() throws IllegalAccessException, InstantiationException {
        return SampleObject.class.newInstance();
    }
}

createSampleObjectメソッド内でClass#newInstanceを実行してSampleObjectのインスタンスを生成していますが、
createSampleObjectメソッドのシグニチャにはスローする例外としてIllegalAccessException, InstantiationExceptionのみが登場しており、
FileNotFoundExceptionは登場しません。


これを実行してみると以下の結果が出ます

■実行結果

Exception in thread "main" java.io.FileNotFoundException: target file not found.
    at sample.app.reflection.SampleObject.<init>(SampleObject.java:8)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at sample.app.reflection.ClazzNewInstanceTrial.createSampleObject(ClazzNewInstanceTrial.java:16)
    at sample.app.reflection.ClazzNewInstanceTrial.main(ClazzNewInstanceTrial.java:7)

なんとまぁ、メソッドのシグニチャに登場していなかったのに、createSampleObjectメソッドがFileNotFoundExceptionをスローしています。
コード上に現れていないチェック例外がスローできてしまっています。


代替案の Constructor#newInstanceの場合

Class#newInstanceは使うなとなってどうすればいいかと言うと、Constructor#newInstanceによるインスタンス生成で代替すればいいようです。
(実際にはClass.getDeclaredConstructor().newInstance()を実行することになります)

SampleObjectのインスタンス化をしてみてClass#newInstanceとの例外に関する動きの違いを確認してみます


■実行用のサンプルコード

import java.lang.reflect.InvocationTargetException;

public class ConstructorNewInstance {

    public static void main(String[] args) {
        try {
            SampleObject obj = createSampleObject();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private static SampleObject createSampleObject()
            throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        return SampleObject.class.getDeclaredConstructor().newInstance();
    }

}


これを実行してみると以下の結果が出ます

■実行結果

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at sample.app.reflection.ConstructorNewInstance.createSampleObject(ConstructorNewInstance.java:23)
    at sample.app.reflection.ConstructorNewInstance.main(ConstructorNewInstance.java:9)
Caused by: java.io.FileNotFoundException: target file not found.
    at sample.app.reflection.SampleObject.<init>(SampleObject.java:8)
    ... 6 more

createSampleObjectメソッドからは、InvocationTargetExceptionでラップされたFileNotFoundExceptionがスローされて、それをcatchできています。
メソッドのシグニチャ通りの例外がスローされています。


蛇足

Java7から、java.lang.ReflectiveOperationExceptionがリフレクション関係の例外の親クラスとして定義されてますので
上記の実行サンプルのコードはReflectiveOperationExceptionを使ってもう少しシンプル記述できます。


■実行用のサンプルコード

public class ConstructorNewInstance2 {

    public static void main(String[] args) {
        try {
            SampleObject obj = createSampleObject();
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
    }

    private static SampleObject createSampleObject() throws ReflectiveOperationException {
        return SampleObject.class.getDeclaredConstructor().newInstance();
    }

}

■実行結果

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at sample.app.reflection.ConstructorNewInstance2.createSampleObject(ConstructorNewInstance2.java:14)
    at sample.app.reflection.ConstructorNewInstance2.main(ConstructorNewInstance2.java:7)
Caused by: java.io.FileNotFoundException: target file not found.
    at sample.app.reflection.SampleObject.<init>(SampleObject.java:8)
    ... 6 more

InvocationTargetExceptionでラップされたFileNotFoundExceptionがスローされて、それをReflectiveOperationExceptionでcatchできています


まとめ

Class#newInstanceConstructor#newInstanceの例外に関する動きの違いを確認しました。
Class.newInstance()を使っている箇所は、早めにClass.getDeclaredConstructor().newInstance() に置き換えましょう。



関連エントリ

MavenでOWASP Dependency CheckによるJavaライブラリの脆弱性をチェックする

OWASP Dependency Checkで使用しているJavaライブラリの脆弱性をチェックすることができます。

今回はMavenのpluginを使用します。


設定

pom.xmlに以下を追記します。

<plugins>
・・・
  <plugin>
    <groupId>org.owasp</groupId>
    <artifactId>dependency-check-maven</artifactId>
    <version>2.0.0</version>
    <configuration>
        <assemblyAnalyzerEnabled>false</assemblyAnalyzerEnabled>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
  </plugin>
・・・
</plugins>


脆弱性のチェック

pom.xmlへの追記が終わった状態で以下コマンドをを実行します

mvn dependency-check:check


すると以下のような出力がされます

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sample-app 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- dependency-check-maven:2.0.0:check (default-cli) @ srcl ---
[INFO] Checking for updates
[INFO] starting getUpdatesNeeded() ...
[INFO] Download Started for NVD CVE - Modified
[INFO] Download Complete for NVD CVE - Modified  (5176 ms)
[INFO] Processing Started for NVD CVE - Modified
[INFO] Processing Complete for NVD CVE - Modified  (6004 ms)
[INFO] Begin database maintenance.
[INFO] End database maintenance.
[INFO] Check for updates complete (14381 ms)
[INFO] Analysis Started
[INFO] Finished Archive Analyzer (1 seconds)
[INFO] Finished File Name Analyzer (0 seconds)
[INFO] Finished Jar Analyzer (0 seconds)
[INFO] Finished Central Analyzer (4 seconds)
[INFO] Finished Dependency Merging Analyzer (0 seconds)
[INFO] Finished Version Filter Analyzer (0 seconds)
[INFO] Finished Hint Analyzer (0 seconds)
[INFO] Created CPE Index (1 seconds)
[INFO] Finished CPE Analyzer (1 seconds)
[INFO] Finished False Positive Analyzer (0 seconds)
[INFO] Finished Cpe Suppression Analyzer (0 seconds)
[INFO] Finished NVD CVE Analyzer (0 seconds)
[INFO] Finished Vulnerability Suppression Analyzer (0 seconds)
[INFO] Finished Dependency Bundling Analyzer (0 seconds)
[INFO] Analysis Complete (8 seconds)
[WARNING]

One or more dependencies were identified with known vulnerabilities in sample-app:

commons-beanutils-1.8.3.jar (commons-beanutils:commons-beanutils:1.8.3, cpe:/a:apache:commons_beanutils:1.8.3) : CVE-2014-0114


See the dependency-check report for more details.


[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 27.974 s
[INFO] Finished at: 2017-07-06T18:33:09+09:00
[INFO] Final Memory: 25M/899M
[INFO] ------------------------------------------------------------------------

今回の結果ではcommons-beanutilsの1.8.3 にCVE-2014-0114の脆弱性があることが指摘されています。


というわけで、簡単にJavaライブラリの脆弱性チェックができました。



関連エントリ

RxJava - RxJavaでHelloWorld

RxJavaを使いながらリアクティブプログラミングを理解していきたい。

とりあえずは、まず何を置いてもHello World!


準備

pom.xmlに以下の依存関係を追加します。Reactive Streamsにも対応しているバージョン2.Xを使います

<dependency>
    <groupId>io.reactivex.rxjava2</groupId>
    <artifactId>rxjava</artifactId>
    <version>2.0.8</version>
</dependency>


サンプルの実行

■サンプルコード

以下は、ほぼ「RxJavaリアクティブプログラミング (CodeZine BOOKS) 」からの写経です。

Hello, World!-Xの文字列を順に発行して、購読側のonNextで受け取れることを確認しました

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.schedulers.Schedulers;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import java.util.Arrays;
import java.util.List;

public class HelloWorldRx {

    public static void main(String[] args) throws Exception {
        // 発行するデータ
        final List<String> helloList = Arrays.asList("Hello, World!-1", "Hello, World!-2", "Hello, World!-3");

        Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() {

            @Override
            public void subscribe(FlowableEmitter<String> emitter) throws Exception {
                helloList.forEach(s -> emitter.onNext(s));

                emitter.onComplete();
            }
        }, BackpressureStrategy.BUFFER);


        flowable.observeOn(Schedulers.computation())
            .subscribe(new Subscriber<String>() {

                private Subscription subscription;

                @Override
                public void onSubscribe(Subscription subscription) {
                    this.subscription = subscription;
                    this.subscription.request(1);
                }

                @Override
                public void onNext(String data) {
                    String threadName = Thread.currentThread().getName();
                    System.out.println(threadName + " onNext -> " + data);

                    this.subscription.request(1);
                }

                @Override
                public void onComplete() {
                    String threadName = Thread.currentThread().getName();
                    System.out.println(threadName + " onComplete");
                }

                @Override
                public void onError(Throwable throwable) {
                    throwable.printStackTrace();
                }
         });

        Thread.sleep(500);
    }
}

■実行結果

RxComputationThreadPool-1 onNext -> Hello, World!-1
RxComputationThreadPool-1 onNext -> Hello, World!-2
RxComputationThreadPool-1 onNext -> Hello, World!-3
RxComputationThreadPool-1 onComplete


もっとシンプルに試すだけなら以下のコードとかでもいいかもしれないですね

■サンプルコード

import io.reactivex.Flowable;

public class HelloWorldRx2 {

    public static void main(String[] args) throws Exception {
        Flowable<String> flowable =
                Flowable.just("Hello, World!-1", "Hello, World!-2", "Hello, World!-3");

        flowable.subscribe(data -> System.out.println(data));

        Thread.sleep(500);
    }
}

■実行結果

Hello, World!-1
Hello, World!-2
Hello, World!-3


とりあえず、RxJavaを使ったHello Worldができました



関連書籍

RxJavaリアクティブプログラミング (CodeZine BOOKS)

RxJavaリアクティブプログラミング (CodeZine BOOKS)

Go言語 - HTMLテンプレートの使い方

GolangでのHTMLテンプレート記述方法や値の展開方法等について学ぶために、html/templateを試してみました。


変数をそのまま展開

コード内の変数をhtmlのテンプレートに展開する例です

■htmlテンプレート(template000.html.tpl)

<!DOCTYPE html>
<html>
<body>
    msg: {{.}} 
</body>
</html>

■サンプルコード

package trial

import (
    "html/template"
    "log"
    "net/http"
)

func htmlHandler0(w http.ResponseWriter, r *http.Request) {
    // テンプレートをパース
    t := template.Must(template.ParseFiles("templates/template000.html.tpl"))

    str := "Sample Message"

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "template000.html.tpl", str); err != nil {
        log.Fatal(err)
    }
}

func main() {
    http.HandleFunc("/page0", htmlHandler0)

    // サーバーを起動
    http.ListenAndServe(":8989", nil)
}


■ブラウザでのアクセス結果

f:id:nini_y:20170702144443p:plain


mapの値を展開

mapをhtmlのテンプレートに展開する例です

■htmlテンプレート(template001.html.tpl)

<!DOCTYPE html>
<html>
<body>
    key1: {{.key1}}, key2: {{.key2}}, key3: {{.key3}} 
</body>
</html>

■サンプルコード

package trial

import (
    "html/template"
    "log"
    "net/http"
)

func htmlHandler1(w http.ResponseWriter, r *http.Request) {
    // テンプレートをパース
    t := template.Must(template.ParseFiles("templates/template001.html.tpl"))

    m := map[string]int{
        "key1": 101,
        "key2": 202,
        "key3": 303,
        "key4": -404,
    }

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "template001.html.tpl", m); err != nil {
        log.Fatal(err)
    }
}

func main() {
    http.HandleFunc("/page1", htmlHandler1)

    // サーバーを起動
    http.ListenAndServe(":8989", nil)
}


■ブラウザでのアクセス結果

f:id:nini_y:20170702144531p:plain


構造体を展開

構造体をhtmlのテンプレートに展開する例です

■htmlテンプレート(template002.html.tpl)

<!DOCTYPE html>
<html>
<body>
    Name: {{ .Name }}, Age: {{ .Age }} 
</body>
</html>

■サンプルコード

package trial

import (
    "html/template"
    "log"
    "net/http"
)

func htmlHandler2(w http.ResponseWriter, r *http.Request) {

    t := template.Must(template.ParseFiles("templates/template002.html.tpl"))

    type SampleData struct {
        Name string
        Age  int
    }

    data := SampleData{Name: "Taro", Age: 25}

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "template002.html.tpl", data); err != nil {
        log.Fatal(err)
    }
}

func main() {
    http.HandleFunc("/page2", htmlHandler2)

    // サーバーを起動
    http.ListenAndServe(":8989", nil)
}


■ブラウザでのアクセス結果

f:id:nini_y:20170702144541p:plain


関数を実行

htmlのテンプレート内で関数呼び出しを行う例です

■htmlテンプレート(template003.html.tpl)

<!DOCTYPE html>
<html>
<body>
    Func1 -> {{ samplefunc1 }}
<br/>
    Func2 -> {{.msg1 | samplefunc2}}
<br/>
    Func3 -> {{.msg2 | samplefunc3}}
</body>
</html>

■サンプルコード

package trial

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
    "strings"
    "time"
)

func htmlHandler3(w http.ResponseWriter, r *http.Request) {

    funcMap := template.FuncMap{
        "samplefunc1": func() string { return time.Now().String() },
        "samplefunc2": func(src string) string { return fmt.Sprintf("[$$ %s $$]", src) },
        "samplefunc3": strings.ToUpper,
    }
    // テンプレートをパース
    t := template.Must(template.New("t").Funcs(funcMap).ParseFiles("templates/template003.html.tpl"))

    m := map[string]string{
        "msg1": "golang is programming language.",
        "msg2": "hello template app.",
    }

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "template003.html.tpl", m); err != nil {
        log.Fatal(err)
    }
}

func main() {
    http.HandleFunc("/page3", htmlHandler3)

    // サーバーを起動
    http.ListenAndServe(":8989", nil)
}


■ブラウザでのアクセス結果

f:id:nini_y:20170702144551p:plain


ループ

htmlのテンプレート内でループを行う例です

■htmlテンプレート(template004.html.tpl)

<!DOCTYPE html>
<html>
<body>
    <div>
        <h4>DataList</h4>
        {{range .}}
        <p>{{.}}</p>
        {{end}}
    </div>
</body>
</html>

■サンプルコード

package trial

import (
    "html/template"
    "log"
    "net/http"
)

func htmlHandler4(w http.ResponseWriter, r *http.Request) {

    t := template.Must(template.ParseFiles("templates/template004.html.tpl"))

    strArray := []string{"aa", "bbb", "ccc", "dddd"}

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "template004.html.tpl", strArray); err != nil {
        log.Fatal(err)
    }
}

func main() {
    http.HandleFunc("/page4", htmlHandler4)

    // サーバーを起動
    http.ListenAndServe(":8989", nil)
}


■ブラウザでのアクセス結果

f:id:nini_y:20170702144607p:plain


リクエストパラメータをテンプレートにセットして表示

htmlのテンプレート内で受け取ったリクエストパラメータを反映する例です

■htmlテンプレート(template005.html.tpl)

<!DOCTYPE html>
<html>
<body>
<div>
  Request Param1 -> {{.Param1 |safehtml}}
</div>
<div>
  Request Param2 -> {{.Param2 |safehtml}}
</div>
</body>
</html>

■サンプルコード

package trial

import (
    "html/template"
    "log"
    "net/http"
)

func htmlHandler5(w http.ResponseWriter, r *http.Request) {
    funcMap := template.FuncMap{
        "safehtml": func(text string) template.HTML { return template.HTML(text) },
    }
    t := template.Must(template.New("T").Funcs(funcMap).ParseFiles("templates/template005.html.tpl"))

    st := struct {
        Param1 string
        Param2 string
    }{
        Param1: r.FormValue("param1"),
        Param2: r.FormValue("param2"),
    }

    // テンプレートを描画
    if err := t.ExecuteTemplate(w, "template005.html.tpl", st); err != nil {
        log.Fatal(err)
    }
}

func LoadTemplate() {
    http.HandleFunc("/page5", htmlHandler5)

    // サーバーを起動
    http.ListenAndServe(":8989", nil)
}


■ブラウザでのアクセス結果

f:id:nini_y:20170702144616p:plain



関連エントリ