‘Hello World’ with Glassfish, Metro and Maven

As might be clear by my latest posts I am currently working on a project where we use Glassfish and EJB3 as platform for our JEE application. One thing that we had to decide upon was the WebService framework we were going to use. There are quite some options available but I decided to have a look at Metro, the JAX-WS reference implementation. Also due to the fact that it is integrated with EJB3 and Glassfish.
To create my ‘HelloWorld’ service with Metro and Maven2 I used this post as a guideline. I am also going to work top-down (WSDL -> Java approach) so I will be starting with an existing WSDL and then generate/create the web service interface for that. Although the post I used as a guideline is very detailed I ran into some issues, mostly the result of using different versions of dependencies and plugins. In this post I show the steps I made to get it working. I am using Glassfish-v2ur2 (comes with Netbeans 6.5) , JDK1.5 and Maven 2.0.9.

  1. Create the Maven2 project
  2. Issue the command: mvn archetype:create -DgroupId=net.pascalalma.ws -DartifactId=echo-service
    This results in a standard Maven project. I removed the generated java files since we don’t need them.

  3. Setup the pom
  4. The default pom that was created in the first step has to be modified. I added several things which I explain next:

    <dependencies>
            ...
            <dependency>
                <groupId>com.sun.xml.ws</groupId>
                <artifactId>jaxws-rt</artifactId>
                <version>2.1.4</version>
            </dependency>
            <dependency>
                <groupId>javax.jws</groupId>
                <artifactId>jsr181-api</artifactId>
                <version>1.0-MR1</version>
            </dependency>
        ...
        </dependencies>
    

    These are dependencies that are used by the JAXWS plugin, which is used to generate the Webservice interface based on the supplied WSDL.

       <dependencies>
       ...
            <dependency>
                <groupId>glassfish</groupId>
                <artifactId>appserv-rt.jar</artifactId>
                <version>LATEST</version>
                <scope>system</scope>
                <systemPath>${glassfish.home}/lib/appserv-rt.jar</systemPath>
            </dependency>
            <dependency>
                <groupId>glassfish</groupId>
                <artifactId>javaee.jar</artifactId>
                <version>LATEST</version>
                <scope>system</scope>
                <systemPath>${glassfish.home}/lib/javaee.jar</systemPath>
            </dependency>
       ...
       </dependencies>
    

    These dependencies are used to compile the generated code and the WebService implementation class.

    Next there are some plugins to be configured:

        <build>
            <plugins>
            ...
                <!-- Plugin to generate JAXB classes and webservice interface -->
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>jaxws-maven-plugin</artifactId>
                    <version>1.10</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>wsimport</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <wsdlDirectory>
                            src/main/resources/wsdl
                        </wsdlDirectory>
                        <sourceDestDir>
                            ${basedir}/generated/src/main/java
                        </sourceDestDir>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>javax.jws</groupId>
                            <artifactId>jsr181-api</artifactId>
                            <version>1.0-MR1</version>
                        </dependency>
                    </dependencies>
                </plugin>
                ...
            </plugins>
        </build>
    

    This plugin is used for the actual generation of the Java code. It will put the code in the ‘generated’ folder.
    The next two plugins are used for compiling and cleaning the code. I have described the use of these plugins here.

     <build>
            <plugins>
            ...
                <!-- Plugin to add delete path to build cycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>2.2</version>
                    <configuration>
                        <filesets>
                            <fileset>
                                <directory>generated/src/main/java</directory>
                                <includes>
                                    <include>**/*.java</include>
                                </includes>
                            </fileset>
                        </filesets>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        ...
      </plugins>
    </build>
    

    And finally I add the necessary code to tell the compiler JDK 1.5 has to be used:

     <build>
            <plugins>
            ...
                 <!-- plugin to compile Java1.5 code -->
                 <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.0.2</version>
                    <configuration>
                        <source>1.5</source>
                        <target>1.5</target>
                    </configuration>
                </plugin>
            ...
           </plugins>
      </build>
    

    The complete pom.xml can be found here.

  5. Create the WSDL
  6. As shown in the plugin configuration I have added a WSDL file to a ‘wsdl’ folder in the ‘resource’ folder. The WSDL looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <wsdl:definitions name="DoubleIt"
       xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
       xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
       xmlns:tns="http://www.pascalalma.net/EchoIt"
       xmlns:types="http://www.pascalalma.net/EchoIt/types"
       targetNamespace="http://www.pascalalma.net/EchoIt">
        <wsdl:types>
            <xsd:schema targetNamespace="http://www.pascalalma.net/EchoIt/types">
                <xsd:element name="EchoIt">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="textToEcho" type="xsd:string"/>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
                <xsd:element name="EchoItResponse">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="echoedText" type="xsd:string" />
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
            </xsd:schema>
        </wsdl:types>
        <wsdl:message name="EchoItRequest">
            <wsdl:part element="types:EchoIt" name="parameters" />
        </wsdl:message>
        <wsdl:message name="EchoItResponse">
            <wsdl:part element="types:EchoItResponse" name="parameters" />
        </wsdl:message>
        <wsdl:portType name="EchoItPortType">
            <wsdl:operation name="EchoIt">
                <wsdl:input message="tns:EchoItRequest" />
                <wsdl:output message="tns:EchoItResponse" />
            </wsdl:operation>
        </wsdl:portType>
        <wsdl:binding name="EchoItBinding" type="tns:EchoItPortType">
            <soap:binding style="document"
             transport="http://schemas.xmlsoap.org/soap/http" />
            <wsdl:operation name="EchoIt">
                <soap:operation soapAction=""/>
                <wsdl:input>
                    <soap:body use="literal"/>
                </wsdl:input>
                <wsdl:output>
                    <soap:body use="literal"/>
                </wsdl:output>
            </wsdl:operation>
        </wsdl:binding>
        <wsdl:service name="EchoItService">
            <wsdl:port name="EchoItPort" binding="tns:EchoItBinding">
                <soap:address
                location="http://localhost:8080/echoit/echoit"/>
            </wsdl:port>
        </wsdl:service>
    </wsdl:definitions>
    
  7. Generate the code
  8. When all this is in place we can generate the Java code by simply issue the command:
    mvn clean install
    In Netbeans we can see the generated code in our project browser:

  9. Create Web Service implementation
  10. Next step is to create the implementation class for the web service. Please note that I will create a EJB Web Service endpoint. This way I don’t need a web container nor any web deployment descriptor.
    Here is the web service implementation:

    package net.pascalalma.ws;
    
    import javax.ejb.Stateless;
    import javax.jws.WebService;
    
    /**
     * Hello world!
     *
     */
    @WebService(targetNamespace = "http://www.pascalalma.net/EchoIt",
                portName="EchoItPort",
                serviceName="EchoItService",
                endpointInterface="net.pascalalma.echoit.EchoItPortType")
    @Stateless
    public class EchoServiceImpl
    {
        public String echoIt(String it)
        {
            return "Echo " + it +"!";
        }
    }
    
  11. Deploy it to Glassfish
  12. With the implementation in place rebuild the project so a ejb-jar is created. Again issue the command:
    mvn clean install
    The created jar file in the ‘target’ directory can then be deployed to Glassfish. This can be done by using a Maven plugin as described here or by using the Glassfish Admin Console. I used the last one in this case. It should look similar to this after successful deployment:

  13. Test the service
  14. The easiest way to test it is, if you already have the Glassfish Admin Console open, to click the ‘test’ button and fill in a text as input parameter. As result you should get something like:

Well, if you did the things as I described you have a big chance it will work in one time, but in my case there were some problems when trying to get this to work. Some of the Issues I ran into while building the projects:

  1. Missing dependencies
  2. Missing:
    ———-
    1) com.sun.xml.ws:jaxws-tools:jar:2.1.5

    I had to use another plugin version then the one that is recommended at the plugin homepage:

     <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>jaxws-maven-plugin</artifactId>
                    <version>1.10</version>
         ...
       </plugin>
    
  3. More missing libraries
  4. I then ran into this one:

    org.apache.maven.lifecycle.LifecycleExecutionException: Error executing: wsimport [-s, /Users/pascal/projects/metro-service/echo-service/target/generated, -d, /Users/pascal/projects/metro-service/echo-service/target/classes, /Users/pascal/projects/metro-service/echo-service/src/main/webapp/WEB-INF/wsdl/echo-it.wsdl]

    See also this thread.

    It appears it has something to do with JDK1.5 instead of JDK1.6. I solved it by adding the dependencies for the JSR181.

I hope that this posts avoids the exceptions which I encountered and make the use of JAXWS with Maven more smoothly because in the end it is a very nice solution!

About Pascal Alma

Pascal is a senior IT consultant and has been working in IT since 1997. He is monitoring the latest development in new technologies (Mobile, Cloud, Big Data) closely and particularly interested in Java open source tool stacks, cloud related technologies like AWS and mobile development like building iOS apps with Swift. Specialties: Java/JEE/Spring Amazon AWS API/REST Big Data Continuous Delivery Swift/iOS
This entry was posted in Maven, Web Service and tagged , , , . Bookmark the permalink.