tech_memo / java


tech_memo

プロファイラ

async-profiler

Java Mixed-Mode Flame Graphs で Java の CPU ネックをフルスタックで分析する

ヒープ・GC

SAStrutsで外だし設定ファイルを利用する方法(S2configを使う)


DB関連

Oracle PL/SQLファンクションをコールするときの注意

  • JDBCドライバの制約で、callを小文字で記入する必要がある。
    connection.prepareCall("{ ? = call pkg_hoge.func_hoge(?) }" );
    • CallやCALLのように大文字だと以下のようなエラーが出る
      sql.SQLException: Malformed SQL92 string at position: .....
  • 参考

Oracleプロシージャでユーザ定義型(STRUCT)、ユーザ定義型を引数に指定

Oracleプロシージャ(ファンクション)にARRAY引数を渡すのが遅い

  • ArrayDescripter?からARRAYオブジェクトを生成するときが激遅い。[ key1, key2 ] の配列1000個以上で10秒以上かかる
    ArrayDescriptor ad = new ArrayDescriptor(MY_KEY_TYPE, con);
    ARRAY array = new ARRAY(ad, con, key1AndKey2Array);    // ★ここが遅い。key1AndKey2Arrayは、ORADataを実装した自作クラスの配列
  • ARRAYオブジェクトをJava側で定義するときに、ORADataを実装するのではなく、SQLDataを実装すると早くなるらしい
  • 確かに、ARRAYの生成は早くなったが、今度はプロシージャの中が遅くなった。(上記対応前は早かった)
  • 上記ARRAYはプロシージャ内で、TABLE型にキャストしてIN句のリストとして使用している。
  • なぜ遅いかは謎。。。

Seasar2のConnection(ConnectionWrapperImpl?)からOracleプロシージャにユーザ定義型引数を設定

  • ユーザ定義型引数を指定するためにはOracleConnection?で手続きが必要だが、Seasar2のDIで取得したConnectionは、org.seasar.extension.dbcp.impl.ConnectionWrapperImpl?のため、ユーザ定義型変数のCastがエラーになる
  • ConnectionWrapperImpl?OracleConnection? にキャストする方法は以下
    SingletonS2ContainerFactory.setConfigPath("app.dicon");
    SingletonS2ContainerFactory.init();
    ConnectionPool pool = SingletonS2Container.getComponent(ConnectionPool.class);
    Connection con = pool.checkOut();
    DatabaseMetaData dmd = con.getMetaData();
    con = (OracleConnection) dmd.getConnection();
  • 上記OracleConnection?を利用してユーザ定義型を引数に渡す方法
    CallableStatement stmt = con.prepareCall("Call TEST(?)");
    String[] strArry = { "121313", "12121" };
    ArrayDescriptor ad = new ArrayDescriptor("STR_TABLE_TYPE", con);
    ARRAY array = new ARRAY(ad, con, strArry);
    stmt.setArray(1, array);
    stmt.execute();

Javaからストアドプロシージャのコール

  • 以下はOracleの場合
    • プロシージャ
      CREATE OR REPLACE PROCEDURE TEST1(
      	n1 IN     INT,
      	n2 IN OUT INT,
      	n3 OUT    INT) AS
      BEGIN
      	n3 := n1 * n2;
      	n2 := n2 + 1;
      END;
      /
    • Javaソース
      try (Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:TESTDB", "TEST", "testpass")) {
          try (CallableStatement statement = connection.prepareCall("CALL TEST1(?, ?, ?)")) {
      
              statement.registerOutParameter(2, Types.INTEGER);
              statement.registerOutParameter(3, Types.INTEGER);
      
              statement.setInt(1, 5);
              statement.setInt(2, 7);
      
              statement.execute();
      
              System.out.println(String.format("n2 = %d", statement.getInt(2)));
              System.out.println(String.format("n3 = %d", statement.getInt(3)));
          }
      }
  • MySQLの場合

Seasar2を使った場合

JDBC関連システムプロパティ

thinドライバでのORACLE接続

RAC

  • scan-ipを使う場合
    @//scan名:1521/globa_db_name
    
    // sample
    @//rac-cluster-sacn:1521/rac
  • scanを使用しない場合(orcle-ds.xmlのケース)
    <connection-url>jdbc:oracle:thin:@(DESCRIPTION =
        (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.X)(PORT = 1521)))
        (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.Y)(PORT = 1521)))
        (CONNECT_DATA = (SERVICE_NAME = TESTDB_RAC)))
    </connection-url>

Webコンテナなしで、簡単なSoap Webサーバ・クライアント作成

Soap Webサーバ

  • 参考 : http://java.keicode.com/lib/ws-create-service.php
  • javax.xml.ws.Endpoint#publish() を利用すると、標準Javaオンリーで、JAX-WS(Java API for XML-Based Web Services) による単純な Web サービスを起動可能
    • Webサービスクラス
      package jp.noorg.web;
      
      import javax.jws.WebParam;
      import javax.jws.WebService;
      
      @WebService
      public class HelloWeb {
      
      	public String hello(@WebParam(name = "name") String name) {
      		return "Hello " + name + "!!";
      	}
      }
    • Webサーバ起動メインクラス
      package jp.noorg.main;
      
      import javax.xml.ws.Endpoint;
      
      import jp.noorg.web.HelloWeb;
      
      public class HelloMain {
      
      	public static void main(String[] args) {
      		Endpoint.publish(
      				"http://localhost:8888/WebServices/hello",
      				new HelloWeb());
      	}
      }
  • 上記メインクラスを起動後、上記URLに"?wsdl"を付随してブラウザでアクセスするとWSDLを参照可能

Soapクライアント

  • Eclipseで、上記WSDLからソースを取り込む方法
    • プロジェクトファイルを右クリック
    • 新規>その他>Webサービス>Webサービス・クライアント
    • サービス定義に、WSDLのURLを指定
    • あとは適当にポチポチ
  • 取り込んだソースからWebサービスを呼び出す
    package jp.noorg.main;
    
    import java.rmi.RemoteException;
    
    import javax.xml.rpc.ServiceException;
    
    import jp.noorg.web.HelloWeb;
    import jp.noorg.web.HelloWebService;
    import jp.noorg.web.HelloWebServiceLocator;
    
    public class ClientMain {
    
    	public static void main(String[] args) throws ServiceException, RemoteException {
    		HelloWebService locator = new HelloWebServiceLocator();
    		HelloWeb port = locator.getHelloWebPort();
    		System.out.println(port.hello("Hoge"));
    	}
    }

Webスクレイピング

テスト関連


アサーション

Setup

JDKをWindowsでインストールせずに利用

  • 参考 : http://qiita.com/t-okushima/items/5010b9ab1b3dc8da317f
  • JDK7で実施。JDK8u144ではインストーラの中身が異なり、以下の方法ではできない。(サイトによってはJDK8でやってる人もいるので、古いマイナーバージョンであればできるかも)
  • 下記サイトのExtractJDK.zipをダウンロードして、バッチファイルを実行すれば、完結する。
  • 自分で手動でやる場合は以下の手順になる
  1. 7zipでJDKのインストーラを解凍
    • ちなみに、cygwinのp7zipコマンドではエラーになった
      $ p7zip -d jdk-8u144-windows-x64.7z
      
      7-Zip (a) [64] 15.14 : Copyright (c) 1999-2015 Igor Pavlov : 2015-12-31
      p7zip Version 15.14.1 (locale=en_US.utf8,Utf16=on,HugeFiles=on,64 bits,4 CPUs Intel(R) Core(TM) i3-4005U CPU @ 1.70GHz (40651),ASM,AES-NI)
      
      Scanning the drive for archives:
      1 file, 207382584 bytes (198 MiB)
      
      Extracting archive: jdk-8u144-windows-x64.7z
      ERROR: jdk-8u144-windows-x64.7z
      jdk-8u144-windows-x64.7z
      Open ERROR: Can not open the file as [7z] archive
      
      
      ERRORS:
      Is not archive
      
      Can't open as archive: 1
      Files: 0
      Size:       0
      Compressed: 0
  2. 解凍したフォルダにtools.zipができるので、それも解凍
    • cygwinでunzipすると解凍ファイルに実行権限が付与されない。実行権限を付与しないと、以降の作業がうまくいかないので注意。
  3. 解凍したフォルダ内の、一部のjarファイルが、pack200形式で圧縮されているので、解凍したフォルダ内にあるunpack.exeを使用して、jarファイルに変換する
    • Windowsコマンドプロンプトで実行
      $ cd <tool.zip解凍フォルダ>
      $ for /r %x in (*.pack) do .\bin\unpack200 -r "%x" "%~dx%~px%~nx.jar"
  4. <tool.zip解凍フォルダ>をJAVA_HOMEとして、パスを通せばOK

Excel操作

セル 結合


罫線

  • 参考 : https://www.javadrive.jp/poi/style/index4.html
       Workbook wb = new HSSFWorkbook();
       Sheet sheet = wb.createSheet();
      
       Row row1 = sheet.createRow(1);
      
       Cell cell1_1 = row1.createCell(1);
       cell1_1.setCellValue("Sample");
    
       CellStyle style = wb.createCellStyle();
    
       style.setBorderTop(CellStyle.BORDER_DASHED);
       style.setBorderBottom(CellStyle.BORDER_DOUBLE);
       style.setBorderLeft(CellStyle.BORDER_MEDIUM_DASH_DOT);
       style.setBorderRight(CellStyle.BORDER_MEDIUM);
    
       style.setTopBorderColor(IndexedColors.MAROON.getIndex());
       style.setBottomBorderColor(IndexedColors.SKY_BLUE.getIndex());
       style.setLeftBorderColor(IndexedColors.ORANGE.getIndex());
       style.setRightBorderColor(IndexedColors.BLUE_GREY.getIndex());
    
       cell1_1.setCellStyle(style);

SSL/TLS

client

自身のPIDを取得

String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];

ManagedExecutorService?


Java Flight Recorder

ArrayList?HashSet?の検索アルゴリズム

Objectが同じものかのAssertion

複数Mainクラスを持つjarファイルの実行

[tmi@sv11 ~]$ java -classpath test-driver.1.0.0-jar-with-dependencies.jar  myapp.main.SimpleServletMain

Network

HttpClient?

HttpURLConnectionのタイムアウト

  • http://www.ku6.jp/keyword14/1.htmlから抜粋
  • connect timeout
    connect timeoutは接続にかかった時間で、setConnectTimeoutで設定します。
    
    引数はミリ秒で指定し、0を指定すると無限になります。
    デフォルト値はJavadocに書いてないのですが、0になっています。
    
    
    connect timeoutが発生するのはconnectメソッド内です。
    接続にかかった時間がtimeout値を超えるとSocketTimeoutExceptionが発生します。
  • read timeout
    read timeoutはデータ取得にかかった時間で、setReadTimeoutで設定します。
    (リクエストを投げてレスポンスが帰ってくるまでの時間)
    
    引数はミリ秒で指定し、0を指定すると無限になります。
    デフォルト値はJavadocに書いてないのですが、0になっています。 
    
    
    read timeoutが発生するのは、レスポンスデータを参照するメソッドです。 
    
    &#9702;getContent
    &#9702;getHeaderFields
    &#9702;getInputStream
    &#9702;getResponseCode
    &#9702;getResponseMessage
    &#9702;getContentEncoding
    &#9702;getContentLength
    &#9702;getContentLengthLong
    &#9702;getContentType
    &#9702;getDate
    &#9702;getExpiration
    &#9702;getHeaderField
    &#9702;getHeaderFieldDate
    &#9702;getHeaderFieldInt
    &#9702;getHeaderFieldKey
    &#9702;getLastModified 
    
    ただ、上記の内、SocketTimeoutExceptionが発生するのは次のメソッドだけです。
    
    &#9702;getContent
    &#9702;getHeaderFields
    &#9702;getInputStream
    &#9702;getResponseCode
    &#9702;getResponseMessage 
    
    他のメソッドはnullとか0とかエラー値を返すだけです。
    SocketTimeoutExceptionが発生しないメソッドだけを使うと、
    timeoutが起こったことがわからないので注意が必要です。
    
    どのメソッドが例外を投げるかはJavadocに書いてないので実際の動作からしか読み取れません。
    (getInputStreamだけは書いてあったりしてますますよくわかりません。)
    実際に使用する環境でも念のため調べておいた方が無難でしょう。

Spring

JdbcTemplate?作成方法

Spring-boot

Java EE

Java SE

byte配列から値参照

			byte[] b = Encoder.stringToBinary(lowResImageB64)
			String hexHeight = String.format("%02x%02x", b[8], b[9])
			int height = Integer.decode("0x${hexHeight}")
			println height

Mapの全要素参照

  • Mapの要素のkeyの型を定義している場合はkeySet()メソッドをfor文で受け取れる
    Map<String, String> map = null;
    for(String key : map.keySet()){
    	System.out.println(map.get(key));
    }
  • 未定義の場合は以下のようにkeySet().iterator()を使用
    Iterator it = map.keySet().iterator();
    while (it.hasNext()) {
     Object o = it.next();
     System.out.println(o + " = " + map.get(o));
    }

JVM

Classのprivateメソッドを参照する