Javaのメソッド呼び出し階層を表示する

Threadオブジェクトからスタックトレースを取得できるのでそれを使用する。

System.out.println(java.util.Arrays.stream(Thread.currentThread().getStackTrace())
    .skip(1).limit(4).map(t -> t.getClassName() + "." + t.getMethodName()).collect(java.util.stream.Collectors.joining(",")));

skip(1)をかましているのは結果にgetStackTraceメソッド呼び出しも含まれているため。

JavaからActive Directory(LDAPS)接続(自己署名証明書の検証スルーコード付き)

自分向けの備忘録として。

基本はこちら。

kazuhira-r.hatenablog.com

こちらの記事だと自己証明書のスルーに使用しているのが X509TrustManager だが、新しいTLSに対応するためには代わりに X509ExtendedTrustManager を実装してあげる必要がある。

よって、以下のような感じになる。

接続側

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, LDAP_URL);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, AD_USER_NAME);
        env.put(Context.SECURITY_CREDENTIALS, AD_PASSWORD);
        env.put("java.naming.security.protocol", "ssl");
        env.put("java.naming.ldap.factory.socket", LooseSSLSocketFactory.class.getName());

        DirContext ctx = null;
        try {
            List<Map<String, String>> ret = new ArrayList<>();
            ctx = new InitialDirContext(env);

            for (NamingEnumeration<SearchResult> search = ctx.search("OU=XX,dc=XXXX,dc=local", null); search.hasMoreElements();) {
                SearchResult next = search.next();
                Attributes attributes = next.getAttributes();
                //実際の処理
            }
            return ret;
        } catch (AuthenticationException ae) {
            //認証に失敗した
            ae.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ctx != null) {
                try {
                    ctx.close();
                } catch (NamingException ex) {
                }
            }
        }

LooseSSLSocketFactory

package dev.megascus.ssl;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;

public class LooseSSLSocketFactory extends SSLSocketFactory {

    SSLSocketFactory delegate;

    public LooseSSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, new X509TrustManager[] { new X509ExtendedTrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String string, Socket socket)
                        throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String string, Socket socket)
                        throws CertificateException {
                }

                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String string, SSLEngine ssle)
                        throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String string, SSLEngine ssle)
                        throws CertificateException {
                }
            } }, new SecureRandom());

            delegate = sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
        return delegate.createSocket(socket, s, i, b);
    }

    @Override
    public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
        return delegate.createSocket(s, i);
    }

    @Override
    public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
        return delegate.createSocket(s, i, inetAddress, i1);
    }

    @Override
    public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
        return delegate.createSocket(inetAddress, i);
    }

    @Override
    public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
        return delegate.createSocket(inetAddress, i, inetAddress1, i1);
    }

    public static SocketFactory getDefault() {
        return new LooseSSLSocketFactory();
    }
}

なお、Active Directoryは普通にやると1000件しか結果が返ってこない。 1000件以上登録されている可能性がある場合は以下の記事を参考にする。

qiita.com

JavaMailでメールアドレスに名前を付ける

JavaMailで送信したメールに宛先や送信元に名前を表示したい場合がある。

以下のような感じですね。

ゆとり<megascus@megascus.dev>

InternetAddressクラスの3つの引数があるバージョンを使えば対応できる。

docs.oracle.com

日本語を扱う場合、charsetとして"iso-2022-jp"を使用しないと文字化けるので注意。

ネットワークドライブの割り当てを行ったNASに保管されているExcelファイルの元の場所のURLを取得する

\XXXnas\share\hoge.xlsx みたいなでアクセスするのを嫌がって、 \XXXnas\share\ をZドライブに割り当てみたいなことをした場合に、他の人に共有する場合はZドライブではなく元のネットワークドライブ上のパスで指定したい場合があります。

その場合、リボンのユーザー設定からリボンにないコマンド→ドキュメントの場所を選択、追加することで、ネットワークドライブ上のパスをリボン上に表示することができるようになります。

f:id:megascus:20200313175911p:plain
リボンのユーザー設定

aws-sdk-java-v2を使用してs3からオブジェクトを取得する。

aws-sdk-javaのバージョン2が出ていたので試してみました。 v1と比べて、パッケージ名が変更されていたり、APIがビルダー形式(いわゆる流れるようなインターフェース)になっていたりと微妙に差はありますが、大きく差があるわけではないというのが印象です。 東京リージョンのs3のエンドポイントがきちんととれないというのも従来通り。なんでやねん。

pomには以下のような感じで記載します。group idが変わってます。

    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>ec2</artifactId>
            <version>2.10.82</version>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
            <version>2.10.82</version>
        </dependency>
        <!-- proxy設定を行う場合は以下を追加する必要がある。 -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>apache-client</artifactId>
            <version>2.10.82</version>
            <type>jar</type>
        </dependency>
    </dependencies>
package dev.megascus.s3access;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.core.sync.ResponseTransformer;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.http.apache.ProxyConfiguration;

public class Main1 {

    //おまじない()
    private static final String ENDPOINT_URL = "https://s3-ap-northeast-1.amazonaws.com";

    public static void main(String[] args) throws IOException, URISyntaxException {
        String accessKey = "your_access_key";
        String secret = "your_secret_key";

        //通常は認証情報をプログラム内では設定しない。環境変数等から指定する。
        AwsCredentials credentials = AwsBasicCredentials.create(accessKey, secret);
        
        //東京
        Region region = Region.AP_NORTHEAST_1;

        //Proxy設定が必要な場合
        ProxyConfiguration proxy = ProxyConfiguration.builder().endpoint(new URI("http://proxy_server_url")).build();
        SdkHttpClient client = ApacheHttpClient.builder().proxyConfiguration(proxy).build();

        S3Client s3 = S3Client.builder()
                .region(region)
                .endpointOverride(new URI(ENDPOINT_URL))
                .credentialsProvider(StaticCredentialsProvider.create(credentials))
                .httpClient(client) //Proxy設定が必要な場合
                .build();

        String bucketName = "your-bucket-name";
        String fileObjKeyName = "ファイル名";
        s3.getObject(GetObjectRequest.builder().bucket(bucketName).key(fileObjKeyName).build(),
                ResponseTransformer.toFile(Paths.get("c:\\temp", fileObjKeyName)));
    }
}

なんで作り直したのに、わざわざJavaの慣習に従わないパッケージ名に変更したのだろうか・・・・・・

なお、公式ドキュメントでも差分は公開されています。

https://docs.aws.amazon.com/ja_jp/sdk-for-java/v2/migration-guide/whats-different.htmldocs.aws.amazon.com

github

github.com

maven

mvnrepository.com

「みんなのJava」は最近5年間のJavaの動向概要を復習するための本 #minjava

「みんなのJava」を著者の方から頂いたので読みました。 ありがとうございます。*1

さっそく読ませていただきましたが、Java 8以降から始まったJavaの大変革についてまとまった良い本だと思いました。 直近5年間でJavaの言語仕様として入った新しい機能、大きな誤解とともに広まったJavaの有償化問題、Jakarta EEと名前を変えたJava EEはどうなっているのか、今後期待される新しいJavaの実行方法の形。新しいトレンドに伴った新しいJavaのライブラリ。

Java 8まではなんとなくJavaについてわかっていたけれども、そのあとどうなったのかあまりよくわかっていない、5年ぐらいJavaから離れていた人が最新情報をキャッチアップするのに良い本だと思います。 Javaが有償化するって記事を読んだけど、あれっていつ有償化するの?って思っている人とか。

もちろん、きちんとJavaの動向について追っていたけれども、漏れがないか気になるみたいな人にもお勧めです。

俺はこの5年間のJavaの動向について完璧に知ってます!!!!!みたいな人にはお勧めはできません。 これからJavaについて学びますって人にはちょっと内容が重い感じでしょうか。

ただ、200ページ弱という少ないページ数の中に多大なトピックを詰め込んでいるため、それぞれのトピックについては内容が薄いというところがあります。 そういったところについては、例えば1章については以下の本を追加で読むとよいのかもしれません。

他の章については残念なことにまだ過渡期であるため、きちんとした本は出ていませんし出てくる予定もありません。 ただ、2章~4章については参考文献が幅広く記載されているので、必要に応じてそちらを参照するようにすればよいのではないでしょうか。

5章、6章については詳しく知りたければそれぞれのライブラリのドキュメントを読むのがよいと思われます。

ともかく、直近のJavaの動向について知りたい方はぜひ買うべきだと思います。 この内容を知っておくことで今後5年ぐらいのJavaの動向についても見当がつくようになるのではないでしょうか。

*1:ほかの人はバイネームで誰からもらったかみたいなのを書いてる人もいるけど、わかる人わからない人ではどういう差があるのでしょうか。