posts - 495,comments - 227,trackbacks - 0

构建 SOAP 服务

如果您觉得构建 Web 服务客户机的过程相当简单,事实的确如此。而就很多方面而言,构建服务的过程也同样简单。

总体过程

创建 Axis2 Web 服务的整个过程涉及以下步骤:

  1. 创建服务清单
  2. 创建类
  3. 将其打包为 Axis 存档文件
  4. 将 Axis 存档文件上载到 Axis2 Web 应用程序
  5. 重新启动服务器(如果有必要)

这就是全部步骤。让我们首先从服务清单开始。





回页首


创建清单

服务清单告知 Axis2 应用程序(就更大的范围而言,应用服务器)哪个请求与哪个类对应。例如,可以如清单 22 中所示的那样指定两个服务函数。


清单 22. 在清单中指定两个服务函数
                    
<service name="CMSService">
    <description>
        This is a sample Web Service for the newspaper's
 Content Managment System.
    </description>

    <parameter name="ServiceClass" locked="false"
>CMSService</parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>
    <operation name="addArticle">
        <messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
    </operation>
</service>

首先,定义服务,提供其名称和描述,并指定实际为请求服务的类。接下来,定义实际的操作。请注意,此示例指定了两种不同类型的 messageReceiver。第一个 RawXMLINOutMessageReceiver 用于传统的请求/响应服务。第二个 RawXMLINOnlyMessageReceiver 用于单向消息。操作的名称与有效负载的根元素以及要执行的方法对应。

将此文件保存为 services.xml。

接下来,让我们创建实际的应用程序。





回页首


创建应用程序

让我们首先创建模拟前面看到的 echo 函数的类(将直接返回原始有效负载的副本),如清单 23 中所示。


清单 23. CMSService 类
                    
import org.apache.axis2.om.OMElement;
import javax.xml.stream.XMLStreamException;

public class CMSService {

    public OMElement getNumberOfArticles(OMElement element)
                              throws XMLStreamException {

        element.build();
        element.detach();

        return element;
    }
}

要编译此应用程序,请确保 <axis2_home>/lib 中的所有 *.jar 文件都在您的 CLASSPATH 上。

此应用程序相当简单,仅包含一个与 getNumbereOfArticles 操作对应的类。此函数和任何要作为操作的函数一样,接收单个 OMElement 参数(表示有效负载)。此处,您将首先使用 build() 方法来确定已接收到所有数据——AXIOM 使用一个 pull 方法访问数据——然后将元素从其当前树中分离,以便能够将其返回。

如果喜欢冒险,可以自由地部署服务访问服务,以访问服务并查看结果。应该看到与清单 24 中所示类似的结果输出。


清单 24. CMSService 类响应
                    
<cms:getNumberOfArticles><cms:category>classifieds</cms:category></cms:
getNumberOfArticles>

接下来让我们了解如何实际处理数据。





回页首


提取有效负载

为了从有效负载提取信息,将使用与 DOM 非常类似的技术来对接收到的有效负载元素进行操作(请参见清单 25)。


清单 25. 提取有效负载信息
                    
...
import javax.xml.stream.XMLStreamException;

public class CMSService {
    public OMElement getNumberOfArticles(OMElement element) 
                          throws XMLStreamException {
        element.build();
        element.detach();

        String rootName = element.getLocalName();
        OMElement categoryElement = element.getFirstElement();
        String categoryElementName = categoryElement.getLocalName();
        String categoryValue = childElement.getText();

        return element;
    }
}

请记住,有效负载的根是 getNumberOfArticles 函数接收的元素。在此情况下,将提取元素的名称,然后移动到第一个元素子项(与第一个子项不同,后者可能是空格文本节点)并提取其名称和值。请注意,使用的是 getText() 方法来提取实际上是 category 元素的文本节点子项的值。这无疑非常简捷!





回页首


创建并返回响应

最后,将需要使用从请求的有效负载提取数据来创建响应。在本例中,将从第二个函数(在实际应用程序中,该函数将进行一些其他的工作)提供响应(请参见清单 26)。


清单 26. 创建响应
                    
...
import javax.xml.stream.XMLStreamException;

public class CMSService {
    public OMElement getNumberOfArticles(OMElement element) 
                         throws XMLStreamException {
        element.build();
        element.detach();

        String rootName = element.getLocalName();
        OMElement childElement = element.getFirstElement();
        String childName = childElement.getLocalName();
        String categoryValue = childElement.getText();

        SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
        OMNamespace namespace = factory.createOMNamespace(
                            "http://daily-moon.com/cms/", "resp");
        OMElement resultElem = factory.createOMElement(
                                   "numberOfArticles",namespace);

        String actualValue = 
                         (articleCount(categoryValue)).toString();
        resultElem.setText(actualValue);

        return resultElem;
    }

    private Integer articleCount(String catId){

       //Perform some function such as searching the CMS 
       //database, and return the actual value.  For our 
       //purposes, you'll hardcode it.
       return new Integer(42);

    }
}

首先,创建将用于创建所有其他对象的工厂,然后创建将添加到响应的有效负载的命名空间。接下来,创建实际结果元素,在本例中为名为 numberOfArticles 的元素。

numberOfArticles 元素的内容将为 articleCount() 函数返回的一个数字,在本例中,该函数可以为任何内容。在实际的应用程序中,将进行所需进行的任何工作来获取此数据。获取了此数据后,会将其设置为 numberOfArticles 元素的内容,并直接返回该元素。

现在剩下的就是部署服务了。





回页首


部署服务

为了部署服务,需要创建一个 Axis 存档文件。此文件和 *.jar 或 *.war 文件类似,实际是使用特殊文件扩展名(在本例中使用的是 .aar)的 zip 文件。请按照以下步骤创建此文件:

  1. 将 <AXIS2_HOME>/lib 目录中的所有文件添加到 CLASSPATH 并编译 CMSService.java 文件。
  2. 在与 CMSService.class 文件相同的目录中创建名为 META-INF 的新目录。
  3. 从包含 CMSService.class 文件的目录中发出以下命令:<code type="section" width="100"> jar cvf CMSService.aar ./* </code> 应该看到与以下类似的结果:<code type="section" width="100"> added manifest adding:CMSService.class(in = 513) (out= 330)(deflated 35%) adding:CMSService.java(in = 328) (out= 182)(deflated 44%) ignoring entry META-INF/ adding:META-INF/services.xml(in = 391) (out= 229)(deflated 41%) </code>
  4. 使用安装示例服务中列出的步骤将此服务添加到服务器上。(如果看到 Web 接口上有 Servlet 错误,请确保登录到了 Axis2 应用程序。如果会话已过期,应用程序将不一定会通知您,而可能会直接显示错误。)
  5. 如果有必要,请重新启动 Geronimo。(将可能不必在添加服务后进行此操作,但在进行更改后可能必须这样做。)

如果单击 View services 链接,应该看到与图 4 中所示类似的内容。


图 4. 可用服务
可用服务 




回页首


访问服务

现在已经完成了服务构建,接下来要通过客户机对其进行访问。对前面创建的 ClassifiedClient.java 文件进行以下更改(请参见清单 27)。


清单 27. 修改 ClassifiedClient
                    
...
public class ClassifiedClient {
    private static EndpointReference targetEPR = 
         new EndpointReference(
           "http://localhost:8080/axis2/services/CMSService");

    public static OMElement getEchoOMElement() {
        SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
        OMNamespace omNs = fac.createOMNamespace(
                "http://daily-moon.com/cms", "cms");
        OMElement method = fac.createOMElement("getNumberOfArticles", omNs);
        OMElement value = fac.createOMElement("category", omNs);
        value.addChild(fac.createText(value, "classifieds"));
        method.addChild(value);

        return method;
    }

    public static void main(String[] args) {
        try {
            OMElement payload = ClassifiedClient.getEchoOMElement();
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

            ServiceClient sender = new ServiceClient();
            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);

            String response = result.getText();
            System.out.println("There are "+response+" classifieds at the moment.");

        } catch (Exception e) { //(XMLStreamException e) {
System.out.println(e.toString());
        }
    }
}

编译并运行了此应用程序后,应看到清单 28 中所示的响应。


清单 28. ClassifiedClient 响应
                    
There are 42 classifieds at the moment.





回页首

单向服务

继续讨论之前,让我们了解一下处理单向服务(而非请求/响应服务)时涉及到的不同之处。

服务

创建单向服务非常简单。此过程与创建请求/响应服务完全类似,至少不会实际返回任何内容。例如,可以为 CMSService 类创建 addArticle 操作,如图 29 中所示。


清单 29. CMSServiceclass 中的 addArticle 操作
...
    private Integer articleCount(String catId){
...
    }

    public void addArticle(OMElement element) 
                             throws XMLStreamException{
       element.build();
       System.out.println(element);
    }
}

在 services.xml 文件中,将 addArticle 操作指定为“in only”操作,因此不会等待返回任何内容,但即使这样,也能看到会实际发生一些事项,会在命令行输出接收到的有效负载。您将在 Geronimo 窗口中看到此信息。

在实际应用程序中,此方法将从有效负载提取信息,并会实际添加到某种类型的数据库或其他存储库。





回页首


客户机

此服务的客户机也与请求/响应服务所使用的服务类似(请参见清单 30)。


清单 30. 创建客户机
                    
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.om.OMElement;
import org.apache.axis2.SOAP.SOAPFactory;
import org.apache.axis2.om.OMAbstractFactory;
import org.apache.axis2.om.OMNamespace;

public class AddArticleClient {
    private static EndpointReference targetEPR = 
         new EndpointReference(
             "http://localhost:8080/axis2/services/CMSService");

    private static OMElement getOMElement(){

        SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
        OMNamespace omNs = fac.createOMNamespace(
                "http://daily-moon.com", "cms");
        OMElement method = fac.createOMElement("addArticle", omNs);

        OMElement category = fac.createOMElement("category", omNs);
        category.setText("classifieds");

        OMElement subcategory = 
                        fac.createOMElement("subcategory", omNs);
        category.setText("wantads");

        OMElement adtext = fac.createOMElement("article", omNs);
        adtext.setText("Do you  have good head for numbers"+
              " and a great deal of patience?  Do you like"+
              " to sit for hours sorting objects by their"+
              " size?  If so, then you could be the"+
              " next goober counter in the world famous"+
              " Murphy Brothers peanut factory. "+
              " Willingness to dress up as our mascot"+
              " helpful, but not required.");

        method.addChild(category);
        method.addChild(subcategory);
        method.addChild(adtext); 

        return method;

    }

    public static void main(String[] args) {
        try {
            OMElement payload = AddArticleClient.getOMElement();
            ServiceClient serviceClient = new ServiceClient();

            Options options = new Options();
            serviceClient.setOptions(options);
            options.setTo(targetEPR);

            serviceClient.fireAndForget(payload);

        } catch (AxisFault axisFault) {
            axisFault.printStackTrace();
        }
    }

}

尽管有效负载不同,但正如您在 getOMElement() 方法中看到的,编程方面目前的唯一真正的更改是使用 fireAndForget() 方法替代 sendReceive() 方法。此方法并不会返回响应。

如果运行此客户机,应该在 Geronimo 窗口中看到与图 5 中所示类似的输出。


图 5. 命令行输出
命令行输出




回页首

posted on 2006-12-29 18:39 SIMONE 阅读(810) 评论(0)  编辑  收藏 所属分类: AXISJAVA

只有注册用户登录后才能发表评论。


网站导航: