Tomcatのログの保持日数がTomcat 9から90日になっていた。

題名のとおり。

ついでに、Tomcat-9.0.13からはログの出力文字がUTF-8に変更されました。 よって、現状は以下のような感じになっています。

※conf/logging.propertiesから抜粋

※下2行が増えた。

1catalina.org.apache.juli.AsyncFileHandler.level = FINE
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina.
1catalina.org.apache.juli.AsyncFileHandler.maxDays = 90
1catalina.org.apache.juli.AsyncFileHandler.encoding = UTF-8

追記:

バックポートもされて古いのも更新されているみたい。

Oracle DBのjdbcドライバをmavenから利用する。

日本語情報だと、どこからか取ってきたjdbcドライバを自前でローカルリポジトリにインストールしろという記事しか見つからなかったので。

Oracle社はOracle DB用のjdbcドライバを自前のmavenリポジトリでリリースしており、そちらから取得する設定を行うことで、ローカルリポジトリに個別にインストールしなくても使用することが出来ます。

基本的には以下の記事のとおりです。

blogs.oracle.com

記事自体は2016年に公開されたものですが、細かいバージョン等はアップデートされているようで、現時点では以下のバージョンが利用できるとの事。

  • 18.3.0.0
  • 12.2.0.1
  • 12.1.0.2
  • 12.1.0.1
  • 11.2.0.4

まずは、Oracleのアカウントを作成して以下にアクセスし、利用規約に同意する必要があります。

https://www.oracle.com/webapps/maven/register/license.html

%USER_HOME%/.m2/setting.xmlに以下の記述を追加してください。 serverのusernameとpasswordはOracleにアカウントを登録した自分のものを使用する必要があります。

<settings>
         <!-- Oracleのサーバーのプロファイルでの有効化 -->
    <profiles>
        <profile>
            <id>oracle</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <repositories>
                <repository>
                    <id>maven.oracle.com</id>
                    <name>oracle-maven-repo</name>
                    <url>https://maven.oracle.com</url>
                    <layout>default</layout>
                    <releases>
                        <enabled>true</enabled>
                        <updatePolicy>always</updatePolicy>
                    </releases>
                </repository>
            </repositories>
        </profile>
    </profiles>
    <!-- Oracleのサーバーの追加 -->
    <servers>
        <server>
            <id>maven.oracle.com</id>
            <username>OracleアカウントのID</username>
            <password>Oracleアカウントのパスワード</password><!-- 暗号化したい場合は後述 -->
            <configuration>
                <basicAuthScope>
                    <host>ANY</host>
                    <port>ANY</port>
                    <realm>OAM 11g</realm>
                </basicAuthScope>
                <httpConfiguration>
                    <all>
                        <params>
                            <property>
                                <name>http.protocol.allow-circular-redirects</name>
                                <value>%b,true</value>
                            </property>
                        </params>
                    </all>
                </httpConfiguration>
            </configuration>
        </server>
    </servers>
</settings>

この状態で、pom.xmldependencyに以下のように記載すればOKです。atrifactIdやversionについてはサポート情報を参照しつつ適切なものを指定してください。

<dependency>
    <groupId>com.oracle.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>18.3.0.0</version>
</dependency>

パスワードの暗号化

パスワードを暗号化したい場合は、setting.xmlの隣にsettings-security.xmlを置く必要があります。 以下のコマンドでmaven用のマスターパスワードを暗号化します。

mvn -encrypt-master-password "マスターパスワード"

(例)

$ mvn -encrypt-master-password password
{9w4lYAShAwsHjAeOPalqAanbuKtz+vReNStoIHpd0wc=}

setting-security.xmlの内容としては以下のように記述します。

<settingsSecurity> 
<master>上記のコマンドの出力結果</master> 
</settingsSecurity> 

以下のコマンドを打つことでOracleアカウントのパスワードを暗号化することが出来ます。

mvn -encrypt-password Oracleアカウントのパスワード

(例)

$ mvn -encrypt-password password
{cmpjcpQb1KsH1O6ljNnoidSMmsYshOwW4kF90QFXzd0=}

この出力内容をpasswordのタグの中に記載することでパスワードが暗号化された状態で使用できます。 マスターパスワードが隣に保存されているかぎりあまり意味はないですが、pom.xmlに記載したい場合は意味がある・・・・・はず。

JavaのAPIを使用して証明書にアクセスする(keytoolは使用せずに)

証明書の期限切れが世の中をにぎわせている今、プログラムから証明書の期限を取得してAPIとして期限切れかどうかをチェックできるものがあるといいよなぁと思い、Javaから証明書にアクセスする方法を調べてみました。

証明書の自動更新とかの実装例を見てると3か月に1回の定期起動みたいな感じになっているので、証明書の中身を見て、切れそうになったら更新みたいな感じで実装できると幸せになる?ならない?もうありそう?

とりあえず、簡単にできます。

keystoreから取得する場合

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Enumeration;

public class KeyStoreAccess {

    public static void main(String[] args) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {

        SimpleDateFormat f = new SimpleDateFormat("yyyy/MM/dd");

        // Javaのキーストアから取得
        KeyStore ks = KeyStore.getInstance("JKS");
        try (FileInputStream in = new FileInputStream("C:\\Program Files\\Java\\jdk-11\\lib\\security\\cacerts")) {
            ks.load(in, "changeit".toCharArray()); //changeitはJavaのキーストアのデフォルトパスワード
        }
        Enumeration<String> aliases = ks.aliases();
        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            X509Certificate certificate = (X509Certificate) ks.getCertificate(alias);
            System.out.println("名前:" + alias + ".発行者:" + certificate.getIssuerX500Principal().getName() + "," + f.format(certificate.getNotAfter()) + "まで");
        }
    }
}

単体の証明書から取得する場合

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Enumeration;

public class KeyStoreAccess {

    public static void main(String[] args) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {

        SimpleDateFormat f = new SimpleDateFormat("yyyy/MM/dd");

        // 直接証明書を取得する。
        try (FileInputStream fis = new FileInputStream("C:\\work\\aaa.cer")) {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);

            System.out.println("発行者:" + cert.getIssuerX500Principal().getName() + "," + f.format(cert.getNotAfter()) + "まで");
        }
    }
}

参考:

Java PKI APIプログラマーズ・ガイド

http://apis.jpn.ph/fswiki/wiki.cgi?page=Java%2Fkeytool

AWS RDSでOracle DB 12cに当たってるパッチセットを確認する。

twitterで @ktz_alias さんに教えてもらったとおりですが。

www.dba-oracle.com

DBMS_QOPATCH

以下でパッチセットが取れます。

select dbms_qopatch.GET_OPATCH_LIST from dual;

以下でパッチの当たったバグの一覧が取れます。(上にも含まれている情報です)

select dbms_qopatch.GET_OPATCH_BUGS from dual;

XMLで取得できますが、大きいデータなので注意してください。 結果例は以下に貼り付けてあります。

https://gist.github.com/megascus/19b862335afd05c4cc417d29f538fe3e

Tomcatのリモートデプロイが2017年からずっと失敗している件

いまだにAntでTomcatのリモートデプロイをしているのですが、ここ最近のバージョンだとずっと動いていなかったようです。

Antの中身で呼ばれているクラスを実行するとエラーになります。

DeployTask deployer = new DeployTask();
deployer.setUpdate(true);
deployer.setWar("C:\\tmp\\WebApplication1.war"); // if change to setLocalWar, it works.
deployer.setUsername("tomcat");
deployer.setPassword("tomcat");
deployer.setUrl("http://localhost:8080/manager/text");
deployer.setPath("/WebApplication1");

deployer.execute();
Exception in thread "main" java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
    at org.apache.catalina.ant.AbstractCatalinaTask.execute(AbstractCatalinaTask.java:270)
    at org.apache.catalina.ant.DeployTask.execute(DeployTask.java:178)
    at tomcattest.TomcatTest.main(TomcatTest.java:28)
Caused by: java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1692)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
    at org.apache.catalina.ant.AbstractCatalinaTask.execute(AbstractCatalinaTask.java:231)
    ... 2 more

機能追加で埋め込んでしまった不具合で、ワークアラウンドとしては、実行前に以下のコードを動かせばよいとの事。

ListTask list = new ListTask();
list.setUsername("tomcat");
list.setPassword("tomcat");
list.setUrl("http://localhost:8080/manager/text");
list.execute();

やったね!

影響しているバージョンは以下のものです。

  • 9.0.0.M22 - 9.0.12
  • 8.5.16 - 8.5.34
  • 8.0.45 -
  • 7.0.78 - 7.0.91

https://bz.apache.org/bugzilla/show_bug.cgi?id=62809

IPAの非機能要求グレードを使ってみた。

2018年4月25日に更新されて、話題になっていたので。
実は、この非機能要求グレードという資料については私は最近まで全く知りませんでした。

https://www.ipa.go.jp/sec/softwareengineering/reports/20100416.html

非機能要求とは

そもそも頭に"非"が付いている時点で、もやっとしたものであり、"機能"の"要求"ではないという程度です。
要求という言葉は、要件という言葉にも置き換えができるので、非機能要件という言葉で認識している人も多いのではないでしょうか。

Wikipediaによると、
非機能要件(Non-functional requirement)とは、システム設計や情報システム開発上の要求分析において、要件、システム要件といった機能面以外の全般を指す。
https://ja.wikipedia.org/wiki/%E9%9D%9E%E6%A9%9F%E8%83%BD%E8%A6%81%E4%BB%B6


という書き方がされており、結局のところ、ユーザー(=非エンジニア)が実現したいと考えているもの(=機能)ではないが、決めておかないと後々困るものといった程度になるのでしょうか。

非機能要求にて決められるもの

多くのものはサーバーが壊れた場合にどうするべきか(もしくはどれくらい壊れにくくするか)、という話で、ユーザーは基本的にインフラは壊れないものとして想定しがちだけれども、そうではないよーという共通認識を作った上で数字を決めていきましょうという感じになります。
一度システム構築したら10年ぐらいノーメンテナンスで動き続けて当然ぐらいの認識をしている人がいたりもするので、そうではないんですよというのを明示できるのはありがたい。

そして、その共有化すべき認識の一覧が公開されているものをベースとすれば、ユーザーがベンダーを選定する場合にフェアな状態で情報を提供できるというのは公平な比較・検討の材料と出来るので、ものすごいメリットかと。

IPAの非機能要求グレードそのものについての個人的な感想

IPAの非機能要求グレードに対する説明については冒頭のリンクからいけるページに、趣旨から始まり、使いかたまで含めて全部書かれた説明書があるので、そちらを見ていただければよいと思います。なので、自分が見てみての感想を箇条書きにしたいと思います。
全体としては、いろいろと気になるところはあるけれども、全体として漏れがないかという確認には使えるし、粒度が粗いと判断した時点で、別途詳細な要件を決めればいいだけなので、道具としては便利という印象です。
内容としても情報処理技術者試験程度の内容を理解していれば(≠資格を持っていれば)読み解ける程度なので、容易い。

  • 基本的に公官庁のユーザーがベンダーにシステム開発を丸投げにする前提なので、そうでない場合はいくつか合わない項目が存在する。
  • 公官庁の商流(ビジネス上の慣習)を知らない場合はチンプンカンプンだと思われる項目が存在する。
  • ハードウェアに対する要求は細かいが、ソフトウェアに対する要求は粗い。自分たちで保守していくのならもっと詳細にルールを決めるべき。
  • オンプレ前提なので、クラウドの場合は決めなくてよい場所がある。(というより勝手に決まって動かせない)
  • それぞれの数値がコストにどれくらい影響するのかは記載がない。そのため、コスト感覚がない人がこれをベースに考えるとひどいことになる可能性がある。
  • それぞれの項目間の影響度についての記載がない。そのため、レベルの選択具合によっては実現が非常に難しい場合がある。
  • 何をもってこれが非機能だと規定したのかについては疑問がある。例えばユーザー管理とかはどんなアプリケーションでも必要なのだけれども、検討を忘れがちなものでもあるので、非機能に入れた方が良かったのではないか。逆に、セキュリティについては機能要求として、非機能からは外したほうが良いという意見もある。

と、ざっと思いついたところこんな感じ。読んでみてほかにも何かあれば教えてくれるとありがたいです。

今のシステムで非機能要求とか考えたことがなかったよという人は、現状がどうなってるのかを考え直すためにも読んでみるといいのではないでしょうか。

Microsoftのドキュメントの誤訳を報告したら炎上した件について(当事者目線での話)

この件について改善がなされるとの発表がMicrosoft DOCS International Teamからありました。
少なくとも、誤訳の報告についてはやりやすくなるそうです。
ご担当者様及びに尽力してくださった方々には感謝いたします。
https://github.com/dotnet/docs.ja-jp/issues/118#issuecomment-408283458


-----------------------------------追記ここまで----------------------------------------------

ということで、おとといぐらいから炎上している件ですが、レポーター目線で今のところきちんとした解説がないので、何があったのかを説明したいと思っています。
(タイトルが正確でないのは自覚があります)

以下のチケットですね。
https://github.com/dotnet/docs.ja-jp/issues/118

なお、以下の記事がMicrosoftエヴァンジェリスト様からよくまとまってると評価されて広まっていますが、まったくもって正しくないです。*1
https://ufcpp.net/blog/2018/7/DocsMistranslation/

// 有識者を名乗るテレビのコメンターが物知り顔で適当なことを言っているのをお茶の間で眺めてしまった当事者の気持ちがよくわかった。

20180727追記ここから
記事の中で、「こんなのわかるわけないよっていうチケット」という表現を使っていますが、Microsoftの社員様からこんなチケット判るわけがないという言葉をいただいたためそのように表現しています。実際にわかりにくいかどうかはgithubのチケットを確認のうえ、各自でご判断ください。
20180727追記ここまで

この記事を書いた人の属性

普段はMicrosoft製品はWindowsぐらいしか使っていません。今回の誤訳の報告もtwitter上で、翻訳おかしいよpgrというのが回ってきてみてみたら、ページにフィードバックフォームがあったから報告した程度のライト層です。なので、Microsoft社とのビジネス上のつながりは薄い(ほぼ皆無)ですし、Microsoft製品のコミュニティには数えるほどしか参加したことがありません。

ページに紐づいたフィードバックフォームからgithubに転載されるMicrosoftのドキュメントフィードバックの仕組み

以下のページにもフィードバックフォームがあるので適当に遊んでみるとよいと思います。
https://docs.microsoft.com/ja-jp/azure/architecture/patterns/

右上にフィードバックというボタンがあります。

それを押すと画面の下に移動し、githubのログインを求められます。

githubにログインするとフォームが現れるので、それに入力してsubmitするとgithubに転載されます。

この記事書くためにキャプチャ撮った時に初めて気が付いたけど、直接githubにフィードバックを残すってオプションもあるのね・・・・・・(このフォームを介するかどうか程度でしかない)


その結果、githubだけ見るとこんなのわかるわけないよっていうチケットが出来上がりました。

投稿者が思いもよらない運用

  • 後から見たほかの人がわからない形でgithubに転記される(せめて、ソースへのリンクがgithub上のmdファイルへではなくdocs.microsoftの対象ページへのリンクだったらわかりやすかったかもしれない)
  • フィードバックのページ自体はすべて日本語で運用されているので、まさかその先が日本語がわからない人しかいないとは思わない

githubに転記された段階で他の人がわかりやすいように書き直せよって言われればそうかもしれないけど、ぽっと出の人にそこまで求めるのか・・・・・・・・

利用者に深いコントリビュートを求めるMicrosoftの報告の仕組み

これだけは最初のページでの報告の仕方を読んで理解しました。最初に全然正しくないと書きましたが、ここに関しては正しいんだろうなぁと思います。
以下のような感じでスクショを張ればよいとのこと。
https://github.com/dotnet/docs.ja-jp/issues/118#issuecomment-407252836

ここまでの報告は無理だろ

最初のフォームだとそもそもスクショを張ることはできないし、というあたりで、まったく外した記事になっている。そもそも通りすがり程度で報告しただけの人にそこまでの労力を求めないでほしい。

深いコントリビュートが求められるマイクロソフトコミュニティ

なんとなく見ててそうだろうなぁとは思っていたのですが、マイクロソフトコミュニティはビジネス上のつながりが強すぎて、深い形でのコントリビュートがされて当然、そうでなければやらないほうが良いというのがあるんだろうなぁと思いました。
私なんかはコミュニティ関係は完全に無償でやってて趣味程度なので、特にまじめにやるつもりはないのですが、お金もらってるMicrosoftの担当者きちんと仕事しろではなく、報告者ちゃんとしろみたいな記事を、Microsoftエヴァンジェリスト様が広める程度なのは、マイクロソフトコミュニティのヒエラルキーの底辺としては悲しい。MSMVPとかもあって、Microsoftの機嫌を損ねるわけにもいかないのでしょうがないのかもしれませんが。

個人的な反省

  • githubに転記された段階できちんと書き直すべきだったかもしれない。ただし、自称有識者が物知り顔で外した解説記事を書く程度になるとは思わなかったし、Microsoftの中の人から空リプで、こんな報告わかるわけないだろと非難されるとは思っていなかった。
  • -1をお願いするようなツイートはよくなかった。ただし、githubのコミュニケーションとして問題がある対応については-1をつけるというのは通常の範囲だと思うし、そのコミュニケーションを設計したのはgithub(現:Microsoft)だし、Microsoftの中の人からDMで代替手段の提示がないまま-1つけるのを煽るのは止めろ的な発言されたのは割と悲しい。だれか解決方法わかる人を探せと言われても、そこまでのコストを払わなければいけないのか・・・・・・・

Microsoftへのお願い

コミュニティである以上、自称有識者が出てきて物知り顔でちんぷんかんぷんな解説が始まり、レポーターが疲弊するってことは今後もあり得るので、コミュニティを介さない形でのフィードバックの仕方を検討してほしい。
以上の通り、上記のブログについては正しくない内容なので、なぜこれを御社がこの記事は正しい記事ですと広めたのかについては、今回の顛末報告のなかできちんと説明してほしい。
(顛末報告があるのか知らんけど)
自分たちで作ったシステムを棚に上げて、SNS上でこんなのわかるわけないだろみたいな発言は慎むべきかと。


という感じで。

お願い

これはあくまでレポーター目線の話なので、間違えていることもたくさんあると思います。これは間違えてるぞということがあればコメント欄に記載ください。(その時に参考文献があるとより望ましい)
空リプでdisられてもわからんよ・・・・・

追記

空リプでこんなのわかるわけないと投げてきたMS社員等はいましたが、チケット内外でサポートしてくださった @yoshioterada さんや @okazuki さんなどには感謝を申し上げます。
ただ、MSMVPの人がMSのドキュメントは昔からこうなんだ!文句があるならもっとコントリビュートするかMSの社員になってから言えや!的なことを呟いていたのはめっちゃ笑ったw

togetterでも悪意のあるまとめられ方してて面白いw
https://togetter.com/li/1250494
上記は消されてしまったので、保管していた人のツイートでも
https://twitter.com/_sfus/status/1022404526811176960

追記の追記

空リプでこの記事の内容間違ってるってツイートしているMS社員がいたので記念に張り付けておきます。(空リプで文句言う人がいて悲しいって話をしたのに・・・・・・)
https://twitter.com/wreulicke/status/1022356995607683072

追記の追記の追記

当初チケットが立つまでの履歴ができました。ありがとうございます!!!
https://togetter.com/li/1250507

追記の追記の追記の追記

変なこと言ってたMSMVPがいたよーとかコメント欄で報告してくださっている方もいますが私はMSMVPにかかわっているわけではないので、必要があればMSに直接お伝えくださるようお願いします。
以下からその人が本当にMSMVPであるかも検索できますので、そちらから特定したうえでMSに伝えれば伝わるでしょう。
https://mvp.microsoft.com/en-us/MvpSearch?lo=Japan&sc=e

*1:githubのみで閉じており、docs.microsoftとの関連について記載がないため、なぜあのわかりにくいチケットが生まれたのかについての記載がない。そのため、チケットの切り方が悪かった方向に終始していた。現在は加筆され、正しくなっているもよう?