RWT / RAP + Jetty + JAX-WS統合

RAP / RCPアプリケーションの開発時に問題が発生しました。カスタムエラーページを作成し、それらを組み込み桟橋に統合する方法です。 Jettyをアプリケーションに組み込む場合の方法については、インターネット上に多くのチュートリアルがあります。 しかし、RWTを使用すると、事態はさらに複雑になります。 RWT自体がJettyを起動し、管理サービスとして開始します。 同時に、Jettyインターフェース自体は他のバンドルから隠されており、直接動作しません。

さらに少し進んで、機能を拡張して、RWTアプリケーションに組み込まれているJettyでサーブレットを実行することにしました。 そして、最も重要なこととして、JAX-WS Webサービスもそこに統合します。 同情的、猫へようこそ。







アプリケーションがOSGiプラットフォームから起動されることを暗示しています。



まず、ドキュメントから、Jettyカスタマイザーを作成し、システムプロパティの名前を渡して、カスタマイズできることがわかっています。 やってみましょう:アプリケーション全体を実行すると、合格します



-Dorg.eclipse.equinox.http.jetty.customizer.class = en.futurelink.jetty.customizer.MyJettyCustomizer



カスタマイザーコード:



public class MyJettyCustomizer extends JettyCustomizer { @Override public Object customizeContext(Object context, Dictionary<String, ?> settings) { ServletContextHandler c = (ServletContextHandler) context; // ,   c.getServletHandler().addServletWithMapping( MyFileServlet.class, "/files/*"); // ,  - JAX-WS // import com.sun.xml.ws.transport.http.servlet.WSServlet; c.getServletHandler().addServletWithMapping( WSServlet.class, "/service/mobile"); // -   ErrorHandler errorHandler = new MyJettyErrorHandler(); errorHandler.setShowStacks(true); c.setErrorHandler(errorHandler); //  - JAX-WS (  ) c.getServletContext().getContextHandler(). addEventListener(new MyServletContextListener()); return c; } }
      
      





ここでは次のことを行います。

1)特定のURLによると、いくつかのサーブレットをMapimで利用できるようになりました。ここではすべてが簡単です。

2)エラーページのカスタムハンドラーをインストールします。

3)JAX-WS Webサービスサービスを追加します。これについては、最後にさらに詳しく説明します;)



最初の段落ですべてが明確でシンプルな場合-サーブレットを作成し、それをURLにマッピングして使用可能にすると、2番目のコードはハンドラコードの例を必要とします。



 public class MyJettyErrorHandler extends ErrorHandler { @Override protected void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message) throws IOException { if (code == 404) { writer.write("No,no,no!!! This page does not exist!"); return; } super.handleErrorPage(request, writer, code, message); } }
      
      





これで、必要な方法でHTTP応答コードを処理できます。



面白いことに、JAX-WSをRWTアプリケーションに統合しています。 ここでの問題は、Webサービス自体を実装するときに発生します。 WEB-INF / sun-jaxws.xmlに配置されるXML記述を作成する必要があります。



 <?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="ClientService" implementation="ru.futurelink.mo.mobile.server.ClientService" url-pattern="/service/mobile"/> </endpoints>
      
      





しかし、アプリケーションはこの記述ファイルを参照してこれらのエンドポイントを作成することを望みません。 また、ランタイムでエンドポイントを作成するためにJAX-WSに提案されている標準ソリューションは、別のWebサーバーcom.sun.net.httpserverを生成するため、適切ではありません。 別のポートに吊るす必要があり、実際、なんとなく不器用です。 既存のJettyを使用してWebサービスのリクエストを処理する別のソリューションが必要です。



Webサービスへのリクエストを処理するサーブレット自体を既に追加しましたが、動作するようにエンドポイントが必要になりました。 ただし、プロジェクトはOSGiフレームワークで動作するため、JAX-WSを作成したばかりの記述ファイルは表示されません。 問題は、JAX-WSはOSGi互換のバンドルではないということです。ただし、単純なJARからバンドルに再パッケージし(そうすることを望みます)、マニフェストを追加しました。 OSGiのスタイルですべてを正しく行いながら、彼にこのファイルを食べさせる必要があります。



カスタマイザー全体をorg.eclipse.equinox.http.jettyホストへのフラグメントにパックします。 ご存知のように、これはフラグメントがクラスパスを拡張するために必要です。これにより、ホストはフラグメントのクラスパスから独自のパーツを見つけて読み込むことができます。 通常のデフォルトのcom.sun.net.httpserverの代わりに、JAX-WSにHTTPトランスポートとしてjettyを使用するように強制します。



次に、 com / sun / xml / ws / transport / http / servletから、JAX-WSからいくつかのクラスを取得します(残念ながら、このパッケージのアーキテクチャでは正しく継承できないため、すべてを再定義する必要があります)。 以下に例を示します。



 public final class WSServletContextListener {…}
      
      





なぜ彼らがこれをしたのかわかりません...今、JAX-WSの一部をフラグメントに書き換える必要があります。 上書きされたファイルはgithubで見つけることができます: github.com/futurelink/habrahabr



合計で、4つのクラスが必要です。

WSServletContextListener-MyServletContextListener、

ServletResourceLoader-MyServletResourceLoader、

ServletContainer-MyServletContainer、

DeploymentDescriptorParser-MyDeploymentDescriptorParser



WSServletContextListenerの1行のコードを変更するために、これらすべてを必要としました。



 static final String JAXWS_RI_RUNTIME = "/WEB-INF/sun-jaxws.xml";
      
      





次のものに置き換えられます:



 static final String JAXWS_RI_RUNTIME = "/META-INF/sun-jaxws.xml";
      
      





問題は、JAX-WSの新しいバージョンのデプロイメントでは、このフラグメントを正常に機能させるためにこのフラグメントに従う必要があることです。 しかし、私はJettyに統合する別の方法を見つけませんでした。 誰かが最初からこの方法で行きたいと思うなら、別の解決策を読むのは面白いでしょう。



All Articles