ラベル Java の投稿を表示しています。 すべての投稿を表示
ラベル Java の投稿を表示しています。 すべての投稿を表示

2018年10月15日月曜日

【Java】301 moved parmanently 【HttpClient】

ある日突然JavaのWebアプリ内のWebアクセスのログに、 301 moved parmanentlyが出た。該当のWebページがページを移転したようだ。
Webアプリでは、apache commons HttpClientを使用していて、このライブラリは自動でリダイレクトをしてくれるため、特に対処不要だった。
JavaのWebアクセスって3~4行で簡単に出来るから自分で実装してしまいがちだが、やっぱりライブラリ使った方が安全だった。

2018年9月21日金曜日

【SEの仕事】原因不明なエラーの解析【Java】【C#】

お客さんの都合により、複数の会社が同じWebアプリ内の機能を作成する事があります。もちろんそれぞれの会社の作成している機能は別物です。

OutOfMemoryErrorや原因が不明なエラーが発生した場合にどの会社が解析するのかと言う問題があります。

お客さんが事前にどの会社がやるのか決めてくれている場合は良いんですが、そうでない場合が厄介で、本来であれば契約に従う必要があり、契約書に無いことをやってはいけません。が、どの会社も契約してない場合は誰かがやるしかないんです。

しかし、誰もやろうとしないんですよね。
恩を売る、または勉強と割り切って自分で実施しましょう。やって見ないといつまでも機会がありません。こういうバグの解析は稀にしかありません。なぜなら、かなり出来る人間が毎回解析するため。年次が高くなっても出来ないと困ったことになります。プロジェクトを任されて、外のメンバーは1~3年目のみとか詰みます。

■解析方法
JavaやC#のExceptionがログファイルに出ていれば、ソースコードのファイル名と行番号からエラーが特定出来ます。

今回はそうではなく、良く分からないエラーの場合です。
良く分からないエラーって何です?って思いますよね?

例えば、定期処理が動かなくなったとか、画面にもログファイルにも何も出てないが操作が出来ないとか、操作が途中で止まるとか、砂時計のままとか、少し違和感があるとか、異常に遅いとか、・・・。

Exceptionが出てない場合はエラー箇所が分からないため、ソースコードのどこに問題があるのか分からなかったりします。この場合、見るべきことが沢山あります。主なものを以下に記載します。

●Javaの場合
・ログファイル
 エラーが発生したと思われる時間帯の前のログなど。ログファイルは膨大なのでgrep、egrep、head、tail、unique、cut、sort、sed、awk、viewなどのテキスト関連のコマンド、サクラエディタ※1の正規表現置換、ブロック選択、Excelなどを駆使してエラー箇所を絞り込み、エラーの特定、そこまで行かなくても何の処理が動いてたかを把握して解析の取っ掛かりにしたりします。

・Catalina.out
 まずはOutOfMemoryErrorでgrep。Catalina.outも大量にログが出てる場合があります。なのでログファイルと同様の解析をしたりします。皆なんでCatalina.outに余計なログ出すかなあ?Catalina.outはOutOfMemoryとかErrorの子クラスだけにして欲しい。それ以外はロガーに出してくれ。

・リソース使用量
 ・sar
  サーバーのcpu使用量。グラフ化すれば、おかしくなり始めた時間帯などを特定出来ます。

 ・top
  現在の各プロセスのCPU使用量、メモリ使用量。

 ・ps
  スレッド数、ファイルディスクリプタ数などを調べられる。出来れば事前に定期観測しておく。

 ・free(Javaでは余り見ない)
  サーバーのメモリ使用量。

 ・iostat、vmstat記録してたが何に使ったっけ?

 ・コネクション数
  DBコネクション数が限界に達してないか?定期的に記録しておきましょう。何のコマンドだったな?vmstat?netstat?

 ・jconsole
  JavaのCPU使用量、ヒープ使用量、メモリ使用量。

 ・jstat
 ヒープ使用量定期観測。事前に仕掛けておく。

 ・ヒープ内の各クラスのメモリ使用量。コマンド名は何だったかな?
  メモリリークの場合、どのクラスがリークしてるか分かるので必須です。特に正常時と異常時の比較、起動直後と時間経過後の比較をすると、あっさり原因特定出来たりします。

・jstack
 ・スレッドの状態(最近はスレッド数が多くて一苦労)
 ・スタックの状態
 ・ロック残り、デッドロックの有無

●Windowsの場合
・タスクマネージャー
 windows用。列追加すると色々見られる。プロセスのCPU使用量、メモリ使用量、ファイルディスクリプタ、スレッド数、GDIオブジェクトなどのリーク。

・リソースマネージャー
 タスクマネージャーより詳しく見られるらしい。余り使ったこと無い。

・typeperf
 プロセスのCPU、メモリ使用量、ファイルディスクリプタ、スレッド数などを定期観測。事前にしかけておく。何れも増え続けているものは注意。typeperfはGDIオブジェクトが記録出来ない。何でだ?

●DBがある場合(製品によって確認方法が違うのでざっくり記載。)
・トランザクション残り
 デッドロックやトランザクション残りの特定。
 実行中のselect文が見られる場合があり、問題のある機能が特定出来る。また、手動でinsert文実行時にトランザクション途中でウィンドウを閉じて、トランザクションが残ってしまい、他の機能が動かない問題などの特定。トランザクション残りって呼んでますが、本当は何て呼ぶんでしょう?

・ロック残り
 トランザクション残りとほぼ同じ。デッドロックの特定。

怪しい箇所は時系列順にメモして、最初のエラーを特定します。リーク系は最初ではなく、時系列でみます。
また、正常時との比較も重点です。

※1 他のエディタでもいいですが、巨大なログファイルを扱える必要があります。サクラエディタは結構耐えてくれます。分割してもいいですが。

【Java】「OutOfMemoryError」で親スレッドダウン【cron4j】

当然といえば当然ですが、落ちます。Tomcatは落ちずに画面は使えているので気付きづらいのですが(いや、OutOfMemoryなんてすぐに気づくべきですよね。)、定期処理が動かなくなっていて、何かと調べていたらOutOfMemoryErrorが出ていました。

cron4jについて詳しく調べてなくて、間違いがあったらすみません(時間があったら、調べます)。cron4jには親スレッド※1がいるみたいですね。jstackでみるとtimerと言う名のスレッドが存在します。たぶんこのtimerスレッドが親で、登録されている時刻になると子スレッドを生成(scheduleという名のスレッド)して、処理を行わせるのでしょう。

ということは、極、すごーく簡単に書くと親スレッドが動いているコードは以下のようになっていると思われます。
で、ExceptionはOutOfMemoryをキャッチしない※2ので、このスレッドはアボートしてしまうってことだと思います。

while (runFlg ) {
  try {
    if (定期時刻を満たした) {
      処理を実行
    }
  } catch (Exception ex) {
     :
  }
}

人命に関わるシステムでなければ、落ちた方が良いと言う考え方がありますが、落ちたほうが良いんですかね?Tomcatは生きているので、cron4jは落ちたけど、画面は生きているって状態になってしまって統一性が無い状態になってしまいますが。
そもそもOutOfMemoryを監視するようになってないのがまずいのでしょうが。

※1 呼び方は私が勝手に言ってますので、本来の名前があるはずで、timerスレッド?かもしれません。
※2 Javaの例外処理では、トップにThrowableがいて、Throwableを継承したErrorクラスとExceptionクラスに分かれます。catch (Exception ex)と書いた場合、Errorの子クラスであるOutOfMemoryはcatchできません。

2017年10月25日水曜日

【Java】try with resourcesのカバレッジ

◆EclEmmaでどうしても通せないルートがある。
 各サイトが説明しているようにカバレッジに拘る必要はないのだが、
テスト漏れを即検出したいので、できれば100%にしたい。
しかし、下記のようにtry-with-resources 文など一部のコードがEclEmmaで全ルートパスできない。

ツールチップを表示すると7ルートミス。

Jmockit(下記コード参照)で1まで行くのだが、あと1ルートがパスできない。

◆テスト対象
package sampl.junitsample;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class App {
 public static void main(String[] args) throws IOException {
  HttpURLConnection conn = (HttpURLConnection) new URL("http://localhost").openConnection();
  conn.setDoOutput(true);

  try (OutputStream st = conn.getOutputStream()) {
   st.write("abc".getBytes());
  }
 }
}

◆テストコード
package sampl.junitsample;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.junit.Test;

import mockit.Mock;
import mockit.MockUp;

public class AppTest {
 @Test
 public void testApp1() throws IOException {
  App.main(null);
 }

 @Test
 public void testApp2() throws IOException {
  new MockUp<sun.net.www.protocol.http.HttpURLConnection>() { // 何故かsun.~
   @Mock
   public OutputStream getOutputStream() throws IOException {
    throw new IOException("mock exception.");
   }
  };
  try {
   App.main(null);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 @Test
 public void testApp3() throws IOException {
  new MockUp<java.io.ByteArrayOutputStream>() { // デバッガで実際の型を調べるとPosterOutputStream
   @Mock
   public void write(byte[] b) throws IOException {
    throw new IOException("mock exception.");
   }
  };
  try {
   App.main(null);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 @Test
 public void testApp5() throws IOException {
  new MockUp<ByteArrayOutputStream>() { // デバッガで実際の型を調べるとPosterOutputStream
   @Mock
   public void write(byte[] b) throws IOException {
    throw new IOException("mock exception.");
   }

   @Mock
   public void close() throws IOException {
    throw new IOException("mock exception.");
   }
  };

  try {
   App.main(null);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 @Test
 public void testApp6() throws IOException {
  new MockUp<sun.net.www.protocol.http.HttpURLConnection>() { // 何故かsun.~
   @Mock
   public OutputStream getOutputStream() throws IOException {
    return null;
   }
  };
  new MockUp<ByteArrayOutputStream>() {
   @Mock
   public void write(byte[] b) throws IOException {
    return;
   }

   @Mock
   public void close() throws IOException {
    throw new IOException("mock exception.");
   }
  };

  try {
   App.main(null);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

◆Maven(pom.xml)
<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>sampl</groupId>
 <artifactId>junitsample</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>junitsample</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <!-- https://mvnrepository.com/artifact/junit/junit -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.4</version>
   <scope>test</scope>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.jmockit/jmockit -->
  <dependency>
   <groupId>org.jmockit</groupId>
   <artifactId>jmockit</artifactId>
   <version>1.35</version>
   <scope>test</scope>
  </dependency>
 </dependencies>

</project>

◆環境

  • Eclipse:4.7(pleiades)
  • EclEmma:3.0.0.201706140232


2017年8月21日月曜日

【Java】File Downloadその3(commons-io)

String str = IOUtils.toString(new URL(targetUrl), Charset.defaultCharset());
FileUtils.writeStringToFile(new File(filePath), str, Charset.defaultCharset());

ファイル保存される。ちょっとしたものは上記で良いが、apache httpclientを推奨。apache httpclientはアクセス先がページ移動(301)したとき等に自動で移動してくれる。

◆ソースコード
package sample.httpget;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

public class App {
  public static void main(String[] args) {
    try {
      download("http://google.com/", "/tmp/google.htm", Charset.forName("Shift_JIS"));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public static void download(String targetUrl, String filePath, Charset ch) throws IOException {
    String str = IOUtils.toString(new URL(targetUrl), ch);
    FileUtils.writeStringToFile(new File(filePath), str, Charset.defaultCharset());
  }
}

◆pom.xml
<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>sample</groupId>
 <artifactId>HttpGet</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>HttpGet</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
  <dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>2.5</version>
  </dependency>

 </dependencies>
</project>

2017年8月20日日曜日

【Java】簡易HTTP Post

■3つ程。3番目はcommons-ioが必要。

◆ソースコード
package sample.httppost;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;

import org.apache.commons.io.IOUtils;

import javafx.util.Pair;

public class App {
  public static void main(String[] args) {
    try {
      sendPost1("http://localhost:8090/", "abc");
      System.out.println(sendPost2("http://localhost:8090/", "abc"));
      System.out.println(sendPost3("http://localhost:8090/", "abc", Charset.defaultCharset()));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public static void sendPost1(String targetUrl, String sendStr) throws IOException {
    URLConnection conn = new URL(targetUrl).openConnection();
    conn.setDoOutput(true);

    try (OutputStream st = conn.getOutputStream()) {
      st.write(sendStr.getBytes());
    }
  }

  public static int sendPost2(String targetUrl, String sendStr) throws IOException {
    HttpURLConnection conn = (HttpURLConnection) new URL(targetUrl).openConnection();
    conn.setDoOutput(true);

    try (OutputStream st = conn.getOutputStream()) {
      st.write(sendStr.getBytes());
    }
    return conn.getResponseCode();
  }


  public static Pair<Integer,String> sendPost3(String targetUrl, String sendStr, Charset chSet) throws IOException {
    HttpURLConnection conn = (HttpURLConnection) new URL(targetUrl).openConnection();
    conn.setDoOutput(true);
    conn.setRequestProperty("Accept-Charset", chSet.name());
    conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + chSet.name());
    conn.setRequestProperty("User-Agent", "Mozilla/5.0");

    try (OutputStream st = conn.getOutputStream()) {
      st.write(sendStr.getBytes());
    }

    try (InputStream st = conn.getInputStream()) {
      int code = conn.getResponseCode();
      String str = IOUtils.toString(st, chSet);
      return new Pair<Integer, String>(code, str);
    }
  }
}

◆pom.xml
<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>sample</groupId>
 <artifactId>HttpPost</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>HttpPost</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
  <dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>2.5</version>
  </dependency>
 </dependencies>
</project>

【Java】File Downloadその2(commons-io)

FileUtils.copyURLToFile(new URL("http://google.com/"), new File("/tmp/google.htm"));

1行ですむが文字コードが指定できない。保存したファイルをブラウザで開くとサイトによっては文字化けする。何故だ…
ちょっとしたものは上記で良いが、apache httpclientを推奨。apache httpclientはアクセス先がページ移動(301)したとき等に自動で移動してくれる。

◆ソースコード
package sample.httpget;

import java.io.File;
import java.io.IOException;
import java.net.URL;

import org.apache.commons.io.FileUtils;

public class App {
 public static void main(String[] args) {
  try {
   download("http://google.com/", "/tmp/google.htm");
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

 public static void download(String targetUrl, String filePath) throws IOException {
  FileUtils.copyURLToFile(new URL(targetUrl), new File(filePath)); // 文字コードが設定できないのでサイトによっては文字化けする?
 }
}



◆pom.xml
<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>sample</groupId>
 <artifactId>HttpGet</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>HttpGet</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
  <dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>2.5</version>
  </dependency>

 </dependencies>
</project>



【Java】File Downloadその1(commons-io)

IOUtils.toString(new URL("http://google.com/"), "Shift_JIS");

ちょっとしたものは上記で良いが、apache httpclientを推奨。apache httpclientはアクセス先がページ移動(301)したとき等に自動で移動してくれる。

◆ソースコード
package sample.httpget;

import java.io.IOException;
import java.net.URL;

import org.apache.commons.io.IOUtils;

public class App {
  public static void main(String[] args) {
    try {
      System.out.println(download("http://google.com/", "Shift_JIS"));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public static String download(String targetUrl, String ch) throws IOException {
    return IOUtils.toString(new URL(targetUrl), ch);
  }
}

◆pom.xml
<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>sample</groupId>
 <artifactId>HttpGet</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>HttpGet</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
  <dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>2.5</version>
  </dependency>

 </dependencies>
</project>



2017年8月19日土曜日

【Java】ServletでFile download(nio)

Files.copyでiostreamが指定可能とのことなので、試してみる。ちなみにサーブレットコンテナはJetty。
◆ソース(必要に応じてtry-catchを入れること。でないとexception発生時にexceptionがブラウザに出てしまう。)
package sample.niocopy;

import java.io.BufferedOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;

public class MyServlet extends HttpServlet {
  public static void main(String[] args) throws Exception {
    ServletHandler handler = new ServletHandler();
    handler.addServletWithMapping(MyServlet.class, "/*");

    Server server = new Server(8090);
    server.setHandler(handler);
    server.start();
    server.join();
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse res) {
    try {
      Path uri = Paths.get("c:/tmp" + req.getRequestURI());

      if (Files.notExists(uri) || Files.isDirectory(uri)) {
        res.setStatus(404);
      } else {
        res.setContentType("application/octet-stream");
        res.setContentType("text/html; charset=UTF-8");
        res.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", uri.getFileName()));
        try (BufferedOutputStream bos = new BufferedOutputStream(res.getOutputStream())) {
          Files.copy(uri, bos);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

◆速度

◆結論
普通に使える。パット見メモリリークはないが、要確認。BufferedOutputStream,BufferedInputStreamの2つを利用した場合と比較したが、速度は同じ。

◆pom.xml
<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>sample</groupId>
 <artifactId>NioCopy</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>NioCopy</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <jetty.version>9.3.6.v20151106</jetty.version>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-server</artifactId>
   <version>${jetty.version}</version>
  </dependency>
  <dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-webapp</artifactId>
   <version>${jetty.version}</version>
  </dependency>
 </dependencies>
</project>

◆環境
  • 速度確認した仮想マシン
    • CPU core数:4
    • メモリ:2.5GB
    • OS:Windows10 Pro x64
    • 仮想マシン:VMWare vShpere ESXi6.5
    • Java:1.8

  • ホストPCの性能(参考)
    • CPU:Intel Core i5-4250U(2Core 2HT)
    • メモリ:16GB
    • ドライブ:SSD(ウルトラ II mSATA SSD SDMSATA-512G-G25C)
    • 仮想マシン:VMWare ESXi6.5上の仮想マシン

2017年7月26日水曜日

【Java】【Spring Integration】Service Activatorで例外送出

Service Activatorで例外送出するとどうなるのか?
下記のsaServiceで例外を発生させる。

◆integration-graph

◆ファイル構成

ソースコードのvalはlombokを使用。
◆Main.java
public class Main {
  public static void main(String[] args) {
    try (val ctx = new ClassPathXmlApplicationContext("SpringIntegration.xml")) {
      val inCh = ctx.getBean("inCh", MessageChannel.class);
      val outCh = ctx.getBean("outCh", PollableChannel.class);

      inCh.send(MessageBuilder.withPayload("test").build());
      System.out.println(outCh.receive());

      System.in.read();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

◆SampleService
@Component
public class SampleService {
  @ServiceActivator
  public String Exec(String msg) throws IllegalArgumentException {
    throw new IllegalArgumentException("err");
  }
}

◆SpringIntegration.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  xmlns:int="http://www.springframework.org/schema/integration"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.1.xsd">

  <context:component-scan base-package="sample.springint.exception" />
  <int:channel id="inCh" />
  <int:channel id="outCh">
    <int:queue capacity="10" />
  </int:channel>

  <int:service-activator id="saService"
    input-channel="inCh" output-channel="outCh" ref="sampleService" />
</beans>

◆log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration
  xmlns:log4j='http://jakarta.apache.org/log4j/'>
  <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%p] %m%n" />
    </layout>
  </appender>
  <root>
    <priority value="info" />
    <appender-ref ref="STDOUT" />
  </root>
</log4j:configuration>


◆実行結果
2017-07-26 01:43:34 [INFO] Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2e18f2: startup date [Wed Jul 26 01:43:34 JST 2017]; root of context hierarchy
2017-07-26 01:43:34 [INFO] Loading XML bean definitions from class path resource [SpringIntegration.xml]
2017-07-26 01:43:35 [INFO] Loading properties file from URL [jar:file:/C:/Users/root/.m2/repository/org/springframework/integration/spring-integration-core/4.1.4.RELEASE/spring-integration-core-4.1.4.RELEASE.jar!/META-INF/spring.integration.default.properties]
2017-07-26 01:43:35 [INFO] No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2017-07-26 01:43:35 [INFO] No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
2017-07-26 01:43:35 [INFO] No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
2017-07-26 01:43:35 [INFO] JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2017-07-26 01:43:35 [INFO] Loading properties file from URL [jar:file:/C:/Users/root/.m2/repository/org/springframework/integration/spring-integration-core/4.1.4.RELEASE/spring-integration-core-4.1.4.RELEASE.jar!/META-INF/spring.integration.default.properties]
2017-07-26 01:43:35 [INFO] Initializing ExecutorService  'defaultSockJsTaskScheduler'
2017-07-26 01:43:35 [INFO] Initializing ExecutorService  'taskScheduler'
2017-07-26 01:43:36 [WARN] Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping
2017-07-26 01:43:36 [INFO] Starting beans in phase -2147483648
2017-07-26 01:43:36 [INFO] Starting beans in phase 0
2017-07-26 01:43:36 [INFO] Adding {service-activator:saService} as a subscriber to the 'inCh' channel
2017-07-26 01:43:36 [INFO] Channel 'org.springframework.context.support.ClassPathXmlApplicationContext@2e18f2.inCh' has 1 subscriber(s).
2017-07-26 01:43:36 [INFO] started saService
2017-07-26 01:43:36 [INFO] Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2017-07-26 01:43:36 [INFO] Channel 'org.springframework.context.support.ClassPathXmlApplicationContext@2e18f2.errorChannel' has 1 subscriber(s).
2017-07-26 01:43:36 [INFO] started _org.springframework.integration.errorLogger

2016年10月8日土曜日

【Java】例外キャッチ時の各メソッドの文字列

Javaで例外発生時にログファイルへ書き込む場合、e.getMessage(),e.toString(),…どのメソッドを使うべきか?それぞれのエラーメッセージを実際に動かして確認する。

◆メインコード
package main;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

public class Main {
  public static void main(String[] args) {
    try {
      int tmp = 0 / 0;
    } catch (Exception e) {
      String s = e.getMessage();    // ★★★この行を変更する。
      System.err.println(s);
    }
  }

  public static String exToStr(Exception arg) {  // 後述する。
    try (StringWriter sw = new StringWriter()) {
      arg.printStackTrace(new PrintWriter(sw));
      return sw.toString();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return "";
  }
}

◆結果
No コード 結果 時間※
1 e.getMessage() / by zero 1ms
2 e.getLocalizedMessage()
(例外クラスによって文字列が変わる。)
/ by zero 2ms
3 e.toString() java.lang.ArithmeticException: / by zero 231ms
4 StringWriterによる変換
(上記のメインコードのexToStr()を参照のこと。)
java.lang.ArithmeticException: / by zero
  at main.Main.main(Main.java:12)
1973ms
5 ExceptionUtils.getStackTrace(e)
(apache commons Lang)
java.lang.ArithmeticException: / by zero
  at main.Main.main(Main.java:12)
1930ms
6 e.getStackTrace().toString() [Ljava.lang.StackTraceElement;@1db9742 491ms
※100万回実行した時の処理時間で、以下のコード(100万回でこの時間なら気にする必要無い気もする)
String s = "";
long start = System.nanoTime();
for (int i = 0; i < 1000 * 1000 * 1; i++)
  s = ExceptionUtils.getStackTrace(e);    // ★★★この行を変更する。
long end = System.nanoTime();
System.out.println((end - start) / 1000000  + "ms");
◆実行環境
 ■VMware WorkStation10上の仮想マシン
  ・CPU:2
  ・メモリ:2GB
  ・OS:Windows7
  ・Java ver:eclipse同梱のJava8
  ・IDE:eclipse(pleiades) Version: Neon.1 Release (4.6.1)

 ■ホストPCの性能(参考)
  ・CPU:Intel Core i5-4250U
  ・メモリ:8GB
  ・ドライブ:SSD(Plextor PX-512M3P)
  ・OS:Windows10