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

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


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

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


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

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

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


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

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


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

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

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

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


    為了動態(tài)地調(diào)用 Web 服務(wù),您需要知道四條信息。您必須知道 UDDI 注冊中心的查詢 URL、UDDI 的發(fā)布 URL、業(yè)務(wù)實(shí)體的名稱以及業(yè)務(wù)服務(wù)的名稱。您可以在 清單 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";
     


    這段代碼說明了 UDDI 的位置、要查找哪個(gè)業(yè)務(wù)實(shí)體以及找到了這個(gè)業(yè)務(wù)實(shí)體后選擇哪個(gè)業(yè)務(wù)服務(wù)。我使用 UDDI URL 創(chuàng)建到 UDDI 注冊中心的代理,然后我用這個(gè)代理對注冊中心進(jì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ù)名稱的 Vector 并將它作為參數(shù)傳送給了 UDDIProxy.find_business 。這個(gè)調(diào)用返回了一個(gè)包含 BusinessInfos 對象的 BusinessList 對象。 BusinessInfos 僅包含若干個(gè) BusinessInfo 對象的一個(gè)向量。這是 uddi4j API 的共性,在這個(gè) API 中,一個(gè)對象有到另一個(gè)僅包裝一個(gè)向量的對象的引用。整個(gè)客戶機(jī)代碼中將使用這種編程模式,所以在本文接下來的部分中,我不想解釋這段代碼的語義,它只是查找向量中的一個(gè)類,而這個(gè)向量包裝在一個(gè)父對象中。

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

    現(xiàn)在我需要查找名為 WebMathService 的業(yè)務(wù)服務(wù)。這是通過搜索 BusinessInfo 對象引用的(雖然是間接地)所有 BusinessService 對象實(shí)現(xiàn)的。當(dāng)我找到名為 WebMathService 的 BusinessService 時(shí),我就得到了正確的類。 清單 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è)對象引用另一個(gè)對象(它僅包含我正在查找的對象的一個(gè)向量)的編程方式的模式。

    既然我擁有了業(yè)務(wù)服務(wù),我就需要以某種方式收集服務(wù)提供者機(jī)器上的 WSDL 實(shí)現(xiàn)的 URI。這將由 UDDI 注冊中心中的 tModle 的 Overview URL 元素表示。要查找這個(gè)元素,我必須先找到業(yè)務(wù)服務(wù)的綁定模板,它包含了一個(gè)基于 http 的訪問點(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 類型的綁定模板。然后,我用綁定模板反復(fù)進(jìn)行對 tModel 的所有引用,在找到第一個(gè) overview URL(即 WSDL 實(shí)現(xiàn)的位置)時(shí)停止。既然我知道 WSDL 實(shí)現(xiàn)的 URL,那我就可以繼續(xù)用 wsdl4j 直接請求來自服務(wù)提供者的文檔并對其進(jìn)行解析,從而獲得我為了調(diào)用服務(wù)所需要傳送給 Axis 的參數(shù)。

    請注意:根據(jù)您正在使用的遵循 UDDI 2.0 注冊中心的實(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 來解析它。為了使用 Axis 調(diào)用該服務(wù),您將需要從 WSDL 收集下列信息:


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

    在我的示例中,為了收集這些信息,我必須首先獲取表示 WSDL 實(shí)現(xiàn)和 WSDL 接口的 Definition 對象。我的代碼如 清單 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 注冊中心時(shí)收集到的實(shí)現(xiàn) URL 處獲取了 WSDL 實(shí)現(xiàn)的一個(gè) Definition 對象。然后,我通過搜索實(shí)現(xiàn) WSDL 中定義的所有 imports 獲取了另一個(gè) Definition 對象,它表示 WSDL 接口。一個(gè)格式良好的實(shí)現(xiàn) WSDL 應(yīng)該擁有一個(gè)指向其對應(yīng)的 WSDL 接口的 imports。

    現(xiàn)在,查找要被傳送給 Axis 的目標(biāo)名稱空間很簡單。我只要調(diào)用 WSDL 實(shí)現(xiàn)對象上的 Definition.getTargetNamespace() 就可以了。接下來,我們要查找包含了我想要調(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)用程序,我就會希望開發(fā)某種類型的算法來選擇期望的端口和操作。但是,為了簡練起見,我不會這樣做。

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

    您可能發(fā)現(xiàn)這有點(diǎn)兒過于復(fù)雜,所以我將簡化它。請看一看 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ù)和綁定。

    請?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;
     }
     


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

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

    清單 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++;
     }
     


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

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

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

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

    如果 Class 是基本類型,那么我需要將它包裝在一個(gè) Java 對象中。這里沒有介紹實(shí)現(xiàn)這個(gè)包裝的代碼,因?yàn)樗唵瘟耍牵绻胍榭创舜a,您可以在 DynamicInvoke.java 找到它。當(dāng)我擁有了要傳送給 Axis 的 Java 對象后,我需要對它進(jìn)行實(shí)例化,給構(gòu)造程序提供一個(gè)值,然后存儲它。我使用反射(reflection)查找這個(gè)對象的構(gòu)造程序,并提供 1 到 10 之間的一個(gè)隨機(jī)數(shù)字對其實(shí)例化。當(dāng)然,如果這不僅僅是一個(gè)演示的話,某個(gè)其他的邏輯將選擇參數(shù),可能會提示用戶提供該信息。最后,我將實(shí)例化的對象存儲在 Object 數(shù)組中。

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

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


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

    清單 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è)表示端口名稱的 QName 。 Axis 不提供從一個(gè)完整的名稱空間創(chuàng)建 QName 的構(gòu)造程序,所以我不得不把端口名稱分割成名稱空間和本地部件。然后,我創(chuàng)建一個(gè) Service 對象(它提供 WSDL 實(shí)現(xiàn)的 URL)和 QName (它表示端口名稱)。

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


    總結(jié)


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

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

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

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 皇色在线视频免费网站| 免费一级毛片在线观看| 韩国亚洲伊人久久综合影院| 亚洲国产精品视频| 最近中文字幕电影大全免费版 | 日韩电影免费在线观看网址| 亚洲精品无码Av人在线观看国产| av无码国产在线看免费网站| 一级毛片人与动免费观看| 亚洲大香人伊一本线| 亚洲无码日韩精品第一页| 免费在线观看视频网站| 人成免费在线视频| 亚洲中文字幕无码中文字| 久久亚洲精品无码播放| 成年人在线免费看视频| 男人的天堂网免费网站| 视频免费1区二区三区| 亚洲成年网站在线观看| 亚洲国产精品自在线一区二区| 免费人成在线观看网站视频| 在线视频精品免费| 免费在线中文日本| 少妇亚洲免费精品| 亚洲码欧美码一区二区三区| 亚洲欧美自偷自拍另类视| 国产精品亚洲片在线观看不卡| 日本大片在线看黄a∨免费| 中文字幕免费视频一| yy一级毛片免费视频| 亚洲日本VA午夜在线电影| 亚洲免费视频在线观看| 红杏亚洲影院一区二区三区| 四虎www成人影院免费观看| 永久黄色免费网站| a毛片久久免费观看| 一进一出60分钟免费视频| 国产亚洲漂亮白嫩美女在线| 亚洲综合成人婷婷五月网址| 亚洲午夜久久影院| 亚洲AV无码乱码国产麻豆穿越|