跳轉到內容

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 中產生正確的結果。

華夏公益教科書