#author("2021-12-14T02:32:26+00:00","","")
#topicpath
----

あ、これってべんりだなあって思ったコーディングのメモ。

#contents

** AWS のLinuxでJavaを使う [#h783f118]
ふつうにwgetでrpm取ってきて、あとはJavaの切り替え。
 wget --no-check-certificate --no-cookies --header \
 "Cookie: oraclelicense=accept-securebackup-cookie" \
 http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.rpm
 sudo rpm -Uvh jdk-8u161-linux-x64.rpm
 sudo alternatives --config java
 export JAVA_HOME=/usr/java/jdk1.8.0_161

ちなみにダウンロード先はこちら
http://www.oracle.com/technetwork/java/javase/downloads/index.html


** HttpURLConnection での接続において、Proxyを越える(SSLも) [#ha57c93f]
Jersey などライブラリを使ってる場合はこちら。。

[[JavaでSSLでRESTを投げるときに、プロキシを通す方法 - Qiita>https://qiita.com/masatomix/items/c1f8674213500f54df0f]]


ピュア(?)のHttpURLConnection を使ってるときはこんな感じで行けそう((行けそう、ってのはMacのProxyソフトは越えてくれなかった。。Fiddlerや、いわゆる認証プロキシはOKでしたが。。))

 Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888));
 
 final String authUser = "user";
 final String authPassword = "pass";
 Authenticator.setDefault(
    new Authenticator() {
       @Override
       public PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication(
                authUser, authPassword.toCharArray());
       }
    }
 );
 
 System.setProperty("http.proxyUser", authUser);
 System.setProperty("http.proxyPassword", authPassword);
 
 HttpsURLConnection.setDefaultSSLSocketFactory( createSSLContext().getSocketFactory());
 
 // setup a hostname verifier that verifies everything
 HttpsURLConnection.setDefaultHostnameVerifier(createHostNameVerifier() );
 
 
 HttpsURLConnection con = (HttpsURLConnection)url.openConnection(proxy);
 //        HttpURLConnection con = (HttpURLConnection)url.openConnection();

createSSLContext()、createHostNameVerifier() メソッドは、上記サイトと同じモノを使います





 


** JavaでAWSのプロファイルを切り替える件 [#kcffb36a]
 AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
         .withRegion(Regions.AP_NORTHEAST_1)
         .withCredentials(new ProfileCredentialsProvider("default")) ←プロファイル名
         .build();

こんな感じ。

参考:
http://www.masatom.in/pukiwiki/AWS/AWS%20CLI/#w1297a6a


** Mavenから AWS SDK for Java を使う場合 [#p24dc007]
-[[Apache Maven での SDK の使用 - AWS SDK for Java>https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/setup-project-maven.html]]

**Jerseyのエラー [#dd13ed6b]
 org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException:
  MessageBodyWriter not found for media type=application/json, 
 type=class java.util.HashMap, genericType=class java.util.HashMap.

ってエラーが出る場合。pom.xmlやクラスパスに、
 <!-- jersyでJavaBeansをJSON でPOSTする場合。 -->
 <dependency>
   <groupId>org.glassfish.jersey.media</groupId>
   <artifactId>jersey-media-json-jackson</artifactId>
   <version>${jersey.version}</version>
 </dependency>

これが足りないから、かも!



**よく出てくるコマンド。 [#f2fc0494]
Eclipseの設定。
 mvn -DdownloadSources=true -DdownloadJavadocs=true eclipse:clean eclipse:eclipse

Eclipse上からデバッグできるようにする
 export MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"

SpringBootの起動
 mvn spring-boot:run

Jettyの起動
 mvn jetty:run

ファイルをつくる。
 $ cat << __EOF__ >> output.txt
 > aaa
 > bbb
 > ccc
 > __EOF__
 $ cat output.txt
 aaa
 bbb
 ccc

もはやJava関係ないな。。



**AWSのLinuxで Mavenを使う [#sb1c834a]
AWSのLinuxで、速攻でMavenでビルドしたくなって、しらべた内容。ついでにJavacを切り替えるやり方まで。

-[[Mavenをyumからインストール - Qiita>http://qiita.com/digdagdag/items/87fef7ce7c97be10bee1]]
-[[Amazon LinuxでJava8/Tomcat8の環境を構築する | Developers.IO>http://dev.classmethod.jp/cloud/aws/java8_tomcat8_on_amazon_linux/]]


**Logの制御 [#pff20c16]
かつては Log4j がただ唯一の選択肢でしたが、どうやら乱立してるっぽい。そんなかでも多分コレがデファクト。

-[[SLF4J+Lobackの基本 | Java好き>http://javazuki.com/articles/logback-xml-settings.html]]

SLF4J経由でLogback。ついでにLombokでAnnotation。これで決まりかな。。



** 設定ファイルの制御 [#k95a870d]
ResourceBundleを使った設定ファイルの制御について。ResourceBundleってpropertiesファイルで設定できるのみだと思ってたんですけど、どうやら設定情報(key/value)を返却するクラスを実装する機構があって、さらにその設定情報をpropertiesファイルで記述できる機能もある、って構造なんですね。。

下記のサンプルは設定情報をクラスパス上のプロパティファイルで設定できるようにしつつ、ファイルがなかった場合はデフォルト値を適用する、なんてケース。よくあるケースですね。ここで、デフォルト値は DefaultResources クラスというListResourceBundleを拡張したクラスを使用しています。

 package nu.mine.kino.resourcesamples;
 
 import java.util.Enumeration;
 import java.util.ResourceBundle;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
 public class Main {
     public static void main(String[] args) {
         new Main().execute();
 
     }
 
     // sample.properties をクラスパスから探して、なかったらデフォルト値を適用する。
     // デフォルト値は、nu.mine.kino.resourcesamples.DefaultResources クラスで定義している。
     private void execute() {
         String propertyFile = "sample";
         ResourceBundle bundle = null;
         try {
             bundle = ResourceBundle.getBundle(propertyFile);
             doSettings(bundle);
         } catch (java.util.MissingResourceException e) {
             String message = "設定ファイルが存在しません。必要ならクラスパス上に {}.propertiesを配置してください。({})";
             log.warn(message, propertyFile, e.getMessage());
             doSettings(ResourceBundle.getBundle(
                     "nu.mine.kino.resourcesamples.DefaultResources"));
         }
     }
 
     private void doSettings(ResourceBundle bundle) {
         Enumeration<String> keys = bundle.getKeys();
         while (keys.hasMoreElements()) {
             String key = keys.nextElement();
             log.debug("key[{}]:{}", key, bundle.getString(key));
         }
     }
 }



 package nu.mine.kino.resourcesamples;
 
 import java.util.ListResourceBundle;
 
 public class DefaultResources extends ListResourceBundle {
      @Override
     protected Object[][] getContents() {
         return new Object[][] { { "param1", "default value1" },
                 { "param2", "default value2" } };
     }
  }

sample.properties
 param1=property value1
 param2=property value2






** ファイルパスの操作(Java7版) [#md2ed45b]
ファイルのパスをつなげるようなときに、もちろんStringでつなぐとかは論外として、、いままでは
 File base = new File("/tmp/base");
 new File(new File(base, "more1"), "more2");
こんな風にくるんでくるんで、みたいな処理をしていたのが、

 Paths.get("/tmp/base","more1","more2").toFile();
このように可変長引数を使ってつなげるようになりました。いまどきの言語だと当たり前なんですけど、Javaもキレイになりました。。


** バイナリファイルをbyte配列に変換する(Java7版) [#va30b8e1]
便利な世の中になりました。
 try {
     byte[] bytes = Files.readAllBytes(Paths.get("パス"));
 } catch (IOException e) {
     // TODO 自動生成された catch ブロック
     e.printStackTrace();
 }

自前で書く必要なくなっちゃいました。AutoCloseableで自動でStreamをcloseしてくれてるし。


**ある配列に配列を追加して新しい配列を作る [#vfc530c0]
 Object[] newArray = ArrayUtils.addAll(array1, array2);


**ある配列に単一のObjectを追加して新しい配列を作る [#j9aba188]
 Object[] array = ...;
 Object element = ...;
 Object[] newArray = ArrayUtils.add(array, element);


**Commonsのデリミタで分割するヤツ [#y2ba4cd9]
 String[] splits = StringUtils.splitPreserveAllTokens(target, delimiter);


**StringBufferでカンマつなぎしたとき、最後のカンマはいらない件 [#o1591aac]
 StringBuffer buf = new StringBuffer();
 for (String str : array) {
     buf.append(str);
     buf.append(',');
 }
 buf.deleteCharAt(buf.length() - 1);
 return new String(buf);



**わすれがちな、Dateの比較 before/after [#l032efcf]
 Date base = new Date();
 Date target = base;
 System.out.println(base.after(target));  //おなじ日はfalse
 System.out.println(base.before(target)); //おなじ日はfalse
 System.out.println(base.before(DateUtils.addDays(target, 1)));  // targetより前か → true
 System.out.println(base.after(DateUtils.addDays(target, -1)));  // targetより後か → true

結果は
 false
 false
 true
 true

**バイト列を表示する。 [#j0b5477a]
テキストファイルが文字化けしてて、どんなバイナリの値なんだろって確認したいときとかに、バイト列を取得し16進で画面表示するには以下のようにします。

 private void printByte1(byte[] bytes) {
     String hexString = toHexString(bytes);
     System.out.println(hexString);
 }
 
 // byte[] -> 16進文字列へ変換
 private String toHexString(byte[] b) {
     StringBuffer hexString = new StringBuffer();
     String plainText = null;
     for (int i = 0; i < b.length; i++) {
         plainText = Integer.toHexString(0xFF & b[i]);
         if (plainText.length() < 2) {
             plainText = "0" + plainText;
         }
         hexString.append(plainText);
         hexString.append(" ");
     }
     return new String(hexString);
 }

String#formatメソッドを使えば書式の指定で対応出来ますね。。
 private void printByte2(byte[] bytes) {
     for (byte b : bytes) {
         System.out.printf(String.format("%1$x ", b));
     }
     System.out.println();
 }

そもそもどうやってバイナリでファイル読むのっていうのは下記の通りやればできます。

**ファイルをバイナリで読み込む。。 [#t3df6b6b]
定番はコレですかね
 String baseDirStr = "/tmp";
 String fileName = "data.txt";
 FileInputStream in = new FileInputStream(new File(baseDirStr, fileName));
 int ch;
 while ((ch = in.read()) != -1) {
     // System.out.print(Integer.toHexString(ch) + " ");
     System.out.printf(String.format("%1$x ", ch));
 }

こういうのもある。。
 RandomAccessFile accessFile = null;
 try {
     File file = new File(baseDirStr, fileName);
     accessFile = new RandomAccessFile(file, "r");
     int length = (int) file.length();
     byte[] bytes = new byte[length];
 
     accessFile.read(bytes);
     printByte1(bytes);
     printByte2(bytes);
 } finally {
     if (accessFile != null) {
         accessFile.close();
     }
 }

RandomAccessFile にはバイナリファイルを readDouble とかやって型を指定して取得できたりするので、まさにバイナリをファイルを読むときにはこっちが良さそうです。

テキストファイルをバイナリで読んでみるときとかは前者が良さそうです。
 




**数値の文字列フォーマット変換 [#hb5bb0e4]
doubleとかの数値をフォーマッティングした文字列を取得するメソッドです。こんな感じ。
 String.format("%1$,.0f" + " KB中、" + "%2$,.0f"+ " KB処理しました。" + "%3$,.0f" + " %%処理完了",
       a / 1024.0, b / 1024.0,  c / 1024.0);

なかのプレースホルダは、それぞれ
 %1$ -> a / 1024.0
 %2$ -> b / 1024.0
 %3$ -> c / 1024.0
って可変長の引数に対応。さらに
 ,.0f
で、「3ケタでカンマ区切り」「小数点以下は0ケタ」って意味。ちなみにフォーマット内で%を使う場合は、上記のように%%ってエスケープ。。

-[[数値の文字列フォーマット変換 ( Javaサンプル集 )>http://bit.ly/zTsJfM]]
-[[Java書式付き出力メモ(Hishidama's Java Formatter/Formattable Memo)>http://www.ne.jp/asahi/hishidama/home/tech/java/formatter.html]]


**java.util.Date -> int [#t19069d3]
ついでに。。
 Calendar calendar = Calendar.getInstance();
 calendar.setTime(new Date());  <-2009/6/8に実行した
 int year = calendar.get(Calendar.YEAR);
 int month = calendar.get(Calendar.MONTH);
 int day = calendar.get(Calendar.DAY_OF_MONTH);
 System.out.println(year);
 System.out.println(month);
 System.out.println(day);
などで、Dateをintに変換可能です。
 2009
 5
 8
Monthだけは日本人の感覚と一つ値がずれるので注意。

同様に、Calendar#set(int year, int month, int date) 、、具体的には
 Calendar calendar = Calendar.getInstance();
 calendar.clear(); <-下で時分を指定しないから、clearしないと現在時刻が保持されちゃうので。
 calendar.set(year, month, day);
 Date time = calendar.getTime();

とすることで、int -> java.util.DateもOKそうですね。

[[Calendar (Java 2 Platform SE 5.0)>http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/Calendar.html#clear()]]


**String -> java.util.Date [#w5cb107d]
文字列からjava.util.Dateを生成する方法ですが、
 Date parseDate = new SimpleDateFormat("yyyy/MM/dd").parse(date);
 System.out.println(parseDate);
などとやればできますが、Commons Langの org.apache.commons.lang.time.DateUtils をつかえばいくつかのフォーマットを同時に指定してDateを生成することができます。
 Date date = DateUtils.parseDate(dateStr, new String[] { "yyyyMMdd","yyyy/MM/dd" });
引数のパターンで順々にdataStrをパースして、Dateクラスを生成してくれます。

**java.util.Date -> String [#i44fc664]
逆に、Dateから文字列を取得する方法。
 String nowDateString = DateFormatUtils.format(nowDate, "yyyy/MM/dd");
 System.out.println(nowDateString);
フォーマットの指定の仕方によって、年を取得、月を取得、日付を取得、とかができますね。


**「日」より下を切り捨てたDateを取得する [#z1f98e71]
日付だけ管理したいんだよなぁってときがよくありますが、DateUtils はその要求に応えてくれます。
 Date nowDate = new Date();
 System.out.println("Today: " + nowDate);
 // 「日」より下を切り捨て
 Date dateTruncate = DateUtils.truncate(nowDate, Calendar.DAY_OF_MONTH);
 System.out.println("Today: " + dateTruncate + " <-「日」より下を切り捨て");
 // 「月」より下を切り捨て
 dateTruncate = DateUtils.truncate(nowDate, Calendar.MONTH);
 System.out.println("Today: " + dateTruncate + " <-「月」より下を切り捨て");
 // 「年」より下を切り捨て
 dateTruncate = DateUtils.truncate(nowDate, Calendar.YEAR);
 System.out.println("Today: " + dateTruncate + " <-「年」より下を切り捨て");
結果は以下の通り:
 Today: Mon Jun 08 10:00:54 JST 2009
 Today: Mon Jun 08 00:00:00 JST 2009 <-「日」より下を切り捨て
 Today: Mon Jun 01 00:00:00 JST 2009 <-「月」より下を切り捨て
 Today: Thu Jan 01 00:00:00 JST 2009 <-「年」より下を切り捨て




**stackTraceを取得する [#mcb50e85]
標準エラーに出力するならe.printStackTrace()ですが、文字列として取得したい場合は、ストリームにスタックトレースを出力します。
 private String exception2String(Exception e) {
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   e.printStackTrace(new PrintStream(baos));
   return baos.toString();
 }
文字コードとか大丈夫だっけとかありますが、こんな感じでできます。


**プロパティファイルから、複数のデータを配列で取得する [#m45a59f9]
[[Java Collections Framework>http://commons.apache.org/collections/]] の org.apache.commons.collections.ExtendedProperties を用いると、
-hoge.properties
 data=hoge@fuga.com
 data=hogehoge@fuga.jp
などという複数のデータを配列で取得することができます。このファイルはクラスパスが通った場所に置いておきます。

上記データにアクセスするサンプルコードは以下の通り。
 ExtendedProperties props = new ExtendedProperties();
 ClassLoader loader = Thread.currentThread().getContextClassLoader();
 InputStream resourceAsStream = loader
         .getResourceAsStream("hoge.properties");
 InputStream in = new BufferedInputStream(resourceAsStream);
 props.load(in);
 String[] dataArray = props.getStringArray("data");
などとしてデータを取り出すことができます。

-[[リソースへのアクセス>http://java.sun.com/j2se/1.5.0/ja/docs/ja/guide/lang/resources.html]]
-[[プロパティファイルから、String配列の値を取り込むには? - Java Solution>http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?mode=viewtopic&topic=10964&forum=12&start=0]]
-[[ExtendedPropertiesの自動読み込みについて - Java Solution>http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=25089&forum=12]]
-[[Commons Collections>http://muimi.com/j/jakarta/commons/collections/]]






**パイプされた標準入力を取得する [#uf4f1804]
そういえばJavaって標準入力をどう受け取るんだっけ??ということで調べたメモ。パイプされた標準入力をechoするサンプル。

 package nu.mine.kino.mail.utils;
 
 import java.io.BufferedInputStream;
 import java.io.IOException;
 
 public class Echo {
     public static void main(String[] args) {
         BufferedInputStream in = new BufferedInputStream(System.in);
         try {
             int size = in.available();
             byte[] bytes = new byte[size];
             in.read(bytes);
             System.out.println(new String(bytes));
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
 }

結果はたとえば
 [hogehoge@www Test]$ ls  |  java -cp lib/sample.jar nu.mine.kino.mail.utils.Echo
 build.win.properties
 build_jar.xml
 classes
 lib
 source
 
 [hogehoge@www Test]$
lsの結果を受け取り、echoできました。

-シェルからJavaを呼び出すときもOK
 [hogehoge@www Test]$ cat sample.sh
 export JAVA_HOME=/opt/jdk1.5.0_12
 export LIBDIR=lib
 export CLASSPATH=${LIBDIR}/sample.jar
 java nu.mine.kino.mail.utils.Echo
 [hogehoge@www Test]$ ls  |  ./sample.sh
 build.win.properties
 build_jar.xml
 classes
 lib
 sample.sh
 source
 
 [hogehoge@www Test]$

ちなみに標準入力を待ち受けてるときに入力完了を通知するための終了文字は
[[Platform-Specific Details: The End-of-Input Character>http://www.ei.fukui-nct.ac.jp/~yfa/java/jtutorial/java/nutsandbolts/_endofinput.html]] に書いてありました。

参考
-[[標準入出力ストリーム>http://www.ei.fukui-nct.ac.jp/~yfa/java/jtutorial/java/nutsandbolts/inputOutput.html]]




**Apache Axis 1.4のSSL処理にはバグがありそう [#f0df163f]
詳しくはまた時間がとれたらにしますが、Basic認証するプロキシサーバ越えでSSL通信するときのAxisの挙動がヘン。Axisが生成する Proxy-Authorizationヘッダの改行コードがおかしい模様。HTTPSの仕様的には、ほんとは\r\nが推奨されるらしいけど\nしかないため、まれに解析に失敗するプロキシサーバがあるようです。
-[[Svn内のソース>http://svn.apache.org/viewvc/webservices/axis/trunk/java/src/org/apache/axis/components/net/JSSESocketFactory.java?view=co]]





**BigDecimalのコンストラクタにdoubleは使わないほうがいい [#n2d3905d]
ちゃんと数値計算しようと思って、doubleとかの代わりにBigDecimalを使ってたんだけど、やっぱ誤差が出ちゃう。何でだろーと思ってたら、BigDecimalのコンストラクタでStringでなくdoubleを使ってたからでした。doubleを引数に取るコンストラクタの方は、引数自体が誤差が出ちゃってるから、正確な計算ができないって事ですね。素直にStringを使ったところ、ビシっと計算が合いました。

って、よく見たらJavaDocにも書いてありますね。
-[[BigDecimal>http://docs.oracle.com/javase/jp/6/api/java/math/BigDecimal.html#BigDecimal%28double%29]]




**classesディレクトリを一括で削除するワンライナー [#x2da51de]
 rm -rf `find ./ -type d -name classes`

**ファイル <-> byte[]に変換するUtil [#xf90100f]
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 
 /*******************************************************************************
  * Copyright (c) 2007 Masatomi KINO. All rights reserved. 
  * $Id$
  ******************************************************************************/
 public class Utils {
   public static byte[] file2Byte(String file) throws IOException {
     InputStream in = null;
     byte[] pix = null;
     try {
       in = new FileInputStream(file);
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       byte[] b = new byte[1024];
       int j;
       while ((j = in.read(b)) != -1) {
         baos.write(b, 0, j);
       }
       pix = baos.toByteArray();
     } finally {
       if (in != null) {
         try {
           in.close();
         } catch (IOException e) {
           e.printStackTrace();
         }
       }
     }
     return pix;
   }
 
   public static void byte2File(byte[] b, String outputFile)
       throws IOException {
     BufferedOutputStream stream = null;
     try {
       File file = new File(outputFile);
       FileOutputStream fstream = new FileOutputStream(file);
       stream = new BufferedOutputStream(fstream);
       stream.write(b);
     } finally {
       if (stream != null) {
         try {
           stream.close();
         } catch (IOException e1) {
           e1.printStackTrace();
         }
       }
     }
   }
 } 



** 整数を16進や2進で表示する [#nd33ef2c]
 System.out.println(Integer.toHexString(15));
 System.out.println(Integer.toBinaryString(15));
実行結果は以下の通り。
 f
 1111

-[[16進数とは>http://www.kab-studio.biz/Programing/JavaA2Z/Word/00000297.html]]


**Base64でエンコードする [#i2fb78c1]
Base64とはE-mailなどバイナリデータを使用できない環境で、バイナリデータを扱うためのエンコード方式です(( http://ja.wikipedia.org/wiki/Base64 ))。バイナリデータをテキストデータに可逆変換します。

[[Commons Codec>http://jakarta.apache.org/commons/codec/]]を用いれば、バイナリデータを簡単にBase64エンコード可能です。
 public class Base64Main {
   public static String encode(String input) {
     byte[] bs = Base64.encodeBase64(input.getBytes(), false); 
                 // booleanはある単位で改行を入れるかどうか
     return new String(bs);
   }
 
   public static void main(String[] args) {
     String string = encode("kino");
     System.out.println(string);
   }
 }
実行結果は以下の通り
 a2lubw==

簡単ですね。引数にbyte[]を取るので、バイナリファイルからbyte[]を作成し、メソッドに渡してあげればバイナリファイルも簡単にエンコード可能なわけです((なぜ戻り値がbyte[]なのかは不明))。

ちなみにこのCodecライブラリは下に出てくる byte[] -> HexStringな変換をするメソッドなどもあります。
  new String(Hex.encodeHex(b));
とすればOKです。

あ、よく見たらSHA-1でハッシュするメソッドもありました。
 System.out.println(DigestUtils.shaHex("kino".getBytes()));
でしたと同じ結果を得ることができます。実行結果は以下の通り。
 c108a2616c020deeb71df83906f039e3dfcc6752
おなじですね。





**SHA1でハッシュ化 [#q33bfba0]
SHA-1はパスワードのハッシュ化などに使われるアルゴリズムです(( http://ja.wikipedia.org/wiki/SHA ))
  public static String encrypt(String input) {
    try {
      MessageDigest md = MessageDigest.getInstance("SHA1");
      md.update(input.getBytes("MS932"));
      return toHexString(md.digest());
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    return null;
  }

  private static String toHexString(byte[] b) {
    StringBuffer hexString = new StringBuffer();
    String plainText=null;
    for (int i = 0; i < b.length; i++) {
      plainText = Integer.toHexString(0xFF & b[i]);
      if (plainText.length() < 2) {
        plainText = "0" + plainText;
      }
      hexString.append(plainText);
    }
    return new String(hexString);
  }

  public static void main(String[] args) {
    String string = encrypt("kino");
    System.out.println(string);
  }

実行結果は以下の通り。
 c108a2616c020deeb71df83906f039e3dfcc6752
SHA1でハッシュ化できました。MessageDigest.getInstance("SHA1");の「SHA1」を「MD5」にすればMD5でハッシュ化できます。



**java.lang.ThreadLocalについて [#wf809851]
 thlocal.set( new LegacySystemImpl2());
 thlocal.set( new LegacySystemImpl());
 LegacySystem impl = (LegacySystem) thlocal.get();
などと同じ型のクラスをセットした場合、どうも上書きになるっぽい。ソースを調べた分けじゃないけど。。

http://www.hyuki.com/dp/dpinfo_ThreadSpecificStorage.html#i1

**Eclipseのヒープとタスクマネージャの関係 [#h1eae651]
Eclipseのヒープサイズと、タスクマネージャのjavawのメモリ使用量の関係。Eclipseのヒープが
 1024M中の500M
とかなってる場合、1024Mの方がタスクマネージャ上に表示される。だから実際どれだけjavaプロセスがメモリを使用しているかはOSからはわからないみたいですね。



** EclipseでCVSのブランチを取り扱う。 [#e7289d1e]
CVSのトランク(メインっていう?)とブランチをマスターしたくちょっと触ってみました。

まずはバージョンとしてタグ付け。タグ名はたとえば
 V20061026_01
とする。次にブランチの作成。チーム >> ブランチ より作成。ブランチ名はたとえば
 V20061026_01_BRANCH
とする。そのとき、ブランチをマージするための開始点のタグも併せて登録される。これは自動的に
 Root_V20061026_01_BRANCH
というタグ名になる。メインのモジュールにブランチをマージするには、開始点ってのが重要みたいだ。


ここまででCVSには上の3つのタグ
 V20061026_01                メイン側
 V20061026_01_BRANCH         ブランチ側
 Root_V20061026_01_BRANCH    メイン側
ができる。

Eclipseプロジェクトに、メインとブランチ両方落としておく。ブランチの方はプロジェクト名を_branchとかつけとく。

Eclipseで各プロジェクトでソースを修正してコミットする。
 メイン側はバージョンは   1.1 -> 1.2 
 ブランチ側はバージョンは 1.1 -> 1.1.2.1
となるみたい。

さあ、ブランチからメインへマージします。メインのプロジェクトで、チーム >> マージを選択し
 マージされるバージョン(終了タグ) をブランチのバージョン   i.e. V20061026_01_BRANCH 
 共通基本バージョン(開始タグ)     をさっきの開始バージョン i.e. Root_V20061026_01_BRANCH
と選択すると、左がメイン、右がブランチのソース比較画面が現れます。適宜Updateすればブランチのソースがメインに取り込まれます。後はメインにコミットすれば、ブランチ分のマージは完了です。


※これはローカルコピーに、開始タグと終了タグの差分を取り出すって事かな?実際ブランチ側でマージしようとしたら、V20061026_01_BRANCH  とV20061026_01_BRANCH  には差分がないっていう当たり前の表示になってしまった。



**実行中のメソッド名を取得する。 [#c5807e06]
 new Throwable().getStackTrace()[0].getMethodName();
何故これでメソッド名が取れるんだろう。。。でもうまくいきますねー



**byte配列をバイナリに変換する。 [#b141cf0a]
逆に、byte[]をファイルに書き出す方法
 public static void write(byte[] b) {
   BufferedOutputStream stream = null;
   try {
     File file = new File("after.bin");
     FileOutputStream fstream = new FileOutputStream(file);
     stream = new BufferedOutputStream(fstream);
     stream.write(b);
   } catch (IOException e) {
     e.printStackTrace();
   } finally {
     if (stream != null) {
       try {
         stream.close();
       } catch (IOException e1) {
         e1.printStackTrace();
       }
     }
 
   }
 }


**バイナリファイルをbyte配列に変換する [#lbd2e6f7]
Webサービスでバイナリをアップするときなどは、byte[]で渡すみたいです。


 public byte[] createBin() {
   InputStream in = null;
   byte[] pix = null;
   try {
     in = new FileInputStream("before.bin"); <-バイナリファイル
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     byte[] b = new byte[1024];
     int j;
     while ((j = in.read(b)) != -1) {
       baos.write(b, 0, j);
     }
     pix = baos.toByteArray();
   } catch (IOException e) {
     e.printStackTrace();
   } finally {
     if (in != null) {
       try {
         in.close();
       } catch (IOException e) {
         e.printStackTrace();
       }
     }
   }
   return pix;
 }


**Apache Axisで、プロキシーを越える。 [#l2d74872]
Apache Axisを使ったWEBサービスのProxyクライアントで、HTTPのプロキシー(ややこしい)を越える方法を探していました。

いやあEclipseでソースにブレークポイントつけまくって、探したー。。。。どうやら、
  org.apache.axis.components.net.DefaultHTTPTransportClientProperties
てクラスが、なにやらプロパティをセットしていて、そこがAxisの環境設定値になってる模様。そしてこのクラスは、org.apache.axis.AxisPropertiesというjava.util.Properties みたいなのを使っている。ソースを見ると、httpプロキシを越えるためのキー値は
 AxisProperties.setProperty("http.proxyHost", "proxyのサーバ名");
 AxisProperties.setProperty("http.proxyPort", "proxyのポート番号");
 AxisProperties.setProperty("http.proxyUser", "xxxx");
 AxisProperties.setProperty("http.proxyPassword", "xxxx");
越えた。。キター。。。


**Apache Axisで、自己署名証明書を使用してSSLさせる方法 [#b37818cb]
-[[中里一日記: Axisにオレオレ証明書を食わせる方法>http://kaoriha.org/nikki/archives/000464.html]]

すげー

** HSQLDBの起動、フロントエンドの起動 [#lb92f311]
-データベースサーバの起動
 java -cp /opt/hsqldb/hsqldb.jar org.hsqldb.Server 
   -database /tmp/bd -port 9001 -system_exit=true

-フロントエンドの起動
 java -cp lib/hsqldb.jar org.hsqldb.util.DatabaseManager

** ブラウザのCookieを手軽に参照する [#hc2bdd7f]
JavaのTIPではないけど、J2EE開発中によく使うので。ブラウザのURLに
 javascript:document.cookie;
と入力すると、クライアントのCookie(今開いているサイトに対するもののみ)を参照できます。


** Jakarta Commons Langのいろいろ [#pdcb3fd8]
[[Jakarta Commons Lang:http://jakarta.jp/commons/lang.html]]はJavaのライブラリだけでは足りないようなユーティリティ的な機能を提供するクラスライブラリです。たとえば、こんな感じで使うことができます。
-toString()を実装するときに使う
 public String toString() {
   return new ToStringBuilder(this)
     .append("id", getId())
     .append("title",getTitle())
     .toString();
 }
とかで
 nu.mine.kino.rss.hibernate.Rss@33441dfb[id=10,title=hoge]
と出力できたり、

-equals()を実装するときに使う
  public boolean equals(Object other) {
    if (!(other instanceof Rss)){
      return false;
    }
    Rss castOther = (Rss) other;
    return new EqualsBuilder()
         .append(this.getId(), castOther.getId())
         .isEquals();
  }
とかで、getIdが同じならtrue、なんてことができたりします。ちなみにappendはどんどん後ろに追加することができます。これは便利!!


**フィールドをカプセル化する [#h2d5feab]
設定ファイルとかの場所がフィールドに定数で埋め込まれていて、単体テストのときだけそのパスを変えたいなあなんてときがあります。最近はDIとかで変えれるようにするのがはやってますが、DIコンテナなども使ってないときなどはどうすればよいでしょうか。

例としてテスト対象クラスがHogeだとして
 public class Hoge{
   private String path ="hoge/hogehoge.properties";
   .....
   public void exe(){
     new File(path).....;
   }
 }
なんてのがあるとき、どうすればよいかってことです。

この場合、まずはソースを変更して単体テストしやすくします。そのソースの変更はEclipseなどを用いて、きっちりやる、と。やる手順は

- フィールドへのアクセスをgetter経由にする(getterはデフォルトやprotectedにする)
- 単体テスト時、anonymousクラスにして、そのgetterをoverrideして、値を変更する

具体的には上のクラスは以下のように変更します。

- フィールドへのアクセスをgetter経由にする(getterはデフォルトやprotectedにする)
 public class Hoge{
   private String path ="hoge/hogehoge.properties";
   .....
   public void exe(){
     new File(getPath()).....;
   }
   
   String getPath(){
     return path;
   }
 }

- 単体テスト時、anonymousクラスにして、そのgetterをoverrideして、値を変更する
 public class HogeTest{
   private Hoge hoge;
   .....
   public void testExe(){
     hoge=new Hoge(){
       String getPath(){
         return "新しいパス";
       }
     };
     hoge.exe();.......
   }
 }
こうするとパスを変更することができます。気になるのは
-フィールドを公開しちゃってる(デフォルトはパッケージ内、protectedはさらにサブクラスも)
-ソースを変更している
-anonymousのクラスに対するテストが、元のクラスのテストとしちゃってよいの?

ってところですね。。ソースの変更に関してはEclipseなどで論理的に安全に行うことはできますが。手順は、
 変数を参照している箇所(new File(path)の"path")を選択して、リファクタリング >> フィールドのカプセル化
定数がフィールドにすらいない場合は、上の前にさらにこれをやる
 変数を選択して、 リファクタリング >> ローカル変数を フィールドに変換



**プレースホルダを使う [#w78f5e80]
MessageFormatを使うと、{0}のようなプレースホルダを使うことができます。
 SimpleDateFormat yyyy = new SimpleDateFormat("yyyy");
 SimpleDateFormat MM = new SimpleDateFormat("MM");
 SimpleDateFormat dd = new SimpleDateFormat("dd");
 Date selectedDate = new Date();
 String year = yyyy.format(selectedDate);
 String month = MM.format(selectedDate);
 String date = dd.format(selectedDate);
 Object[] dateArgs = { year, month, date };
 MessageFormat form = new MessageFormat("{0}年{1}月{2}日"); <-プレースホルダ
 System.out.println(form.format(dateArgs));
実行結果は
 2005年03月18日



**e.printStackTrace()の文字列を取得する、出力先を変更する [#e954b60f]
例外のインスタンスをexとして
 StringWriter stringWriter = new StringWriter();
 ex.printStackTrace(new PrintWriter(stringWriter));
 String message = stringWriter.getBuffer().toString();




**WSAD5.1.2でサーバの設定が格納されているディレクトリ [#t58f1bdf]
 ${WORKSPACE}\.metadata\.plugins\com.ibm.wtp.server.core\configs

**プロクシ認証などなど [#u29f0f6c]
 -Dhttp.proxyHost=[プロクシサーバ名] -Dhttp.proxyPort=[ポート番号]
 -Dhttp.proxyUser=[UserID] -Dhttp.proxyPassword=[password]

** privateなフィールドにアクセスする [#x6b27408]
たとえばインスタンス名instance のフィールド(Stringで変数名aField)にアクセスするには
 Class clazz = instance.getClass();
 Field field = clazz.getDeclaredField("aField");
 field.setAccessible(true);
 String answer = (String)field.get(instance));
で取得できる。[[ここ:http://www.javadeveloper.jp/members/general/Article.html?category=topic&article=tips&issue=015]]が参考になりました。

**<%@ page %> タグ内の意味。 [#j854efb6]
たとえば
 <%@ page contentType=text/html; charset=EUC-JP" pageEncoding="Shift_JIS" %>
とした場合、pageEncodingがソースコードの文字コード、contentTypeで指定できるのが出力文字コードです((JSP1.1の場合は、pageEncoding が使えないので、ページの文字コードと出力文字コードは同じになります。))。この場合はソースをShift_JISで書いて、EUC-JPで出力するってことですね。

** key=value&...の形式ではないPOSTリクエストの電文を取得する方法 [#ae1215cb]
requestからReaderを取得して、そこから文字を取得すればよいわけですね。
 BufferedReader reader = request.getReader();
 StringBuffer buffer = new StringBuffer();
 String line = null;
 while ((line = reader.readLine()) != null) {
   buffer.append(URLDecoder.decode(line));
   buffer.append("\n");
 }
 String reqMsg = new String(buffer);



**DOM2String [#f98f8729]

 ByteArrayOutputStream out = new ByteArrayOutputStream();
 try {
   TransformerFactory tfactory = TransformerFactory.newInstance();
   Transformer transformer = tfactory.newTransformer();
   transformer.setOutputProperty("encoding", encoding);
   transformer.transform(new DOMSource(document), new StreamResult(out));
 } catch (TransformerConfigurationException e) {
   logger_.error(e);
 } catch (TransformerException e) {
   logger_.error(e);
 }
 return out.toString();

**String2DOM [#h9052b8c]
例外処理はとりあえずおいといて
 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 DocumentBuilder builder = factory.newDocumentBuilder();
 StringReader stringReader = new StringReader(str); <- str: xmlの文字列
 InputSource inputSource = new InputSource(stringReader);
 return builder.parse(inputSource); <- Document

** ファイル書きだし(バイナリで)[#hdf7a70e]
 private void streamToFile(InputStream in, File file) throws IOException {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     byte[] b = new byte[1024];
     int j;
     while ((j = in.read(b)) != -1)
         baos.write(b, 0, j);
     byte[] pix = baos.toByteArray();
     write(pix, file);
 }

 private void write(byte[] b, File file) {
     BufferedOutputStream stream = null;
     try {
         FileOutputStream fstream = new FileOutputStream(file);
         stream = new BufferedOutputStream(fstream);
         stream.write(b);
     } catch (IOException e) {
         e.printStackTrace();
     } finally {
         if (stream != null) {
             try {
                 stream.close();
             } catch (IOException e1) {
                 e1.printStackTrace();
             }
         }
 
     }
 }



** ファイル書きだし(テキスト) [#y7921044]
 public boolean write(String log) {
   BufferedWriter writer = null;
   try {
     //第二引数がtrueなら追記、falseなら上書き。
     writer = new BufferedWriter(new FileWriter("./log.txt", true));
     writer.write(log, 0, log.length());
     writer.newLine();
   } catch (FileNotFoundException e) {
     e.printStackTrace();
     return false;
   } catch (IOException e) {
     e.printStackTrace();
     return false;
   } finally {
     try {
       if (writer != null) {
         writer.flush();
         writer.close();
       }
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
   return true;
 }

** あるディレクトリからの相対パスを計算して、他のディレクトリに連結したい。 [#qfc98245]
うまく説明できませんが、別のディレクトリに同じパス構成をコピーしたいときなどに使用できると思います。
  //たとえば "c:/temp", "c:/temp/fuga/aaaaa.txt", "d:/huge/hoho" に対して
  // d:/huge/hoho/fuga/aaaaa.txt としたい
  public static String trimAndConcat(String base, String path, String other) {
    URI uriBase = new File(base).toURI();
    URI uriPath = new File(path).toURI();
    URI uriRelativised = uriBase.relativize(uriPath);
    return new File(other, uriRelativised.toString()).getAbsolutePath();
  }

**URLからファイルパスへ。 [#d93417e6]
URLクラスからそのファイルまでのパスを取得する方法です。
 String path = new File(url.getPath()).getPath();
とやることで、
 URL : file:/C:/hoge/config/hoge.txt
 File: C:\hoge\config\hoge.txt
に変換ができます。((URLクラスをそのままtoStringすると、よけいな文字(file)がついちゃうんですよね。))((スペースなどが入っている場合のために、URLDecoder#decodeをかけねばっ))

**(たとえば)拡張子がxmlのファイルをリストする [#y61287c6]
 File mainDirectory = new File([ディレクトリ]);
 String[] files = mainDirectory.list(new FilenameFilter() {
   public boolean accept(File dir, String name) {
     if (name.endsWith("xml")) {
       return true;
     }
     return false;
   }
 });
filesが拡張子がxmlのファイル(ファイル名、の配列)


** 拡張子より後ろの文字列を取得する [#x1ca454f]
 String hoge="aaa.xml";
 hoge.substring(hoge.lastIndexOf('.'));
で.xmlが取得できる。

** 拡張子より前の文字列を取得する [#n90b832d]
 String hoge="aaa.xml";
 hoge.substring(0, hoge.indexOf('.'));
でaaaが取得できる。/etc/aaa.xml.bakとかには使えないけど。。


** Javaから、WEBブラウザを起動(Windowsのみ) [#p27aaf30]
 try {
 	Runtime.getRuntime().exec(
 		new String[] {
 			"rundll32.exe",
 			"url.dll,FileProtocolHandler",
 			"http://jp.sun.com/" });
 } catch (IOException e) {
 	e.printStackTrace();
 }
SWTから起動したい方は
[[こちら>SWT/TIPS集#ccfe5930]]

**WEBアプリケーションのルートを取得してパスを生成する [#c2d091c7]
 String root_path = this.getServletContext().getRealPath("/");
 String file_path = root_path + "hoge.dat"

** DOMオブジェクトをファイルに書き出す [#uf8d51a5]
 try {
 	TransformerFactory tfactory = TransformerFactory.newInstance();
 	Transformer transformer = tfactory.newTransformer();
 	//			transformer.setOutputProperty("encoding", "EUC-JP");
 	transformer.transform(new DOMSource(document), <-document : XMLのDOMです
 	//new StreamResult(System.out)); <- こっちだとコンソール出力
 	new StreamResult(new FileOutputStream(new File(output))));
 
 } catch (TransformerConfigurationException e) {
 	e.printStackTrace();
 } catch (TransformerFactoryConfigurationError e) {
 	e.printStackTrace();
 } catch (TransformerException e) {
 	e.printStackTrace();
 } catch (FileNotFoundException e) {
 	// TODO 自動生成された catch ブロック
 	e.printStackTrace();
 }

**JSPやServletのOutにDOMを書き出したい。 [#nd5a4674]

 public void write(HttpServletRequest request, HttpServletResponse response) {
 	response.setContentType("text/xml; charset=UTF-8");
 	try {
 		PrintWriter out = response.getWriter();
 		transformer.transform(new DOMSource(getDocument()),
 		new StreamResult(out));
 	} catch (IOException e) {
 	} catch (TransformerException e) {
 	}
 }


** Servletで、コンテンツタイプを指定する。 [#q2320937]
 response.setContentType("text/xml; charset=UTF-8");


**プロキシ越えとか、HttpConnection [#zaa38fb4]
#ref(http://www.masatom.in/cgi-bin/viewvc.cgi/*checkout*/FrameworkConnector/source/kino/framework/connector/Connector.java?rev=HEAD&content-type=text/plain&root=cvs)

 //プロキシ認証の記述方法
 BASE64Encoder encoder = new BASE64Encoder();
 urlConnection.setRequestProperty(
  "Proxy-Authorization",
  "Basic " + encoder.encode((userid + ":" + password).getBytes()));


**javaの実行 [#p089762b]
 >java -classpath ".;lib;classes;lib\log4j-1.2.8.jar;swt.jar" kino.swt.JavaDocSearchForm
 >java -classpath ".;lib;classes;lib\log4j-1.2.8.jar;swt.jar;lib\kino_javadocsearch.jar" 
  kino.swt.JavaDocSearchForm

 >java -classpath "クラスパス(セミコロン区切り)" クラス

[[このサイト:http://www.dmz.hitachi-sk.co.jp/Java/Tech/jre/execution.html]]よいかも。


**Javadoc書き方 [#se0aae76]
 @see	UserInformationManager#getUserInformation(String)
とすると、リンクが張られる。
 {@link	InformationController	InformationController}のファイル読み込みの実装です。
とか
 {@link クラス名#メンバ名 表示テキスト}
なんて使い方もできる

** コレクションを配列に変換 [#od8490a0]
 type: 型
 collection: コレクションクラス
 (type[]) collection.toArray(new type[collection.size()]);

** 配列をコレクションに変換 [#vba52599]
 fileList: Object[]型
 java.util.Arrays.asList(fileList);

** ファイルを読み込む [#qbe6ff1a]
 BufferedReader reader = null;
 try {
 	reader = new BufferedReader(new FileReader(path));
 	//もしくは
 	//new BufferedReader(
 	//  new InputStreamReader(url.openStream(), "JISAutoDetect"));
   
 	String line;
 	while ((line = reader.readLine()) != null) {
 		buffer.append(line);
 		buffer.append("\n");
 	}
 } catch (FileNotFoundException e) {
 	e.printStackTrace();
 } catch (IOException e) {
 	e.printStackTrace();
 } finally {
 	if (reader != null) {
 		try {
 			reader.close();
 		} catch (IOException e) {
 			e.printStackTrace();
 		}
 		reader = null;
 	}
 }

** Objectのシリアライズ [#sbe039ca]
 try {
 	//FileInputStreamオブジェクトの生成
 	FileInputStream inFile =
 		new FileInputStream([serializeしたファイル名]);
 
 	//ObjectInputStreamオブジェクトの生成 
 	ObjectInputStream inObject = new ObjectInputStream(inFile);
 
 	Object object = (クラス名) inObject.readObject();
 
 	inObject.close(); //オブジェクト入力ストリームのクローズ
 	inFile.close(); //ファイル入力ストリームのクローズ
 
 	//FileOutputStreamオブジェクトの生成
 	FileOutputStream outFile =
 		new FileOutputStream([書き出したいファイル名]);
 
 	//ObjectOutputStreamオブジェクトの生成 
 	ObjectOutputStream outObject = new ObjectOutputStream(outFile);
 
 	//クラスVectorのオブジェクトの書き込み
 	outObject.writeObject(object);
 
 	outObject.close(); //オブジェクト出力ストリームのクローズ
 	outFile.close(); //ファイル出力ストリームのクローズ
 
 } catch (FileNotFoundException e) {
 } catch (IOException e) {
 } catch (ClassNotFoundException e) {
 }

** オブジェクトが配列かどうかをチェックする [#s26aac0f]
 String model = "hogehoge";
 // String[] model = new String[] { "hogehoge", "hugahuga" };
 
 List list = new ArrayList();
 if (model.getClass().isArray()) {
     Object tmp = model;
     list = Arrays.asList((Object[]) tmp);
 } else {
     list.add(model);
 }
 System.out.println(list);

** インナクラス、無名クラス [#zd144d0a]
インナークラス・無名クラスは、フィールドにはアクセス可能、ローカル変数には不可能。

** finalなフィールドの初期化 [#fe672971]
宣言時に初期化する必要があるのかと思ってたんですが、コンストラクタ内でもよいんですね。知らなかった。


----
この記事は
#vote(おもしろかった[62],そうでもない[11])
#vote(おもしろかった[63],そうでもない[11])
-役に立ちました。 プレースフォルダ→プレースホルダ(place holder)? --  &new{2005-04-25 12:56:23 (月)};
-お恥ずかしい。なおしました。ありがとうございました。 -- [[きの]] &new{2005-04-25 16:39:01 (月)};
- ファイル アップロード --  &new{2010-07-06 (火) 14:14:42};
- いつも参考にしてます。 -- [[通りすがりのSE]] &new{2011-09-01 (木) 22:34:41};
- ハッシュ化のコードですが、md.digest()の後に、md.rest()呼んだ方がいいですね。 -- [[通りすがりのSE]] &new{2011-09-01 (木) 22:35:47};

#comment

#topicpath

SIZE(10){現在のアクセス:&counter;}

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS