カテゴリー「java」

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   [コメントがあればどうぞ]

まだwebsocketのネタが完成しないので、

小ネタを。

 

windowsでjmeterをGUIで起動するとき、

jmeter.bat

なるものをたたく。

 

ただ、こいつをたたくと、

一緒にcommandプロンプトのコンソールがあがるので、

若干わずらわしい。

 

そのため、

jmeter.batをちょっと修正。

 

%JM_START% %JM_LAUNCH% %ARGS% %JVM_ARGS% -jar “%JMETER_BIN%ApacheJMeter.jar” %JMETER_CMD_LINE_ARGS%

start javaw %ARGS% %JVM_ARGS% -jar “%JMETER_BIN%ApacheJMeter.jar” %JMETER_CMD_LINE_ARGS%

 

これで、batを起動してもコンソールがでなくなる。

 

さらに、

Bat To Exe Converter

というソフトを使えば、batをexeファイルに変換してくれるから、

スタートにピン止めできる。

 

以上

投稿日時:2015年02月25日 16:41   カテゴリー:java, jmeter, windows   [コメントがあればどうぞ]

ずいぶん間が空いたけど、

javaでwebsocketやるときのサーバ側クラス設計ができました。

↓のような感じです。

websocket_uml

(クラス図あってるかな??)

 

ポイントとしては、

  • websocketのSessionインスタンスを内包するクラスを作る
  • ユーザ情報はセッション内で管理する
  • ペア(自分と相手)の情報を管理するクラスを作成しておく
  • 実際のwebsocket処理では、スレッドセーフなCollectionを使ってインスタンスを管理する

という感じになります。

 

スレッドセーフなCollectionでないと、インスタンスの取り違えが起きますので、ご注意を。

ThreadLocalを使うという手もありますが、

websocketの場合、

  • openハンドラの呼び出しは1回
  • messageハンドラの呼び出しはn回
  • closeハンドラの呼び出しは1回

なので、open時に必要なインスタンスを作成して、closeで破棄するとよいです。

(※messageで作成するときもありますが)

 

実は、websocketではこの考えは結構重要で、

たとえば、DB接続する際、

messageハンドラで、

connect -> disconnect

を繰り返すと、高負荷に耐えられないです。

ここで、

openハンドラでconnectし、closeハンドラでdisconnectする。

そして、messageハンドラで操作する、

という形だと接続のコストが抑えられるので、

結構有効です。

(※もちろん、アプリケーションの特性によりますが)

 

次は、javaのソースコードを公開する予定。

node.js側は気力があったら作成します。。

 

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

javaからのmail送信ですが、

いろいろ情報が混在しております。

 

ただ、現時点で、

pom.xmlに以下を記載すれば、

javaSEでも動きます。


<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.5.0-b01</version>
</dependency>

 

以上

 

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

jdk7からjdk8に変えた時、

Runnableのスコープ外で宣言した変数が、

Runnable内でfinalを付けないで参照できた。

 

java7だと、


int numberLocal = 1;

Thread t = new Thread(new Runnable() {

    final int numberThread = numberLocal;

};

java8だと、


int numberLocal = 1;

Thread t = new Thread(new Runnable() {

    int numberThread = numberLocal;

};

のような感じで、java8だとfinalが不要らしい。

ただし、書き換えるとエラーになるので、

暗黙的なfinalということになるようです。

 

投稿日時:2014年12月09日 15:36   カテゴリー:java   [コメントがあればどうぞ]

前回ゲーム仕様を決めたので、

今回は詳細は処理フローを作成します。

以下のような感じを想定しています。

websocket_seq

上記イメージの解説です。

  1. マッチングサーバと接続します。
  2. エントリーに必要な情報をおくります。サーバ側が1人目の受付の場合、「受付完了」という情報を返します。もし、ここで、2人目なら、「成立完了」という情報を2人に返します。
  3. 「成立完了」を受け取ったクライアントは、マッチングサーバから抜けて、対戦サーバ側と接続します。
  4. 対戦サーバと接続したら、「準備完了」を送ります。ここで、2人がそろって初めて「開始」を返します。
  5. ゲーム中は、片側(相手)から送られた情報を、2人に送信します。
  6. 無事ゲームが終わったら(終了判断はクライアントに依存)、1人1人が別々に「終了」を送信し、「終了」を受け取ったら各人で、対戦サーバから抜けます。
  7. もし、ゲームが始まっている状態で、片側(相手)が切断したら、残っている方に「相手が切断した」という情報を送ります。今回の仕様では、相手の勝利となり、相手側は「終了」を送信します。

ポイントは4、6、7です。

4のとき、相手が来ないケースもあるので、制限時間以内に相手が来なかったらどのような情報を返すかをサーバ側で対応する必要があります。

6はなぜ2人に送信しないかというと、下手に2人に送信してしまうと、終了時のクライアントの表示を片側が変更可能となってしまうからです。

7は片方の切断時に、残っている方へ何かしらの通知を行う対応です。

 

pub/subを使わない前提である以上、

上記の操作をすべてメモリ上の変数にて制御をかけます。

(※当然サービスのレベルでは、何かしらのデータベースへ書き込む等がありますが、ここでは考慮しません。)

 

次は、サーバ側のクラス設計を書きます。

 

投稿日時:2014年12月01日 12:43   カテゴリー:java, node.js, websocket   [コメントがあればどうぞ]

今のところ、3回にわたりwebsocketの比較を書いてきましたが、

これからは、

  • 処理フローの設計
  • プログラミング

となります。

 

とその前に、一服。

 

個人的な見解としては、

node.jsよりjavaの方がwebsocketは組みやすいかなと思っています。

理由は、

  • 過去資産が豊富なので、選択肢が多い
  • 型制約があるので、全体的に堅牢になる
  • eclipseなどのIDEが優秀

といったところでしょうか。

node.jsはjavascriptなので、

なんでもできてしまう分(たとえば、ユーザ定義オブジェクトになんでも突っ込めるとか)、

コードがわかりにくくなりがちです。(※規約で気を付けないとね)

また、IOが基本的に非同期で実行されるとかが、

やっぱりやりにくいなと感じてます。

ただ、java側はAPサーバを動かすコスト(メモリ消費)がやや高いので、

省エネなのはnode.jsかなとも思います。

 

ちなみに、javaでwebsocketをやる場合、

jetty8とかは独自実装になっており、

jetty9でJSR356に対応してます。

※jetty9の場合、jettyの独自パッケージの中で、JSR356に読み替えているようです。mavenのpomファイルも後で作成します。

JSR356に対応しておけば、tomcatに移植しても動くので、独自実装はもう使わないほうがよかです。

なお、あのplayframework2.3のwebsocketはjetty8でした。(playは機能面はすごいけど、ちょっと重いよね。。)

 

最終的には、どちらもクセはあります。

取り巻く環境、開発者の経験等を考慮して、

選択するとよいと思います。

(go言語なんかでもやっている人はいるのかな?goはこれから勉強します。)

 

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

前回の続き。

前回の大切な前提として、

pub/subはなし(つまり、メモリ内で処理を完結可能)

というのがありました。

 

実際に対戦ゲームの作成を通して、処理フローを整理しましょう。

別に面白いものを作る必要はないので、

簡単なゲームとして、以下のような仕様とします。

  1. 2人対戦の神経衰弱
  2. ゲームの種別として、4×4、4×8、4×12の3種類(使用枚数が16枚、32名、48枚)
  3. ユーザはマッチング時に、ゲーム種別を選択可能
  4. マッチングが成立したらゲーム開始
  5. ゲーム中に離脱した場合、その時点で残っている人の勝利
  6. 離脱者なしにゲームが終わった場合、自分の取得枚数が多ければ勝利で、少なければ敗北

 

pub/subはないので、

スケールアウトの手段が現状皆無です。

そこで、URLを絡めて、効果的にスケールアウトができるようにしておきましょう。

URLはこんな感じです。

【マッチング】 /ws/matching/${type}

${type}とは、上記の4×4などをコード化したもの

【対戦】 /ws/round/${pairId}

${pairId}とは対戦者同士を結びつける一意のキーで、形式は0-9a-zの繰り返し

 

こんな感じでURLを設計しておくことで、

websocketのリバースプロキシ可能なサーバ(nginxやapache2.4など)で、

URLに応じた振り分けが可能となります。

この設計方式だと、マッチングが成立したら、

一旦マッチングサーバとの接続を閉じて、

新たに対戦サーバと接続する必要があります。

 

※nginxの設定例

vim /etc/nginx/websocket_params

proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Document-URI $document_uri;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";

vim /etc/nginx/conf.d/game.conf


# マッチング4x4
upstream ws_matching_4x4 {
    server localhost:8081;
    server localhost:8082 backup;
}
# マッチング4x8
upstream ws_matching_4x8 {
    server localhost:8083;
    server localhost:8084 backup;
}
# マッチング4x12
upstream ws_matching_4x12 {
    server localhost:8085;
    server localhost:8086 backup;
}

# 対戦(ペアIDの先頭がcからnまでの12個)
upstream ws_round_0b {
    server localhost:8181;
    server localhost:8182 backup;
}
# 対戦(ペアIDの先頭がcからnまでの12個)
upstream ws_round_cn {
    server localhost:8183;
    server localhost:8184 backup;
}
# 対戦(ペアIDの先頭がoからzまでの12個)
upstream ws_round_oz {
    server localhost:8185;
    server localhost:8186 backup;
}

server {
    listen 80;
    server_name game.example.com;

    charset utf-8;
    root /var/www/game/public;

    # エラーページ
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    # websocket_paramsのインクルード
    include /etc/nginx/websocket_params;

    # マッチング4x4
    location ~ ^/ws/matching/4/$ {
        proxy_pass http://ws_matching_4x4;
    }
    # マッチング4x8
    location ~ ^/ws/matching/8/$ {
        proxy_pass http://ws_matching_4x8;
    }
    # マッチング4x12
    location ~ ^/ws/matching/12/$ {
        proxy_pass http://ws_matching_4x12;
    }

    # 対戦(ペアIDの先頭がcからnまでの12個)
    location ~ ^/ws/round/[0-9a-b][0-9a-z]+?/$ {
        proxy_pass http://ws_round_0b;
    }
    # 対戦(ペアIDの先頭がcからnまでの12個)
    location ~ ^/ws/round/[c-n][0-9a-z]+?/$ {
        proxy_pass http://ws_round_cn;
    }
    # 対戦(ペアIDの先頭がoからzまでの12個)
    location ~ ^/ws/round/[o-z][0-9a-z]+?/$ {
        proxy_pass http://ws_round_oz;
    }
}

※全部localhostにしてポートを変更していますが、細分化すれば、上記設定で12台に切り分けられます。

※もちろん、もっと細かく分けることも可能です。

 

という具合で考えると、

ちょっと大げさに以下のようなイメージでインフラが考えられます。

websocket_struct

 

 

このようにフロントのサーバの機能を利用することで、

pub/subを使わずにwebsocketを通じたメッセージのやり取りができます。

狙いとしては

同一属性者を同じブロセスに閉じ込めることで、メモリ内の操作で処理を完結させる

ということになります。

 

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

さて、本腰入れて。

今回の比較に当たり、大きな前提として、

pub/subはなし(つまり、メモリ内で処理を完結可能)

というのをあげておきます。

というのも、pub/subがあるときと、ないときでは、

結構実装が異なってしまうためです。

(※うまく抽象化できればいいのですが、node.js側は上手に継承を使うのが難しいので)

 

この前提のもと、

javaとnode.jsの大きな違いは、

java:マルチスレッド

node.js:シングルスレッド

ということであります。

 

この違いは、プログラムを書く上で、

排他制御」が必要か、不要かということにつながります。

 

たとえば、対戦ゲームを作るとした場合、

ゲームには「マッチング」と「対戦中」で処理が大きく2つに分かれます。

マッチングは諸条件あるものの、基本的には来た順番にさばく手法がとられると思います。

このとき、javaでは必ず排他制御をかける必要があります。

それに対し、node.jsでは、シングルスレッドなので、排他制御をかける必要はありません。

 

ここが両者の最大の違いとなります。

 

※あくまでメモリ内で完結する場合です。(つまり1プロセス)

複数台を使う場合は、node.jsでも排他制御が必要となる場合があります。

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

websocketというと、チマタではnode.jsが流行っていますね。

 

しかし、javaもJSR356という規約の下、

各サーブレットコンテナで対応が完了しており、

個人的にはnode.jsと対をなす位までの能力があるかと思います。

 

javaでもnode.jsでもwebsocketを構築した筆者が、

数回にわたりお互いの特徴と実装の注意点などを書いていきます。

 

なお、バージョンは

【java】

jetty9.X(JSR356に対応した形)

【node.js】

v10.3X

となります。

 

 

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