tokuhirom's Blog

jetty で vhost でいい感じにアプリケーション動かしていく

jetty で vhost 使う方法みたいな話が、意外と情報ない。

例えば、web 画面と admin 画面があるようなサイトで、実際には vhost を利用して運用したいという場合、一般的な ide や servlet container の想定では PATH_INFO でアプリケーションを切り替えて頑張る、みたいなのが多いのだが、こういったアプローチはあまり現代的ではないと思う。

named vhost でやりたいよ!!

最近、以下のような構造のでアプリケーションを構築している。

- pom.xml
+ common ← jar
  - pom.xml
+ admin ← war
  - pom.xml
  - src/main/webapp/WEB-INF/web.xml
+ web   ← war
  - pom.xml
  - src/main/webapp/WEB-INF/web.xml

このような状況で、local で開発したいというシナリオだと思いねえ。

ってわけで、jetty でやるには、vhost を設定したWebAppContext を HandlerCollection に詰め込んでハンドラとして設定すればよろしい。

private Server startServer(int port) throws Exception {
	Server server = new Server(port);
	HandlerCollection handler = new HandlerCollection();
	for (final String module : Arrays.asList("web", "admin")) {
		handler.addHandler(createContext(module));
	}
	server.setHandler(handler);
	server.start();
	return server;
}

それで、WebAppContext は以下のような形で作れば、IntelliJ から起動する分には意外といい感じに動く。mvn exec:java からだとなんかうまくイカなくて困ってるけど。。本当は war を作って explode したほうが正しいが、そのへん工夫してる暇ないのでこういう感じになっている。

private WebAppContext createContext(String module) throws Exception {
	String descriptorPath = appBase + "/" + module + "/src/main/webapp/WEB-INF/web.xml";
	if (!new File(descriptorPath).exists()) {
		log.error("There is no {}", descriptorPath);
		throw new RuntimeException("Invalid descriptor path: " + descriptorPath);
	}

	String resourcePath = appBase + "/" + module + "/src/main/webapp/";
	if (!new File(resourcePath).exists()) {
		log.error("There is no {}", resourcePath);
		throw new RuntimeException("Invalid resourcePath " + resourcePath);
	}

	String hostname = module + "-proj.example.com";

	log.info("Starting {} server: {}, {}, {}", module, descriptorPath, resourcePath, hostname);

	WebAppContext context = new WebAppContext();
	context.setDescriptor(descriptorPath);
	context.setResourceBase(resourcePath);
	context.setContextPath("/");
	context.setParentLoaderPriority(true);
	context.setVirtualHosts(new String[] {hostname});
	return context;
}