アーカイブ「2015年04月」

ちまたでは、chefやらansibleといった

インフラ構成ツールが流行っている。

 

しかし、個人的にはどっちもめんどくさい。

ドキュメントは充実しているが、

それなりに扱うには独自の書き方を習得する必要がある。

 

そこで、以下のように考えてみた。

  • ssh接続でコマンドを発行できる
  • ssh接続でファイルを操作し、部分置換・全体置換・追記ができる

以上があれば十分で、あと必要なものは、

  • 環境ごとの設定
  • サーバ用途でのグルーピング

ってくらいだろうか。。

 

そして、「冪等性」ってのを保つのは非常に重要。

 

これらを踏まえつつ、

基本的にはシェルスクリプトを作成し、

WEBベースで、実行・管理できればよいかなと思っている。

そんなツールに着手してみようかな。。

 

投稿日時:2015年04月16日 10:40   カテゴリー:server   [コメントがあればどうぞ]

どうも「バッチサーバ」というのが好きでない。

 

WEB系をやっていると、WEBサーバ(APサーバも含む)とは別に、

バッチサーバなるものを用意するケースがあるが、

これって実はあんまりいらないと思っている。

(というか、外したいと思っている)

 

確かに、WEBサーバ側の負荷と切り離して考えられるメリットもある。

しかし、自分にとってはリソースを有効活用できていない感がある。。

 

最近では、

スクリプト言語でも、WEBサーバ内にバッチ処理用のソースコードを持つことが多々ある。

これは、どのサーバでも代替実行が出来るようにするという狙いからのものであるが、

実際はWEBサーバは複数あるケースが多く、

夜間などのアクセスが少ない時間帯で、

複数サーバで、一気にバッチを実行してしまうほうが処理が速く終わってよいと思う。

 

javaなんかでは、APサーバ内の1スレッドとして、

バッチ処理を動かすケースなんかもあるだろう。

 

ということで、こんな風にできたらいいなと思うバッチ処理をまとめてみる。

  • WEBサーバ(APサーバも含む)の1スレッドとしてバッチが実行できる
  • 手動でも実行できる
  • 同一のバッチが複数サーバで動いて欲しくないケースは排他制御をかける
  • 空いているリソースを見つけて分散できる
  • さらに、実行結果を1か所で確認できる

という感じ。

 

zookeeperなどの組み合わせることで、

上記を実現できるが、

インフラがやや複雑になり、プログラマーの管理ではなかなか厳しい。。

 

javaではcron4jなどがあったり、

nodeではcronのモジュールがあったりするので、

上手いことスレッドとして、組み込みつつ、

外側からも実行可能で、分散的に、必要あらば排他的に、

そして、出来るだけ簡素に。

そんなバッチが組めるような仕組みを考えてみたい。

 

投稿日時:2015年04月14日 17:01   カテゴリー:server   [コメントがあればどうぞ]

まとめをしてみます。

  1. 第1回
  2. 第2回
  3. 第3回
  4. 第4回
  5. 第5回
  6. 第6回
  7. 第7回

という感じにまとまりました。

結局java側だけしかかけなったけど、

javaでは排他制御をかける(synchronizedブロック)がほんとに重要。

 

nodeはシングルスレッドだから、

排他制御は基本的には不要。

 

その他、大事なトピックとしては、

  • クライアントに送信しようとしても送信できないケースがある(たぶん避けらない)
  • バックエンドでDBを使う場合は、基本的にはつなぎっぱなし(ただし、RDBとRedisではちょっと扱いが違うので注意)

などでしょうか。

 

最後にスケールアウトについて。

単純にスケールアウトする場合、pub/subを使うしか手がない。

pub/subができるのは、

  • redis
  • ActiveMQ
  • Java Message Service

などがあるが、pub/subがあるとないとでは、

実装がかなり異なる。

重要なのは、

「sub」の接続を先に確立して、

処理を行い、

対象者に「pub」して、

「sub」でメッセージ送信を行う

という流れである。

 

pub/subを行うと、

データ自体もメモリに持てなくなるので、

十分注意しながらやっていただければと思います。

 

以上で、websocketの話はほんとにおしまい。

 

投稿日時:2015年04月02日 18:36   カテゴリー:java, node.js, websocket   [コメントがあればどうぞ]

ラウンド編。

また、websocketの処理だけ書く。

package trmpj.ws;

import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import trmpj.TPair;
import trmpj.TReq;
import trmpj.TSession;
import trmpj.TWs;
import trmpj.req.TReqEnd;
import trmpj.req.TReqGame;
import trmpj.req.TReqPrepared;
import trmpj.res.TResEnded;
import trmpj.res.TResError;
import trmpj.res.TResGame;
import trmpj.res.TResInvalid;
import trmpj.res.TResNone;
import trmpj.res.TResStart;
import trmpj.res.TResWait;

/**
 * 対戦用処理
 *
 */
@ServerEndpoint(value = "/ws/round/{pairId}")
public class TWsRound extends TWs {

    /**
     * pairId => TPairのマップ
     */
    private static ConcurrentHashMap<String, TPair> pairs = new ConcurrentHashMap<String, TPair>();

    /**
     * pairId => Threadのマップ
     */
    private static ConcurrentHashMap<String, Thread> threads = new ConcurrentHashMap<String, Thread>();

    /**
     * openハンドラ
     * @param pairId
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("pairId") String pairId, Session session) {
        // セッションにアクセスIDを格納する
        String accessdId = generateAccessId();
        session.getUserProperties().put(KEY_ACCESS_ID, accessdId);

        // アクセスIDを、onMessage, onCloseで取得するときの関連を付ける
        // ※sessionsのキー側はsessionでもよいのですが、
        // runnableからの参照時に、セッションが破棄されていると困るので、
        // あえて文字列にしている
        TSession ts = new TSession(session);
        sessions.putIfAbsent(accessdId, ts);
    }

    /**
     * messageハンドラ
     * @param pairId
     * @param session
     * @param message
     */
    @OnMessage
    public void onMessage(@PathParam("pairId") String pairId, Session session, String message) {
        // アクセスIDを取得
        String accessdId = (String) session.getUserProperties().get(KEY_ACCESS_ID);
        TSession ts = null;

        try {
            // アクセスIDをもとに、openハンドラで登録したTSessionを呼び出す
            if (!sessions.containsKey(accessdId)) {
                throw new Exception();
            }
            ts = sessions.get(accessdId);

            // リクエストを解析
            TReq req = ts.receiveMessage(message, TReq.class);
            if (req == null) {
                throw new Exception();
            }

            // ペアIDに応じたペア情報をマップから取り出す
            if (!pairs.containsKey(pairId)) {
                pairs.putIfAbsent(pairId, new TPair(pairId));
            }
            TPair pair = pairs.get(pairId);

            // ペア情報に排他制御をかける
            // ※重要
            synchronized (pair) {
                if (req.command.equals(TReq.COMMAND_PREPARED)) {
                    // preparedコマンド
                    TReqPrepared reqPrepared = ts.receiveMessage(message, TReqPrepared.class);
                    if (reqPrepared == null) {
                        throw new Exception();
                    }

                    // 既にペアが揃った状態ならここで終了
                    if (pair.isPrepared()) {
                        throw new Exception();
                    }

                    // 自分の情報をセッションに追加
                    ts.setUser(reqPrepared.user);

                    // ペア情報に自分の情報を追加
                    pair.addTSession(ts);

                    // 同一ユーザIDはエラー
                    if (pair.isDuplicated()) {
                        throw new Exception();
                    }

                    // 2人そろった状態なら、2人にstartを返す
                    if (pair.isPrepared()) {
                        // スレッドを止める
                        threads.remove(pairId);

                        TResStart resStart = new TResStart();
                        resStart.users.addAll(pair.getUsers());
                        pair.sendMessage(resStart);
                        return;
                    }

                    // 揃っていない状態なので、自分にwaitを返す
                    TResWait resWait = new TResWait();
                    ts.sendMessage(resWait);

                    // 別スレッドで、相手がくるまで数秒待機する
                    if (!threads.containsKey(pairId)) {
                        threads.putIfAbsent(pairId, new Thread(new TRunnable(pairId)));
                        threads.get(pair).start();
                    }
                    return;

                } else if (req.command.equals(TReq.COMMAND_GAME)) {
                    // gameコマンド
                    TReqGame reqGame = ts.receiveMessage(message, TReqGame.class);
                    if (reqGame == null) {
                        throw new Exception();
                    }

                    // 同一ユーザIDはエラー
                    if (pair.isDuplicated()) {
                        throw new Exception();
                    }

                    // 揃った状態でない、または終了状態なら何もしない
                    if (!pair.isPrepared() || pair.isEnded()) {
                        throw new Exception();
                    }

                    // 2人に返す
                    TResGame resGame = new TResGame();
                    resGame.useId = ts.getUser().userId;
                    resGame.data = reqGame.data;
                    pair.sendMessage(resGame);
                    return;

                } else if (req.command.equals(TReq.COMMAND_END)) {
                    // endコマンド
                    TReqEnd reqEnd = ts.receiveMessage(message, TReqEnd.class);
                    if (reqEnd == null) {
                        throw new Exception();
                    }

                    // 同一ユーザIDはエラー
                    if (pair.isDuplicated()) {
                        throw new Exception();
                    }

                    // ペアを終了状態にする
                    pair.setEnded(true);

                    // 自分に返す
                    TResEnded resEnded = new TResEnded();
                    ts.sendMessage(resEnded);
                    return;

                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        // エラー処理
        if (ts != null) {
            TResError resError = new TResError();
            ts.sendMessage(resError);
        }
    }

    /**
     * closeハンドラ
     * @param pairId
     * @param session
     * @param reason
     */
    @OnClose
    public void onClose(@PathParam("pairId") String pairId, Session session, CloseReason reason) {
        // アクセスIDを取得
        String accessdId = (String) session.getUserProperties().get(KEY_ACCESS_ID);
        TSession ts = null;

        try {
            // アクセスIDをもとに、openハンドラで登録したTSessionを呼び出す
            if (!sessions.containsKey(accessdId)) {
                throw new Exception();
            }
            ts = sessions.get(accessdId);

            // ペアIDに応じたペア情報をマップから取り出す
            if (!pairs.containsKey(pairId)) {
                throw new Exception();
            }
            TPair pair = pairs.get(pairId);

            // ペア情報に排他制御をかける
            // ※重要
            synchronized (pair) {
                // 自分の情報削除
                pair.removeTSession(ts);

                // 空になっていたら削除
                if (pair.isEmpty()) {
                    pairs.remove(pairId);
                    return;
                }

                // game中で、endでない場合は、残っている方にnoneを送信
                if (pair.isPrepared() && !pair.isEnded()) {
                    TResNone resNone = new TResNone();
                    pair.sendMessage(resNone);
                    return;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        // セッション情報も破棄する
        sessions.remove(accessdId);
    }

    /**
     * 2人が揃うまで待つ別スレッド
     * @author furuta
     *
     */
    public class TRunnable implements Runnable {

        /**
         * ペアID
         */
        private String pairId;

        /**
         * コンストラクタ
         * @param pairId
         */
        public TRunnable(String pairId) {
            this.pairId = pairId;
        }

        /**
         * 処理
         */
        public void run() {
            try {
                // 10秒まつ
                Thread.sleep(10000);

                // ペアを取得
                if (!pairs.containsKey(pairId)) {
                    throw new Exception();
                }
                TPair pair = pairs.get(pairId);

                synchronized (pair) {
                    if (!pair.isPrepared()) {
                        // 揃っていない状態であれば、残っている人にinvalidを返す
                        TResInvalid resInvalid = new TResInvalid();
                        pair.sendMessage(resInvalid);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

            // スレッドを削除
            threads.remove(pairId);
        }
    }
}

ポイントはsynchronizedでしっかり排他制御をかけること。
これをやらないとだめだぜ。。

ソースコードはちゃんとテストしてないけど、
処理の流れはわかるはず。。

とりあえず、作成したコードをzipで固めておきます。

ダウンロード

 

これで、websocketは終了。

nodeは書く気力なし。。

投稿日時:2015年04月02日 18:23   カテゴリー:java, node.js, websocket   [コメントがあればどうぞ]

やっとかく。

とりあえず、websocketのメイン処理をさらす。

 

マッチング

package trmpj.ws;

import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import trmpj.TReq;
import trmpj.TSession;
import trmpj.TWs;
import trmpj.req.TReqEntry;
import trmpj.res.TResEntried;
import trmpj.res.TResError;
import trmpj.res.TResPrepare;

/**
 * マッチング用処理
 *
 */
@ServerEndpoint(value = "/ws/matching/{type}")
public class TWsMatching extends TWs {

    /**
     * type => Set<TSession>のマップ
     */
    private static ConcurrentHashMap<Integer, LinkedList<TSession>> entries = new ConcurrentHashMap<Integer, LinkedList<TSession>>();

    /**
     * openハンドラ
     * @param type
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("type") int type, Session session) {
        // セッションにアクセスIDを格納する
        String accessdId = generateAccessId();
        session.getUserProperties().put(KEY_ACCESS_ID, accessdId);

        // アクセスIDを、onMessage, onCloseで取得するときの関連を付ける
        // ※sessionsのキー側はsessionでもよいのですが、
        // runnableからの参照時に、セッションが破棄されていると困るので、
        // あえて文字列にしている
        TSession ts = new TSession(session);
        sessions.putIfAbsent(accessdId, ts);
    }

    /**
     * messageハンドラ
     * @param type
     * @param session
     * @param message
     */
    @OnMessage
    public void onMessage(@PathParam("type") int type, Session session, String message) {
        // アクセスIDを取得
        String accessdId = (String) session.getUserProperties().get(KEY_ACCESS_ID);
        TSession ts = null;

        try {
            // アクセスIDをもとに、openハンドラで登録したTSessionを呼び出す
            if (!sessions.containsKey(accessdId)) {
                throw new Exception();
            }
            ts = sessions.get(accessdId);

            // リクエストを解析
            TReq req = ts.receiveMessage(message, TReq.class);
            if (req == null) {
                throw new Exception();
            }

            // タイプに応じたエントリー情報をマップから取り出す
            if (!entries.containsKey(type)) {
                entries.putIfAbsent(type, new LinkedList<TSession>());
            }
            LinkedList<TSession> es = entries.get(type);

            // タイプごとのエントリー情報に排他制御をかける
            // ※重要
            synchronized (es) {
                if (req.command.equals(TReq.COMMAND_ENTRY)) {
                    // entryコマンド
                    TReqEntry reqEntry = ts.receiveMessage(message, TReqEntry.class);
                    if (reqEntry == null) {
                        throw new Exception();
                    }

                    // 自分の情報をセッションに追加
                    ts.setUser(reqEntry.user);

                    try {
                        // 先にエントリーしている人の情報をとる
                        TSession tsPrev = es.pop();

                        // 情報をとった結果、同じユーザIDの場合は、エラーとする
                        if (tsPrev.getUser().userId.equals(ts.getUser().userId)) {
                            throw new Exception();
                        }

                        // エントリーしている人の情報と、自分の情報を、マッチング成立として両者に返す
                        TResPrepare resPrepare = new TResPrepare();
                        resPrepare.type = type;
                        resPrepare.seed = (int) (Math.random() * 10000) + 1;
                        resPrepare.users.add(ts.getUser());
                        resPrepare.users.add(tsPrev.getUser());

                        ts.sendMessage(resPrepare);
                        tsPrev.sendMessage(resPrepare);
                        return;

                    } catch (Exception e) {
                        // ここはpopで例外が発生するが、無視する
                    }

                    // 自分を加える
                    es.add(ts);

                    // 自分にエントリー完了を送信する
                    TResEntried resEntried = new TResEntried();
                    ts.sendMessage(resEntried);
                    return;

                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        // エラー処理
        if (ts != null) {
            TResError resError = new TResError();
            ts.sendMessage(resError);
        }
    }

    /**
     * closeハンドラ
     * @param type
     * @param session
     * @param reason
     */
    @OnClose
    public void onClose(@PathParam("type") int type, Session session, CloseReason reason) {
        // アクセスIDを取得
        String accessdId = (String) session.getUserProperties().get(KEY_ACCESS_ID);
        TSession ts = null;

        try {
            // アクセスIDをもとに、openハンドラで登録したTSessionを呼び出す
            if (!sessions.containsKey(accessdId)) {
                throw new Exception();
            }
            ts = sessions.get(accessdId);

            // 自分が既に登録されていたら、削除する
            if (!entries.containsKey(type)) {
                throw new Exception();
            }
            LinkedList<TSession> es = entries.get(type);
            es.remove(ts);

        } catch (Exception e) {
            e.printStackTrace();
        }

        // セッション情報も破棄する
        sessions.remove(accessdId);
    }
}

最大のポイントは、
onMessageにおけるsynchronizedブロックである。

これでちゃんと排他制御をかけないと、

エラーになるぜ。。

 

ながいので、ラウンド編は次回に。

 

投稿日時:2015年04月02日 18:11   カテゴリー:java, node.js, websocket   [コメントがあればどうぞ]

maven3で使うプラグインなのだが、

どうも情報が古かったりするので、

最新版でまとめてみた。

 

【環境】

OS:windows8.1 – 64bit

JDK:1.8 – 64bit

maven:3.2.1 – eclipse lua embedded

 

【プラグイン】

  • maven-compiler-plugin 3.3
  • maven-project-info-reports-plugin 2.8
  • org.apache.maven.plugins 3.4
  • maven-checkstyle-plugin 2.15
  • maven-javadoc-plugin 2.10.2
  • org.apache.maven.plugins 3.4
  • findbugs-maven-plugin 3.0.1
  • maven-jxr-plugin 2.5
  • taglist-maven-plugin 2.4
  • cobertura-maven-plugin 2.7

 

ローカルPCのmavenで各種レポートを作成する場合、

mvn clean site

で作れるのだが、

chekstyleプラグインが独自のcheckstyleファイルを用いていると、

ビルドが失敗する(理由がわからない)

とりあえず、簡単にpomをさらす。

 

ローカルmaven用pom

<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>

  :
  :

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencyManagement>
    :
    :
  </dependencyManagement>

  <dependencies>
    :
    :
  </dependencies>

  <build>
    <pluginManagement>
      <plugins>
        <!-- compiler plugin -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.3</version>
          <configuration>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <compilerVersion>${java.version}</compilerVersion>
            <encoding>${project.build.sourceEncoding}</encoding>
          </configuration>
        </plugin>
        <!-- project info reports plugin -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <!-- site plugin -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.4</version>
          <configuration>
            <inputEncoding>${project.build.sourceEncoding}</inputEncoding>
            <outputEncoding>${project.build.sourceEncoding}</outputEncoding>
          </configuration>
        </plugin>
        <!-- checkstyle plugin -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-checkstyle-plugin</artifactId>
          <version>2.15</version>
          <dependencies>
            <dependency>
              <groupId>com.puppycrawl.tools</groupId>
              <artifactId>checkstyle</artifactId>
              <version>6.5</version>
            </dependency>
          </dependencies>
          <configuration>
            <configLocation>${basedir}/config/google_checks.xml</configLocation>
            <encoding>${project.build.sourceEncoding}</encoding>
          </configuration>
        </plugin>
        <!-- javadoc plugin -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-javadoc-plugin</artifactId>
          <version>2.10.2</version>
          <configuration>
            <locale>ja</locale>
            <charset>${project.build.sourceEncoding}</charset>
            <encoding>${project.build.sourceEncoding}</encoding>
          </configuration>
        </plugin>
        <!-- pmd plugin -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-pmd-plugin</artifactId>
          <version>3.4</version>
          <configuration>
            <outputEncoding>${project.build.sourceEncoding}</outputEncoding>
          </configuration>
       </plugin>
       <!-- findbugs plugin -->
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <version>3.0.1</version>
         <configuration>
           <effort>low</effort>
           <xmlOutput>true</xmlOutput>
           <encoding>${project.build.sourceEncoding}</encoding>
           <outputEncoding>${project.build.sourceEncoding}</outputEncoding>
         </configuration>
       </plugin>
       <!-- jxr plugin -->
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jxr-plugin</artifactId>
         <version>2.5</version>
         <configuration>
           <inputEncoding>${project.build.sourceEncoding}</inputEncoding>
           <outputEncoding>${project.build.sourceEncoding}</outputEncoding>
         </configuration>
       </plugin>
       <!-- taglist plugin -->
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>taglist-maven-plugin</artifactId>
         <version>2.4</version>
         <configuration>
           <encoding>${project.build.sourceEncoding}</encoding>
         </configuration>
       </plugin>
       <!-- cobertura plugin -->
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>cobertura-maven-plugin</artifactId>
         <version>2.7</version>
         <configuration>
           <formats>
             <format>html</format>
             <format>xml</format>
           </formats>
           <encoding>${project.build.sourceEncoding}</encoding>
         </configuration>
       </plugin>
     </plugins>
   </pluginManagement>
   <plugins>
     <!-- mvn site -->
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-site-plugin</artifactId>
       <configuration>
       <reportPlugins>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>findbugs-maven-plugin</artifactId>
         </plugin>
         <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-project-info-reports-plugin</artifactId>
         </plugin> -->
         <!-- checkstyle はsiteでエラーになるためコメントアウト -->
         <!--
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-checkstyle-plugin</artifactId>
         </plugin>
         -->
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-javadoc-plugin</artifactId>
           <reportSets>
             <reportSet>
               <reports>
                 <report>javadoc</report><!-- テスト用をださないための指定 -->
               </reports>
             </reportSet>
           </reportSets>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-pmd-plugin</artifactId>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>findbugs-maven-plugin</artifactId>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jxr-plugin</artifactId>
           <reportSets>
             <reportSet>
               <reports>
                 <report>jxr</report><!-- テスト用を出さないための指定 -->
               </reports>
             </reportSet>
           </reportSets>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>taglist-maven-plugin</artifactId>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>cobertura-maven-plugin</artifactId>
         </plugin>
       </reportPlugins>
     </configuration>
    </plugin>
  </plugins>
</build>

</project>

 

上記の状態で、

mvn clean site

でうまいこと、htmlが出力される。

 

で、jenkisでやる場合だが、

これだと実はうまく動かない。

結論としては、

mvn clean checkstyle:checkstyle javadoc:javadoc pmd:pmd pmd:cpd taglist:taglist cobertura:cobertura compile site

がよいかなと。

 

pomは以下。

  <build>
    <pluginManagement>
      : <!--  localの場合と同じ -->
      :
    </pluginManagement>
    <plugins>
    <!-- mvn site -->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-site-plugin</artifactId>
      <configuration>
        <reportPlugins>
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>findbugs-maven-plugin</artifactId>
          </plugin>
        </reportPlugins>
      </configuration>
    </plugin>
  </plugins>
</build>

上記の感じで、findbugsだけ出力の指定をすればよい。

(findbugsは単体でレポートが出せないため)

これで、jenkins上でも各種レポートが上手いこと出力されるはず。

 

※jenkinsのビルド後の処理において、
集計するファイルはちゃんと指定したほうがよい。
Coberturaのxmlが上手く見つけられなかったりする。

 

なげ~~。

 

投稿日時:2015年04月02日 17:51   カテゴリー:java   [コメントがあればどうぞ]