PebbleをApache経由で使う。
8080は、メンテ用にローカルからしかアクセスできないポートとして残し、Apacheから、8009経由でTomcatにアクセスする。しかし、Apache経由でアクセスした場合に、Pebbleが出力する、baseタグが、なぜかhttp://192.168.0.250:8080のようになってしまい、ページ中のリンクが、8080経由にされてしまう。
HttpServletRequest.getServerPort()の結果は80だった。どこで、8080なんて値を仕入れているんだろう。
あった、BlogLookupFilterでやっている模様。
String url = pebbleContext.getConfiguration().getUrl();
if (pebbleContext != null && (url == null || url.length() == 0)) {
String scheme = httpRequest.getScheme();
url = scheme + "://" + httpRequest.getServerName() + ":" + httpRequest.getServerPort() + httpRequest.getContextPath();
log.info("Setting Pebble URL to " + url);
PebbleContext.getInstance().getConfiguration().setUrl(url);
}
ん〜、そもそもスレッドセーフとか考えていないような... というか、これシングルトンだから、先に来たやつを覚えて、ずっと使い回しちゃうじゃん。
さて、どうするか... まずは以下の戦略を試してみる。
PebbleContextをスレッドローカルに持たせ、シングルトンはやめてリクエストごとにUrlを設定させる。
まずは、PebbleContextをちょっといじって、
// private static final PebbleContext instance = new PebbleContext();
static final ThreadLocal<PebbleContext> instance = new ThreadLocal<PebbleContext>() {
@Override protected PebbleContext initialValue() {
return new PebbleContext();
}
};
public static PebbleContext getInstance() {
// return instance;
return instance.get();
}
BlogLookupFilterを修正。
PebbleContext pebbleContext = PebbleContext.getInstance();
AbstractBlog blog;
String url = pebbleContext.getConfiguration().getUrl();
// if (pebbleContext != null && (url == null || url.length() == 0)) {
String scheme = httpRequest.getScheme();
url = scheme + "://" + httpRequest.getServerName() + ":" + httpRequest.getServerPort() + httpRequest.getContextPath();
log.info("Setting Pebble URL to " + url);
PebbleContext.getInstance().getConfiguration().setUrl(url);
// }
pebbleContextがnullになるわけないから、if文自体を削除。そして、ぬるぽ。
12:54:37,310 ERROR [[jsp]] サーブレット jsp のServlet.service()が例外を投げました java.lang.NullPointerException at net.sourceforge.pebble.web.filter.BlogLookupFilter.doFilter(BlogLookupFilter.java:91) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)以下の行で発生している模様。
String url = pebbleContext.getConfiguration().getUrl();
pebbleContextがnullになるわけないんだから、getConfiguration()がnullなんでしょう。これを、設定しているのは、、、PebbleContextListenerみたい。
Configuration config = (Configuration)applicationContext.getBean("pebbleConfiguration");
DAOFactory.setConfiguredFactory(config.getDaoFactory());
PebbleContext ctx = PebbleContext.getInstance();
ctx.setConfiguration(config);
これが呼ばれていないんかなぁ。あ、そうか、このConfigurationは全スレッドに見えないといけないのに、これじゃ、たまたま実行したスレッドにしか設定されないじゃん。とりあえず、ServletContextListenerとして、アプリケーション起動時に一度呼ばれるだけみたいなんで、PebbleContextを以下のように応急処置。
// private Configuration configuration;
static volatile Configuration configuration;
...
// private String webApplicationRoot;
static volatile String webApplicationRoot;
...
public void setConfiguration(Configuration conf) {
// this.configuration = configuration;
configuration = conf;
}
...
public void setWebApplicationRoot(String root) {
// this.webApplicationRoot = webApplicationRoot;
webApplicationRoot = root;
}
動いた!。ちゃんとポート80経由で行った場合も8080経由で行った場合もうまく行くようになった。そろそろ本番サーバも切り替えて大丈夫そうかな。








