ASP.NETを利用していると
static HttpContext HttpContext.Current からリクエスト情報を取得して
IPADDRESS等の情報をどこででも取得することができます
似たような意識でJavaで実装していると
どうしてもHttpServletRequestの取得でつまずいてしまいます。
そこで、スレッド毎に値を保持するThreadLocalを利用して
HttpServletRequest をスレッド内で参照できるようにします
private final static ThreadLocal<HttpServletRequest> servletRequests = new ThreadLocal<HttpServletRequest>();
public static void setServletRequest(HttpServletRequest request) {
servletRequests.set(request);
}
public static HttpServletRequest getServletRequest() {
return servletRequests.get();
}
もちろん非同期な実装では参照できなくなる(かな?)
リクエスト初期化時にセットする必要があります。
リクエスト終了後はガベージコレクション対象になります。
2013年1月4日金曜日
Logbackメモ
Logback を利用してログ出力しているのですが、
これまでサンプルのままだったのを少し見直しました。
次のような要件を満たすように変更、
1.レベルがエラーの場合にメールで送信する
2.ファイル出力、日毎、100M毎 にローリング
main/resource/logback.xml :
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<configuration debug="true" scan="true" scanPeriod="30 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</appender>
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<smtpHost>smtp.gmail.com</smtpHost>
<smtpPort>587</smtpPort>
<STARTTLS>true</STARTTLS>
<username>[YOUR_NAME]@gmail.com</username>
<password>[YOUR_PASSWORD]</password>
<to>[TO]</to> <!-- additional destinations are possible -->
<from>[FROM]</from>
<subject>TESTING: %logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.PatternLayout">
<charset>UTF-8</charset>
<Pattern>[%-5level][%d{yyyy-MM-dd HH:mm:ss.SSS}] %class - %msg%n</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logFile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>logFile.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<charset>UTF-8</charset>
<Pattern>[%-5level][%d{yyyy-MM-dd HH:mm:ss.SSS}] %class - %msg%n</Pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
<appender-ref ref="EMAIL" />
</root>
</configuration>
SMTPAppenderを利用してメールを送信します。
サンプルではGMAILで送信する設定にしています。
メールで送信する場合はLevelFilterを利用してERRORの場合のみ送信するようにしています。
File出力に関しては、ここのサンプルのままです。
File出力がネックになりそうな場合は、下のAsyncAppenderをFileAppenderの
前に挟んでAsync処理にする。
SMTPはAsyncで送信されているようなので気にしない 。
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
アクセスログを出力したい場合は、ここを参照する
2013年1月3日木曜日
jetty maven gzipフィルター適用
maven上のjetty plugin でgzip を適用する方法。
このあたりの内容です。
http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin#Using_GZip_Compression_and_Other_Jetty_Extensions
pom.xmlのプラグイン設定にdependancyを追加
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId> <version>8.1.8.v20121106</version>
<configuration>
[...]
</configuration>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>8.1.8.v20121106</version>
</dependency>
</dependencies>
web.xmlにgzipフィルターを定義
<filter>
<filter-name>GzipFilter</filter-name>
<filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
<init-param>
<param-name>mimeTypes</param-name>
<param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>GzipFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
pom.xmlにdependancyを追加していないと
ClassNotFoundExceptionで怒られます
このあたりの内容です。
http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin#Using_GZip_Compression_and_Other_Jetty_Extensions
pom.xmlのプラグイン設定にdependancyを追加
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId> <version>8.1.8.v20121106</version>
<configuration>
[...]
</configuration>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>8.1.8.v20121106</version>
</dependency>
</dependencies>
web.xmlにgzipフィルターを定義
<filter>
<filter-name>GzipFilter</filter-name>
<filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
<init-param>
<param-name>mimeTypes</param-name>
<param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>GzipFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
pom.xmlにdependancyを追加していないと
ClassNotFoundExceptionで怒られます
2012年12月28日金曜日
Jersey (JAX-RS) での JSON 取り扱いTIPS
JerseyはレスポンスとしてXMLを前提にしていて
JSON扱おうとするとたまに問題が起こるのでその対応をメモ
1.Listに要素がひとつしかないとArrayではなくObject渡してくる
このあたり参考にして、サーブレットを登録しているパッケージ中に
@Providerを定義する
http://tugdualgrall.blogspot.jp/2011/09/jax-rs-jersey-and-single-element-arrays.html
2.…to be continued
もしくは、stackoverflowにJSONパーサをJacksonに変更する方法が乗っていたので
これを利用すると全て解決しそう(うまく動かなかった)
how-can-i-customize-serialization-of-a-list-of-jaxb-objects-to-json
追記:
JSONの扱いは上記の方法を取る必要はなく、POJOMappingFeatureを利用すればいいもよう
Web.xmlのサーブレット定義に追加します
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
JSON扱おうとするとたまに問題が起こるのでその対応をメモ
1.Listに要素がひとつしかないとArrayではなくObject渡してくる
このあたり参考にして、サーブレットを登録しているパッケージ中に
@Providerを定義する
http://tugdualgrall.blogspot.jp/2011/09/jax-rs-jersey-and-single-element-arrays.html
2.…to be continued
もしくは、stackoverflowにJSONパーサをJacksonに変更する方法が乗っていたので
これを利用すると全て解決しそう(うまく動かなかった)
how-can-i-customize-serialization-of-a-list-of-jaxb-objects-to-json
追記:
JSONの扱いは上記の方法を取る必要はなく、POJOMappingFeatureを利用すればいいもよう
Web.xmlのサーブレット定義に追加します
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
2012年12月23日日曜日
wine on mac でつまづいたこと
wineでアプリをインストールするにはwinetricksを利用するのですが
winetricksの挙動がおかしく、アプリ選択してインストールしようとしても
一向に先に進まない現象が起こっていました。
解決方法というか回避策としてコンソールからインストールしました。
1.winetricksで対象のアプリの一覧を取得する
winetricks apps list | grep -i "hoge"
2. 取得したアプリ名を指定してインストール
winetricks hoge
#手動でX window 入れた後にwine入れて競合してるのが問題なのだろうか
winetricksの挙動がおかしく、アプリ選択してインストールしようとしても
一向に先に進まない現象が起こっていました。
解決方法というか回避策としてコンソールからインストールしました。
1.winetricksで対象のアプリの一覧を取得する
winetricks apps list | grep -i "hoge"
2. 取得したアプリ名を指定してインストール
winetricks hoge
#手動でX window 入れた後にwine入れて競合してるのが問題なのだろうか
2012年12月9日日曜日
Java 重み付けランダム抽選
車輪の再発明かもしれませんが、
重み付けをしたランダム抽選ロジック作ったので共有
package org.chikishe.Util;
import java.util.ArrayList;
import java.util.Collection;
public class RandomUtil {
@SuppressWarnings("unchecked")
public static <T> T weightedRandom(Collection<T> resource,
Weight<T> delegate) throws Exception {
ArrayList<WeightCompare> weightedResource = new ArrayList<WeightCompare> ();
int totalWeight = 0;
for (T temp : resource) {
int weight = delegate.getWeight(temp);
if (weight <= 0)
continue;
totalWeight += weight;
weightedResource.add(new WeightCompare(temp, totalWeight));
}
if (totalWeight <= 0)
throw new Exception("No Resource");
int random = randomNext(1, totalWeight + 1);
int lower = -1;
int upper = weightedResource.size();
while (upper - lower > 1) {
int index = (lower + upper) / 2;
if (weightedResource.get(index).weight >= random) {
upper = index;
} else {
lower = index;
}
}
return (T) weightedResource.get(upper).obj;
}
public static int randomNext(int from, int to) {
return (int) (Math.random() * (to - from) + from);
}
public interface Weight<T> {
int getWeight(T temp);
}
private static class WeightCompare {
private Object obj;
private int weight;
public WeightCompare(Object obj, int weight) {
this.obj = obj;
this.weight = weight;
}
}
}
呼び出しは、次のようになります。
public String getTest4() {
ArrayList<TestMember> members = new ArrayList<TestMember>();
members.add(new TestMember(1, 50));
members.add(new TestMember(2, 80));
members.add(new TestMember(3, 130));
try {
TestMember member = RandomUtil.weightedRandom(members,
new Weight<TestMember>() {
public int getWeight(TestMember m) {
return m.weight;
}
});
return "" + member.id;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new WebApplicationException(500);
}
}
private class TestMember {
public int id;
public int weight;
public TestMember(int id, int weight) {
this.id = id;
this.weight = weight;
}
}
RandomUtil.weightedRandomはジェネリック型を受け取るようにしているので
第1引数のリストに指定した型を返します。
第2引数には重み付けを与えるメソッドの定義を渡しています。
サンプルの場合は、リストのTestMemberクラスのweightを重みとして取得しています。
ジェネリックの使い方がようやくわかってきた。
追記
2014/01/* Java 8でのラムダ式を使った使用方法はこちら
重み付けをしたランダム抽選ロジック作ったので共有
package org.chikishe.Util;
import java.util.ArrayList;
import java.util.Collection;
public class RandomUtil {
@SuppressWarnings("unchecked")
public static <T> T weightedRandom(Collection<T> resource,
Weight<T> delegate) throws Exception {
ArrayList<WeightCompare> weightedResource = new ArrayList<WeightCompare> ();
int totalWeight = 0;
for (T temp : resource) {
int weight = delegate.getWeight(temp);
if (weight <= 0)
continue;
totalWeight += weight;
weightedResource.add(new WeightCompare(temp, totalWeight));
}
if (totalWeight <= 0)
throw new Exception("No Resource");
int random = randomNext(1, totalWeight + 1);
int lower = -1;
int upper = weightedResource.size();
while (upper - lower > 1) {
int index = (lower + upper) / 2;
if (weightedResource.get(index).weight >= random) {
upper = index;
} else {
lower = index;
}
}
return (T) weightedResource.get(upper).obj;
}
public static int randomNext(int from, int to) {
return (int) (Math.random() * (to - from) + from);
}
public interface Weight<T> {
int getWeight(T temp);
}
private static class WeightCompare {
private Object obj;
private int weight;
public WeightCompare(Object obj, int weight) {
this.obj = obj;
this.weight = weight;
}
}
}
呼び出しは、次のようになります。
public String getTest4() {
ArrayList<TestMember> members = new ArrayList<TestMember>();
members.add(new TestMember(1, 50));
members.add(new TestMember(2, 80));
members.add(new TestMember(3, 130));
try {
TestMember member = RandomUtil.weightedRandom(members,
new Weight<TestMember>() {
public int getWeight(TestMember m) {
return m.weight;
}
});
return "" + member.id;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new WebApplicationException(500);
}
}
private class TestMember {
public int id;
public int weight;
public TestMember(int id, int weight) {
this.id = id;
this.weight = weight;
}
}
RandomUtil.weightedRandomはジェネリック型を受け取るようにしているので
第1引数のリストに指定した型を返します。
第2引数には重み付けを与えるメソッドの定義を渡しています。
サンプルの場合は、リストのTestMemberクラスのweightを重みとして取得しています。
ジェネリックの使い方がようやくわかってきた。
追記
2014/01/* Java 8でのラムダ式を使った使用方法はこちら
java でのmemcached ラッパー
Javaでmemcachedを利用する際に、
1.キーからオブジェクトget
2.オブジェクトがnullならデータ取得
3.2で取得したデータをmemcachedにset
というのは割りとよくある一連の実装だと思います。
前職でC#を使っているときはdelegate(ラムダ式)を使って
1つのメソッドで一連の処理を実装していました。
Javaでも同じように実装してみます。
Delegateはこんなかんじでいいのかな…
Delegate interfaceを定義、そのgetメソッドから取得するように。
public class Memcached {
protected static MemCachedClient mcc = new MemCachedClient();
static {
SockIOPool pool = SockIOPool.getInstance();
//設定
pool.initialize();
}
public static <T> T get(String key, Memgetable<T> delegate, Date expire){
Object ret = null;
ret = mcc.get(key);
if (ret != null) return ret;
ret = (T) delegate.get();
if (ret == null) return null;
mcc.set(key, ret, expire);
return ret;
}
public interface Memgetable<T> {
public T get();
}
}
呼び出しは、
String key = "test_key";
final String value = "test_value";
Memcached.get(key, new Memgetable<String>() {
public String get() {
return value;
}
}, new Date());
こんなかんじで、一行で出来ます。
Delegate interfaceにgetメソッドを定義し値がなければメソッドから値を取得します。
ラムダ式周りはC#が素晴らしすぎてJavaの非力さが露呈してしまう。。
Java 8ではもっと楽に実装できるようになるのかしら。
1.キーからオブジェクトget
2.オブジェクトがnullならデータ取得
3.2で取得したデータをmemcachedにset
というのは割りとよくある一連の実装だと思います。
前職でC#を使っているときはdelegate(ラムダ式)を使って
1つのメソッドで一連の処理を実装していました。
Javaでも同じように実装してみます。
Delegateはこんなかんじでいいのかな…
Delegate interfaceを定義、そのgetメソッドから取得するように。
public class Memcached {
protected static MemCachedClient mcc = new MemCachedClient();
static {
SockIOPool pool = SockIOPool.getInstance();
//設定
pool.initialize();
}
public static <T> T get(String key, Memgetable<T> delegate, Date expire){
Object ret = null;
ret = mcc.get(key);
if (ret != null) return ret;
ret = (T) delegate.get();
if (ret == null) return null;
mcc.set(key, ret, expire);
return ret;
}
public interface Memgetable<T> {
public T get();
}
}
呼び出しは、
String key = "test_key";
final String value = "test_value";
Memcached.get(key, new Memgetable<String>() {
public String get() {
return value;
}
}, new Date());
こんなかんじで、一行で出来ます。
Delegate interfaceにgetメソッドを定義し値がなければメソッドから値を取得します。
ラムダ式周りはC#が素晴らしすぎてJavaの非力さが露呈してしまう。。
Java 8ではもっと楽に実装できるようになるのかしら。
登録:
投稿 (Atom)