Friday, September 5, 2014

No room to fit Maven-Ear-Plugin in one pom.xml

After I have the WAR file build completed, then I'm going to build the EAR file. Unfortunately it doesn’t work as in ANT. In Ant I can do all stuff of work in just one build.xml but not in Maven. Too bad huh?!! OK, I understand this can't be done but I still insist want to do it. Anyhow, there is still no EAR file being generate after the build. What a joke? No joking, Maven doesn't allow me to do that. Take the following code snippet as my use case:

    4.0.0
 
    org.huahsin
    MyWebService
    0.0.1-SNAPSHOT
    war
 
    MyWebService

    
        
         org.huahsin
         MyWebService
         0.0.1-SNAPSHOT
         war
        

        ...
        ...

    

    
        
            
             org.apache.maven.plugins
             maven-ear-plugin
             2.9.1
             
                 7
                 
                     
                         org.huahsin
                         MyWebService
                         MyWebService.war
                     
                 
                 MyWebService
             
            
 
            ...
            ...
 
        
    

The <packaging> will cause by the build failed. I mean it would working fine for building WAR file but not for building EAR file. Now I have knew the root cause, changing to ear in <packaging> line but I'm still not satisfied with the final output. Because I have a special requirement to this EAR file not to contain all other libraries except the custom build library. Now the EAR file has mess up all others libraries in it, this could a disaster when I deploy to WebSphere Application Server.

To make it clean, I create another pom.xml that only perform one task, which is EAR packaging. And this pom.xml contain only one dependency which is my newly created WAR. To make the picture clear, the WAR file should contain all only the libraries, whereas EAR file should contain only the WAR file. This is the primary objective of having a separate pom.xml, following code snippet worth thousand of these nonsense.

    4.0.0

    org.huahsin
    MyWebServiceEar
    0.0.1-SNAPSHOT
    ear

    MyWebServiceEar

    
        
         org.huahsin
         MyWebService
         0.0.1-SNAPSHOT
         war
        
    

    
        
            
            org.apache.maven.plugins
            maven-ear-plugin
            2.9.1
            
                7
                
                    
                        org.huahsin
                        MyWebService
                        MyWebService.war
                    
                
                MyWebService
            
            
        
    

Now I have another question, how could I fit 2 pom.xml in one project? I don't know??? I just put them somewhere as long as there wouldn't crash each other in the project. Am I doing this in the right approach?

Wednesday, September 3, 2014

Maven default deployment path locate at target/tomcat/webapps?

In order for me to establish a JNDI connection in Tomcat, I have the data source declare inside server.xml as shown in the code snippet below:
     
         
         
     
And then I have the JNDI data source declared in Spring like this:
    
        
        
        
        
    
Let’s do some experiment on maven-war-plugin, if this plugin went missing, an error message mention Name [comp/env] is not bound in this Context. Unable to find [comp]. as shown in the following stack trace could be seen:
javax.naming.NameNotFoundException: Name [comp/env] is not bound in this Context. Unable to find [comp].
 at org.apache.naming.NamingContext.lookup(NamingContext.java:820)
 at org.apache.naming.NamingContext.lookup(NamingContext.java:168)
 at org.apache.catalina.deploy.NamingResources.cleanUp(NamingResources.java:988)
 at org.apache.catalina.deploy.NamingResources.stopInternal(NamingResources.java:970)
 at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
 at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5495)
 at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:160)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
 at java.util.concurrent.FutureTask.run(FutureTask.java:262)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at java.lang.Thread.run(Thread.java:745)
If the plugin were there (as shown in following code snippet) but without any configuration being done, the above error message could be seen too.
 
  org.apache.maven.plugins
  maven-war-plugin
  2.2
 
Now if <outputDirectory> is configure to the plugin as shown in following code snippet:
 
  org.apache.maven.plugins
  maven-war-plugin
  2.2
  
   ${project.basedir}/target/tomcat/webapps
  
 
Tada! It works. Now change to use <warSourceDirectory> in the configuration as shown in following code snippet and start up the Tomcat, the same error could be seen as well.
 
  org.apache.maven.plugins
  maven-war-plugin
  2.2
  
   ${project.basedir}/src/main/webapp/
  
 
Try make some adjustment to the docBase attribute of <Context> in server.xml as shown in following code snippet, it will works again.
     
         
    ...

     
What a surprise?! If I pay close attention on the stack trace, I would notice MyService folder wasn’t there actually as mention in another message trace as shown in below:
java.lang.IllegalArgumentException: Document base C:\MyService\target\tomcat\webapps\MyService does not exist or is not a readable directory
 at org.apache.naming.resources.FileDirContext.setDocBase(FileDirContext.java:140)
 at org.apache.catalina.core.StandardContext.resourcesStart(StandardContext.java:4906)
 at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5086)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
 at java.util.concurrent.FutureTask.run(FutureTask.java:262)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at java.lang.Thread.run(Thread.java:745)
Another message I got was whenever Maven build is trigger, Maven will expect the output to be deploy into target/tomcat/webapps folder. Since I didn’t configure <outputdirectory> in POM.xml, then Maven will go for the default path searching my web app. By adjusting the docBase attribute 2 lever up will tell Maven "Hey! go search my app there".

Tuesday, September 2, 2014

Let’s see how profiles could help in Maven build?

Taking the following code snippet as my use case:

 ${project.name}
     
 
  
   org.apache.tomcat.maven
   tomcat7-maven-plugin
   ...
   ...
  

  
   org.apache.maven.plugins
   maven-compiler-plugin
   ...
   ...
  

  
   org.apache.maven.plugins
   maven-war-plugin
   ...
   ...
  
 

In most situation, I will just run mvn clean install tomcat7:run to bring up my application instance. But somehow, in some situation, I would like to have some special configuration on the WAR packaging to be different from the regular build. For example, to exclude some particular JAR out from the build during packaging stage, if I'm using the regular configuration as shown in the code snippet above, I will hit error when I bring up my application instance due to some libraries were gone missing during packaging stage.

In order to play well on both mvn clean install tomcat7:run and mvn clean package, my colleague suggest me to use profiles for this situation. As shown in the following code snippet, another piece of maven-war-plugins configuration is created inside the <profile>:
 
    
       CUSTOM
       
         
            
               org.apache.maven.plugins
               maven-war-plugin
               2.2
               
                  %regex[WEB-INF/lib/(?!mycustomlibrary).*.jar]
               
            
         
         myfinalName
       
    
 
With this new configuration, the regular build process will continue to work as expected while I have another separate piece to build a custom made build process for packaging. But separated piece need to be done with following command:

mvn clean package –PCUSTOM

Do take note on the <finalName> usage, it allows me to specify a custom package output file name that is different from the regular ugly Maven style name.

Using regular expression during Maven packaging stage

During maven build, the default Maven implementation will package all libraries into WEB-INF/lib folder. But the requirement has remind me that I shouldn’t include those libraries in the build except those custom build library since those libraries has already been deploy into WebSphere Application Server (WAS). Thus it helps in reducing the resulting jar and making the deployment process run faster in WAS.

Now my objective is to ensure the resulting jar is clean except those custom made library. To achieve this mission, the clue is to use packagingExcludes of maven-war-plugin’s configuration, as shown in the code snippet below:

 org.apache.maven.plugins
 maven-war-plugin
 2.2
 
  ...  
 

The challenge of this mission is to exclude any other libraries except those with custom made. I have been struggling for quite some while until my colleague has discover this could be done by using regular expression as shown below:

 org.apache.maven.plugins
 maven-war-plugin
 2.2
 
  %regex[WEB-INF/lib/(?!mycustomelibrary).*.jar]  
 

The code snippet above telling Maven to exclude any libraries other than mycustomlibrary.jar during the build. This has brought up another issue to me, what if I need to retain 2 libraries while ignoring the rest during the build? Fortunately right after this discovery, I found the solution on this problem which is by using packagingIncludes where I only need to specified the particular library that need to be includes.

Tuesday, August 19, 2014

Tomcat fail to start if webservices-rt were declare as provided scope in Maven

Arrghhhh! Tomcat failed to start again! And I see the same error message again!

org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]

For this round was cause by the webservices-rt dependency has been declare as provided scope.
  
   org.glassfish.metro
   webservices-rt
   2.2
   provided
  
Interestingly if I declare provided scope to webservices-api, the Tomcat were just run fine.

Monday, August 11, 2014

Missing in tomcat7-maven-plugin causing Tomcat fail to start

I just felt the following stack trace very annoying and too hard to digest.
SEVERE: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[/MavenTest]]
 at java.util.concurrent.FutureTask.report(FutureTask.java:122)
 at java.util.concurrent.FutureTask.get(FutureTask.java:188)
 at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
 at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:785)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
 at java.util.concurrent.FutureTask.run(FutureTask.java:262)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[/MavenTest]]
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
 ... 6 more
Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/catalina/loader/WebappClassLoader) previously initiated loading for a different type with name "javax/servlet/ServletContext"
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
 at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
 at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
 at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
 at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1190)
 at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1681)
 at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
 at com.sun.xml.ws.transport.http.servlet.WSServletContainerInitializer.onStartup(WSServletContainerInitializer.java:61)
 at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5274)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
 ... 6 more

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.045s
[INFO] Finished at: Mon Aug 11 17:16:16 SGT 2014
Aug 11, 2014 5:16:16 PM org.apache.catalina.core.ContainerBase startInternal
SEVERE: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]
 at java.util.concurrent.FutureTask.report(FutureTask.java:122)
 at java.util.concurrent.FutureTask.get(FutureTask.java:188)
 at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
 at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
 at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
 at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
 at org.apache.catalina.startup.Tomcat.start(Tomcat.java:335)
 at org.apache.tomcat.maven.plugin.tomcat7.run.AbstractRunMojo.startContainer(AbstractRunMojo.java:1018)
 at org.apache.tomcat.maven.plugin.tomcat7.run.AbstractRunMojo.execute(AbstractRunMojo.java:478)
 at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
 at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
 at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
 at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
 at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
 at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
 at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
 at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
 at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
 at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
 at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
 at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
 at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
 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:606)
 at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
 at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
 at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
 at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
 at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
 at java.util.concurrent.FutureTask.run(FutureTask.java:262)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
 at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131)
 at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:785)
 at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
 ... 6 more

In short, the key error message in this stack trace was Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]. What causes fail to start? I ask to myself. I check and re-check on my pom.xml, I'm sure it has nothing to do with the dependencies, but I just wonder whether the problem could be rise from the plugin as shown in the following code snippet:
    
     ${project.name}
     
     
          ...
          ...
     

        
            
                org.apache.tomcat.maven
                tomcat7-maven-plugin
                2.0
                
                    8086
                    ${project.basedir}/target/${project.name}
                
            

            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.1
                
                    1.7
                    1.7
                    
                        ${endorsed.dir}
                    
                
            
        
    
Although I found the solution on similar problem on forum but it doesn’t really help me out. While struggling for a solution, I realize that missing <serverXml> tag may cause the rise of this error. The tag belongs to tomcat7-maven-plugin’s configuration telling Tomcat plugin where to locate server.xml, the master piece on how Tomcat should behave during runtime. If the tag went missing, Tomcat may gone wild. Try and error on this tag, I got the final piece on tomcat7-maven-plugin configuration. Now it should look like following code snippet:
    
        org.apache.tomcat.maven
        tomcat7-maven-plugin
        2.0
        
            8086
            ${project.basedir}/target/${project.name}
            ${project.basedir}/src/main/tomcatconf/server.xml
        
    

Tuesday, July 29, 2014

Using cocos to create a new project from scratch

cocos is a very useful command when creating a new Cocos2d-x project from scratch. However it has to be install before I can use it. But how? Due to the information on Cocos2d-x site were scatter around, I have overlook the very important piece where the manual did actually describe how it could be install. The article mention that I must first setup in order to use this tool by just run ./setup.py on console. This program can be found on Cocos2d-x root directory. I did it on Windows 8, and it works! After the setup, a new environment variable will be create on Windows. For my case, I'll see:

Variable name: COCOS_CONSOLE_ROOT
Variable value: D:\tool\cocos2d-x-3.2\tools\cocos2d-console\bin

And then I use following command to create a new project:

C:\Users\huahsin68>cocos new MyGame1 -p org.huahsin68.puzzle -l cpp -d D:\Cocos2
dxProject

Tada! A new game project is initialize for android, ios_mac, linux, win32, and wp8 platform.