Heroku - Can I call Maven from Procfile? - deployment

I'm investigating Heroku as a platform and am trying to get a basic Java webapp to run on it. The webapp already builds and runs with Maven (using Tomcat and the cargo-maven-plugin), so I figured this should be a breeze given that Heroku uses Maven to manage its installation/deployment tasks.
That's not the case however, as I'm unable to get the thing to actually start up. My Procfile has the following in it:
web: sh ./startServer-heroku.sh
And the startServer-heroku.sh is just:
mvn clean install cargo:start -Dcargo.maven.wait=true
This works fine when I test locally using the foreman start command, as described in the Heroku tutorial docs. But when I try it on the actual Heroku server, I get the following log messages:
2011-11-09T02:30:27+00:00 heroku[web.1]: State changed from created to starting
2011-11-09T02:30:27+00:00 heroku[slugc]: Slug compilation finished
2011-11-09T02:30:33+00:00 heroku[web.1]: Starting process with command `sh ./startServer-heroku.sh`
2011-11-09T02:30:33+00:00 app[web.1]: ./startServer-heroku.sh: 1: mvn: not found
2011-11-09T02:30:33+00:00 heroku[web.1]: Process exited
2011-11-09T02:30:34+00:00 heroku[web.1]: State changed from starting to crashed
It appears that mvn is nowhere to be found on the system's PATH, so the command is failing.
Is it possible to invoke mvn from the Heroku Procfile? And is there anywhere that has a definitive list of commands that are and are not available from the Procfile?

Maven is not in the slug that gets deployed to dynos. It's only available at compile time. One option for dealing with this is to use the appassembler-maven-plugin and jar packaging to generate a start script:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<programs>
<program>
<mainClass>foo.Main</mainClass>
<name>webapp</name>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
Then the Procfile would be:
web: sh target/bin/webapp
Another option is the maven-dependency-plugin and war packaging:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-runner</artifactId>
<version>7.5.3.v20111011</version>
<destFileName>jetty-runner.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
With a Procfile of:
web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war

James's answer provides good instructions for getting Jetty to work on Heroku, and his comment includes a link to a good reference on using embedded Tomcat. But it is also possible to run the standard, standalone version of Tomcat on Heroku. Here's how I was able to get it to work:
First, set up your POM to install and configure Tomcat as part of your build, and also to deploy your application to the installed Tomcat instance:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<container>
<containerId>tomcat6x</containerId>
<zipUrlInstaller>
<url>http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.zip</url>
</zipUrlInstaller>
<dependencies>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</dependency>
</dependencies>
</container>
<configuration>
<type>standalone</type>
<deployables>
<deployable>
<groupId>com.yourcompany.name</groupId>
<artifactId>yourArtifact</artifactId>
<type>war</type>
<properties>
<context>ROOT</context>
</properties>
</deployable>
</deployables>
</configuration>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>install</goal>
<goal>configure</goal>
<goal>deploy</goal>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
Next, create a trimmed-down server.xml file that will work on Heroku:
<?xml version='1.0' encoding='utf-8'?>
<Server port="-1">
<Listener className="org.apache.catalina.core.JasperListener" />
<Service name="Catalina">
<Connector port="${http.port}" protocol="HTTP/1.1" connectionTimeout="20000"/>
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"/>
</Engine>
</Service>
</Server>
...this is necessary because your Heroku app is only allowed to bind to a single port (which changes each time a new instance is created, and is specified in the $PORT environment variable). Attempting to bind to any other port will crash your app. As the port is dynamic, it must be passed to server.xml via the http.port system property, but we'll get to that later.
While you're at it, also create a persistence.xml file that will work with Heroku:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="quiz_devel">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show.sql" value="true"/>
<property name="hibernate.c3p0.acquire_increment" value="1"/>
<property name="hibernate.c3p0.idle_test_period" value="10"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.max_statements" value="40"/>
<property name="hibernate.c3p0.min_size" value="1"/>
<property name="hibernate.c3p0.timeout" value="30"/>
</properties>
</persistence-unit>
</persistence>
Note that there is no hibernate.connection.url specified here. This is because Heroku specifies the database url that your app should use in the $DATABASE_URL environment variable.
Now it's time to create a simple shell script that configures the environment and sets everything up so that Tomcat can actually run:
#point to the correct configuration and webapp
CATALINA_BASE=`pwd`/target/cargo/configurations/tomcat6x
export CATALINA_BASE
#copy over the Heroku config files
cp ./server-heroku.xml ./target/cargo/configurations/tomcat6x/conf/server.xml
cp ./persistence-heroku.xml ./target/cargo/configurations/tomcat6x/webapps/ROOT/WEB-INF/classes/META-INF/persistence.xml
#make the Tomcat scripts executable
chmod a+x ./target/cargo/installs/apache-tomcat-6.0.18/apache-tomcat-6.0.18/bin/*.sh
#set the correct port and database settings
JAVA_OPTS="$JAVA_OPTS -Dhttp.port=$PORT -Dhibernate.connection.url=$DATABASE_URL"
export JAVA_OPTS
#start Tomcat
./target/cargo/installs/apache-tomcat-6.0.18/apache-tomcat-6.0.18/bin/catalina.sh run
This is doing a number of things:
It tells Tomcat to use the configuration and deployment artifacts that cargo packaged as part of your build, by setting CATALINE_BASE to point at the correct place.
It overwrites the default server.xml and persistence.xml files with their heroku-specific variants.
It marks all the startup scripts in the Tomcat instance that cargo installed as part of the build as executable.
It specifies values for http.port and hibernate.connection.url based upon the environment variables provided by the Heroku platform.
Finally, it runs Tomcat. Note that you cannot use startup.sh to do this, as startup.sh will launch Tomcat in a new process and then terminate. Heroku doesn't understand this, and thinks that the termination of startup.sh is the termination of the Tomcat process.
Finally, the last step is to set up your Procfile to call your startup script, something along the lines of:
web: sh startServer-heroku.sh
With this approach you can have a project that is compatible with Heroku, while still retaining its ability to run standalone as a standard Java webapp.

Yes, you can call maven from your Procfile.
To do so you need to include maven in your slug by making a small modification to the 'compile' script in the java build pack as described in the README.md file from the "heroku-buildpack-java" project:
For example if you want to have maven available to use at runtime in your application you simply have to copy it from the cache directory to the build directory by adding the following lines to the compile script:
for DIR in ".m2" ".maven" ; do
cp -r $CACHE_DIR/$DIR $BUILD_DIR/$DIR
done
I added these lines right after maven download, and before changing to BUILD_DIR.
In your Procfile you can then call .maven/bin/mvn
If you are building an artifact (war/jar) that you can run from java or in a servlet container, then you should probably do something along the way of the other answers, but if you really need to run maven, then this is the way.

Related

Eclipse deploying unfiltered .WAR-Archive on Tomcat

i have the following problem: I want to use maven profiles and the maven-war-plugin for filtering my webapplication, so that it's just one click to deploy it either on the live- or on the development server.
When i build the .WAR-archive via Eclipse (Maven-Plugin) and then manually deploy it on the tomcat-server via the tomcat-manager-interface, my application works as expected. (all variables are replaced correctly inside the generated .WAR-archive)
But when i want to run the application using Eclipse's "Run on Server", an exception occurs:
[..] nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.security.web.authentication.logout.LogoutFilter]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: ${security.casEntryPoint.logoutSuccessUrl} isn't a valid redirect URL
This is the configuration of the maven profiles in my pom.xml:
<profiles>
<profile>
<id>prod</id>
<build>
<filters>
<filter>src/main/filters/dfnaaiAgreement-prod.properties</filter>
</filters>
</build>
</profile>
<profile>
<id>devLocal</id>
<build>
<filters>
<filter>src/main/filters/dfnaaiAgreement-devLocal.properties</filter>
</filters>
</build>
</profile>
This is an example entry for the *.properties file:
security.casEntryPoint.logoutSuccessUrl = https://example_entry/please_logmeout
This is one entry in the settings.xml that should be replaced by the value in the *.properties file:
<security:logout logout-url="/logout" logout-success-url="${security.casEntryPoint.logoutSuccessUrl}" />
and this is the configuration for the maven plugin (in the pom.xml), that is used for filtering the configuration files:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<warName>dfnaaiAgreement</warName>
<webResources>
<resource>
<directory>${basedir}/src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</webResources>
</configuration>
This is my maven build configuration:
Maven-Build configuration (Sorry, not enough reputation to post images directly)
It seems like eclipse's "run on server" deploys the unfiltered application on the tomcat-server.
What am i doing wrong?
Update:
I followed this Link Run Maven webapp on server from Eclipse with properties injection from profile, but i'am still receiving the same Exception.
Here's the adjustment of my project's configuration: Active Maven Profiles
Update: Eclipse (Luna) deploys the webapplication to workspace/.metadata/.plugins/.org.eclipse.wst.server.core/tmp0/wtpwebapps/applicationName. The settings.xml that's deployed there still contains the unfiltered variables, whereas the generated .WAR-Archive (that is located at workspace/applicationName/target) has the correctly filtered settings.xml. How is this possible?
Thanks for your help!
Although it's not an optimal solution i found a workaround to fix my problem. Therefor i adjusted the project's deployment assembly settings in the way that the WEB-INF-Folder of the target-Folder will be taken for deployment.
You can do this by rightclicking your project and choose "Properties". Here's a screenshot of how i adjusted the settings:
Web_Deployment_Assembly.PNG

How to launch browser automatically after war deployment?

I have a war maven project and I want that when I deploy it on the server the default browser (Mozilla in my case) is launched automatically with the default url for access to the main page.
Of course with JBoss EAP6 I have just to run the Maven command clean install jboss-as:deploy to generate the war file and deploy it on the server.
Do I have to add something to the pom.xml or make any configurations in Eclipse?
Use maven's exec plug-in. More information here.
I used this and it works good but juste for the maven phase : install but for the deploy no:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>Run URL in system browser.</id>
<phase>install</phase>
<configuration>
<target>
<exec executable="start" vmlauncher="false">
<arg line="http://localhost:8080/mywarApp" />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
I use eclipse and i made for goals "clean install jboss-as:deploy" into the run configurations. and when in click in , once the install phase is runing the browser is runing too but i want that it will happen when the deploy phase is end of runing , have you any idea

GWT 2.5.1 SuperDevMode not enabled

i work on a GWT/GWTPHONEGAP/MGWT project and i need using gwt 2.5.1 with SuperdevMode.
I use maven and the following command "classpath gwt:runcodeServer", when i compile my project no error occur, but when i go to my webBrowser to using superDevMode, it's impossible to recompile, the error message is "this module has doesn't have Super Dev mode enabled" although my *.gwt.xml contains the following line enabled superDevMode.
<add-linker name="xsiframe"/>
<set-configuration-property name="devModeRedirectEnabled" value="true"/>
<set-property name="compiler.useSourceMaps" value="true" />
with following entrypoint
<entry-point class="**.**.*.client.MgwtAppEntryPoint" />
When i go to the localhost:9876 the project is present & source are available.
Following my configuration of maven :
jetty :
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.2.v20140210</version>
<configuration>
<reload>manual</reload>
<httpConnector>
<port>9090</port><!-- port 8080 already use by tiviz-web -->
</httpConnector>
<webApp>
<baseResource implementation="org.eclipse.jetty.util.resource.ResourceCollection">
<resourcesAsCSV>src/main/webapp,${basedir}/target/tiviz-gwt-0.0.1-SNAPSHOT</resourcesAsCSV>
</baseResource>
<extraClasspath>${basedir}/src/main/webapp/WEB-INF/classes</extraClasspath>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
</webApp>
<systemProperties>
<systemProperty>
<name>gwt.codeserver.port</name>
<value>9876</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>
and my configuration of gwt-maven-plugin
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<!-- Plugin configuration. There are many available options, see gwt-maven-plugin
documentation at codehaus.org -->
<configuration>
<!-- run params -->
<copyWebapp>false</copyWebapp>
<productionMode>false</productionMode>
</configuration>
</plugin>
problem come from an bad configuration in the path of my webapp ressource in jetty plugin.

Only copy modified files in maven-war-plugin

I'm currently using maven 3.x with the maven-war-plugin. For developer builds I would like to be able to use the war:exploaded goal, but only copy resources that have changed. Is there a way to do this?
I've been looking through the docs and have not been able to find a way to do this in the current versions, but there used to be (in the old maven 1.x version) a property maven.war.resources.overwrite that would allow this.
Thanks.
I'm not aware of a way to do this using the maven-war-plugin, but if your IDE supports it, you could have the IDE auto-deploy changes. For example, the Web Tools Platform for Eclipse supports this feature for Tomcat. However, if your build process is complex or does something weird before invoking the maven-war-plugin, this may not work for you.
A second option: if you're running Linux, set up rsync to copy recently modified files to your servlet container. A co-worker did this by having the servlet container's web app directory sync with the Eclipse project's output directory, and it worked well (just modify your code, Eclipse will build it automatically, and rsync will copy your changes).
For this purpose I use maven-antrun-plugin
Example:
<project xmlns="http://maven.apache.org/POM/4.0.0"
....
....
<!--DJ: Settings for deploy only-->
<!--DJ: Dir to where copy files-->
<!--DJ: And date when build have been started, to select only modified files in the future-->
<properties>
<tomcat.dir.rootDir>C:\apache-tomcat-6.0.35\webapps\ROOT1</tomcat.dir.rootDir>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
</properties>
.....
<!--Ohter dependensies here-->
.....
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copyModifiedFilesFrom_ExplodedWAR_Dir</id>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo message="Upload new files to dir ${tomcat.dir.rootDir} modified after date ${maven.build.timestamp} "/>
<copy todir="${tomcat.dir.rootDir}">
<fileset dir="${project.build.directory}/${project.build.finalName}" includes="**/*">
<!-- Include only recompiled files -->
<date datetime="${maven.build.timestamp}" pattern="yyyy-MM-dd HH:mm:ss" when="after"/>
<!-- and only *.class files -->
<filename name="**/*.class"/>
</fileset>
</copy>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
.....
.....
</plugins>
</build>
</project>
Then run maven with params:
mvn pom.xml compile install org.apache.maven.plugins:maven-war-plugin:2.1-alpha-1:exploded
As result only changed files will be recompiled and only recompiled filed will be replaced in tomcat webapp dir.

maven eclipse checkstyle plugin

I have custom checkstyle checks file (called checks.xml), and I'm trying to use that same file in both maven and eclipse. It all works well, except for the SuppressionFilter.
In this checks.xml file, I have
<module name="SuppressionFilter">
<property name="file" value="src/main/resources/checkstyle/checkstyle-suppressions.xml"/>
</module>
This works when I run through maven. However, when I run through eclipse, I need to change the config to be
<module name="SuppressionFilter">
<property name="file" value="${basedir}/src/main/resources/checkstyle/checkstyle-suppressions.xml"/>
</module>
If I run with the ${basedir} property with maven though, I get the error that property ${basedir} has not been set.
Is there a way use this same configuration file in both maven and eclipse? I feel like there should be, but I'm just missing something on how to properly populate the suppression filter.
thanks,
Jeff
This is hell. Eclipse and Maven handle suppressions different and don't share variables.
Derived from Rolf Engelhard
So in pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.8</version>
<configuration>
<propertyExpansion>config_loc=${basedir}/src/main/checkstyle</propertyExpansion>
<configLocation>${basedir}/src/main/checkstyle/checkstyle.xml</configLocation>
<suppressionsLocation>${basedir}/src/main/checkstyle/suppressions.xml</suppressionsLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
Now in checkstyle.xml (${config_log} is an Eclipse specific thing, but by specifying it in the pom we make it available to maven as well):
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml" />
</module>
And if you're using maven-site-plugin or any other plugins that also rely on CheckStyle don't forget to update those to have the config_loc property as well (or declare it global to the pom, though I wasn't able to get this to work properly).
Sure there is a way to use the same configuration file in both maven and eclipse but it requires a little setup first. I wrote a blog post on how to achieve this even for a multi-module maven project. see: maven-checkstyle-and-eclipse
<propertyExpansion>basedir=${session.executionRootDirectory}</propertyExpansion> works for me, but only when added to the <plugin>node, not to <execution>!
project.basedir does not work well in multi-module projects, because it will point to the submodule folder instead of the root folder.
You could try defining ${basedir} as a property in your pom.
See the pom reference quick overview.
<property>
<name>basedir</name>
<value>${project.basedir}</value>
</property>