Java – IntelliJ – Maven – Remote deploy/debug standalone apps

This method uses a Maven plugin called Wagon to upload and execute/debug a jar on another machine.  IntelliJ supports executing any kind of scripts or programs during a remote deploy beyond Maven commands, so you may find those easier to create and use. 

Install an SSH server on your remote box.

Windows Servers:

Linux:

  • sudo apt-get install openssh-server
  • sudo vim /etc/ssh/sshd_config
  • sudo /etc/init.d/ssh restart

Add a <server> block to settings.xml in .m2 folder on the box with the code:

<server>

    <id>remote-box</id>

    <username>sshuser</username>

    <password>mysshpassword</password>

</server>

 

Your project’s pom.xml additions:

Replace [ip.address] with your remote box’s ip.  Replace the <fromDir> with your project’s target directory.  Replace the <includes> with the jar or file patterns that you wish to deploy.

<build>

        <extensions>

            <extension>

                <groupId>org.apache.maven.wagon</groupId>

                <artifactId>wagon-ssh</artifactId>

                <version>1.0</version>

            </extension>

        </extensions>

        <plugins>

            <plugin>

                <groupId>org.codehaus.mojo</groupId>

                <artifactId>wagon-maven-plugin</artifactId>

                <version>1.0-beta-5</version>

                <configuration>

                    <url>scp://[ip.address]</url>

                    <serverId>dev-box</serverId>

                    <fromDir>C:/myproject/target/</fromDir>

                    <includes>testcron-1.0-SNAPSHOT.jar</includes>

                    <commands>

                        <command>./start.sh</command>

                    </commands>

                </configuration>

                <executions>

                    <execution>

                        <id>upload-jar</id>

                        <phase>deploy</phase>

                        <goals>

                            <goal>upload</goal>

                        </goals>

                    </execution>

                    <execution>

                        <id>execute-test-commands</id>

                        <phase>deploy</phase>

                        <goals>

                            <goal>sshexec</goal>

                        </goals>

                        <configuration>

                            <serverId>remote-box</serverId>

                        </configuration>

                    </execution>

                </executions>

            </plugin>

        </plugins>

    </build>

 

Place a startup script ‘start.sh’ in the root SSH directory of your remote box:

Replace the classpath with the root scp folder and your project’s jar artifact.  Replace the TestCron class with your main class.  Replace 4001 with your desired debugging port (open this port in your remote box firewall).  Use suspend=n if you don’t want to wait for the debugger.  Replace log.txt with what you want to catch stdin and stderror.

java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=4001 -cp “C:\Program Files (x86)\ICW\testcron-1.0-SNAPSHOT.jar” com.test.TestCron > log.txt 2>&1 &

Alternative:

You can also put the start.sh command(s) in the pom.xml file in the <commands> section.  I had issues with the ampersands in xml, so I created a script to execute instead.

Create a new Run/Debug Configuration in IntelliJ on your code box with the following params and Maven goals:

Host: 192.168.1.10 (your remote box’s ip)

Port: 4001 (The debug port from the start.sh script)

Maven goals:

  • jar:jar
  • wagon:upload
  • wagon:sshexec

 

Click ‘Debug’ and your jar will be built, scp’d to your remote box, executed with an ssh exec of your start.sh script, and the IntellIJ debugger will connect.  Debug as normal and tail log.txt for output, or whatever file log4j is set to.  Package any property files into the jar or place them in the root scp folder for the jar to use.

  

References:

Advertisements

Remote deployment and debugging to Tomcat from IntelliJ including Remote JRebel updates.

Sometimes it’s nicer or required to develop code by deploying to a remote server. After a lot of trial and error, and frustration with lack of documentation on how this is to be done.  Here’s what I got to work. 

These instructions are mainly for windows, but can be adapted for other operating systems.

REMOTE TOMCAT BOX:

 Software needed:

 Delete the existing ROOT webapp folder in tomcat if you will be deploying to ‘/’

 Open up these ports in your firewall:

  • 1099
  • 8080
  • 5005 (Or whatever port you configure IntelliJ with for debugging)

 Add these lines to config/tomcat-users.xml:

<role rolename=”manager-gui” />

<role rolename=”manager-script” />

<role rolename=”manager-jmx” />

<role rolename=”manager-status” />

<user username=”admin” password=”password” roles=”manager-gui, manager-script, manager-jmx, manager-status” />

 Add setenv.bat (Windows) or setenv.sh to apache-tomcat/bin:

set CATALINA_OPTS=-Drebel.remoting_plugin=true -javaagent:C:\jrebel\jrebel.jar -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,suspend=n,server=y -Xms64m -Xmx2048m -XX:MaxPermSize=768m -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

 Update the javaagent param with the path to your installed jrebel.jar and the Xrunjdwp port with your IntelliJ debug port.

 Use startup.bat and shutdown.bat to control your tomcat instance.

LOCAL DEV BOX:

 Software needed:

  • IntelliJ 13
  • JRebel plugin
  • Maven 3

 Update your .m2/settings.xml file with:

<servers>

   <server>

      <id>RemoteTomcatServer</id>

      <username>admin</username>

      <password>password</password>

   </server>

</servers>

 Update the project’s main module’s pom.xml file with:

<plugin>

   <groupId>org.apache.tomcat.maven</groupId>

   <artifactId>tomcat7-maven-plugin</artifactId>

   <version>2.2</version>

   <configuration>

       <url>http://remotehost:8080/manager/text</url>

       <server>RemoteTomcatServer</server>

       <path>/</path>

   </configuration>

</plugin>

 With this maven plugin, you can run ‘mvn tomcat7:deploy’, ‘mvn tomcat7:redeploy’, etc to build and send war files to the remote tomcat instance.  You can do this from the command line or the Maven Projects tab in IntelliJ.

 Create an IntelliJ ‘Remote’ run configuration with your debugging port information and add a maven command to the ‘Before launch’ box with tomcat7:redploy as the command in the project’s main module directory.  You can have these actions in separate run configurations if you want the debugging and deployment to be executed as needed.

 IntelliJ JRebel settings:

File->Settings->Compiler->  check ‘Make project automatically

File->Project Settings->Modules->  enable ‘Remote Host’ in the modules’ JRebel configuration with your remote host url (http://remotehost:8080/)

To send changed resources, jsps, and class files over to the remote server: Run->JRebel Remoting: Synchronize project

 References:

http://wiki.aiwsolutions.net/2014/02/20/deploy-web-application-to-remote-tomcat- 7-server/

http://tomcat.apache.org/maven-plugin-2.0/tomcat7-maven-plugin/usage.html

http://zeroturnaround.com/software/jrebel/learn/remoting/setting-up-jrebel-remot ing-with-intellij-idea-and-tomcat/

http://player.vimeo.com/video/54855437

http://rockycode.com/blog/debugging-remote-tomcat-intellij/

 

java.lang.NoSuchMethodError

Maven can be nice, but sometimes you can end up with one jar loading before another and that causes unpredictable results at run-time.

An example exception:

  
Exception in thread "Thread-24" java.lang.NoSuchMethodError: 
 com.sun.mail.util.SocketFetcher.getSocket(Ljava/lang/String;ILjava/util/Properties;Ljava/lang/String;Z)Ljava/net/Socket;
	at  com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1359)
	at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:412)
	at javax.mail.Service.connect(Service.java:288)
	at javax.mail.Service.connect(Service.java:169)

How to find the offending jar file:

     
     Class cls = SocketFetcher.class;
     ProtectionDomain pDomain = cls.getProtectionDomain();
     CodeSource cSource = pDomain.getCodeSource();
     URL loc = cSource.getLocation();
     System.out.println(loc.toString());

How to fix it:

   <dependency>
      ...
      <exclusions>
        <exclusionv
          <groupId>com.google</groupId>
          <artifactId>googleapi-nomail</artifactId>
        </exclusion>
     </exclusions>
   </dependency>