WebObjects/Web 服务/控制 WSDL 服务位置
外观
本手册由 Andrew Lindesay ( http://www.lindesay.co.nz) 于 2006 年撰写,作为 LEWOStuff 框架中支持代码的一部分,但本材料已在此转录。它是在 WebObjects 5.2 和 5.3 以及 1.4 JVM 同时期编写的。
AXIS 提供了许多处理程序,最终用于执行 WS。这通常在 WebObjects 环境中开箱即用。但是,在 servlet 部署的情况下,URL 会被 servlet 容器操作,因此它们看起来像这样。
...ects/FOO.woa/ws/FooService;jsessionid=abc.i1?wsdl
如果客户端在 WS 调用时启动一个会话,那么您希望所有后续请求都返回到相同的 servlet 容器(这里我们假设一个冗余部署,其中有多个 servlet 容器)中,该会话驻留在其中。但是,servlet 容器的 HTTP 适配器通常只通过查看修改后的 URL 来知道这一点。不幸的是,AXIS 生成的默认 WSDL 将包含如下部分。
... <wsdl:service name="FooService"> <wsdl:port name="FooService" binding="impl:FooService SoapBinding"> <wsdlsoap:address location="http://foo.co.nz/FOO/WebObjects/FOO.woa/ws/FooService"/> </wsdl:port> </wsdl:service> ...
这样的 WSDL 不包含由于上下文在服务位置具有会话而导致的修改后的 URL。以下 LEWOStuff 中提供的示例处理程序 _LEWOWebServicesWSDLLocationHandler_ 将更正 WSDL 中提供的 URL,使其包含会话信息。要安装此处理程序以在 WebObjects 中使用,请找到项目中的 _server.wsdd_ 文件,并修改以下部分,使其如下所示。
... <transport name="http"> <requestFlow> <handler type="HTTPActionHandler"/> <handler type="URLMapper"/> <handler type="java:nz.co.lindesay.common.webobjects.LEWOWebServicesWSDLLocationHandler"/> </requestFlow> </transport>
然后,您需要将以下类放入您的项目中。
package nz.co.lindesay.common.webobjects; /* ------------------------------------------------------------ LICENSE ------------------------------------------------------------ Copyright (c) 2006, Andrew Lindesay All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------ */ import com.webobjects.foundation.*; import com.webobjects.appserver.*; import org.apache.axis.*; /** * <P>This class is an AXIS request handler that is designed to * manipulate the outbound WSDL that is generated for a * request. The manipulation undertaken here is to modify the * location of the actual service. The reason for doing this is * that if you have a web service deployed into a servlet * container as a WO application, the session'ed URLs can look * a bit like this.</P> * * <P><TT>http://foo.co.nz/FOO/WebObjects/FOO.woa/ws/FooService;jsessionid=abc.i1?wsdl</TT></P> * * <P>However, once the URL is returned as a location for a service * from AXIS, the session part at the end is removed and if you are * using a multi-container deployment, the subsequent requests will * not arrive at the correct servlet container.</P> * * <P>By installing this AXIS handler, this problem is resolved. * To install it, locate the "<TT>server.wsdd</TT>" file in your * WO project and add the following line to the "<I>requestFlow</I>" * handler list as the last item in the list. This should be the * request flow in the HTTP transport section.</P> * * <P><TT><handler type="java:nz.co.lindesay.common.webobjects.LEWOWebServicesWSDLLocationHandler"/></TT></P> * * <P>This should also work with the "<I>wotaskd</I>" deployment * style as well.</P> */ public class LEWOWebServicesWSDLLocationHandler extends org.apache.axis.handlers.BasicHandler { // -------------------------------------------------------------- public LEWOWebServicesWSDLLocationHandler() { super(); } // -------------------------------------------------------------- /** * <P>This is the AXIS hook where we can manipulate the outbound * WSDL.</P> */ public void generateWSDL(MessageContext msgContext) throws AxisFault { WOContext context = WOWebServiceUtilities.currentWOContext(); WORequest request = context.request(); String host = LEWOHelper.getExternalHostnameFromInboundRequest(request); int port = LEWOHelper.getExternalPortFromInboundRequest(request); int appi = request.applicationNumber(); if((null==host)||(0==host.length())) throw new IllegalStateException("the host cannot be determined from the inbound request."); if(context.hasSession()) context.session(); StringBuffer sb = new StringBuffer(); sb.append("http://"); sb.append(host); if(-1!=port) { sb.append(":"); sb.append(Integer.toString(port)); } String path = context.urlWithRequestHandlerKey( request.requestHandlerKey(), request.requestHandlerPath(), null); // Unless the context has a session, we can't get it to come back // to a specific instance, but in the case of a 'wotaskd' deploy, // there is no way to specify the session for a WSDL request, so // we'll do a nasty hack to make this work. if((-1!=appi)&&(!context.hasSession())) { String webServiceRequestHandlerKey = WOApplication.application().webServiceRequestHandlerKey(); String startPath = request.adaptorPrefix()+"/"+request.applicationName()+".woa"; // ''/cgi-bin/WebObjects/Foo.woa'' if(!path.startsWith(startPath)) throw new IllegalStateException("The path '"+path+"' should have started with '"+startPath+"'"); if(path.startsWith(startPath+"/"+webServiceRequestHandlerKey)) { StringBuffer pathSB = new StringBuffer(); pathSB.append(startPath); pathSB.append("/"); pathSB.append(Integer.toString(appi)); pathSB.append(path.substring(startPath.length())); path = pathSB.toString(); } } sb.append(path); msgContext.setProperty(MessageContext.WSDLGEN_SERV_LOC_URL,sb.toString()); } // -------------------------------------------------------------- /** * <P>Basically there is nothing to do here because we are not * interested in messing with the request/response cycle - rather * we want only to manipulate the WSDL.</P> */ public void invoke(MessageContext msgContext) throws AxisFault { } // -------------------------------------------------------------- }
虽然这有点粗糙,但它应该在 WSDL 中产生正确的结果。