If You're Having Trouble with Netbeans...

adorableautomaticSoftware and s/w Development

Aug 15, 2012 (5 years and 2 months ago)

326 views

page 1
If You're Having Trouble
with Netbeans...
...here's an alternative.
This chapter is an 'aside' that presents an alternative method of building Java-based web services (using JAX-WS
specifically), but does not require Netbeans. It also does not require Java EE (which you are using if you have
the correct version of Netbeans) and works in 'ordinary' Java SE 1.6 (or even 1.5).
There is however a big disadvantage - you must use the RPC style, which means you are restricted to the XML
Schema simple types - which for the purposes of this work means Booleans, strings and integers. There are
some other simple types - but you're not likely to find them useful. Whether or not this is a problem for your
implementation depends on how you have done it, or intend to do it. And I do suggest you try Netbeans first.
The reason I'm giving you this alternative is that some people are having configuration problems with Netbeans.
This is more-or-less inevitable given the range of variations of platforms that people are running. I do suggest
though that you still try Netbeans first. It deals with the server launch code for you, and allows you to deal with
substantially more complex types.
.1. The Server
We will rebuild one of the simple examples shown in the lectures. Unlike the Netbeans version, we have to first
write an interface (like RMI). You should note though that even in Netbeans (where you don't have to do this) it
is good practice. Here is the interface code, which we will explain below.
package BoldlyGo;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
@WebService
@SOAPBinding(style = Style.RPC)
public interface CptKirkInterface {
@WebMethod public String quote();
}

This is very similar to the example server code we have seen before, except that it's obviously an interface
and leaves off the definitions of the method and the launch code. The only thing that is new compared to the
examples is the use of @SOAPBinding and we saw that in the WSDL chapter
. We have explicitly set the SOAP
binding style to RPC. Notice we also need to import two packages to do this.
Now, we will look at the implementing class:
package BoldlyGo;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
@WebService(endpointInterface = "BoldlyGo.CptKirkInterface")
public class CptKirk implements CptKirkInterface {
public String quote() {
return("To boldly go where no man has gone before...");
}
public static void main(String[] args) {
page 2
Endpoint.publish("http://127.0.0.1:1664/st", new CptKirk());
}
}
We have included both the implementation of the web method and the launch code (in 'main') in the same class.
It would be better to separate them in a more complex example. Things that are new (or a bit different) here are:

WebService argument. The @WebService annotation has an argument 'endpointInterface =
"BoldlyGo.CptKirkInterface"'. This links the web service implementation to the interface.
Notice that this is in addtion to the implements CptKirkInterface clause. In fact, the code will
work if we leave implements off, but this is not good practice as it prevents the compiler from catching
some types of error. (Always better to get the compiler to spot errors when you can.)

Endpoint.publish. We saw Endpoint.publish when we looked at writing web services without
Netbeans. But just to be clear, the first arguement is the URL at which it will be deployed. 127.0.0.1 is the
same as localhost (and you can put localhost if you want); 1664 is an arbitrary port number (just make sure
it's not being used by something else); and /st is an arbitrary name - you can choose whatever you like. The
second argument is just an instance of the service.
.1.1. Compiling and Running
You compile and run this application just like any other Java code. There is no need to run tools like wsgen.
However, in case you are not familiar with using packages (or you are a bit rusty). You must create a directory
with the same name as the package (mkdir BoldlyGo in this case). You must then put all the source code
files in that directory. You can compile the code from within the directory, but to run it, you must change to the
one above. So for example, assuming you are already in the directory BoldlyGo:
NervousEnergy:BoldlyGo neal$ javac *.java #Compile the
code
NervousEnergy:BoldlyGo neal$ cd .. #Go up one level
NervousEnergy:webserv neal$ java BoldlyGo.CptKirk #run the code
Note that NervousEnergy is just the machine name; BoldlyGo is the directory with the code in it, and
webserv is the parent directory of BoldlyGo. You can avoid the potentially-tedious going up and down
directories by messing with the classpath, but in simple cases like this it's probably not worth the trouble. A
simple 'trick' is to just have two terminal windows, one for each directory.
.2. The WSDL File
Just like the more sophisticated Netbeans-based examples, you can look at the WSDL file at the published URL
with '?wsdl' appended. So in this case:
http://127.0.0.1:1664/st?wsdl
However, unlike the Netbeans/Glassfish versions, you can't test the web service from a browser. You may have
to 'view source' to see the actual WSDL - I do with Safari.
For information, here is the WSDL file.
<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-
WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI
2.1.6 in JDK 6. --><!-- Generated by JAX-WS RI at http://jax-
ws.dev.java.net. RI's version is JAX-WS RI 2.1.6 in JDK 6. --><definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://
BoldlyGo/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://
schemas.xmlsoap.org/wsdl/" targetNamespace="http://BoldlyGo/"
name="CptKirkService">
<types></types>
<message name="quote"></message>
<message name="quoteResponse">
<part name="return" type="xsd:string"></part>
</message>
<portType name="CptKirkInterface">
<operation name="quote">
<input message="tns:quote"></input>
page 3
<output message="tns:quoteResponse"></output>
</operation>
</portType>
<binding name="CptKirkPortBinding" type="tns:CptKirkInterface">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="quote">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal" namespace="http://BoldlyGo/"></soap:body>
</input>
<output>
<soap:body use="literal" namespace="http://BoldlyGo/"></soap:body>
</output>
</operation>
</binding>
<service name="CptKirkService">
<port name="CptKirkPort" binding="tns:CptKirkPortBinding">
<soap:address location="http://localhost:1664/st"></soap:address>
</port>
</service>
</definitions>
Notice that (a) it's not that long and (b) the types section is empty.
.3. The Client
The client code is a bit different from the Netbeans version, and needs a bit more explanation. First, here's the
code.
package BoldlyGo;
import javax.xml.ws.Service;
import javax.xml.namespace.QName;
import java.net.URL;
public class Main {
public static void main(String[] args) throws Exception {
URL url = new URL("http://127.0.0.1:1664/st?wsdl");
QName qualName = new QName("http://BoldlyGo/","CptKirkService");
Service service = Service.create(url, qualName);
CptKirkInterface endPoint =
service.getPort(CptKirkInterface.class);
java.lang.String result = endPoint.quote();
System.out.println("Result = "+result);
}
}

Notice we have put this in the same package as the service code. This is acceptable in simple examples, and is
OK for the coursework. But in a real application you would obviously separate them. The code works as follows.

URL. First we create a URL object representing the WSDL file of the service we want to connect to. This
is hopefully pretty obvious. The URL class is well-established in Java though you have probably not used
it before.

Qualified Name. The QName class is less obvious and deserves explanation. A qualified name represents
the name of the service in XML complete with the attached namespace. This will be explained a bit more
page 4
below, but for now the service name is CptKirkService and the namespace chosen for us is http://
BoldlyGo/, which is created from the package name.

Create the Service. The next line calls the static Service.create factory method to return an instance
of a Service object, constructed from the URL of it's WSDL file, and the fully-qualified name of the
service.

Cast to Correct Class. Finally, we call the service.getport method to effectively 'cast' the Service
object to an instance of CptKirkInterface (note the interface not the implementation) on which we
can finally invoke our methods.
.4. Be Carefull
The most common mistake here, and one that is difficult to diagnose quickly, is not being careful enough where
you use the name of hte interface of the service, and the name of its implementation. Unfortunately, you can get
this wrong and still have code that compiles (but does not work). Look very carefully at both the service and the
client to see where to use which one.
One other warning that is only important if you create 'nested' package names. That is, instead (in this case) of
just 'BoldlyGo' we create a package 'Startrek.BoldlyGo'. In that case, the namespace for the fully-qualified name
(in the call to the QName constructor) is going to be: http://BoldlyGo.Startrek/. Notice the order of
the package name components is reversed.
And finally... notice the final '/' in the namespace name. If you leave it out, it won't work!
.5. Fully-Qualified Names
We have seen fully-qualified names in XML very commonly: for example, when we looked at stylesheets and
schemas. If you look at the top of the WSDL file above, you will see:
targetNamespace="http://BoldlyGo/" name="CptKirkService"
(The namespace also appears in other places in the WSDL file.) This information tells us that the fully-qualified
name of the service is going to be 'http://BoldlyGo:CptKirkService' and consequently service calls
will appear between tags:
<http://BoldlyGo:CptKirkService> ... </http://
BoldlyGo:CptKirkService>

.6. Running the Client
With the service running, then running the client is again just simply a matter of running a 'normal' java program.
In this case: 'java BoldlyGo.Main