<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    一路拾遺
    Collect By Finding All The Way ......
    posts - 81,comments - 41,trackbacks - 0

    為了充分發(fā)揮 Web 服務(wù)的靈活性和力量,用戶(hù)必須能夠動(dòng)態(tài)地發(fā)現(xiàn)和調(diào)用 Web 服務(wù)實(shí)現(xiàn)。這是 Web 服務(wù)的最終承諾,也是開(kāi)發(fā)像 UDDI 這樣的技術(shù)的最初原因。甚至有人這樣提議:企業(yè)能提供可供公眾訪(fǎng)問(wèn)的 Web 服務(wù)的實(shí)現(xiàn),無(wú)論張三李四都可以用這些實(shí)現(xiàn)來(lái)購(gòu)買(mǎi)打折的鼻涕熊玩具或更實(shí)用的東西(如保險(xiǎn))。盡管這個(gè)想法還不能成為主流,我們還是可以在防火墻后進(jìn)行這樣的動(dòng)態(tài)調(diào)用。在本文中,Damian Hagge 演示了 Web 服務(wù)客戶(hù)機(jī)在事先不了解一個(gè) Web 服務(wù)的組成的情況下如何動(dòng)態(tài)地發(fā)現(xiàn)和調(diào)用該 Web 服務(wù)。
    在本文中,我將根據(jù) Web 服務(wù)的基本原則進(jìn)行構(gòu)建。如果您不是很了解 UDDI、WSDL 和 Axis,或者說(shuō)您以前未曾創(chuàng)建過(guò)一個(gè)基本的 Web 服務(wù),那么您可能不會(huì)覺(jué)得這篇文章很有用。如果是這種情況,那么我建議您先看看 參考資料,那里解釋了 Web 服務(wù)及相關(guān)的一些技術(shù)。另一方面,如果您確實(shí)了解 Web 服務(wù)并且對(duì)本文中出現(xiàn)的任何資料感到困惑或不確定,那么請(qǐng)?jiān)?Web Services Technical 論壇上張貼您的意見(jiàn),我將定期進(jìn)行查看。

    服務(wù)器實(shí)現(xiàn)


    雖然本文不是關(guān)于 Web 服務(wù)的服務(wù)器端實(shí)現(xiàn)的,但還是值得提一下我將使用的 Web 服務(wù)的組成。我將以一個(gè)簡(jiǎn)單的 Java 類(lèi)作為我的 Web 服務(wù)的基礎(chǔ),這個(gè) Java 類(lèi)所帶的方法將接受兩個(gè)整數(shù)作為參數(shù),并返回一個(gè)整數(shù)(兩個(gè)參數(shù)的乘積)。當(dāng)然,這個(gè)類(lèi)將被作為一個(gè) Web 服務(wù)公開(kāi),而且這個(gè)服務(wù)將需要被發(fā)布到 UDDI。

    如果您正在使用 WebSphere SDK for Web Services(WSDK),那么只需下載我已經(jīng)為您創(chuàng)建的服務(wù)器端實(shí)現(xiàn)(請(qǐng)參閱 參考資料部分),并遵循下列步驟:


    將已下載的文件解壓縮到 WSDK 的 services\applications 目錄下。(即 services\applications\WebMath)。
    運(yùn)行 wsdkconfig 并安裝 WebMath。
    啟動(dòng)應(yīng)用程序服務(wù)器。
    在 services\applications\WebMath\client 目錄下的命令行中輸入 run publish。

    這樣就可以了!Web 服務(wù)被發(fā)布到 UDDI 并等待客戶(hù)機(jī)請(qǐng)求。

    如果您沒(méi)有 WebSphere SDK for Web Services,那么您可以免費(fèi)下載它(請(qǐng)參閱 參考資料部分)。否則,您將需要在您想要使用的任何一個(gè)平臺(tái)上從零開(kāi)始創(chuàng)建上面描述的 Web 服務(wù)。只要確定當(dāng)這個(gè) Web 服務(wù)被發(fā)布到 UDDI 時(shí),業(yè)務(wù)實(shí)體為“ Damian Hagge Ltd.”且業(yè)務(wù)服務(wù)為“ WebMathService” 就可以了。如果您這么做了,那么用于本文的包中提供的客戶(hù)機(jī)代碼(請(qǐng)參閱 參考資料)應(yīng)該很好用。


    我現(xiàn)在可以談?wù)撚腥さ牟糠至?— 動(dòng)態(tài)發(fā)現(xiàn)和調(diào)用。我將討論的代碼是 DynamicInvoke.java ,您可以在 下載文件的 WebMath\client 目錄下找到該代碼。雖然這個(gè)代碼稍微有點(diǎn)兒長(zhǎng),但我還是會(huì)努力盡可能簡(jiǎn)練地解釋它。

     調(diào)用 Web 服務(wù)的開(kāi)放源碼 API


    uddi4j - 查詢(xún)和發(fā)布到 UDDI
    wsdl4j - 解析和收集來(lái)自 WSDL 的信息
    Apache Axis - 對(duì) SOAP 消息進(jìn)行編碼/解碼

     
     
    那么,我需要做什么才能動(dòng)態(tài)地發(fā)現(xiàn)和調(diào)用這個(gè)服務(wù)?首先,我需要發(fā)現(xiàn)來(lái)自 UDDI 的關(guān)于此服務(wù)的信息。其次,我將需要閱讀來(lái)自服務(wù)提供者的 WSDL 實(shí)現(xiàn)文件并進(jìn)行解析,以獲取各種信息。最后,我將擁有足夠的信息來(lái)用 Axis 編入(編碼)對(duì) Web 服務(wù)實(shí)現(xiàn)的 SOAP 請(qǐng)求。

    在客戶(hù)機(jī)代碼中,這是通過(guò)使用開(kāi)放源碼包 uddi4j 、 wsdl4j 和 Apache Axis 實(shí)現(xiàn)的。我將用 uddi4j 來(lái)瀏覽 UDDI 注冊(cè)中心,因?yàn)樗芴峁┮粋€(gè)使用戶(hù)能夠查詢(xún)和發(fā)布到任何 UDDI 2.0 注冊(cè)中心的 API。 wsdl4j 包將被用于以編程方式表示 WSDL 文件的元素,所以我可以瀏覽和收集來(lái)自該文件的各種信息。然后我將用 Axis 向服務(wù)器發(fā)出真正的 SOAP 請(qǐng)求并等待應(yīng)答。

    在 UDDI 中查找 Web 服務(wù)


    為了動(dòng)態(tài)地調(diào)用 Web 服務(wù),您需要知道四條信息。您必須知道 UDDI 注冊(cè)中心的查詢(xún) URL、UDDI 的發(fā)布 URL、業(yè)務(wù)實(shí)體的名稱(chēng)以及業(yè)務(wù)服務(wù)的名稱(chēng)。您可以在 清單 1中找到這些信息。

    清單 1. DynamicInvoke.java — 第 38 行     public class DynamicInvoke {
            private String uddiInquiryURL = "http://localhost:80/uddisoap/inquiryapi";
            private String uddiPublishURL = "http://localhost:80/uddisoap/publishapi";
            private String businessName = "Damian Hagge Ltd.";
            private String serviceName  = "WebMathService";
     


    這段代碼說(shuō)明了 UDDI 的位置、要查找哪個(gè)業(yè)務(wù)實(shí)體以及找到了這個(gè)業(yè)務(wù)實(shí)體后選擇哪個(gè)業(yè)務(wù)服務(wù)。我使用 UDDI URL 創(chuàng)建到 UDDI 注冊(cè)中心的代理,然后我用這個(gè)代理對(duì)注冊(cè)中心進(jìn)行查詢(xún)以查找業(yè)務(wù)服務(wù)。這是如 清單 2中所示完成的。

    清單 2. DynamicInvoke.java — 第 65 行     // create a proxy to the UDDI
        UDDIProxy proxy = new UDDIProxy(
                         new URL(uddiInquiryURL), new URL(uddiPublishURL));
        // we need to find the business in the UDDI
        // we must first create the Vector of business name
        Vector names = new Vector();
        names.add(new Name(businessName));
        // now get a list of all business matching our search criteria
        BusinessList businessList =
               proxy.find_business(names, null, null, null, null, null,10);
        // now we need to find the BusinessInfo object for our business
        Vector businessInfoVector  =
               businessList.getBusinessInfos().getBusinessInfoVector();
        BusinessInfo businessInfo = null;
        for (int i = 0; i < businessInfoVector.size(); i++) {
           businessInfo = (BusinessInfo)businessInfoVector.elementAt(i);
           // make sure we have the right one
           if(businessName.equals(businessInfo.getNameString())) {
              break;
           }
        }


    您在此處可以看到我創(chuàng)建了一個(gè) UDDIProxy 。接著,我創(chuàng)建了一個(gè)包含所期望的業(yè)務(wù)名稱(chēng)的 Vector 并將它作為參數(shù)傳送給了 UDDIProxy.find_business 。這個(gè)調(diào)用返回了一個(gè)包含 BusinessInfos 對(duì)象的 BusinessList 對(duì)象。 BusinessInfos 僅包含若干個(gè) BusinessInfo 對(duì)象的一個(gè)向量。這是 uddi4j API 的共性,在這個(gè) API 中,一個(gè)對(duì)象有到另一個(gè)僅包裝一個(gè)向量的對(duì)象的引用。整個(gè)客戶(hù)機(jī)代碼中將使用這種編程模式,所以在本文接下來(lái)的部分中,我不想解釋這段代碼的語(yǔ)義,它只是查找向量中的一個(gè)類(lèi),而這個(gè)向量包裝在一個(gè)父對(duì)象中。

    然后,我在所有的 BusinessInfo 對(duì)象中反復(fù)查找名為 Damian Hagge Ltd. 的 BusinessInfo 對(duì)象。這就確保了我得到了正確的業(yè)務(wù)實(shí)體。

    現(xiàn)在我需要查找名為 WebMathService 的業(yè)務(wù)服務(wù)。這是通過(guò)搜索 BusinessInfo 對(duì)象引用的(雖然是間接地)所有 BusinessService 對(duì)象實(shí)現(xiàn)的。當(dāng)我找到名為 WebMathService 的 BusinessService 時(shí),我就得到了正確的類(lèi)。 清單 3中是實(shí)現(xiàn)該查找的代碼。

    清單 3. DynamicInvoke.java — 第 88 行     // now find the service info
        Vector serviceInfoVector  =
                businessInfo.getServiceInfos().getServiceInfoVector();
        ServiceInfo serviceInfo = null;
        for (int i = 0; i < serviceInfoVector.size(); i++) {
            serviceInfo = (ServiceInfo)serviceInfoVector.elementAt(i);
            // make sure we have the right one
            if(serviceName.equals(serviceInfo.getNameString())) {
               break;
            }
        }
        // we now need to get the business service object for our service
        // we do this by getting the ServiceDetail object first, and
        // getting the BusinessService objects through it
        ServiceDetail serviceDetail = proxy.get_serviceDetail(
                                               serviceInfo.getServiceKey());
        Vector businessServices = serviceDetail.getBusinessServiceVector();
        BusinessService businessService = null;
        for (int i = 0; i < businessServices.size(); i++) {
        businessService = (BusinessService)businessServices.elementAt(i);
            // make sure we have the right one
            if(serviceName.equals(businessService.getDefaultNameString())) {
                break;
            }
        }


    同樣,您可以看到一個(gè)對(duì)象引用另一個(gè)對(duì)象(它僅包含我正在查找的對(duì)象的一個(gè)向量)的編程方式的模式。

    既然我擁有了業(yè)務(wù)服務(wù),我就需要以某種方式收集服務(wù)提供者機(jī)器上的 WSDL 實(shí)現(xiàn)的 URI。這將由 UDDI 注冊(cè)中心中的 tModle 的 Overview URL 元素表示。要查找這個(gè)元素,我必須先找到業(yè)務(wù)服務(wù)的綁定模板,它包含了一個(gè)基于 http 的訪(fǎng)問(wèn)點(diǎn)。一旦我找到了這個(gè)模板,那么我就可以找到由綁定的模板引用的適當(dāng)?shù)?tModel 了。在 清單 4中,我以編程方式實(shí)現(xiàn)了這個(gè)查找。

    清單 4. DynamicInvoke.java — 第 115 行     // ok, now we have the business service so we can get the binding template
        Vector bindingTemplateVector =
                businessService.getBindingTemplates().getBindingTemplateVector();
        AccessPoint accessPoint = null;
        BindingTemplate bindingTemplate = null;
        for(int i=0; i<bindingTemplateVector.size(); i++) {
            // find the binding template with an http access point
            bindingTemplate = (BindingTemplate)bindingTemplateVector.elementAt(i);
            accessPoint = bindingTemplate.getAccessPoint();
            if(accessPoint.getURLType().equals("http")) {
                break;
            }
        }
        // ok now we know which binding template we're dealing with
        // we can now find out the overview URL
        Vector tmodelInstanceInfoVector =
            bindingTemplate.getTModelInstanceDetails().getTModelInstanceInfoVector();
        String wsdlImplURI = null;
        for(int i=0; i<tmodelInstanceInfoVector.size(); i++) {
            TModelInstanceInfo instanceInfo =
                    (TModelInstanceInfo)tmodelInstanceInfoVector.elementAt(i);
            InstanceDetails details = instanceInfo.getInstanceDetails();
            OverviewDoc wsdlImpl = details.getOverviewDoc();
            wsdlImplURI = wsdlImpl.getOverviewURLString();
            if(wsdlImplURI != null) break;
        }


    我在第一個(gè)代碼塊中查看業(yè)務(wù)服務(wù)引用的所有綁定模板,并找到具有“http”URL 類(lèi)型的綁定模板。然后,我用綁定模板反復(fù)進(jìn)行對(duì) tModel 的所有引用,在找到第一個(gè) overview URL(即 WSDL 實(shí)現(xiàn)的位置)時(shí)停止。既然我知道 WSDL 實(shí)現(xiàn)的 URL,那我就可以繼續(xù)用 wsdl4j 直接請(qǐng)求來(lái)自服務(wù)提供者的文檔并對(duì)其進(jìn)行解析,從而獲得我為了調(diào)用服務(wù)所需要傳送給 Axis 的參數(shù)。

    請(qǐng)注意:根據(jù)您正在使用的遵循 UDDI 2.0 注冊(cè)中心的實(shí)現(xiàn),tModle 中包含的 overview URL 可能并不指向 WSDL 實(shí)現(xiàn)。如果是這種情況,那么您將需要考慮更多事情,比如怎樣才能從 UDDI 或 overview URL 指向的位置收集到服務(wù)提供者的 WSDL 實(shí)現(xiàn)。

    解析 WSDL


    既然您擁有了用于 Web 服務(wù)的 WSDL 實(shí)現(xiàn)的 URL,那么您就可以用 wsdl4j 來(lái)解析它。為了使用 Axis 調(diào)用該服務(wù),您將需要從 WSDL 收集下列信息:


    目標(biāo)名稱(chēng)空間
    服務(wù)名稱(chēng)
    端口名稱(chēng)
    操作名稱(chēng)
    操作輸入?yún)?shù)

    在我的示例中,為了收集這些信息,我必須首先獲取表示 WSDL 實(shí)現(xiàn)和 WSDL 接口的 Definition 對(duì)象。我的代碼如 清單 5所示。

    清單 5. DynamicInvoke.java — 第 159 行  // first get the definition object got the WSDL impl
     try {
         WSDLFactory factory = new WSDLFactoryImpl();
         WSDLReader reader = factory.newWSDLReader();
         implDef = reader.readWSDL(implURI);
     } catch(WSDLException e) {
         e.printStackTrace();
     }
     if(implDef==null) {
            throw new WSDLException(
                WSDLException.OTHER_ERROR,"No WSDL impl definition found.");
     }
     // now get the Definition object for the interface WSDL
     Map imports = implDef.getImports();
     Set s = imports.keySet();
     Iterator it = s.iterator();
     while(it.hasNext()) {
                Object o = it.next();
         Vector intDoc = (Vector)imports.get(o);
         // we want to get the ImportImpl object if it exists
         for(int i=0; i<intDoc.size(); i++) {
      Object obj = intDoc.elementAt(i);
          if(obj instanceof ImportImpl) {
              interfaceDef = ((ImportImpl)obj).getDefinition();
          }
         }
     }
     


    如同您可以看到的,我從細(xì)讀 UDDI 注冊(cè)中心時(shí)收集到的實(shí)現(xiàn) URL 處獲取了 WSDL 實(shí)現(xiàn)的一個(gè) Definition 對(duì)象。然后,我通過(guò)搜索實(shí)現(xiàn) WSDL 中定義的所有 imports 獲取了另一個(gè) Definition 對(duì)象,它表示 WSDL 接口。一個(gè)格式良好的實(shí)現(xiàn) WSDL 應(yīng)該擁有一個(gè)指向其對(duì)應(yīng)的 WSDL 接口的 imports。

    現(xiàn)在,查找要被傳送給 Axis 的目標(biāo)名稱(chēng)空間很簡(jiǎn)單。我只要調(diào)用 WSDL 實(shí)現(xiàn)對(duì)象上的 Definition.getTargetNamespace() 就可以了。接下來(lái),我們要查找包含了我想要調(diào)用的操作的端口。 清單 6中實(shí)現(xiàn)了這個(gè)查找。

    清單 6. DynamicInvoke.java — 第 195 行     // great we've got the WSDL definitions now we need to find the PortType so
     // we can find the methods we can invoke
     Vector allPorts = new Vector();
            Map ports = interfaceDef.getPortTypes();
     s = ports.keySet();
     it = s.iterator();
     while(it.hasNext()) {
            Object o = it.next();
         Object obj = ports.get(o);
         if(obj instanceof PortType) {
          allPorts.add((PortType)obj);
         }
     }
     // now we've got a vector of all the port types - normally some logic would
     // go here to choose which port type we want to use but we'll just choose
     // the first one
     PortType port = (PortType)allPorts.elementAt(0);
     List operations = port.getOperations();
     


    我獲得了接口 WSDL 中聲明的所有端口且只選擇第一個(gè)端口。當(dāng)然,如果這是一個(gè)真正的應(yīng)用程序,我就會(huì)希望開(kāi)發(fā)某種類(lèi)型的算法來(lái)選擇期望的端口和操作。但是,為了簡(jiǎn)練起見(jiàn),我不會(huì)這樣做。

    既然我已經(jīng)選擇了要使用的端口,我就要查找我將提供給 Axis 的服務(wù)名稱(chēng)和端口名稱(chēng)。我通過(guò)在對(duì)應(yīng)于選定的端口的 WSDL 接口中查找綁定來(lái)查找服務(wù)名稱(chēng)和端口名稱(chēng)。然后,我在 WSDL 實(shí)現(xiàn)中收集服務(wù)和端口,該實(shí)現(xiàn)為這個(gè)綁定提供一個(gè)端點(diǎn)。

    您可能發(fā)現(xiàn)這有點(diǎn)兒過(guò)于復(fù)雜,所以我將簡(jiǎn)化它。請(qǐng)看一看 WebMath_Impl.wsdl 文件和 WebMath_Interface.wsdl 文件,您可以在 WebMath\webapp 目錄下找到這兩個(gè)文件。您可以在實(shí)現(xiàn)文件中看到有一個(gè) <service> 標(biāo)記,它包含一個(gè) <port> 標(biāo)記。在接口文件中,您可以看到有一個(gè) <binding> 標(biāo)記,它包含一個(gè) <operation> 標(biāo)記和一個(gè)表示我已經(jīng)選擇的端口的 <port> 標(biāo)記。在這兩個(gè)文件中,可能有這些端口中的幾個(gè)端口,所以我需要做的就是確保我在實(shí)現(xiàn)文件中選擇的服務(wù)包含引用綁定(它包含在接口文件中選擇的端口)的端口。

    換言之,我需要確保我在接口 WSDL 中選擇的綁定包含我已經(jīng)選擇的同一個(gè)端口(在上面的代碼片斷中)。然后,我需要確保在實(shí)現(xiàn) WSDL 中選擇的服務(wù)包含一個(gè)端口,這個(gè)端口的 binding 屬性值和接口 WSDL 綁定的 name 屬性值相同。如果這些是相同的,那么我就已經(jīng)找到了引用我選擇的端口的服務(wù)和綁定。

    請(qǐng)?jiān)?清單 7中看看上面的算法是什么樣的。

    清單 7. DynamicInvoke.java — 第 215 行  // let's get the service in the WSDL impl which contains this port
     // to do this we must first find the QName of the binding with the
     // port type that corresponds to the port type of our chosen part
     QName bindingQName = null;
     Map bindings = interfaceDef.getBindings();
     s = bindings.keySet();
     it = s.iterator();
     while(it.hasNext()) {
         Binding binding = (Binding)bindings.get(it.next());
         if(binding.getPortType()==port) {
          // we've got our binding
          bindingQName = binding.getQName();
         }
     }
     if(bindingQName==null) {
         throw new WSDLException(WSDLException.OTHER_ERROR,
                            "No binding found for chosen port type.");        
     }
     // now we can find the service in the WSDL impl which provides an
     // endpoint for the service we just found above
     Map implServices = implDef.getServices();
     s = implServices.keySet();
     it = s.iterator();
     while(it.hasNext()) {
         Service serv = (Service)implServices.get(it.next());
         Map m = serv.getPorts();
         Set set = m.keySet();
         Iterator iter = set.iterator();
         while(iter.hasNext()) {
          Port p = (Port)m.get(iter.next());
          if(p.getBinding().getQName().toString().equals(
                                            bindingQName.toString())) {
              // we've got our service store the port name and service name
              portName = serv.getQName().toString();
              serviceName = p.getName();
              break;
             }
         }
         if(portName != null) break;
     }
     


    通過(guò)執(zhí)行上面的代碼,我收集到了需要傳送給 Axis 的端口名稱(chēng)和服務(wù)名稱(chēng)。現(xiàn)在,我需要的唯一其他的幾條信息就是要傳送到方法調(diào)用中的方法名稱(chēng)和幾個(gè)參數(shù)。

    清單 8中的代碼將發(fā)現(xiàn)那些參數(shù)以及這些參數(shù)映射的 Java 類(lèi)型(即 Java 類(lèi),或稱(chēng)本機(jī)類(lèi)型)。

    清單 8. DynamicInvoke.java — 第 256 行     // ok now we got all the operations previously - normally we would have some
        logic here to
     // choose which operation, however, for the sake of simplicity we'll just
     // choose the first one
     Operation op = (Operation)operations.get(0);
     operationName = op.getName();
     // now let's get the Message object describing the XML for the input and output
     // we don't care about the specific type of the output as we'll just cast it to
     an Object
     Message inputs = op.getInput().getMessage();
     // let's find the input params
     Map inputParts = inputs.getParts();
     // create the object array which Axis will use to pass in the parameters
     inputParams = new Object[inputParts.size()];
     s = inputParts.keySet();
     it = s.iterator();
     int i=0;
     while(it.hasNext()) {
         Part part = (Part)inputParts.get(it.next());
         QName qname = part.getTypeName();
         // if it's not in the http://www.w3.org/2001/XMLSchema namespace then
         // we don't know about it - throw an exception
         String namespace = qname.getNamespaceURI();
         if(!namespace.equals("http://www.w3.org/2001/XMLSchema")) {
         throw new WSDLException(
                        WSDLException.OTHER_ERROR,"Namespace unrecognized");
         }
         // now we can get the Java type which the the QName maps to
         // we do this by using the Axis tools which map WSDL types
                // to Java types in the wsdl2java tool
         String localPart = qname.getLocalPart();
         javax.xml.rpc.namespace.QName wsdlQName =
                        new javax.xml.rpc.namespace.QName(namespace,localPart);
         TypeMapping tm = DefaultTypeMappingImpl.create();
         Class cl = tm.getClassForQName(wsdlQName);
         // if the Java type is a primitive, we need to wrap it in an object
         if(cl.isPrimitive()) {
          cl = wrapPrimitive(cl);
         }
         // we could prompt the user to input the param here but we'll just
         // assume a random number between 1 and 10. First we need to
         // find the constructor which takes a string representation of a number
         // if a complex type was required we would use reflection to break it
         // down and prompt the user to input values for each member variable
                // in Object representing the complex type
         try {
          Constructor cstr = cl.getConstructor(
                            new Class[] { Class.forName("java.lang.String") });
          inputParams[i] = cstr.newInstance(
                            new Object [] { ""+new Random().nextInt(10) });
         } catch(Exception e) {
          // shoudn't happen
         e.printStackTrace();
         }
         i++;
     }
     


    我來(lái)一步步解釋所發(fā)生的一切。我已經(jīng)有了一個(gè) Operation 對(duì)象,是從我在端口對(duì)象對(duì) Port.getOperations() 的調(diào)用中獲得的。接下來(lái),只需調(diào)用 Operation.getName() 就會(huì)產(chǎn)生方法名稱(chēng)。

    現(xiàn)在,我需要獲取表示 <input> 標(biāo)記的 Message 對(duì)象,這個(gè) input 標(biāo)記由所選的端口引用。 <input> 標(biāo)記指定幾個(gè)應(yīng)該被傳送到方法調(diào)用中的參數(shù)。這是由代碼 Operation.getInput().getMessage() 完成的。一旦我收集到了這個(gè) Message 對(duì)象,我就需要查找 Message 對(duì)象包含的所有部件。

    我反復(fù)查看所有的部件并確保名稱(chēng)空間是 XML Schema 名稱(chēng)空間,這樣我就能確保可以把部件類(lèi)型映射到 Java 代碼。當(dāng)然,在一個(gè)真正的應(yīng)用程序中,這將被擴(kuò)展以便盡可能地支持其他類(lèi)型。

    然后,我稍微向 Axis 方向轉(zhuǎn)換一點(diǎn)兒以便發(fā)現(xiàn)類(lèi)型映射到哪個(gè) Java 類(lèi)上。 Axis 包含一個(gè) TypeMapping.getClassForQName() 方法,用在它的 wsdl2java 工具中。我所需要做的就是創(chuàng)建一個(gè)表示類(lèi)型的 javax.xml.rpc.namespace.QName 對(duì)象。一旦我進(jìn)行了調(diào)用,那么我就擁有了一個(gè)表示類(lèi)型的 Java Class 對(duì)象。

    如果 Class 是基本類(lèi)型,那么我需要將它包裝在一個(gè) Java 對(duì)象中。這里沒(méi)有介紹實(shí)現(xiàn)這個(gè)包裝的代碼,因?yàn)樗?jiǎn)單了,但是,如果您想要查看此代碼,您可以在 DynamicInvoke.java 找到它。當(dāng)我擁有了要傳送給 Axis 的 Java 對(duì)象后,我需要對(duì)它進(jìn)行實(shí)例化,給構(gòu)造程序提供一個(gè)值,然后存儲(chǔ)它。我使用反射(reflection)查找這個(gè)對(duì)象的構(gòu)造程序,并提供 1 到 10 之間的一個(gè)隨機(jī)數(shù)字對(duì)其實(shí)例化。當(dāng)然,如果這不僅僅是一個(gè)演示的話(huà),某個(gè)其他的邏輯將選擇參數(shù),可能會(huì)提示用戶(hù)提供該信息。最后,我將實(shí)例化的對(duì)象存儲(chǔ)在 Object 數(shù)組中。

    好!我已經(jīng)收集到了調(diào)用服務(wù)所需的所有信息。現(xiàn)在我就可以用一個(gè) Axis 調(diào)用來(lái)調(diào)用 Web 服務(wù)了。

    用 Axis 調(diào)用 Web 服務(wù)


    用 Axis 調(diào)用 Web 服務(wù)是一個(gè)相對(duì)簡(jiǎn)單的過(guò)程, 清單 9中是此過(guò)程的編碼。

    清單 9. DynamicInvoke.java — 第 365 行     public void axisInvoke(String targetNamespace, String serviceName,
                String portName, String operationName, Object[] inputParams,
                String implURI) {
         try {
             // first, due to a funny Axis idiosyncrasy we must strip portName of
             // it's target namespace so we can pass it in as
                // targetNamespace, localPart
             int index = portName.indexOf(":",
                        portName.indexOf("http://")+new String("http://").length());
             String portNamespace = portName.substring(0,index);
                portName = portName.substring(
                            index==0?index:index+1); // to strip the :
             javax.xml.rpc.namespace.QName serviceQN =
          new javax.xml.rpc.namespace.QName( portNamespace, portName );
             org.apache.axis.client.Service service =
          new org.apache.axis.client.Service(new URL(implURI), serviceQN);
             javax.xml.rpc.namespace.QName portQN =
          new javax.xml.rpc.namespace.QName( targetNamespace, serviceName );
             // This Call object will be used the invocation
             Call call = (Call) service.createCall();
             // Now make the call...
             System.out.println("Invoking service>> " + serviceName + " <<...");
             call.setOperation( portQN, operationName );
             Object ret = (Integer) call.invoke( inputParams );
                System.out.println("Result returned from call to "+
                                                serviceName+" -- "+ret);
         } catch(java.net.MalformedURLException e) {
             System.out.println("Error invoking service : "+e);
         } catch(javax.xml.rpc.ServiceException e2) {
             System.out.println("Error invoking service : "+e2);
         } catch(java.rmi.RemoteException e3) {
             System.out.println("Error invoking service : "+e3);
         }
       }
     


    那么,我現(xiàn)在在做什么呢?首先,我創(chuàng)建了一個(gè)表示端口名稱(chēng)的 QName 。 Axis 不提供從一個(gè)完整的名稱(chēng)空間創(chuàng)建 QName 的構(gòu)造程序,所以我不得不把端口名稱(chēng)分割成名稱(chēng)空間和本地部件。然后,我創(chuàng)建一個(gè) Service 對(duì)象(它提供 WSDL 實(shí)現(xiàn)的 URL)和 QName (它表示端口名稱(chēng))。

    然后我創(chuàng)建另一個(gè) QName 對(duì)象,這一次它表示服務(wù)名稱(chēng)。現(xiàn)在我從 Service 對(duì)象創(chuàng)建 Call 對(duì)象。我通過(guò)傳入這個(gè) Call 對(duì)象要調(diào)用的端口 QName 和操作名稱(chēng)來(lái)設(shè)置它將調(diào)用的操作。最后,我實(shí)際調(diào)用了在解析 WSDL 時(shí)創(chuàng)建的、傳入 Object[] 參數(shù)中的操作。這樣就可以了!現(xiàn)在我將返回值作為一個(gè) Java Object ,并把它打印出來(lái)。


    總結(jié)


    我希望您已經(jīng)理解了我在本文中講述的所有代碼。這可能有點(diǎn)兒多,但是我已經(jīng)說(shuō)過(guò)了:理解 uddi4j 、 wsdl4j 和 Axis API 如何工作對(duì)于有效編寫(xiě)定制的 Web 服務(wù)客戶(hù)機(jī)是很重要的。現(xiàn)在,您最好是研究研究代碼,然后試著找出 UDDI 注冊(cè)中心或 WSDL 文檔中包含的信息。如果您對(duì) UDDI 元素的結(jié)構(gòu)或 WSDL 的結(jié)構(gòu)有些模糊的話(huà),那么請(qǐng)嘗試著研讀它們。有一些關(guān)于這些主題的優(yōu)秀 參考資料。再重申一遍,如果您對(duì)于本文所介紹的任何內(nèi)容有任何疑問(wèn)的話(huà),請(qǐng)?jiān)?Web Services Technical 論壇上張貼意見(jiàn)。

    【轉(zhuǎn)自】:http://www.ibm.com/developerworks/cn/webservices/ws-udax/index.html 

    posted on 2008-07-31 18:05 胖胖泡泡 閱讀(473) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 久久国产亚洲观看| 国产精品视频全国免费观看| 一区二区三区视频免费| 亚洲国产女人aaa毛片在线 | 亚洲人成影院在线无码观看| 精品熟女少妇av免费久久| 无套内射无矿码免费看黄| 亚洲中文无码永久免费| 国产视频精品免费| 久久久久久毛片免费播放 | 午夜理伦剧场免费| 一边摸一边桶一边脱免费视频| 国产精品亚洲综合五月天| 亚洲乱亚洲乱淫久久| 亚洲三区在线观看无套内射| 亚洲AV中文无码乱人伦在线视色| 免费无码又爽又刺激聊天APP| 亚洲狠狠婷婷综合久久| 亚洲天堂一区二区三区| 亚洲av无码不卡私人影院| 女人18毛片水最多免费观看| 国产在线jyzzjyzz免费麻豆| 亚洲一区二区在线免费观看| 手机看片国产免费永久| 99免费在线视频| 久久久久久噜噜精品免费直播| 深夜a级毛片免费无码| 久久精品国产亚洲AV| 亚洲AV电影天堂男人的天堂| 亚洲乱码在线观看| 77777午夜亚洲| 在线观看亚洲AV日韩AV| 亚洲AV成人影视在线观看| 2017亚洲男人天堂一| 亚洲国产乱码最新视频| 亚洲已满18点击进入在线观看| 亚洲国产电影在线观看| 麻豆狠色伊人亚洲综合网站| 国产成人精品日本亚洲网址| 亚洲精品无码国产片| 亚洲日韩国产精品无码av|