Monday 4 May 2015

Deploy WAR on tomcat from maven command

Many times while doing testing of web project (.war) during development phase we have to deploy project on tomcat server frequently. So every times we have copy war file then paste it to {TOMCAT_HOME}\webapp directory. Some times need to restart tomcat as well.

My this post focuses on reducing this time by automating deployment from maven command.  So we can deploy, un-deploy, update war file and also do start, stop tomcat server from Maven command.

For this automation we have make changes in following files.

    1.{TOMCAT_HOME}/conf/tomcat-users.xml
    2.{MAVEN_HOME}/conf/settings.xml
    3.{PROJECT_HOME}/pom.xml
    4.Use this configured plugin to deploy, undeploy etc.
 
 let's start making above changes one by one. This post uses tomcat6 however if you are using different tomcat version, you can achieve same by using tomcat version specific plugin in step. 3.

1. Update {TOMCAT_HOME}/conf/tomcat-users.xml

   Add 'manager-script' role and its username/password.  Properties highlighted in yellow are only relevant properties with this tutorial.
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="tomcat"/>
  <role rolename="manager-gui"/>
  <!-- 'manager-script' role will be used for deployment from Maven -->
  <role rolename="manager-script"/>
  <user username="admin" password="tomcat" roles="tomcat,manager-gui,manager-script"/>
</tomcat-users>

2. Update {MAVEN_HOME}/conf/settings.xml

   Update you maven settings.xml file with below snippet. Keep rest of the part of settings.xml as it is.
<?xml version="1.0" encoding="UTF-8"?>
<settings>
  ...
  <servers>
   	<server>
		<id>TomcatServer</id>
		<!-- Username/password below should match with one mapped with 'manager-script' role in tomcat_home/conf/tomcat-users.xml file-->
		<username>admin</username>
		<password>tomcat</password>
	</server>
  </servers>
  ...
</settings>

Username/Password should match with username/password configured with role 'manager-script' in step 1.

3. Update {PROJECT_HOME}/pom.xml

   Update the following part in your pom.xml. Value of <server> should match with value of     <id>TomcatServer</id> in {MAVEN_HOME}/conf/settings.xml file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	...
	<build>
		<finalName>ConcatService</finalName>
		<plugins>
			...			
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat6-maven-plugin</artifactId> 
                                <!-- For tomcat7 use -->
                                <!-- <artifactId>tomcat7-maven-plugin</artifactId> -->  
                                <version>2.2</version>
				<configuration>
					<url>http://localhost:8080/manager</url>
					<server>TomcatServer</server>
					<path>/ConcatService</path>
				</configuration>
			</plugin>
			...
		</plugins>
	</build>
</project>


4. Useful tomcat maven plugin goals.
mvn tomcat6:redeploy
mvn tomcat6:undeploy
mvn tomcat6:start
mvn tomcat6:stop 

Some Useful links.
Error Resolutions : 
If you got following error while executing any of the tomcat goals. (Which i had got.)


[INFO] [war:war {execution: default-war}]
[INFO] Packaging webapp
[INFO] ------------------------------------------------------------------------
[ERROR] FATAL ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Cannot construct org.apache.maven.plugin.war.util.WebappStructure as it does not have a no-args constructor
---- Debugging information ----
message             : Cannot construct org.apache.maven.plugin.war.util.WebappStructure as it does not have a no-args constructor
cause-exception     : com.thoughtworks.xstream.converters.reflection.ObjectAccessException
cause-message       : Cannot construct org.apache.maven.plugin.war.util.WebappStructure as it does not have a no-args constructor
class               : org.apache.maven.plugin.war.util.WebappStructure
required-type       : org.apache.maven.plugin.war.util.WebappStructure
path                : /webapp-structure
line number         : 1
-------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Trace
com.thoughtworks.xstream.converters.ConversionException: Cannot construct org.apache.maven.plugin.war.util.WebappStructure as it does not have a no-args constructor
---- Debugging information ----
message             : Cannot construct org.apache.maven.plugin.war.util.WebappStructure as it does not have a no-args constructor
cause-exception     : com.thoughtworks.xstream.converters.reflection.ObjectAccessException
cause-message       : Cannot construct org.apache.maven.plugin.war.util.WebappStructure as it does not have a no-args constructor
class               : org.apache.maven.plugin.war.util.WebappStructure
required-type       : org.apache.maven.plugin.war.util.WebappStructure
path                : /webapp-structure
line number         : 1
-------------------------------
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:63)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:45)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:46)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:117)
    at com.thoughtworks.xstream.core.ReferenceByXPathMarshallingStrategy.unmarshal(ReferenceByXPathMarshallingStrategy.java:29)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:846)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:833)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:781)
    at org.apache.maven.plugin.war.util.WebappStructureSerializer.fromXml(WebappStructureSerializer.java:73)
    at org.apache.maven.plugin.war.AbstractWarMojo.buildWebapp(AbstractWarMojo.java:404)
    at org.apache.maven.plugin.war.AbstractWarMojo.buildExplodedWebapp(AbstractWarMojo.java:375)
    at org.apache.maven.plugin.war.WarMojo.performPackaging(WarMojo.java:181)
    at org.apache.maven.plugin.war.WarMojo.execute(WarMojo.java:143)
    at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:535)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
    at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
    at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
    at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: com.thoughtworks.xstream.converters.reflection.ObjectAccessException: Cannot construct org.apache.maven.plugin.war.util.WebappStructure as it does not have a no-args constructor
    at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.newInstance(PureJavaReflectionProvider.java:59)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.instantiateNewInstance(AbstractReflectionConverter.java:257)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:124)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:56)
    ... 31 more

Solutions for above error: Just remove old target directory ({PROJECT_HOME}\target) or run $mvn clean command and then execute tomcat goal again. If still appears try to use updated version of 'tomcat6-maven-plugin'.


Sunday 3 May 2015

Create JAX-WS Web Service with Top down approach from scratch using maven (Java to WSDL)

Create Sample Web Project using maven eg.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.yogesh.patil -DartifactId=ConcatService -DinteractiveMode=false

Project structure must be created in current directory as follow.


Now start creating service implementation. For ease import this project in eclipse as follow.
Select Maven project to import in eclipse as follow ( If maven in not installed in your eclipse here are Steps to configure Maven in eclipse)


Now Select "Existing Maven Projects" option to import project.


Browse and select "ConcatService" project generated using maven. Now click on "Finish" to import project.
Now you can see imported "ConcatService" project in maven.


Create new Interface and implementation class with annotations which is to be exposed as web service as follow.

Interface.

package com.yogesh.patil;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface ConcatService {

    @WebMethod
    public String concatString (String str1, String str2);
}

Implementation class.

package com.yogesh.patil;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;

@WebService(name="ConcatServiceImpService")
// Default biding Document/literal/wrapped
@SOAPBinding(style = Style.DOCUMENT, use=Use.LITERAL,parameterStyle=ParameterStyle.WRAPPED)
public class ConcatServiceImpl implements ConcatService {

    public String concatString (String str1, String str2) {
        return str1 + str2;
    }
}


From @SOAPBinding annotation on Web service class we can say this is Document/literal type web service with parameter types wrapped.

Now configure Apache CXF Plugin to generate WSDL from Java class using java2wsdl goal provided by this plugin.


<plugin>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-codegen-plugin</artifactId>
 <version>2.0.9</version>
  <dependencies>
   <dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>2.0.9</version>
   </dependency>
  </dependencies>
  <executions>
   <execution>
    <id>generate-wsdl</id>
    <phase>process-classes</phase>
    <configuration>
     <outputFile>src/main/resources/WSDL/ConcatServiceImp.wsdl</outputFile>
     <className>com.yogesh.patil.ConcatServiceImp</className>
    </configuration>
    <goals>
     <goal>java2wsdl</goal>
    </goals>
   </execution>
  </executions>
</plugin>

Note- update highlighted part.
Download complete POM.

Create and configure JAX-WS deployment descriptor sun-jaxws.xml  in {PROJECT_HOME}\src\main\webapp\WEB-INF directory as follow.

NOTE - {PROJECT_HOME} indicates the location of project directory. This directory must contain pom.xml in our case.

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
 version="2.0">
 <endpoint name="ConcatServiceImpl"
  implementation="com.yogesh.patil.ConcatServiceImpl"
  url-pattern="/ConcatService" />
</endpoints>

Update web application configuration {PROJECT_HOME}\src\main\webapp\WEB-INF\web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <listener>
        <listener-class>
                com.sun.xml.ws.transport.http.servlet.WSServletContextListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>ConcatService</servlet-name>
        <servlet-class>
         com.sun.xml.ws.transport.http.servlet.WSServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ConcatService</servlet-name>
        <url-pattern>/ConcatService</url-pattern>
    </servlet-mapping>
</web-app>

Add JAX-RT (Runt time) dependency to pom.xml

<!-- JAX-WS RT Dependency -->
<dependency>
 <groupId>com.sun.xml.ws</groupId>
 <artifactId>jaxws-rt</artifactId>
 <version>2.2.8</version>
</dependency>

Now execute $mvn clean install command. This command create .war file and also generate the WSDL file at mentioned location in plugin "<outputFile>src/main/resources/WSDL/ConcatServiceImp.wsdl</outputFile>"

Deployment file must be created in "{PROJECT_HOME}\target\ConcatService.war"


ConcatService\WEB-INF\classes\com\yogesh\patil\jaxws\ConcatString.class (JAWS generated request class)
ConcatService\WEB-INF\classes\com\yogesh\patil\jaxws\ConcatStringResponse.class (JAWS generated response class)
ConcatService\WEB-INF\classes\com\yogesh\patil\ConcatService.class
ConcatService\WEB-INF\classes\com\yogesh\patil\ConcatServiceImpl.class
ConcatService\WEB-INF\classes\WSDL\ConcatServiceImp.wsdl
ConcatService\WEB-INF\web.xml
ConcatService\WEB-INF\sun-jaxws.xml
ConcatService\index.jsp

Following are list of jar present in ConcatService\WEB-INF\lib, there are some jar which are not being used in our current code but these default jar's coming with JAXWS-RT dependency.



Copy ConcatService.war file to {TOMCAT_HOME}/webapps directory. Now start your tomcat server and access the deployed web service at following URL (assuming tomcat is configured to run on 8080 port)

"http://localhost:8080/ConcatService/ConcatService"

You can see deploymet as follow.



Now your web service is ready for testing. You test it by creating web service client or simply by Using tools like SOAP UI. Create new SOaP UI project.


Create Web service client using deployed Web service URL.


Click Ok. Now you are ready to invoke and test your web service.


now submit this request. You will get the response as follow.


You can download:

Some Useful links :

Software's used for this tutorial:
  • Windows 7 (64 bit)
  • JDK 1.6
  • Apache Tomcat 6.0.35
  • Apache CXF maven plugin v2.0.9
  • JAX-WS RT (Run time) v2.2.8
  • Development tool - Eclipse Kepler
Suggestions and recommendations are welcome. :)

Friday 1 May 2015

Simple steps to Configure Maven plugin in eclipse

Step by step approach to install maven plugin in eclipse.
Maven Eclipse plugin installation step by step: (Bold Italic strings you can see as button or options in your eclipse while configuring.)
  • Open Eclipse.
  • Click on Help menu -> Select Install New Software.
  • Click Add button at top right corner
  • New pop up window will open asking to add repository Name and Location.
  • Add Name as "M2Eclipse" and Location as "http://download.eclipse.org/technology/m2e/releases"
  • Now click OK
After this installation of maven plugin will start.
After successful installation you can check installed plugin in you eclipse: (to be safe restart your eclipse before)
  1. Go to Window --> Preferences
  2. Observe, Maven is enlisted at left panel as follow.


Your maven plugin is configure :).