システム開発で思うところ

JavaEEを主にシステム開発をしながら思うところをツラツラを綴る

UIデザインのメモ

非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選 - Qiita

メッセージングのメモ

vermeer.hatenablog.jp

の流れで、ざっくりと拾い集めたもの。

Yahooの取り組み

www.slideshare.net

Kafka

sssslide.com

www.slideshare.net

www.slideshare.net

Pulsar

techblog.yahoo.co.jp

JJUG ナイトセミナー 「メッセージングミドルウェア特集」に参加してきました #jjug

まとめ

togetter.com


メモ

実運用して分かったRabbit MQの良いところ・気をつけること

  • ブローカー無しのメッセージングはダメ!メッセージングミドル導入は絶対
  • メッセージは標準仕様が使えるよ
  • ロードバランサーはいらないよ(というか それが原因でメッセージロストして大変だったよ)
  • トラフィック統計と大量処理はトレードオフ
  • ディスクIO対策でマスタはHDD、スレーブはメモリ。2年運用しているけど 今のところ大丈夫

40分弱でわかるApache Kafka

CCCでも聞かせていただきましたが、今回は「製品の特長」に特化していた印象です。

  • ストリーミング処理に強みがあるよ
  • 事例が多いよ

以前、話を聞いたところもあり、メモは薄いですが 発表は相変わらず良かったですし、製品の特長も分かりやすかったです。ストリーミング処理基盤が必要だったら迷わずKafkaを選ぶと良さそうだ、と思います。

メッセージキュー「Pulsar」の紹介

登壇者はコミッター。

新卒7年目でコミッター。

  • 3つの中では一番新しい製品だよ
  • Yahooが開発元だよ
  • 高いスループットに耐えられるよ
  • スケーリングに強いよ
  • マルチテナントだよ
  • 環境構築については3つの中では、一番手間かもしれないよ
  • 設定が階層的に継承できるよ
  • Kafkaクライアントラッパーがあるので、Kafkaからの移行も楽だよ*1

感想

ざっくり

  • 手始めにメッセージングを試してみたいなら、標準仕様を備えているRabbit MQ
  • メッセージングによるストリーミング処理を検討しているならKafka
  • 高いスループットが想定するならPulsar
  • 高いスループットを想定しなくても、メッセージングだったらPulsar
  • スケーリングが容易なのはPulsar
  • マルチテナントならPulsar
  • 個人的には使い勝手が良さそうな印象なのはKafka
  • Kafkaクライアントで実装しておいて、状況によりバックヤードはPulsarにするとか、っていうのはアリかも

Yahooという1つの企業で、メッセージングだけでも色々な製品を使っているというのが面白いですね。

なんとなくですがRabbit MQPulsarのマルチテナントの1つに まとまる方向になる気がしました。Kafkaはストリーミング処理への強み(便利さ)などを考えると 下手にまとめない方が良いという印象を受けました。

というような感じで、一言にメッセージングミドルで片づけてしまうところについて、製品特徴を鑑みて「ここには これを適用してみたら?」と思えるようになったのが最大の収穫だったと思います。

*1:そこまでは言っていないけど、そう言っているように思えた

要件定義のメモ

【RDRA】リレーションシップ駆動要件分析


speakerdeck.com

Pluggable Annotation Processing API Sample(実践編3)

vermeer.hatenablog.jp

vermeer.hatenablog.jp

実践1で挙げた課題について対応しました。

コマンドの記述が繁雑
実行ライブラリのクラスパスにprocessor-command.xmlを配置しないといけないません。つまり利用側が自分のresources配下に機能一覧を追記したprocessor-command.xmlを配置しないといけません。最低でも提供側が定義ファイルに記述する内容をルートパッケージのJavaDocなどに記載したり、手引きに書いておかないと、何をどうしたら良いのかわかりません

Pluggable Annotation Processing API Sample(実践編1) - システム開発で思うところ

今回の対応でprocessor-command.xmlが任意のオプショナルなものになりました。

利用の手引き

  1. Annotation Processorが実行できるpom.xmlの設定
  2. Command Class を実装
  3. コンパイル時にAnnotation Processorにより実行される(※)

※ プロジェクトのクラスパスリソース直下のprocessor-command.xmlにより、実行時の制御ができます(任意).


pom.xml 記述

利用ライブラリとして、またAnnotation Processorを実行する設定をするためにpom.xmlを編集します.

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>

    <!-- Maven Repository on GitHub  start -->
    <git.branchName>mvn-repo</git.branchName>
    <git.repositoryOwner>vermeerlab</git.repositoryOwner>
    <git.repositoryName>maven</git.repositoryName>
    <!-- Maven Repository on GitHub  end-->
</properties>

<repositories>
    <!-- Maven Repository on GitHub  start -->
    <repository>
        <id>org.vermeerlab</id>
        <url>https://raw.github.com/${git.repositoryOwner}/${git.repositoryName}/${git.branchName}/</url>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
        </snapshots>
    </repository>
    <!-- Maven Repository  on GitHub  end-->
</repositories>

<dependencies>
    <dependency>
        <groupId>org.vermeerlab</groupId>
        <artifactId>annotation-processor-core</artifactId>
        <version>0.3.0</version> <!-- target version -->
    </dependency>
</dependencies>

<build>
    <plugins>

        <!-- for annotation processor start-->
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.0</version>
            <configuration>
                <source>${maven.compiler.source}</source>
                <target>${maven.compiler.target}</target>
                <!-- Disable annotation processing for ourselves. -->
                <compilerArgument>-proc:none</compilerArgument>
                <compilerArgs>
                    <arg>-Xlint</arg>
                </compilerArgs>
                <showDeprecation>true</showDeprecation>
            </configuration>
        </plugin>
        <!-- annotation processor end -->
    </plugins>
</build>

Command Class の実装

AnnotationProcessorがorg.vermeerlab.apt.command.ProcessorCommandInterface、またはorg.vermeerlab.apt.command.PostProcessorCommandInterfaceを実装したクラスをコンパイル時に検索して実行します.

2つのインターフェースの違い

  • ラウンド毎に処理(ProcessorCommandInterface
  • ラウンド毎の処理に加えて、最終ラウンドに処理(PostProcessorCommandInterface

proseccor-command.xml の設定(任意)

ファイルが存在しない場合(デフォルト)

  • コンソールに実行コマンドは表示しません
  • 全ての.classファイル および、jarファイルを検索対象とします

ファイルが存在する場合

processor-command.xmlの設定により、以下の対応が可能です.

  • 実際に実行しているコマンドクラスを確認をコンソールに出力
  • 適用したくないコマンドクラスの除外
  • クラスパス配下のファイルだけを対象にして、jarを対象外
  • 検索対象のjarファイルを指定

詳細は xmlコメントを参照してください.

<?xml version="1.0" encoding="UTF-8"?>
<!--
Annotation Processor で実行するコマンドを登録する設定ファイルです.
コマンドクラスは
org.vermeerlab.apt.command.ProcessorCommandInterface
を実装してください.

全ラウンドで まとめて行うコマンドは
org.vermeerlab.apt.command.PostProcessorCommandInterface
を実装してください.
-->
<root>
    <!--
    実行コマンドリストを標準出力制御を設定してください.
    出力する場合は true.
    デフォルトは false(出力しない)
    -->
    <displayCommandList>true</displayCommandList>

    <!--
    実行対象外とするコマンドクラスの完全修飾名を設定してください.
    -->
    <excludeCommands>
        <excludeCommand>
        </excludeCommand>
    </excludeCommands>

    <!--
    コマンドクラスの検索対象としてクラスパス配下のJarファイルを読み込み有無を設定してください.
    Jarファイルを読み込む場合は true
    -->
    <scanJarFile>true</scanJarFile>

    <!--
    コマンドクラスの検索対象とするクラスパス配下のJarファイルを設定してください.
    -->
    <scanTargetJarFiles>
        <scanTargetJarFile>
        </scanTargetJarFile>
    </scanTargetJarFiles>

</root>

例えば、どんなコマンドが実行されているのか、確認するために いったん <displayCommandList>trueにして確認をした上で、不要なコマンドを <excludeCommands>で除外をすると無駄がありません。
その上で、<scanTargetJarFiles>で使用するコマンドのjarだけを検索対象とすればコンパイル時の性能影響も最小限に留めることができます。

Code

BitBucket バージョン 0.3.0

さいごに

当初、諦めていたことが出来たというだけでも個人的には満足です。それに加えて 使用者が自分だけでも暗黙の手順が不要になったことを素直に嬉しく思います。

次回は、今回のライブラリを利用した具体的な事例として、JavaPoetを使用してJavaコードを生成するライブラリについて記事が書ければと思っています。

ClassPath配下の資産を検索する

vermeer.hatenablog.jp

で、processor-command.xmlに実行コマンドを依存ライブラリ全般を把握した上で登録をしないといけない、という仕組みについて、自分としても「良くない」と思っていたところです。
当初はクラスローダー周りが良く分からないということで後回しにするつもりだったのですが、自分にとっても使いにくいということで、先に取り組むことにしました。この対応をしたことでprocessor-command.xmlは、よりオプショナルなものになり利便性が上がったように思います。

はじめに

ツールではなく、拡張を前提としたライブラリです。
Jarファイルおよび Jarにアーカイブされているクラスも検索対象です。

利用方法

pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>

    <!-- Maven Repository on GitHub  start -->
    <git.branchName>mvn-repo</git.branchName>
    <git.repositoryOwner>vermeerlab</git.repositoryOwner>
    <git.repositoryName>maven</git.repositoryName>
    <!-- Maven Repository on GitHub  end-->
</properties>

<repositories>
    <!-- Maven Repository on GitHub  start -->
    <repository>
        <id>org.vermeerlab</id>
        <url>https://raw.github.com/${git.repositoryOwner}/${git.repositoryName}/${git.branchName}/</url>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
        </snapshots>
    </repository>
    <!-- Maven Repository  on GitHub  end-->
</repositories>

<dependencies>
    <dependency>
        <groupId>org.vermeerlab</groupId>
        <artifactId>vermeerlab-classpath-scanner</artifactId>
        <version>0.2.0</version> <!-- target version -->
    </dependency>
</dependencies>

基本

xxxFinder#findの戻り値の型が、xxxScannerの型です.

ジェネリックを使用した理由

必ずしも戻り値がPathであることが最良ではなかったため.
具体的には、絶対パスのファイル表記を使用するのではなく、取得したファイルをクラスの完全修飾名として編集して、 検索結果を文字列として扱った方が後続処理にて扱い易いユースケースがあったため.

ClassPath

デフォルトの検索クラス(ClassPathFinder)は、ファイル名に対して「.class」の後方一致のみを条件として検索します.

ClassPathScanner<Path> scanner = new ClassPathScanner<>();

JarPath

クラスパス配下のJarファイル内のファイルを検索します. デフォルトの検索クラス(JarPathFinder)は、ファイル名に対して「.class」の後方一致かつ「$」をファイルパスに含まないことを条件として検索します.

JarPathScanner<Path> scanner = new JarPathScanner<>();

応用(検索条件の拡張)

※実際に上述の過去記事のプロジェクトにて行った拡張です.
パッケージフォルダ

ClassPath

呼出先の実装
class ProcessorCommandClassFinder<SCAN_RESULT_TYPE> extends ClassPathFinder<SCAN_RESULT_TYPE> {

    TypeAssignableFrom assignableFrom;

    public ProcessorCommandClassFinder() {
        this.assignableFrom = TypeAssignableFrom.of(ProcessorCommandInterface.class);
    }

    /**
     * {@inheritDoc }
     */
    @Override
    @SuppressWarnings("unchecked") //Generic Cast
    public Stream<SCAN_RESULT_TYPE> find(Object rootPath) throws IOException {
        Stream<SCAN_RESULT_TYPE> pathStream = super.find(rootPath)
                .map(filePath -> {
                    String classFilePath
                           = this.assignableFrom.substringClassFilePath(this.rootPath().toString(), filePath.toString());
                    return (SCAN_RESULT_TYPE) classFilePath.substring(0, classFilePath.length() - 6);
                });
        return pathStream;
    }

    /**
     * {@inheritDoc }
     */
    @Override
    protected boolean match(Path path, BasicFileAttributes attrs) {
        if (super.match(path, attrs) == false) {
            return false;
        }
        return assignableFrom.isValidAbsoluteFilePath(this.rootPath().toString(), path.toString());
    }
}
やっていること
  1. 取得したファイルの絶対パスから、ルートとなるパス文字列と「.class」を除外して、クラスの完全修飾名として編集をする
  2. 編集したクラス名からProcessorCommandInterface.classを継承したクラスか判定をする(TypeAssignableFrom
ポイント

SCAN_RESULT_TYPEのキャスト元がStringであること

(SCAN_RESULT_TYPE) classFilePath.substring(0, classFilePath.length() - 6);
呼出元の実装

ProcessorCommandScanner#scan

ClassPathScanner<String> classScanner = new ClassPathScanner<>(new ProcessorCommandClassFinder<>());
ポイント

戻り値の型が基本ではPathだったところが、このケースではString.

JarPath

呼出先の実装
class ProcessorCommandJarFinder<SCAN_RESULT_TYPE> extends JarPathFinder<SCAN_RESULT_TYPE> {

    TypeAssignableFrom assignableFrom;

    public ProcessorCommandJarFinder() {
        this.assignableFrom = TypeAssignableFrom.of(ProcessorCommandInterface.class);
    }

    /**
     * {@inheritDoc }
     */
    @Override
    protected boolean fileFilter(JarEntry jarEntry) {
        return super.fileFilter(jarEntry)
               ? this.assignableFrom.isValidClassFileName(jarEntry.getName())
               : false;
    }

    /**
     * {@inheritDoc }
     */
    @Override
    @SuppressWarnings("unchecked") //Generic Cast
    protected SCAN_RESULT_TYPE toResultValue(JarEntry entry) {
        return (SCAN_RESULT_TYPE) entry.getName();
    }
}
やっていること
  1. クラス名(entry#getName)からProcessorCommandInterface.classを継承したクラスか判定をする(TypeAssignableFrom
  2. クラス完全修飾名を返却する
ポイント

SCAN_RESULT_TYPEのキャスト元がStringであること

return (SCAN_RESULT_TYPE) entry.getName();
呼出元の実装
ProcessorCommandJarPathScanner<String> jarScanner = new ProcessorCommandJarPathScanner<>(
        new ProcessorCommandJarFinder<>(),
        configXml);
ポイント

戻り値の型が基本ではPathだったところが、このケースではString.


まとめ

Jarファイル名の検索条件を変更する(JarPathScanner#jarFilter)など、xxxScannerおよびxxxFinderの各メソッドを拡張が可能です。
拡張ポイントになりそうな検索、編集についてはメソッドをprotectedにしているので用途に応じた拡張してください。

Code

参考

参照可能なクラスのリストを取得したい - argius note

任意のjarファイルから条件に合ったクラスをロードする - Qiita

Jarファイルメモ(Hishidama's java-archive Memo)

さいごに

今回のライブラリは自作ライブラリを複数組み合わせて構築しています。これまでであれば「すべてのコードをローカルにコピーしてください」という手順が必要だったのですが、 GitHubに作成したMavenリポジトリを使うようにすることで、そのあたりの手順がスッキリしたように思います。

作り方は、以下で紹介しています。公開する前提のライブラリであればMavenCentralよりも手続きが少ないのでお勧めです。 vermeer.hatenablog.jp

次回は、ClassLoaderを使うことでコマンドクラスの読み込みが改善できた版のAnnotationProcessorについて書こうと思います。

GitHubにMavenリポジトリをつくる

Mavenプロジェクトを細かく分割することを前提にしたら、私が作成しているものは公開リポジトリが無いと利用者側*1にとって凄く不便だなと思って調べてみました。

はじめに

さくっとは出来ないだろうなぁとは思いましたが案の定かなり苦戦しました。自分なりに 初めから やり直したので大丈夫な手順だとは思います*2

環境

Windows10、Java8、NetBeans8.2

なぜGitHub

コードの管理は今のところ基本的にBitBucketを使っています。その中でMavenリポジトリGitHubにしました。理由は知見量が多かったことと、当初、BitBucketでやろうとしたのですが良く分からなかったというのが一番の理由です。あと後付け的なところはありますが、公開する資産についてはGitHubの方が多くの人にとって馴染みがあるかな?というところもあってGitHubMavenリポジトリの置き場にすることにしました。

構築の流れ

格納先となるリポジトリを作成する

f:id:vermeer-1977:20170901131727p:plain

  • ブランチを作成

ブランチ名は「mvn-repo」

f:id:vermeer-1977:20170901132124p:plain

f:id:vermeer-1977:20170901132311p:plain

f:id:vermeer-1977:20170901132808p:plain

「save」ボタンを押すのを忘れずに

認証キーを作成する

Webで調べるとユーザー名とパスワードを設定するやり方が多かったように思いますが、OAuthによる認証の方がセキュリティー的にみて良いと思います。

f:id:vermeer-1977:20170901133320p:plain


f:id:vermeer-1977:20170901133524p:plain


Token description は「maven-pass」。ただのラベルなので何でも大丈夫です。

チェックボックスpublic_repo user:email だけ。必要最低限は この2つをチェックすれば良いようです*5

f:id:vermeer-1977:20170901133846p:plain


認証キーが生成されます。

後から確認は出来ませんので ここでメモしておくのを忘れずに。忘れたときは再生成することになるので気を付けましょう。

f:id:vermeer-1977:20170901134123p:plain

pom.xmlを編集する

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vermeerlab</groupId>
    <artifactId>maven-git-sample</artifactId>
    <version>0.1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <github.global.server>github</github.global.server>
        <git.branchName>mvn-repo</git.branchName>
        <git.repositoryOwner>vermeer-1977</git.repositoryOwner>
        <git.repositoryName>maven</git.repositoryName>
        <git.isMerge>true</git.isMerge>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
                <configuration>
                    <altDeploymentRepository>internal.repo::default::file://${project.build.directory}/${git.branchName}</altDeploymentRepository>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.github</groupId>
                <artifactId>site-maven-plugin</artifactId>
                <version>0.12</version>
                <configuration>
                    <!-- git commit message -->
                    <message>Maven artifacts for ${project.version}</message>
                    <noJekyll>true</noJekyll>
                    <outputDirectory>${project.build.directory}/${git.branchName}</outputDirectory>
                    <branch>refs/heads/${git.branchName}</branch>
                    <includes>
                        <include>**/*</include>
                    </includes>

                    <repositoryName>${git.repositoryName}</repositoryName>
                    <repositoryOwner>${git.repositoryOwner}</repositoryOwner>

                    <!-- true:履歴を残す false:直近バージョンのみ repositoryに残る -->
                    <merge>${git.isMerge}</merge>

                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>site</goal>
                        </goals>
                        <phase>deploy</phase>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.source}</target>
                    <compilerArgs>
                        <arg>-Xlint</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
        </plugins>

    </build>

    <distributionManagement>
        <repository>
            <id>internal.repo</id>
            <name>Temporary Staging Repository</name>
            <url>file://${project.build.directory}/${git.branchName}</url>
        </repository>
    </distributionManagement>
</project>
  • ローカル保存先の distributionManagementurl の指定でリポジトリ名と同じフォルダを指定しています。任意のフォルダ名で良く、特に意味を持たせる必然は無いけれど pom内に複数個所指定するので 記述誤りを防ぐために同名にしました。

  • git.isMergetrueであればアップロードした資産の履歴を残します。SNAPSHOTの場合は履歴を残すけど、そうじゃなくなったら履歴は不要というような指定をしたい場合に使用する想定かな?と思っています。

settings.xmlを編集する

...\.m2\settings.xmlに格納されています。

NetBeansMavenプロジェクトだったら、以下のものを編集。見た感じだとプロジェクト毎に存在するように見えますが 全てのプロジェクトで共通の資産です。どのプロジェクトのものを編集してもちゃんと反映されます*6

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>github</id>
            <password>hogehogehogehogehogehogehogehogehogehoge</password>
        </server>
    </servers>
</settings>

hogehoge… は先に取得した認証キーを設定してください。

Maven資産をアップロード

mvn deploy コマンドを実行します。


f:id:vermeer-1977:20170901154750p:plain


f:id:vermeer-1977:20170901154823p:plain


f:id:vermeer-1977:20170901161244p:plain


アップロードされたリポジトリのアドレスは

GitHub - vermeer-1977/maven at mvn-repo

ちなみに通常のビルドではアップロードはされません。

簡易クラスを作成

次の工程で参照するためのクラスを追加します。

public class Sample {

    public void testPrint() {
        System.out.println("maven-test-sample");
    }
}

改めて deploy します。

リポジトリ資産を取り込む

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new org.vermeerlab.maven.git.sample.Sample().testPrint();
    }

}

アップロードをした資産の取り込むための設定。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vermeerlab</groupId>
    <artifactId>maven-git-client</artifactId>
    <version>0.1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <github.global.server>github</github.global.server>
        <git.branchName>mvn-repo</git.branchName>
        <git.repositoryOwner>vermeer-1977</git.repositoryOwner>
        <git.repositoryName>maven</git.repositoryName>
        <git.isMerge>true</git.isMerge>
    </properties>

    <repositories>
        <repository>
            <id>github-maven</id>
            <url>https://raw.github.com/${git.repositoryOwner}/${git.repositoryName}/${git.branchName}/</url>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>maven-git-sample</artifactId>
            <version>0.1.0</version>
        </dependency>
    </dependencies>

</project>

この流れだとローカルリポジトリを参照してしまいます。念のためローカルリポジトリの資産を削除して確認をすると良いと思います。ログをみたら、きちんとダウンロードをしていることが確認できます。

f:id:vermeer-1977:20170901165044p:plain

基本は以上です。

Git(コード)

vermeer_etc / maven-git-sample — Bitbucket

vermeer_etc / maven-git-client — Bitbucket


応用編(親子pomで共通化)

親pomを持つことで重厚なpom記述を全てのプロジェクトに記載しなくて良くなります。

同一ユーザーの別リポジトリにアップしたい

artifact単位でフォルダは作成されますが、意味のある単位としてリポジトリを分けておきたいケースがあります。その場合は、子pomの git.repositoryName を指定します。

子pomで指定

    <properties>
        <git.repositoryName>(変更したいリポジトリ名)</git.repositoryName>
    </properties>

同一ユーザーの別組織のリポジトリにアップしたい

リポジトリ名だけでなく、ライブラリ管理用のOrganizationを作成すると、製品毎に配布資産をグループ化することができます。

子pomで指定

    <properties>
        <git.repositoryOwner>(変更したい組織名)</git.repositoryOwner>
        <git.repositoryName>(変更したいリポジトリ名)</git.repositoryName>
    </properties>

別ユーザーのリポジトリにアップしたい

別ユーザー=認証キーが異なるアカウント管理配下のリポジトリを意図しています。例えばオーナーは別の人だけど配布資産のアップロード権限を持っている状態です。このケースはタグによる上書きだけでなく、対象権限の認証キーも併せて指定する必要があります。

★★あくまで理論上の話です*7。★★

別ユーザーや別組織のリポジトリにアップするためには、アップロード権限のある認証キーが必要です。

認証キーは別途入手できている前提として、いちいちsettings.xmlを書き換えるのは面倒です。ということで切り替えるというのが良いと思います。

  • settings.xmlidと認証キーを追記
<server>
    <id>github</id>
    <password>hogehogehogehogehogehogehogehogehogehoge</password>
</server>

<!-- 追記 -->
<server>
    <id>github-blog</id>
    <password>fugafugafugafugafugafugafugafugafugafuga</password>
</server>

  • 子pom
    <properties>
        <github.global.server>github-blog</github.global.server>
        <git.repositoryOwner>(変更したい組織名)</git.repositoryOwner>
        <git.repositoryName>(変更したいリポジトリ名)</git.repositoryName>
    </properties>

もし基本構造が全く同じであれば指定は不要ですが リポジトリ名など明示的に変更が必要なところがあれば それも指定してください。

間違ってリモートリポジトリにアップしない工夫

とりあえず現時点で私が思いつく懸念事項と対策案です。

  • 履歴を残す

上述していますがgit.isMergeは基本的にtrueにして子pom側で上書きをしないようにすることを推奨します。履歴を持つ分、リポジトリの容量が増えてしまいますが 間違ってアップロードしたときに履歴があれば戻すことが可能です*8

  • github.global.serverの指定は子pomで明示的にする

親pomで宛先を指定しておくと子pomの記述量は減るのですが、上述の事例にあるような切り替えを検討した場合、いくつかの偶然が重なると(各種名称が重複していた&ユーザーとしても更新権限を持っていた、など)、間違った宛先のリポジトリを更新してしまうことが懸念されます。親pomには無効な値を記述しておけば、未指定の場合はアップロードが出来ないのでリスクは減るかと思います。また子pomに本記述があることが先頭で分かるので「これは公開リポジトリにアップロードする対象の資産だな」ということが明示的に分かりやすいように思います。

ただ、切り替えは基本的にしないというのであれば、親pomに記述した方が良いと思います。仕事が増えるとミスの原因も増えます。

子pom

<plugins>
    <plugin>
        <groupId>com.github.github</groupId>
        <artifactId>site-maven-plugin</artifactId>
    </plugin>
</plugins>

のところを基本的にコメントアウトしておけば 間違ってdeploy を実行してもアップロードはされません。リポジトリに資産をアップする頻度にもよりますが、頻繁でないのであれば、こういう運用もありだと思います。

注意事項

親pomのビルドを忘れずに

子pomからローカルリポジトリを参照させたいので、子pomによるビルドの前に親pomのローカルリポジトリの作成またはコードを`git clone'してビルドをするのを忘れないようにしましょう。

ローカルリポジトリの指定を忘れずに

ローカルリポジトリの相対位置をrelativePathで指定しています。こうしておかないと子pomから親pomの参照ができないためエラーになります。今回は同一グループなので、このくらいの記述ですが別グループだと、こうはいかない可能性があります*9。基本的に親pomプロジェクトは同一グループにつくると思いますので、ご自身のグループを適当に作って親と子の資産を1つのグループとして扱うと良いでしょう。

    <parent>
        <groupId>org.vermeerlab</groupId>
        <artifactId>maven-git-parent</artifactId>
        <version>0.1.0</version>
        <relativePath>../</relativePath> <!-- この指定 -->
    </parent>

Git(コード)

  • 親pom

vermeer_etc / maven-git-parent — Bitbucket

  • 子pom

vermeer_etc / maven-git-child — Bitbucket


参考

Github を Maven リポジトリとして使う -

Github上に私設Mavenリポジトリをつくる - M12i.

GitHub の Pages を maven リポジトリとして使用するときのアカウント情報をセキュアにする(OAuth2Token) | KK.Kon の徒然メモ書き

http://synergian.github.io/wagon-git/usage.html

さいごに

これでオレオレリポジトリが気軽に作れるようになりました。
目的としていた「細かいMavenプロジェクトを作っても、利用したいときにコードのダウンロードで地獄を見ない」ということが実現できそうです。

本題とは関係ないですが、目次を初めて使ってみました。これは良いですね。

*1:自分自身も含めて

*2:やり直して思うところとしてはGitHub側の認証キーのところが原因だったかも。もしくはGitPageの作成かな?

*3:作ってから思いましたが紛らわしいので違う名前にした方が分かりやすかったかも

*4:あぁ、いきなり分かりにくい

*5:上手くいかなかったのは、user:email にチェックしていなかったからダメだったかも

*6:反映というか「同じ」なんですけどね

*7:GitHub上で別ユーザーの作成も考えましたが、今回のためだけに作成するのは ちょっと違うかな と思ってやめました

*8:ミスをしない工夫も大事ですが、ミスはするもの という前提を仕組みに入れておくと心理的に安心です

*9:試してはいませんが理屈上はそのはずです