跳转到内容

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 中产生正确的结果。

华夏公益教科书