blob: 540fa6cbbcbb0b86ea4b1d60e171b20ced122ae4 [file] [log] [blame]
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 1.11.1 at 2022-07-14
| Rendered using Apache Maven Fluido Skin 1.6
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="Date-Revision-yyyymmdd" content="20220714" />
<meta http-equiv="Content-Language" content="en" />
<title>Apache Axis2 &#x2013; Axis2 Quick Start Guide</title>
<link rel="stylesheet" href="../css/apache-maven-fluido-1.6.min.css" />
<link rel="stylesheet" href="../css/site.css" />
<link rel="stylesheet" href="../css/print.css" media="print" />
<script type="text/javascript" src="../js/apache-maven-fluido-1.6.min.js"></script>
<meta name="generator" content="HTML Tidy for Windows (vers 14 June 2007), see www.w3.org" /><meta http-equiv="content-type" content="application/xhtml+xml; charset=us-ascii" /> </head>
<body class="topBarDisabled">
<div class="container-fluid">
<div id="banner">
<div class="pull-left"><a href="http://www.apache.org/" id="bannerLeft"><img src="http://www.apache.org/images/asf_logo_wide.png" alt="Apache Axis2"/></a></div>
<div class="pull-right"><a href=".././" id="bannerRight"><img src="../images/axis.jpg" /></a></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Last Published: 2022-07-14<span class="divider">|</span>
</li>
<li id="projectVersion">Version: 1.8.2<span class="divider">|</span></li>
<li class=""><a href="http://www.apache.org" class="externalLink" title="Apache">Apache</a><span class="divider">/</span></li>
<li class=""><a href="../index.html" title="Axis2/Java">Axis2/Java</a><span class="divider">/</span></li>
<li class="active ">Axis2 Quick Start Guide</li>
</ul>
</div>
<div class="row-fluid">
<div id="leftColumn" class="span2">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">Axis2/Java</li>
<li><a href="../index.html" title="Home"><span class="none"></span>Home</a> </li>
<li><a href="../download.html" title="Downloads"><span class="none"></span>Downloads</a> </li>
<li><a href="javascript:void(0)" title="Release Notes"><span class="icon-chevron-down"></span>Release Notes</a>
<ul class="nav nav-list">
<li><a href="../release-notes/1.6.1.html" title="1.6.1"><span class="none"></span>1.6.1</a> </li>
<li><a href="../release-notes/1.6.2.html" title="1.6.2"><span class="none"></span>1.6.2</a> </li>
<li><a href="../release-notes/1.6.3.html" title="1.6.3"><span class="none"></span>1.6.3</a> </li>
<li><a href="../release-notes/1.6.4.html" title="1.6.4"><span class="none"></span>1.6.4</a> </li>
<li><a href="../release-notes/1.7.0.html" title="1.7.0"><span class="none"></span>1.7.0</a> </li>
<li><a href="../release-notes/1.7.1.html" title="1.7.1"><span class="none"></span>1.7.1</a> </li>
<li><a href="../release-notes/1.7.2.html" title="1.7.2"><span class="none"></span>1.7.2</a> </li>
<li><a href="../release-notes/1.7.3.html" title="1.7.3"><span class="none"></span>1.7.3</a> </li>
<li><a href="../release-notes/1.7.4.html" title="1.7.4"><span class="none"></span>1.7.4</a> </li>
<li><a href="../release-notes/1.7.5.html" title="1.7.5"><span class="none"></span>1.7.5</a> </li>
<li><a href="../release-notes/1.7.6.html" title="1.7.6"><span class="none"></span>1.7.6</a> </li>
<li><a href="../release-notes/1.7.7.html" title="1.7.7"><span class="none"></span>1.7.7</a> </li>
<li><a href="../release-notes/1.7.8.html" title="1.7.8"><span class="none"></span>1.7.8</a> </li>
<li><a href="../release-notes/1.7.9.html" title="1.7.9"><span class="none"></span>1.7.9</a> </li>
<li><a href="../release-notes/1.8.0.html" title="1.8.0"><span class="none"></span>1.8.0</a> </li>
</ul>
</li>
<li><a href="../modules/index.html" title="Modules"><span class="none"></span>Modules</a> </li>
<li><a href="../tools/index.html" title="Tools"><span class="none"></span>Tools</a> </li>
<li class="nav-header">Documentation</li>
<li><a href="../docs/toc.html" title="Table of Contents"><span class="none"></span>Table of Contents</a> </li>
<li><a href="../docs/installationguide.html" title="Installation Guide"><span class="none"></span>Installation Guide</a> </li>
<li class="active"><a href="#"><span class="none"></span>QuickStart Guide</a>
</li>
<li><a href="../docs/userguide.html" title="User Guide"><span class="none"></span>User Guide</a> </li>
<li><a href="../docs/jaxws-guide.html" title="JAXWS Guide"><span class="none"></span>JAXWS Guide</a> </li>
<li><a href="../docs/pojoguide.html" title="POJO Guide"><span class="none"></span>POJO Guide</a> </li>
<li><a href="../docs/spring.html" title="Spring Guide"><span class="none"></span>Spring Guide</a> </li>
<li><a href="../docs/webadminguide.html" title="Web Administrator's Guide"><span class="none"></span>Web Administrator's Guide</a> </li>
<li><a href="../docs/migration.html" title="Migration Guide (from Axis1)"><span class="none"></span>Migration Guide (from Axis1)</a> </li>
<li class="nav-header">Resources</li>
<li><a href="../faq.html" title="FAQ"><span class="none"></span>FAQ</a> </li>
<li><a href="../articles.html" title="Articles"><span class="none"></span>Articles</a> </li>
<li><a href="http://wiki.apache.org/ws/FrontPage/Axis2/" class="externalLink" title="Wiki"><span class="none"></span>Wiki</a> </li>
<li><a href="../refLib.html" title="Reference Library"><span class="none"></span>Reference Library</a> </li>
<li><a href="../apidocs/index.html" title="Online Java Docs"><span class="none"></span>Online Java Docs</a> </li>
<li class="nav-header">Get Involved</li>
<li><a href="../overview.html" title="Overview"><span class="none"></span>Overview</a> </li>
<li><a href="../git.html" title="Checkout the Source"><span class="none"></span>Checkout the Source</a> </li>
<li><a href="../mail-lists.html" title="Mailing Lists"><span class="none"></span>Mailing Lists</a> </li>
<li><a href="../release-process.html" title="Release Process"><span class="none"></span>Release Process</a> </li>
<li><a href="../guidelines.html" title="Developer Guidelines"><span class="none"></span>Developer Guidelines</a> </li>
<li><a href="../siteHowTo.html" title="Build the Site"><span class="none"></span>Build the Site</a> </li>
<li class="nav-header">Project Information</li>
<li><a href="../team-list.html" title="Project Team"><span class="none"></span>Project Team</a> </li>
<li><a href="../issue-tracking.html" title="Issue Tracking"><span class="none"></span>Issue Tracking</a> </li>
<li><a href="http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/" class="externalLink" title="Source Code"><span class="none"></span>Source Code</a> </li>
<li><a href="../thanks.html" title="Acknowledgements"><span class="none"></span>Acknowledgements</a> </li>
<li class="nav-header">Apache</li>
<li><a href="http://www.apache.org/licenses/LICENSE-2.0.html" class="externalLink" title="License"><span class="none"></span>License</a> </li>
<li><a href="http://www.apache.org/foundation/sponsorship.html" class="externalLink" title="Sponsorship"><span class="none"></span>Sponsorship</a> </li>
<li><a href="http://www.apache.org/foundation/thanks.html" class="externalLink" title="Thanks"><span class="none"></span>Thanks</a> </li>
<li><a href="http://www.apache.org/security/" class="externalLink" title="Security"><span class="none"></span>Security</a> </li>
</ul>
<hr />
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a>
</div>
</div>
</div>
<div id="bodyColumn" class="span10" >
<html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml">
<h1>Axis2 Quick Start Guide</h1>
<p>The purpose of this guide is to get you started on creating
services and clients using Axis2 as quickly as possible. We'll take
a simple StockQuote Service and show you some of the different ways
in which you can create and deploy it, as well as take a quick look
at one or two utilities that come with Axis2. We'll then look at
creating clients to access those services.</p>
<section>
<h2><a name="Content"></a>Content</h2>
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#ready">Getting Ready</a></li>
<li><a href="#services">Axis2 services</a></li>
<li><a href="#create">Creating services</a>
<ul>
<li><a href="#deploy">Deploying POJOs</a></li>
<li><a href="#axiom">Building the service using AXIOM</a></li>
<li><a href="#adb">Generating the service using ADB</a></li>
<li><a href="#xmlbeans">Generating the service using
XMLBeans</a></li>
<li><a href="#jibx">Generating the service using JiBX</a></li>
</ul>
</li>
<li><a href="#clients">Generating Clients</a>
<ul>
<li><a href="#clientaxiom">Creating a client using AXIOM</a></li>
<li><a href="#clientadb">Generating a client using ADB</a></li>
<li><a href="#clientxmlbeans">Generating a client using XML
Beans</a></li>
<li><a href="#clientjibx">Generating a client using JiBX</a></li>
</ul>
</li>
<li><a href="#summary">Summary</a></li>
<li><a href="#furtherstudy">For Further Study</a></li>
</ul>
<section>
<h3><a name="A_Quick_Setup_Note:"></a>A Quick Setup Note:</h3>
<p>The code for the document can be found in the extracted <a href="../download.cgi">Standard
Binary Distribution</a>, more specifically at Axis2_HOME/samples/
inside the directories- quickstart, quickstartadb, quickstartaxiom,
quickstartjibx and quickstartxmlbeans. (Consider getting it now as
it will help you to follow along.) It includes Ant buildfiles
(build.xml) that we'll refer to throughout the examples to make
compilation easier.</p>
<a name="introduction" id="introduction"></a>
</section><section>
<h2><a name="Introduction"></a>Introduction</h2>
<p>Let's start with the service itself. We'll make it simple so you
can see what is going on when we build and deploy the services. A
StockQuoteService example seems to be mandatory in instances like
this one, so let's use the following (see Code Listing 1).</p>
<p><b>Code Listing 1: The StockQuoteService class</b></p>
<div>
<pre>
package samples.quickstart.service.pojo;
import java.util.HashMap;
public class StockQuoteService {
private HashMap map = new HashMap();
public double getPrice(String symbol) {
Double price = (Double) map.get(symbol);
if(price != null){
return price.doubleValue();
}
return 42.00;
}
public void update(String symbol, double price) {
map.put(symbol, new Double(price));
}
}
</pre></div>
<p>It will be a simple service with two possible calls. One of
which is an in/out message, and the other is an in-only service.
Ultimately, we'll package the service and deploy it in four
different ways.</p>
<p>First, let's look at how this simple Java class corresponds to a
service.</p>
<a name="ready" id="ready"></a>
<section>
<h2><a name="Getting_Ready"></a>Getting Ready</h2>
<p>Before we build anything using Axis2, we have to take care of a
little housekeeping. First off, you'll need to get your environment
ready for working with Axis2. Fortunately, it involves just a few
simple steps:</p>
<ol style="list-style-type: decimal">
<li>Download and install Java (Minimum version is JDK1.5). Set the
JAVA_HOME environment variable to the pathname of the directory
into which you installed the JDK release.</li>
<li>Download Axis2 and extract it to a target directory.</li>
<li>Copy the axis2.war file to the webapps directory of your
servlet engine.</li>
<li>Set the AXIS2_HOME environment variable to point to the target
directory in step. Note that all of the scripts and build files
Axis2 generates depend on this value, so don't skip this step!
Linux users can alternatively run the setenv.sh file in the
AXIS2_HOME/bin directory to set the AXIS2_HOME environment variable
to the pathname of the extracted directory of Axis2.</li>
</ol>
<p>In most cases, we're also going to need a WSDL file for our
service. Axis2's Java2WSDL can be used to bootstrap a WSDL. To
generate a WSDL file from a Java class, perform the following
steps:</p>
<ol style="list-style-type: decimal">
<li>Create and compile the Java class.
<div>
<pre>
(Windows)
%AXIS2_HOME%\bin\java2wsdl.bat -cp . -cn samples.quickstart.service.pojo.StockQuoteService -of StockQuoteService.wsdl
(Linux)
$AXIS2_HOME/bin/java2wsdl.sh -cp . -cn samples.quickstart.service.pojo.StockQuoteService -of StockQuoteService.wsdl
</pre></div></li>
<li>Generate the WSDL using the command:</li>
</ol>
<p>Once you've generated the WSDL file, you can make the changes
you need. For example, you might add custom faults or change the
name of the generated elements. For example, this
StockQuoteService.wsdl is in
AXIS2_HOME/samples/quickstartadb/resources/META-INF folder, which
we'll be using throughout the rest of this guide, replaces the
generic parameters created by the generation process.</p>
<a name="services" id="services"></a>
<section>
<h2><a name="Axis2_Services"></a>Axis2 Services</h2>
<p>Before we build anything, it's helpful to understand what the
finished product looks like.</p>
<p>The server side of Axis2 can be deployed on any Servlet engine,
and has the following structure. Shown in Code Listing 2.</p>
<p><b>Code Listing 2: The Directory Structure of axis2.war</b></p>
<div>
<pre>
axis2-web
META-INF
WEB-INF
classes
conf
axis2.xml
lib
activation.jar
...
xmlSchema.jar
modules
modules.list
addressing.mar
...
soapmonitor.mar
services
services.list
aservice.aar
...
version.aar
web.xml
</pre></div>
<p>Starting at the top, axis2-web is a collection of JSPs that make
up the Axis2 administration application, through which you can
perform any action such as adding services and engaging and
dis-engaging modules. The WEB-INF directory contains the actual
java classes and other support files to run any services deployed
to the services directory.</p>
<p>The main file in all this is axis2.xml, which controls how the
application deals with the received messages, determining whether
Axis2 needs to apply any of the modules defined in the modules
directory.</p>
<p>Services can be deployed as *.aar files, as you can see here,
but their contents must be arranged in a specific way. For example,
the structure of this service will be as follows:</p>
<a name="aarstructure" id="aarstructure"></a>
<div>
<pre>
- StockQuoteService
- META-INF
- services.xml
- lib
- samples
- quickstart
- service
- pojo
- StockQuoteService.class
</pre></div>
<p>Here, the name of the service is StockQuoteService, which is
specified in the services.xml file and corresponds to the top-level
folder of this service. Compiled Java classes are placed underneath
this in their proper place based on the package name. The lib
directory holds any service-specific JAR files needed for the
service to run (none in this case) besides those already stored
with the Axis2 WAR file and the servlet container's common JAR
directories. Finally, the META-INF directory contains any
additional information about the service that Axis2 needs to
execute it properly. The services.xml file defines the service
itself and links the Java class to it (See Code Listing 3).</p>
<p><b>Code Listing 3: The Service Definition File</b></p>
<div>
<pre>
&lt;service name=&quot;StockQuoteService&quot; scope=&quot;application&quot;&gt;
&lt;description&gt;
Stock Quote Sample Service
&lt;/description&gt;
&lt;messageReceivers&gt;
&lt;messageReceiver
mep=&quot;http://www.w3.org/ns/wsdl/in-only&quot;
class=&quot;org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver&quot;/&gt;
&lt;messageReceiver
mep=&quot;http://www.w3.org/ns/wsdl/in-out&quot;
class=&quot;org.apache.axis2.rpc.receivers.RPCMessageReceiver&quot;/&gt;
&lt;/messageReceivers&gt;
&lt;parameter name=&quot;ServiceClass&quot;&gt;
samples.quickstart.service.pojo.StockQuoteService
&lt;/parameter&gt;
&lt;/service&gt;
</pre></div>
<p>Here the service is defined, along with the relevant
messageReceiver types for the different message exchange
patterns.</p>
<p>The META-INF directory is also the location for any custom WSDL
files you intend to include for this application.</p>
<p>You can deploy a service by simply taking this hierarchy of
files and copying it to the webapps/axis2/WEB-INF/services
directory of your servlet engine. (Note the Axis2 WAR file must be
installed first in the servlet engine.) This is known as the
&quot;exploded&quot; format. You can also compress your documents into an
*.aar file, similar to a *.jar file, and place the *.aar file
directly in the servlet engine's webapps/axis2/WEB-INF/services
directory.</p>
<p>Now that you understand what we're trying to accomplish, we're
almost ready to start building.</p>
<p>First, <a href="../download.cgi">download</a>
and unzip the appropriate version of Axis2 Standard Binary
Distribution. Make sure that you set the value of the AXIS2_HOME
variable to match the location into which you extracted the
contents of this release.</p>
<p>Let's look at some different ways to create clients and
services.</p>
<a name="create" id="create"></a>
<section>
<h2><a name="Creating_Services"></a>Creating Services</h2>
<p>In this section, we'll look at five ways to create a service
based on the StockQuoteService class: deploying Plain Old Java
Objects (POJO), building the service using AXIOM's OMElement,
generating the service using Axis2 Databinding Framework (ADB),
generating the service using XMLBeans, and generating the service
using JiBX.</p>
<a name="deploy" id="deploy"></a>
<section>
<h3><a name="Deploying_POJOs"></a>Deploying POJOs</h3>
<p>To deploy the service using POJOs (Plain Old Java Objects),
execute the following steps.</p>
<p>Note the directory structure contained at
AXIS2_HOME/samples/quickstart (the services.xml file is
from the first section of this guide):</p>
<div>
<pre>
- quickstart
- README.txt
- build.xml
- resources
- META-INF
- services.xml
- src
- samples
- quickstart
- service
- pojo
- StockQuoteService.java
</pre></div>
<p>Note that you can generate a WSDL from the quickstart directory
by typing:</p>
<div>
<pre>
ant generate.wsdl
</pre></div>
However, creating StockQuoteService.wsdl is optional. It can be the
version generated directly from the Java class, or a customized
version of that file, and that services.xml is the same file
referenced earlier in this document.
<p>Now build the project by typing ant generate.service in the
quickstart directory, which creates the following directory
structure:</p>
<div>
<pre>
- quickstart/build/classes
- META-INF
- services.xml
- samples
- quickstart
- service
- pojo
- StockQuoteService.class
</pre></div>
<p>If you want to deploy the service in an exploded directory
format, rename the classes directory to StockQuoteService, and copy
it to the webapps/axis2/WEB-INF/services directory in your servlet
engine. Otherwise, copy the build/StockQuoteService.aar file to the
webapps/axis2/WEB-INF/services directory in your servlet engine.
Then check to make sure that the service has been properly deployed
by viewing the list of services at:</p>
<div>
<pre>
http://localhost:8080/axis2/services/listServices
</pre></div>
<p>You can also checkout the WSDL at:</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?wsdl
</pre></div>
<p>And the schema at:</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?xsd
</pre></div>
<p>Once the URLs are working, quickly test the service. Try
pointing your browser to the following URL:</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService/getPrice?symbol=IBM
</pre></div>
<p>You will get the following response:</p>
<div>
<pre>
&lt;ns:getPriceResponse xmlns:ns=&quot;http://pojo.service.quickstart.samples/xsd&quot;&gt;&lt;ns:return&gt;42&lt;/ns:return&gt;&lt;/ns:getPriceResponse&gt;
</pre></div>
<p>If you invoke the update method as,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService/update?symbol=IBM&amp;price=100
</pre></div>
and then execute the first getPrice URL, you will see that the
price has got updated. <a name="axiom" id="axiom"></a>
</section><section>
<h3><a name="Building_the_Service_using_AXIOM"></a>Building the Service using AXIOM</h3>
<p>To build a service &quot;from scratch&quot; using AXIOM, execute the
following steps.</p>
<p>Note the directory structure contained at
/samples/quickstartaxiom:</p>
<div>
<pre>
- quickstartaxiom
- README.txt
- build.xml
- resources
- META-INF
- services.xml
- StockQuoteService.wsdl
- src
- samples
- quickstart
- service
- axiom
- StockQuoteService.java
- clients
- AXIOMClient.java
</pre></div>
<p>Since AXIOM is a little different, you're going to need a
different services.xml file from the one used for POJO. Define it,
as shown in Code Listing 4.</p>
<p><b>Code Listing 4: The Service Definition File.</b></p>
<div>
<pre>
&lt;service name=&quot;StockQuoteService&quot; scope=&quot;application&quot;&gt;
&lt;description&gt;
Stock Quote Service
&lt;/description&gt;
&lt;operation name=&quot;getPrice&quot;&gt;
&lt;messageReceiver class=&quot;org.apache.axis2.receivers.RawXMLINOutMessageReceiver&quot;/&gt;
&lt;/operation&gt;
&lt;operation name=&quot;update&quot;&gt;
&lt;messageReceiver class=&quot;org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver&quot;/&gt;
&lt;/operation&gt;
&lt;parameter name=&quot;ServiceClass&quot;&gt;samples.quickstart.service.axiom.StockQuoteService&lt;/parameter&gt;
&lt;/service&gt;
</pre></div>
<p>Note that it's almost the same, except that the operations are
explicitly defined in the service.xml file, and the
MessageReceivers are now RawXML.</p>
<p>Now, the above referenced StockQuoteService.java class, a plain
Java class that uses classes from the Axis2 libraries, is defined
as shown in Code Listing 5.</p>
<p><b>Code Listing 5: The StockQuoteService Class using
AXIOM</b></p>
<div>
<pre>
package samples.quickstart.service.axiom;
import javax.xml.stream.XMLStreamException;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import java.util.HashMap;
public class StockQuoteService {
private HashMap map = new HashMap();
public OMElement getPrice(OMElement element) throws XMLStreamException {
element.build();
element.detach();
OMElement symbolElement = element.getFirstElement();
String symbol = symbolElement.getText();
String returnText = &quot;42&quot;;
Double price = (Double) map.get(symbol);
if(price != null){
returnText = &quot;&quot; + price.doubleValue();
}
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs =
fac.createOMNamespace(&quot;http://axiom.service.quickstart.samples/xsd&quot;, &quot;tns&quot;);
OMElement method = fac.createOMElement(&quot;getPriceResponse&quot;, omNs);
OMElement value = fac.createOMElement(&quot;price&quot;, omNs);
value.addChild(fac.createOMText(value, returnText));
method.addChild(value);
return method;
}
public void update(OMElement element) throws XMLStreamException {
element.build();
element.detach();
OMElement symbolElement = element.getFirstElement();
String symbol = symbolElement.getText();
OMElement priceElement = (OMElement)symbolElement.getNextOMSibling();
String price = priceElement.getText();
map.put(symbol, new Double(price));
}
}
</pre></div>
<p>Axis2 uses AXIOM, or the AXIs Object Model, a <a class="externalLink" href="http://www.w3.org/DOM/">DOM</a> (Document Object Model)-like
structure that is based on the StAX API (Streaming API for XML).
Methods that act as services must take as their argument an
OMElement, which represents an XML element that happens, in this
case, to be the payload of the incoming SOAP message. Method
getPrice(OMElement), for example, extracts the contents of the
first child of the payload element, which corresponds to the stock
symbol, and uses this to look up the current price of the stock.
Unless this is an &quot;in only&quot; service, these methods must return an
OMElement, because that becomes the payload of the return SOAP
message.</p>
<p>Now build the project by typing ant generate.service in the
Axis2_HOME/samples/quickstartaxiom directory.</p>
<p>Place the StockQuoteService.aar file in the
webapps/axis2/WEB-INF/services directory of the servlet engine, and
check to make sure that the service has been properly deployed by
viewing the list of services at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/listServices
</pre></div>
<p>You can also check the custom WSDL at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?wsdl
</pre></div>
<p>and the schema at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?xsd
</pre></div>
<a name="adb" id="adb"></a>
</section><section>
<h3><a name="Generating_the_Service_using_ADB"></a>Generating the Service using ADB</h3>
<p>To generate and deploy the service using the Axis2 Databinding
Framework (ADB), execute the following steps.</p>
<p>Generate the skeleton using the WSDL2Java utility by typing the
following in the Axis2_HOME/samples/quickstartadb directory:</p>
<div>
<pre>
(Windows)
%AXIS2_HOME%\bin\wsdl2java.bat -uri resources\META-INF\StockQuoteService.wsdl -p samples.quickstart.service.adb -d adb -s -ss -sd -ssi -o build\service
(Linux)
$AXIS2_HOME/bin/wsdl2java.sh -uri resources/META-INF/StockQuoteService.wsdl -p samples.quickstart.service.adb -d adb -s -ss -sd -ssi -o build/service
</pre></div>
<p>Else, simply type ant generate.service in the
Axis2_HOME/samples/quickstartadb directory.</p>
<p>The option -d adb specifies Axis Data Binding (ADB). The -s
switch specifies synchronous or blocking calls only. The -ss switch
creates the server side code (skeleton and related files). The -sd
switch creates a service descriptor (services.xml file). The -ssi
switch creates an interface for the service skeleton. The service
files should now be located at build/service.</p>
<p>If you generated the code by using WSDL2Java directly, next you
have to modify the generated skeleton to implement the service (if
you used &quot;ant generate.service&quot;, a completed skeleton will be
copied over the generated one automatically).</p>
<p>Open the
build/service/src/samples/quickstart/adb/service/StockQuoteServiceSkeleton.java
file and modify it to add the functionality of your service to the
generated methods; shown in Code Listing 6.</p>
<p><b>Code Listing 6: Defining the Service Skeleton File</b></p>
<div>
<pre>
package samples.quickstart.service.adb;
import samples.quickstart.service.adb.xsd.GetPriceResponse;
import samples.quickstart.service.adb.xsd.Update;
import samples.quickstart.service.adb.xsd.GetPrice;
import java.util.HashMap;
public class StockQuoteServiceSkeleton implements StockQuoteServiceSkeletonInterface {
private static HashMap map;
static{ map = new HashMap(); }
public void update(Update param0) {
map.put(param0.getSymbol(), new Double(param0.getPrice()));
}
public GetPriceResponse getPrice(GetPrice param1) {
Double price = (Double) map.get(param1.getSymbol());
double ret = 42;
if(price != null){
ret = price.doubleValue();
}
GetPriceResponse res =
new GetPriceResponse();
res.set_return(ret);
return res;
}
}
</pre></div>
<p>Now you can build the project by typing the following command in
the build/service directory:</p>
<div>
<pre>
ant jar.server
</pre></div>
<p>If all goes well, you should see the BUILD SUCCESSFUL message in
your window, and the StockQuoteService.aar file in the
build/service/build/lib directory. Copy this file to the
webapps/axis2/WEB-INF/services directory of the servlet engine.</p>
<p>You can check to make sure that the service has been properly
deployed by viewing the list of services at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/listServices
</pre></div>
<p>You can also check the custom WSDL at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?wsdl
</pre></div>
<p>and the schema at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?xsd
</pre></div>
<a name="xmlbeans" id="xmlbeans"></a>
</section><section>
<h3><a name="Generating_the_Service_using_XMLBeans"></a>Generating the Service using XMLBeans</h3>
<p>To generate a service using XMLBeans, execute the following
steps.</p>
<p>Generate the skeleton using the WSDL2Java utility by typing the
following in the Axis2_HOME/samples/quickstartxmlbeans
directory.</p>
<div>
<pre>
%AXIS2_HOME%\bin\wsdl2java.bat -uri resources\META-INF\StockQuoteService.wsdl -p samples.quickstart.service.xmlbeans -d xmlbeans -s -ss -sd -ssi -o build\service
</pre></div>
<p>Else simply type ant generate.service in the
Axis2_HOME/samples/quickstartxmlbeans directory.</p>
<p>The option -d xmlbeans specifies XML Beans data binding. The -s
switch specifies synchronous or blocking calls only. The -ss switch
creates the server side code (skeleton and related files). The -sd
switch creates a service descriptor (services.xml file). The -ssi
switch creates an interface for the service skeleton. The service
files should now be located at build/service.</p>
<p>If you generated the code by using WSDL2Java directly, next you
have to modify the generated skeleton to implement the service (if
you used &quot;ant generate.service&quot;, a completed skeleton will be
copied over the generated one automatically).</p>
<p>Next open the
build/service/src/samples/quickstart/service/xmlbeans/StockQuoteServiceSkeleton.java
file and modify it to add the functionality of your service to the
generated methods (see Code Listing 7).</p>
<p><b>Code Listing 7: Defining the Service Skeleton</b></p>
<div>
<pre>
package samples.quickstart.service.xmlbeans;
import samples.quickstart.service.xmlbeans.xsd.GetPriceDocument;
import samples.quickstart.service.xmlbeans.xsd.GetPriceResponseDocument;
import samples.quickstart.service.xmlbeans.xsd.UpdateDocument;
import java.util.HashMap;
public class StockQuoteServiceSkeleton implements StockQuoteServiceSkeletonInterface {
private static HashMap map;
static{ map = new HashMap(); }
public void update(UpdateDocument param0) {
<b>map.put(param0.getUpdate().getSymbol(), new Double(param0.getUpdate().getPrice()));</b>
}
public GetPriceResponseDocument getPrice(GetPriceDocument param1) {
<b>Double price = (Double) map.get(param1.getGetPrice().getSymbol());
double ret = 42;
if(price != null){
ret = price.doubleValue();
}
System.err.println();
GetPriceResponseDocument resDoc =
GetPriceResponseDocument.Factory.newInstance();
GetPriceResponseDocument.GetPriceResponse res =
resDoc.addNewGetPriceResponse();
res.setReturn(ret);
return resDoc;</b>
}
}
</pre></div>
<p>Build the project by typing the following command in the
build/service directory, which contains the build.xml file:</p>
<div>
<pre>
ant jar.server
</pre></div>
<p>If all goes well, you should see the BUILD SUCCESSFUL message in
your window, and the StockQuoteService.aar file in the newly
created build/service/build/lib directory. Copy this file to the
webapps/axis2/WEB-INF/services directory of the servlet engine.</p>
<p>You can check to make sure that the service has been properly
deployed by viewing the list of services at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/listServices
</pre></div>
<p>You can also check the custom WSDL at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?wsdl
</pre></div>
<p>and the schema at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?xsd
</pre></div>
<a name="jibx" id="jibx"></a>
</section><section>
<h3><a name="Generating_the_Service_using_JiBX"></a>Generating the Service using JiBX</h3>
<p>To generate and deploy the service using <a class="externalLink" href="http://www.jibx.org">JiBX data binding</a>, execute the following
steps.</p>
<p>Generate the skeleton using the WSDL2Java utility by typing the
following at a console in the Axis2_HOME/samples/quickstartjibx
directory:</p>
<div>
<pre>
%AXIS2_HOME%\bin\wsdl2java.bat -uri resources\META-INF\StockQuoteService.wsdl -p samples.quickstart.service.jibx -d jibx -s -ss -sd -ssi -uw -o build\service
</pre></div>
<p>Else, simply type &quot;ant generate.service&quot; in the
Axis2_HOME/samples/quickstartjibx directory.</p>
<p>The option -d jibx specifies JiBX data binding. The -s switch
specifies synchronous or blocking calls only. The -ss switch
creates the server side code (skeleton and related files). The -sd
switch creates a service descriptor (services.xml file). The -ssi
switch creates an interface for the service skeleton. The -uw
switch unwraps the parameters passed to and from the service
operations in order to create a more natural programming
interface.</p>
<p>After running WSDL2Java, the service files should be located at
build/service. If you generated the code by using WSDL2Java
directly, you need to modify the generated skeleton to implement
the service (if you used &quot;ant generate.service&quot; a completed
skeleton will be copied over the generated one automatically). Open
the
build/service/src/samples/quickstart/service/jibx/StockQuoteServiceSkeleton.java
file and modify it to add the functionality of your service to the
generated methods, as shown in Code Listing 8.</p>
<p><b>Code Listing 8: Defining the Service Skeleton File</b></p>
<div>
<pre>
package samples.quickstart.service.jibx;
import java.util.HashMap;
public class StockQuoteServiceSkeleton implements StockQuoteServiceSkeletonInterface {
private HashMap map = new HashMap();
public void update(String symbol, Double price) {
map.put(symbol, price);
}
public Double getPrice(String symbol) {
Double ret = (Double) map.get(symbol);
if (ret == null) {
ret = new Double(42.0);
}
return ret;
}
}
</pre></div>
<p>Now you can build the project by typing the following command in
the build/service directory:</p>
<div>
<pre>
ant jar.server
</pre></div>
<p>If all goes well, you should see the BUILD SUCCESSFUL message in
your window, and the StockQuoteService.aar file in the
build/service/build/lib directory. Copy this file to the
webapps/axis2/WEB-INF/services directory of the servlet engine.</p>
<p>You can check to make sure that the service has been properly
deployed by viewing the list of services at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/listServices
</pre></div>
<p>You can also check the custom WSDL at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?wsdl
</pre></div>
<p>and the schema at,</p>
<div>
<pre>
http://localhost:8080/axis2/services/StockQuoteService?xsd
</pre></div>
<p>For more information on using JiBX with Axis2, see the <a href="jibx/jibx-codegen-integration.html">JiBX code generation
integration</a> details.</p>
<a name="clients" id="clients"></a>
</section><section>
<h2><a name="Creating_Clients"></a>Creating Clients</h2>
<p>In this section, we'll look at four ways to create clients based
on the StockQuoteService class: building an AXIOM based client,
generating a client using Axis2 Databinding Framework (ADB),
generating a client using XMLBeans, and generating a client using
JiBX.</p>
<a name="clientaxiom" id="clientaxiom"></a>
<section>
<h3><a name="Creating_a_Client_with_AXIOM"></a>Creating a Client with AXIOM</h3>
<p>To build a client using AXIOM, execute the following steps.</p>
<p>Also, note the directory structure shown in the Creating a
service with AXIOM section, duplicated below for completeness.</p>
<div>
<pre>
- quickstartaxiom
- README.txt
- build.xml
- resources
- META-INF
- services.xml
- StockQuoteService.wsdl
- src
- samples
- quickstart
- service
- axiom
- StockQuoteService.java
- clients
- AXIOMClient.java
</pre></div>
<p>The above referenced AXIOMClient.java class is defined as
follows, shown in Code Listing 9.</p>
<p><b>Code Listing 9: The AXIOMClient class using AXIOM</b></p>
<div>
<pre>
package samples.quickstart.clients;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
public class AXIOMClient {
private static EndpointReference targetEPR =
new EndpointReference(&quot;http://localhost:8080/axis2/services/StockQuoteService&quot;);
public static OMElement getPricePayload(String symbol) {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(&quot;http://axiom.service.quickstart.samples/xsd&quot;, &quot;tns&quot;);
OMElement method = fac.createOMElement(&quot;getPrice&quot;, omNs);
OMElement value = fac.createOMElement(&quot;symbol&quot;, omNs);
value.addChild(fac.createOMText(value, symbol));
method.addChild(value);
return method;
}
public static OMElement updatePayload(String symbol, double price) {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(&quot;http://axiom.service.quickstart.samples/xsd&quot;, &quot;tns&quot;);
OMElement method = fac.createOMElement(&quot;update&quot;, omNs);
OMElement value1 = fac.createOMElement(&quot;symbol&quot;, omNs);
value1.addChild(fac.createOMText(value1, symbol));
method.addChild(value1);
OMElement value2 = fac.createOMElement(&quot;price&quot;, omNs);
value2.addChild(fac.createOMText(value2,
Double.toString(price)));
method.addChild(value2);
return method;
}
public static void main(String[] args) {
try {
OMElement getPricePayload = getPricePayload(&quot;WSO&quot;);
OMElement updatePayload = updatePayload(&quot;WSO&quot;, 123.42);
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
sender.fireAndForget(updatePayload);
System.err.println(&quot;price updated&quot;);
OMElement result = sender.sendReceive(getPricePayload);
String response = result.getFirstElement().getText();
System.err.println(&quot;Current price of WSO: &quot; + response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
</pre></div>
<p>Axis2 uses AXIOM, or the AXIs Object Model, a DOM (Document
Object Model)-like structure that is based on the StAX API
(Streaming API for XML). Here you setup the payload for the update
and getPrice methods of the service. The payloads are created
similar to how you created the getPriceResponse payload for the
AXIOM service. Then you setup the Options class, and create a
ServiceClient that you'll use to communicate with the service.
First you call the update method, which is a fireAndForget method
that returns nothing. Lastly, you call the getPrice method, and
retrieve the current price from the service and display it.</p>
<p>Now you can build and run the AXIOM client by typing ant
run.client in the Axis2_HOME/samples/quickstartaxiom directory.</p>
<p>You should get the following as output:</p>
<div>
<pre>
done
Current price of WSO: 123.42
</pre></div>
<a name="clientadb" id="clientadb"></a>
</section><section>
<h3><a name="Generating_a_Client_using_ADB"></a>Generating a Client using ADB</h3>
<p>To build a client using Axis Data Binding (ADB), execute the
following steps.</p>
<p>Generate the client data bindings by typing the following in the
Axis2_HOME/samples/quickstartadb directory:</p>
<div>
<pre>
%AXIS2_HOME%\bin\wsdl2java.bat -uri resources\META-INF\StockQuoteService.wsdl -p samples.quickstart.clients -d adb -s -o build\client
</pre></div>
<p>Else, simply type ant generate.client in the
Axis2_HOME/samples/quickstartadb directory.</p>
<p>Next take a look at
quickstartadb/src/samples/quickstart/clients/ADBClient.java, and
see how it's defined in Code Listing 10.</p>
<p><b>Code Listing 10: The ADBClient Class</b></p>
<div>
<pre>
package samples.quickstart.clients;
import samples.quickstart.service.adb.StockQuoteServiceStub;
public class ADBClient{
public static void main(java.lang.String args[]){
try{
StockQuoteServiceStub stub =
new StockQuoteServiceStub
(&quot;http://localhost:8080/axis2/services/StockQuoteService&quot;);
getPrice(stub);
update(stub);
getPrice(stub);
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
/* fire and forget */
public static void update(StockQuoteServiceStub stub){
try{
StockQuoteServiceStub.Update req = new StockQuoteServiceStub.Update();
req.setSymbol (&quot;ABC&quot;);
req.setPrice (42.35);
stub.update(req);
System.err.println(&quot;price updated&quot;);
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
/* two way call/receive */
public static void getPrice(StockQuoteServiceStub stub){
try{
StockQuoteServiceStub.GetPrice req = new StockQuoteServiceStub.GetPrice();
req.setSymbol(&quot;ABC&quot;);
StockQuoteServiceStub.GetPriceResponse res =
stub.getPrice(req);
System.err.println(res.get_return());
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
}
</pre></div>
<p>This class creates a client stub using the Axis Data Bindings
you created. Then it calls the getPrice and update operations on
the Web service. The getPrice method operation creates the GetPrice
payload and sets the symbol to ABC. It then sends the request and
displays the current price. The update method creates an Update
payload, setting the symbol to ABC and the price to 42.35.</p>
<p>Now build and run the client by typing ant run.client in the
Axis2_HOME/samples/quickstartadb directory.</p>
<p>You should get the following as output:</p>
<div>
<pre>
42
price updated
42.35
</pre></div>
<a name="clientxmlbeans" id="clientxmlbeans"></a>
</section><section>
<h3><a name="Generating_a_Client_using_XMLBeans"></a>Generating a Client using XMLBeans</h3>
<p>To build a client using the XML Beans data bindings, execute the
following steps.</p>
<p>Generate the databings by typing the following in the
xmlbeansClient directory.</p>
<div>
<pre>
%AXIS2_HOME%\bin\wsdl2java.bat -uri resources\META-INF\StockQuoteService.wsdl -p samples.quickstart.service.xmlbeans -d xmlbeans -s -o build\client
</pre></div>
<p>Else, simply type ant generate.client in the
Axis2_HOME/samples/quickstartxmlbeans directory.</p>
<p>Note that this creates a client stub code and no server side
code.</p>
<p>Next take a look at
quickstartxmlbeans/src/samples/quickstart/clients/XMLBEANSClient.java,
and see how it's defined in Code Listing 11.</p>
<p><b>Code Listing 11: The XMLBEANSClient class</b></p>
<div>
<pre>
package samples.quickstart.clients;
import samples.quickstart.service.xmlbeans.StockQuoteServiceStub;
import samples.quickstart.service.xmlbeans.xsd.GetPriceDocument;
import samples.quickstart.service.xmlbeans.xsd.GetPriceResponseDocument;
import samples.quickstart.service.xmlbeans.xsd.UpdateDocument;
public class XMLBEANSClient{
public static void main(java.lang.String args[]){
try{
StockQuoteServiceStub stub =
new StockQuoteServiceStub
(&quot;http://localhost:8080/axis2/services/StockQuoteService&quot;);
getPrice(stub);
update(stub);
getPrice(stub);
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
/* fire and forget */
public static void update(StockQuoteServiceStub stub){
try{
UpdateDocument reqDoc = UpdateDocument.Factory.newInstance();
UpdateDocument.Update req = reqDoc.addNewUpdate();
req.setSymbol (&quot;BCD&quot;);
req.setPrice (42.32);
stub.update(reqDoc);
System.err.println(&quot;price updated&quot;);
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
/* two way call/receive */
public static void getPrice(StockQuoteServiceStub stub){
try{
GetPriceDocument reqDoc = GetPriceDocument.Factory.newInstance();
GetPriceDocument.GetPrice req = reqDoc.addNewGetPrice();
req.setSymbol(&quot;BCD&quot;);
GetPriceResponseDocument res =
stub.getPrice(reqDoc);
System.err.println(res.getGetPriceResponse().getReturn());
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
}
</pre></div>
<p>This class creates a client stub using the XML Beans data
bindings you created. Then it calls the getPrice and the update
operations on the Web service. The getPrice method operation
creates the GetPriceDocument, its inner GetPrice classes and sets
the symbol to ABC. It then sends the request and retrieves a
GetPriceResponseDocument and displays the current price. The update
method creates an UpdateDocument, updates and sets the symbol to
ABC and price to 42.32, displaying 'done' when complete.</p>
<p>Now build and run the the project by typing ant run.client in
the Axis2_HOME/samples/quickstartxmlbeans directory.</p>
<p>You should get the following as output:</p>
<div>
<pre>
42
price updated
42.32
</pre></div>
<a name="clientjibx" id="clientjibx"></a>
</section><section>
<h3><a name="Generating_a_Client_using_JiBX"></a>Generating a Client using JiBX</h3>
<p>To build a client using JiBX, execute the following steps.</p>
<p>Generate the client stub by typing the following at a console in
the Axis2_HOME/samples/quickstartjibx directory.</p>
<div>
<pre>
%AXIS2_HOME%\bin\wsdl2java.bat -uri resources\META-INF\StockQuoteService.wsdl -p samples.quickstart.clients -d jibx -s -uw -o build\client
</pre></div>
<p>Else, simply type &quot;ant generate.client&quot;.</p>
<p>Next take a look at
quickstartjibx/src/samples/quickstart/clients/JiBXClient.java,
shown below in Code Listing 12.</p>
<p><b>Code Listing 12: The JiBXClient class</b></p>
<div>
<pre>
package samples.quickstart.clients;
import samples.quickstart.service.jibx.StockQuoteServiceStub;
public class JiBXClient{
public static void main(java.lang.String args[]){
try{
StockQuoteServiceStub stub =
new StockQuoteServiceStub
(&quot;http://localhost:8080/axis2/services/StockQuoteService&quot;);
getPrice(stub);
update(stub);
getPrice(stub);
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
/* fire and forget */
public static void update(StockQuoteServiceStub stub){
try{
stub.update(&quot;CDE&quot;, new Double(42.35));
System.err.println(&quot;price updated&quot;);
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
/* two way call/receive */
public static void getPrice(StockQuoteServiceStub stub){
try{
System.err.println(stub.getPrice(&quot;CDE&quot;));
} catch(Exception e){
e.printStackTrace();
System.err.println(&quot;\n\n\n&quot;);
}
}
}
</pre></div>
<p>This class uses the created JiBX client stub to access the
getPrice and the update operations on the Web service. The getPrice
method sends a request for the stock &quot;ABC&quot; and displays the current
price. The update method setsnex the price for stock &quot;ABC&quot; to
42.35.</p>
<p>Now build and run the client by typing &quot;ant run.client&quot; at a
console in the Axis2_HOME/samples/quickstartjibx directory.</p>
<p>You should get the following as output:</p>
<div>
<pre>
42
price updated
42.35
</pre></div>
<p>For more information on using JiBX with Axis2, see the <a href="jibx/jibx-codegen-integration.html">JiBX code generation
integration</a> details.</p>
<a name="summary" id="summary"></a>
</section><section>
<h2><a name="Summary"></a>Summary</h2>
<p>Axis2 provides a slick and robust way to get web services up and
running in no time. This guide presented five methods of creating a
service deployable on Axis2, and four methods of creating a client
to communicate with the services. You now have the flexibility to
create Web services using a variety of different technologies.</p>
<a name="furtherstudy" id="furtherstudy"></a>
<section>
<h2><a name="For_Further_Study"></a>For Further Study</h2>
<p><a href="../index.html">Apache Axis2</a></p>
<p><a href="Axis2ArchitectureGuide.html">Axis2 Architecture</a></p>
<p>Introduction to Apache Axis2-<a class="externalLink" href="http://www.redhat.com/magazine/021jul06/features/apache_axis2/">http://www.redhat.com/magazine/021jul06/features/apache_axis2/</a></p>
</html>
</div>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p>Copyright &copy;2004&#x2013;2022
<a href="https://www.apache.org/">The Apache Software Foundation</a>.
All rights reserved.</p>
</div>
</div>
</footer>
</body>
</html>