実行可能warをmavenで作る場合、
warパッケージの直下にmainファイルを配備する必要がある。
しかし、warアプリケーションをpackageすると、
WEB-INF/classes以下にmainファイルも配備されてしまう。
そのため、maven3では、
antrunプラグインを用いて、mainファイルを移動する必要がある。
pom.xmlはこんな感じかな。
< plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-antrun-plugin</ artifactId > < executions > < execution > < id >move-main</ id > < phase >prepare-package</ phase > < configuration > < tasks > < move todir = "target/${project.build.finalName}" > < fileset dir = "target/classes" > < include name = "app/AppMain.class" /> </ fileset > </ move > </ tasks > </ configuration > < goals > < goal >run</ goal > </ goals > </ execution > </ executions > </ plugin > |
これにより、warファイル直下に実行可能クラスが配備される。
また、jettyなどのembedを組み込む場合、
一緒に依存関係も持って行ってやる必要がある。
こんな感じ。
< plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-dependency-plugin</ artifactId > < executions > < execution > < id >jetty-classpath</ id > < phase >prepare-package</ phase > < goals > < goal >unpack-dependencies</ goal > </ goals > < configuration > < includeGroupIds >org.eclipse.jetty,javax.servlet,javax.websocket</ includeGroupIds > < excludes >META-INF/ECLIPSEF.*</ excludes > < outputDirectory >${project.build.directory}/${project.build.finalName}</ outputDirectory > </ configuration > </ execution > </ executions > </ plugin > |
そして、mainファイルはこんな感じ。
package app; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; import java.net.URL; public class AppMain { public static void main(String[] args) throws Exception { // 初期設定 int port = 8080 ; System.setProperty( "prefix" , "/" ); // サーバ生成 Server server = new Server(port); // warを読み込むコンテクスト生成 URL warUrl = AppMain. class .getProtectionDomain().getCodeSource().getLocation(); String warLocation = warUrl.toExternalForm(); WebAppContext context = new WebAppContext(); context.setWar(warLocation); context.setContextPath( "/" ); // コンテクストにサーバをセットする // ※重要 context.setServer(server); // websocketを使えるようにする WebSocketServerContainerInitializer.configureContext(context); // 開始 server.setHandler(context); server.start(); server.join(); } } |
上記が非常に重要。
これで、websocketのendpointをServletContextListener側で指定してやるとうまくいく。
package app; import websocket.WebsocketIndex; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.websocket.DeploymentException; import javax.websocket.server.ServerContainer; public class AppInitializeListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { // embed用のwebsocketの追加 try { ServerContainer wsContainer = (ServerContainer) sce.getServletContext().getAttribute(ServerContainer. class .getName()); System.out.println(String.format( "wsContainer => %s" , wsContainer)); if (wsContainer != null ) { wsContainer.addEndpoint(WebsocketIndex. class ); } } catch (DeploymentException e) { e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent sce) { } } |
実行可能jarでwebsocketを作成する場合、
mainクラス内でendpointを設定してやればよいのだが、
実行可能warの場合、
mainクラスが実際のwebsocketのendpointのクラスの配備位置が異なるため、
クラスのロードが出来ない状態となる。
そのため、上記のような方法で、動的に指定してやることで、
実行可能warにおいて、websocketが利用できる。
【参考】
・実行可能warの生成の詳細がかかれています。
http://qiita.com/k_ui/items/1d3bbbd7993c4c9adf71
・実行可能jarでのwebsocketの設定方法が書かれています。
以上