【Java】byte型の自分メモ
2012-02-29 02:53:52 Wed
http://www.creativegear.jp/2011/05/09/java_byte_to_int/
http://d.hatena.ne.jp/simply-k/20100825/1282743815
http://d.hatena.ne.jp/vividcode/20091128/1259415771
// javaのbyteは-128(2進数1111 1111)~127(2進数0111 1111)の8ビット=1バイト
System.out.println(0xC8); // 10進数で200。2進数で11001000。
byte a = (byte)0xC8; // 縮小変換。
int b = (int)a; // byteをintに入れる。拡大変換。
System.out.println(b); // 200のはずが-56になる
int c = b & 0xFF; // おまじない
System.out.println(c); // 200になる。
// この挙動は単に符号なし2進数を符号あり2進数に変換すれば起こる。
// 例えば、「1100 1000」は符号なしでは10進数200だが、符号ありでは-56。
// 絶対値を取り出して符号を反転させれば望んでいる結果が得られそうだ。
// それが二項数値昇格と「1111 1111」とのAND演算を組み合わせる「おまじない」。
// 符号なし(のつもりの)2進数「1100 1000」はbyte型にしたときに既に負数で表現されている。
// 引用「符号付き整数値の整数型 T への拡大変換は,
// 単により長い桁を埋めるために整数値の2の補数表現について符号拡張をするだけとする」より
// 2進数「1100 1000」を二項数値昇格で拡大変換すると「1111 1111 1111 1111 1111 1111 1100 1000」となる。
// これに「0000 0000 0000 0000 0000 0000 1111 1111」とAND演算することで、
// 「0000 0000 0000 0000 0000 0000 1100 1000」となり、絶対値「1100 1000」を残しつつ符号だけを変換できた。
// これによって正数となったため、 目的の200が出力される。
// なお、10進数 4294967240 という数値は符号なし2進数で「1111 1111 1111 1111 1111 1111 1100 1000」となるが、
// int型もまた「4バイト符号付整数。-2147483648~2147483647」であり、10進数 4294967240 は表現できない。
int i = 255; // 16進数 0xFF、2進数 1111 1111
byte j = (byte) i; // 整数255をbyte型に縮小変換。
System.out.println((int) j); // 拡大変換。-1になる。
// 10進数255 は 2進数で 1111 1111 となる
// int型からbyteへ縮小したところでbyteは10進数 -1(2進数1111 1111)となる
こういう考え方というのは、どの言語でも変わらないものなんだろうな。
こういう感覚を多く知りたいと思います。
【Java】HttpClient4のコネクションタイムアウトとソケットタイムアウトの設定方法
2012-02-11 22:56:24 Sat
儘引用。
http://www.jiramot.info/how-to-set-timeout-in-apache-httpclient-4
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
HttpClient httpClient = new DefaultHttpClient(httpParams)
コネクションははじめのTCP/IPコネクション確立時のタイムアウト、
ソケットは実際のリクエストしてからレスポンスまでのタイムアウトです。
あと、毎度apacheのwebページってDLとかsampleとかわかりにくい。
HttpClientのusage exaple探してしばらく見つからなかったし。
なのでメモ。
http://hc.apache.org/httpcomponents-client-ga/examples.html
【Java】QuickJunitとMockitoを使ってみる
2012-02-07 00:18:02 Tue
■QuickJunit
今エディタでアクティブなクラスに対応する
テストクラスへ切り替えorテストクラス生成を行なってくれるEclipseプラグイン。
切り替えorテストクラス生成はCtrl + 9 です。
http://quick-junit.sourceforge.jp/
http://www.atmarkit.co.jp/fjava/rensai4/devtool16/devtool16_1.html
■MockitoとPowerMockとは?
モックを簡単に作成してUnitTestを効率化させてくれるライブラリ。
はじめは、うん?って思ったけどすげーよかった。
DBUnitとかJWebUnitはUnitTestとしては本質的ではないということが身にしみた。
例えばデータベースにアクセスするDAOクラスのメソッド、
戻り値がテーブルへのレコード追加件数だったとすると、
このメソッドの戻り値をモック化させておいてメソッド実行時にモックとして定義した戻り値を戻す
ということができます。
また、HTTP経由で他サーバのAPIを呼び出してJSONやXMLを取得するようなI/Oも
モック化させてモック化のときに定義してしたJSONやXMLを戻り値として戻するというこもできます。
その意味で、データベースなど各種ミドルウェアのINとOUTをモック化して
「本当」の単体テストを行うことができます。
MockitoとPowerMockの違いは、私の理解の範囲で言うと
- PowerMockはstaticメソッドをMock化できる
- PowerMockはMock化したstaticメソッドを評価できる
これが大きな違いだと思います。
違う、といってもPowerMock > Mockito で、
実際「powermock-mockito-junit」をDLすれば両方使えます。
誤解を恐れずに言うと、PowerMockはMockitoに機能追加するライブラリ、と言えるかと思います。
あと、PowerMockを使うようなしている方がおかしいと指摘されている方もおられました。
http://hikozaemonchan.blogspot.com/2009/05/mockito.html
何故ダメなのか今の私では理解できませんでした。
シングルトンとかファクトリーパターンを使うとどうしてもPowerMockのお世話になるかと思います。
■MockitoとPowerMockitoをDLする
DLは下記から「powermock-mockito-junit-1.4.11.zip」を選択する。
http://code.google.com/p/powermock/downloads/list
ここでしょうもなくハマったのが、easymock用とmockito用の2つがpowermockとして提供されていること。
mockitoを使っているのにeasymock用をDLして困ってしまった。
しょうもないハマりかたをしてしまいました…。
先程も述べましたが、「powermock-mockito-junit-1.4.11.zip」をDLすれば、
その中にMockito本体である「mockito-all-1.9.0.jar」も含まれています。
使い方は下記。
http://code.google.com/p/powermock/wiki/MockitoUsage13
http://d.hatena.ne.jp/mokkouyou2001/20110330/1301484814
■ハマったこと
ライブラリのところから躓いたワケですが、その後もハマりましたので対応をメモしておきます。
- PowerMockで使用する@RunWith(PowerMockRunner.class)と
PowerMockでstaticメソッドを持ちアクセスすることになるクラスを宣言する@PrepareForTest({Static1.class, Static2.class})は、
クラスレベルでアノテーションを付与する - @PrepareForTest({Static1.class, Static2.class})はstaticメソッドを持つクラスを列挙し、
これは配列型{clazz, clazz, clazz...}で宣言する - staticメソッドの実行回数確認(verify)は下記のステートメントで有効。
スタティックなメソッドごとに呼び出し回数を確認できる
verifyStatic(Mockito.times(1)); // 下記のメソッドの呼び出し回数の検証値を設定
Static1.staticMethod((java.sql.Connection)anyObject()); // 呼び出し回数を確認するメソッド - PowerMockではないMockitoのverifyは下記のようにする。
Mockito.verify(daoMock, Mockito.never()).insert((Entity)anyObject());
参考URL
http://tech.cm55.com/wiki/mockito/Manual
http://d.hatena.ne.jp/mokkouyou2001/20090721/1248164082
http://d.hatena.ne.jp/torutk/20101003/p3
http://d.hatena.ne.jp/Naotsugu/20101109/1289304795
【GoogleAppEngine】サーブレット処理内のデータをBlobstoreに登録する【BlobstoreService】【FileService】【URLFetch】
2012-01-11 02:17:17 Wed
■サーブレット処理内のデータをBlobstoreに登録する
前回記事の延長です。
やりたかったことは、リクエストパラメータで指定された外部URLを受け取り、
これをURLFetchして外部のバイナリデータを取得。
そして取得したバイナリデータをBlobstoreに格納すること。
これができそうで出来なくて困りましたが、結論、できます。
ただし、「experimental」がマークされており、2012/01/11 02:07:22現在、APIが廃止、互換性のない大幅変更される可能性もあります。
なお、参考にしたのは次のURLになります。
●参考
http://webcache.googleusercontent.com/search?q=cache:7UvAdoWK03kJ:d.hatena.ne.jp/knj77/20110414/1302781605+blobstore%E3%80%80%E7%9B%B4%E6%8E%A5%E4%BF%9D%E5%AD%98&cd=2&hl=ja&ct=clnk&gl=jp
http://d.hatena.ne.jp/a-know/20120105/1325764373
http://code.google.com/intl/en/appengine/docs/java/blobstore/overview.html#Writing_Files_to_the_Blobstore
http://www.programminglife.jp/2011/03/blobstore.html
■実装方法
単純な実装をしたので簡単にポイントをメモ。
URLFetchService service = URLFetchServiceFactory.getURLFetchService();
HTTPResponse res = service.fetch(new URL((String)map.get("filename")));
registBlob(res.getContent());
これはただURLFetchServiceを介して外部URLの画像ファイル(とは本来限らないが…)を取得しに行っています。
private BlobKey registBlob(byte[] bytes) throws IOException{
// Get a file service
FileService fileService = FileServiceFactory.getFileService();
// Create a new Blob file with mime-type "application/octet-stream"
AppEngineFile file = fileService.createNewBlobFile("image/jpeg");
// Open a channel to write to it
boolean lock = true;
FileWriteChannel writeChannel = fileService.openWriteChannel(file, lock);
// This time we write to the channel using standard Java
writeChannel.write(ByteBuffer.wrap(bytes));
// Now finalize
writeChannel.closeFinally();
return fileService.getBlobKey(file);
}
URLFetchServiceを介して取得した画像ファイル(画像ファイルと言いたければ、レスポンスヘッダを検証すべきだが…)のバイト配列を取得し、これをメソッドの第一引数として受け取り、
FileServiceを介してBlobstoreにバイナリデータを登録しています。
別に画像と限る必要はなく、ZIP圧縮したファイル、シリアライズしたクラスなどバイナリデータならなんでも格納できます。
FileWriteChannel#writeメソッドの引数にはjava.nioのByteBufferクラスを渡しています。
■サンプル
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import org.slim3.util.RequestMap;
import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
public class UploadExternalUrlController extends Controller {
@Override
public Navigation run() throws Exception {
RequestMap map = new RequestMap(request);
URLFetchService service = URLFetchServiceFactory.getURLFetchService();
HTTPResponse res = service.fetch(new URL((String)map.get("filename")));
registBlob(res.getContent());
BlobstoreService bservice = BlobstoreServiceFactory.getBlobstoreService();
String uploadUrl = bservice.createUploadUrl("/test/Upload");
BlobInfoFactory factory = new BlobInfoFactory();
Listblobs = new ArrayList ();
Iteratorite = factory.queryBlobInfos();
while(ite.hasNext()){
blobs.add(ite.next());
}
requestScope("upload_url", uploadUrl);
requestScope("blobs", blobs);
return forward("DataManager.vm");
}
private BlobKey registBlob(byte[] bytes) throws IOException{
// Get a file service
FileService fileService = FileServiceFactory.getFileService();
// Create a new Blob file with mime-type "application/octet-stream"
AppEngineFile file = fileService.createNewBlobFile("image/jpeg");
// Open a channel to write to it
boolean lock = true;
FileWriteChannel writeChannel = fileService.openWriteChannel(file, lock);
// This time we write to the channel using standard Java
writeChannel.write(ByteBuffer.wrap(bytes));
// Now finalize
writeChannel.closeFinally();
return fileService.getBlobKey(file);
}
}
【GoogleAppEngine】BlobstoreServiceとImageService
2012-01-08 16:30:45 Sun
修正箇所はBlobstoreへのファイルアップロード処理です。(2012/01/11 01:43:00 修正)
※※サーブレット内のデータをBlobstoreへ出力したいときはこちら。
■GoogleAppEngineでBlobstoreを使う
単にクライアントがバイナリファイル(多くの場合は画像ファイル)をアップロードして、
GAE側ではリクエストを受け取りそのままBlobstoreサービスにリクエストを渡せば
バイナリデータはBlobstoreに格納されます。
※環境
JDK1.6.24
GAE SDK1.6.1
GAE API v1.0
ライブラリにslim3とVelocityとJsonicを利用
簡単に書くと次のようなコード。
1.サーバ側でBlobstoreServiceからファイルのアップロード先URLを取得
BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
String uploadUrl = service.createUploadUrl("/test/Upload"); // Blobstoreへのアップロード成功時のコールバックURL
requestScope('uploadUrl', uploadUrl);
2.クライアント側HTMLでformに1のアップロード先URLをformタグのaction属性に指定
<form action=${uploadUrl} method="POST" enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="hidden" name="param1" value="value1">
<input type="submit" value="Submit">
</form>
アップロード処理はこれだけの記述で成功します。
BlobstoreへのファイルアップロードはサーブレットやCGIを介さずに直接行えるという点がメリットになります。
ただし、サーブレットやCGI内で作成したデータを出力するためには、ひと手間必要となります。
■リサイズ
Blobstoreに格納されている画像ファイルをリサイズして表示したい、
というときに使えるのがImageService.
一覧画面で画像サムネイルを表示するときとかに非常に便利。
実装は簡単。
private byte[] createImage(BlobKey blobKey, int width, int height){
ImagesService imagesService = ImagesServiceFactory.getImagesService();
Image oldImage = ImagesServiceFactory.makeImageFromBlob(blobKey);
Transform resize = ImagesServiceFactory.makeResize(width, height);
Image newImage = imagesService.applyTransform(resize, oldImage);
return newImage.getImageData();
}
ImageServiceを使用して上述の処理で得られるBlobkeyを使用してImageインスタンスを取得。(oldImage)
次にImagesServiceFactory.makeResize(width, height)でTransformインスタンスを取得。
最後にImageService#applyTransformでリサイズ後のImageインスタンスを取得。
あとは適当にレスポンスする。
サーブレットを使っているのならばimgタグのsrc属性で指定したサーブレット処理で次のようにすることでバイナリデータをレスポンスできる。
response.setContentType("image/jpeg");
ServletOutputStream os = response.getOutputStream();
os.write(createImage(blobKey, width, height));
■サンプル
適当に動作するサンプルを。
Viewを伴う処理はDataManagerControllerのみ。
あとはアップロード処理のUploadController、
オリジナル画像を返すFileServerController、
リサイズしたバイナリデータを返すGetResizeImageController.
画面はDataManager.vm
●DataManagerController
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
public class DataManagerController extends Controller {
@Override
public Navigation run() throws Exception {
BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
String uploadUrl = service.createUploadUrl("/test/Upload");
BlobInfoFactory factory = new BlobInfoFactory();
Listblobs = new ArrayList ();
Iteratorite = factory.queryBlobInfos();
while(ite.hasNext()){
blobs.add(ite.next());
}
requestScope("upload_url", uploadUrl);
requestScope("blobs", blobs);
return forward("DataManager.vm");
}
}
●UploadController
import java.util.Map;
import java.util.logging.Logger;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
public class UploadController extends Controller {
private BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
Logger logger = Logger.getLogger(this.getClass().getName());
@Override
public Navigation run() throws Exception {
Mapblobs = service.getUploadedBlobs(request);
for(String fileTag : blobs.keySet()){
logger.info(String.format("uploaded: %s, key = %s", fileTag, blobs.get(fileTag).getKeyString()));
}
return redirect("/test/DataManager");
}
}
●FileServerController
import java.util.logging.Logger;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
public class FileServerController extends Controller {
private BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
Logger logger = Logger.getLogger(this.getClass().getName());
@Override
public Navigation run() throws Exception {
BlobKey blobKey = new BlobKey(request.getParameter("blob-key"));
String delete = request.getParameter("delete");
if(delete != null && delete.equals("true")){
service.delete(blobKey);
return redirect("/test/DataManager");
} else {
// 以下はどちらでも画像データをレスポンスすることができます。
// BlobstoreServiceでレスポンスする方法
// service.serve(blobKey, response);
// return null;
// ImageServiceでレスポンス(リダイレクト)する方法
ImagesService imagesService = ImagesServiceFactory.getImagesService();
String url = imagesService.getServingUrl(blobKey);
return redirect(url);
}
}
}
●GetResizeImageController
import javax.servlet.ServletOutputStream;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;
public class GetResizeImageController extends Controller {
@Override
public Navigation run() throws Exception {
BlobKey blobKey = new BlobKey(request.getParameter("blob-key"));
int width = Integer.valueOf(request.getParameter("width"));
int height = Integer.valueOf(request.getParameter("height"));
super.response.setContentType("image/jpeg");
ServletOutputStream os = super.response.getOutputStream();
os.write(createThumb(blobKey, width, height));
return null;
}
private byte[] createThumb(BlobKey blobKey, int width, int height){
ImagesService imagesService = ImagesServiceFactory.getImagesService();
Image oldImage = ImagesServiceFactory.makeImageFromBlob(blobKey);
Transform resize = ImagesServiceFactory.makeResize(width, height);
Image newImage = imagesService.applyTransform(resize, oldImage);
return newImage.getImageData();
}
}
●DataMangaer.vm
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset=utf-8 />
<title>Test</title>
<script type="text/javascript" src="/common/js/jquery.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
<span style="font-size: 200%"> Uploaded Blobs </span>
<table summary="" rules="all" cellpadding="5">
<tr align="center" bgcolor="lightgray">
<th width="100"></th>
<th width="200">ファイル名</th>
<th width="140">Content Type</th>
<th width="80">サイズ</th>
<th width="200">アップロード時刻</th>
<th width="50">削除</th>
</tr>
#foreach(${blob} in ${blobs})
<tr align="right">
<td><img src="/test/GetResizeImage?blob-key=${blob.getBlobKey().getKeyString()}&width=120&height=90" alt="thumbnail"></td>
<td><a href="/test/FileServer?blob-key=${blob.getBlobKey().getKeyString()}">${blob.filename}</a></td>
<td>${blob.contentType}</td>
<td>${blob.size}</td>
<td>${_datetimeFormat.format(${blob.creation})}</td>
<td><a href="/test/FileServer?blob-key=${blob.getBlobKey().getKeyString()}&delete=true">DEL</a></td>
</tr>
#end
</table>
<hr>
<form action="${upload_url}" method="POST" enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="hidden" name="param1" value="value1">
<input type="submit" value="Submit">
</form>
<p><a href="/">トップに戻る</a></p>
</body>
</html>