Fork abendrot on GitHub

abendrot

  • SAP HANA Cloud is build technology and source code management system agnostic, hence these two topics are not covered in the step by step guide of section 1. of this tutorial. abendrot uses maven as build technology and git as source code management system. You have to update SAP HANA Cloud eclipse environment installed in section 1. of this tutorial:

Maven Integration for WTP (m2e-wtp) : open https://www.eclipse.org/m2e-wtp/. Follow the installation procedure at https://www.eclipse.org/m2e-wtp/download/. Install the latest release.

Command line maven: open http://maven.apache.org/. Follow the installation procedure at http://maven.apache.org/download.html. Install the latest release.

Eclipse Git (egit): open http://www.eclipse.org/egit/. Follow the installation procedure at http://www.eclipse.org/egit/download/. Install the latest release.

For more details, Matthias Steiner, Cloud Platform Evangelist @SAP, posted recently a blog entry on the same topic on SAP Community Network: Essentials - Working with Git & Maven in Eclipse

  • abendrot is a tutorial on how to write a SAP HANA Cloud application. You will use a github repository to host and monitor your work. You may want clone abendrot itself to another directory. You may then use your favorite compare tool - mine is Beyond Compare - to diff the two directories at various stages of the tutorial.

Setup a free github account, if you have not already one

Log to your account at https://github.com/<your account>

Create an empty github repository

To create an empty Github repository, this click icon in the top right toolbar:

Name the repository abendrot-test, check 'Initialize this repository with a README' and select maven .gitignore.

Create and clone immediately your repository. I assume that you know how to. If not, Github Bootcamp.

E.g., using the git command line :

$ git clone https://github.com/<your_github_account_name>/abendrot-test.git

You'll get something like this on your box:

  abendrot-test
  ├── .gitignore
  └── README.md

Clone abendrot from https://github.com/cthiebaud/abendrot.git; checkout the initial state, i.e. the first commit

E.g., using the git command line :

$ git clone https://github.com/cthiebaud/abendrot.git
$ cd abendrot
$ git checkout 4d427b99f3b60947e3535e045cdf4b35f979ed7f

Or, to set the directory name to something else than the default :

$ git clone https://github.com/cthiebaud/abendrot.git abendrot-clone 
$ cd abendrot-clone
$ git checkout 4d427b99f3b60947e3535e045cdf4b35f979ed7f

Compare yours (abendrot-test) and mine (abendrot) directories

Beyond-comparing the two directories will show something like :

Open eclipse, switch to java perspective

Create a new dynamic Web project:

Set project name to abendrot-test, change project location from default to te location where you cloned your abendrot-test from Github, accept all other defaults, click Next >

Change the sources directory from eclipse default src to maven default src/main/java

then

Change the output folder from eclipse default build/classes to maven default target/classes, click Next >

Change the webapp folder from eclipse default WebContent to maven default src/main/webapp, click Finish

Be polite and say 'no, thanks', when you are invited to change perspective.

Convert to maven Project. Right-click on the project name in the package explorer to open the context menu, select

Set your groupID, set artifactID to 'abendrot-test', and change packaging type to 'war'.

  • Create a HTML5 page

From Eclipse menu,

Select parent folder 'abendrot-test/src/main/webapp', name your page index.html, click Next >

Select HTML5 format, click Finish

  • We will run the 'Hello World' index.html page on three different servers: 1. a plain Tomcat, 2. a local test server for SAP HANA Cloud, and 3. the actual SAP HANA Cloud on the internet.
'Official' SAP HANA Cloud tutorials are usually targetting only HANA Cloud servers 2. (local) and 3. (on the cloud). We need server 1. (plain Tomcat) for two reasons:
  1. We aim to have zero coupling with SAP HANA Cloud proprietary APIs. Tomcat plain server will tell us if we have.
  2. The development cycle with Tomcat is still faster than with SAP HANA Cloud local test server.

Get Tomcat 7: open http://tomcat.apache.org/. Download .tar.gz or .zip file from http://tomcat.apache.org/download-70.cgi. Unzip it to the directory of your choice, referenced below as $TOMCAT_HOME.

Start 'Run As' wizard on the index.html file we've just created

Select 'Manually define a new server', select 'Apache' folder, choose Tomcat7, make sure that 'Server's host name' is localhost, click Next >

Point the wizard to the $TOMCAT_HOME you've just downloaded

Click Finish, Eclipse starts Tomcat and open the page in its internal browser. The page is empty.

Add <h1>Hello , World!</h1> to index.html, save, back to the browser, refresh, the content is displayed, no restart needed.

  • Steps to run on both local and remote SAP HANA Cloud are fully documented in the 'Deploying from the Eclipse IDE' page of the SAP HANA Cloud Developer Center. Just use 'index.html' instead of 'HelloWorldServlet'.

Right-click on the project name in the package explorer to open the context menu, select

Select Git Source Code Management System, then select your local repo.


Give EGit some time to digest the git repo, and the Egit decorations will eventually appear in the package explorer.

Instruct git to ignore eclipse configuration files.

Eclipse configuration files (e.g. the whole .settings directory, the .classpath and .project files) contain elements of your local configuration that you must not share; e.g. some files in the .settings directory are continously updated by eclipse with timestamps, which will lead to an infinite source of conflicts when stored in git.

Show eclipse hidden resources (such as the .gitgnore file). Uncheck *.resources in the Filters Dialog. For instance, in the perspective :

or in the perspective :

Open .gitignore, now visible in the top project directory. Add eclipse configuration files (.settings, .classpath and .project) to .gitignore file.

.gitignore

target
.settings
.classpath
.project

Commit to local git, then push to remote git on Github.


Checkout state #2 of abendrot, i.e. commit 42da300...

E.g., using the git command line

$ pwd
/C/Users/i051108/Documents/GitHub/abendrot-clone
$ git checkout 42da3002a84ff10f397f1219ead0d9ebcade094f
Previous HEAD position was 4d427b9... Initial commit
HEAD is now at 42da300... Merge branch 'master' of https://github.com/cthiebaud/abendrot.git

Compare yours and mine directories

"Beyond-Comparing" the two directories will now show something along this line :

Create a .travis.yml file in your project top directory with the following content:

language: java
jdk:
  - oraclejdk7

Commit and push to Github.

Open and login to https://travis-ci.org/profile# and hook your project to travis.ci

Trigger your first travis-ci build with a push to Github. You can have a peek at how I did it

On https://travis-ci.org/, your build is under the tab 'My Repositories' :

  • In a previous step, we saw how easy it was to deploy from Eclipse to the Cloud. For automated, unattended deployment, SAP HANA Cloud comes with a powerful command-line interface. I'd like to show here a third way : how to perform unattended deployment with maven

There is a SAP HANA Cloud Deployment Plugin for Maven named nwcloud-maven-plugin on Github ! It has been developed by SAP Research, but it is not included in HANA Cloud distribution. The reason for it being that SAP HANA Cloud is build tool agnostic, as already mentionned.

There does not seem to be any public version of the nwcloud-maven-plugin binaries, at least not in any well known repository such as maven central, therefore, to use it, one must build it. That's what I did, build worked like a charm: version 1.0.1.RELEASE is published to my personal public nexus repositoy. Even if compiling the plugin was a snap, you may not want to go through the exercice. Include the pluginRepositories section below in your pom.xml, your maven build will directly grab nwcloud-maven-plugin binaries from my personal nexus repository, no need to compile.

  <!-- my own repos were I deployed nwcloud-maven-plugin -->
  <pluginRepositories>
    <pluginRepository>
      <id>public.releases.buildeventhub.net</id>
      <url>http://buildeventhub.net:8081/nexus/content/repositories/releases/</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
    <pluginRepository>
      <id>public.snapshots.buildeventhub.net</id>
      <url>http://buildeventhub.net:8081/nexus/content/repositories/snapshots/</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </pluginRepository>
  </pluginRepositories>

Configuration of nwcloud-maven-plugin is done through a nwcloud.properties file. This is well documented in the plugin documentation. Since version 1.0.1.RELEASE, it isn't necessary to include the HANA Cloud account password in the nwcloud.properties file; credential can be stored in the user home, à la maven, in the ~/.m2/settings.xml maven file; just follow the the Using encrypted passwords section of the documentation for the complete how-to. If you choose to keep the password in the nwcloud.properties file, to avoid submitting inadvertently your private password to your public github, you should include immediately nwcloud.properties in .gitignore, commit localy and push to remote.

.gitignore

  target
  .settings
  .classpath
  .project
  nwcloud.properties

For you reference, here is the complete nwcloud.properties file I am currently using, including super sensitive password information, of course.

nwcloud.properties

# =============================================================================
# SAP HANA Cloud - Deployment Configuration
# =============================================================================

# -----------------------------------------------------------------------------
# Location of Neo SDK
# -----------------------------------------------------------------------------
#  - Download Neo SDK from: https://tools.hana.ondemand.com/
#  - Extract Neo SDK to a directory and specify its path in sdk.dir setting.
#     - Windows users: Please use double backslash instead of single backslash (e.g. c:\\Program Files\\Neo-SDK)
#     - Linux/Mac users: Just use normal slash as usual (e.g. /home/myuser/bin/neo-sdk)
sdk.dir=C:\\_neo\\neo-sdk-2.1.0

# Proxy settings for Java Virtual Machine
# - Proxy settings are tried to be autodetected from environment variables.
# - If you are behind a proxy and autodetect does not work or you need to override the settings, this can be done here.
# -Dhttp.proxyUser=proxyuser -Dhttp.proxyPassword=proxypassword -Dhttps.proxyUser=proxyuser -Dhttps.proxyPassword=proxypassword
sdk.proxy=-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy -Dhttps.proxyPort=8080 -Dhttp.nonProxyHosts="localhost|127.0.0.1" -Dhttps.nonProxyHosts="localhost|127.0.0.1" 

# -----------------------------------------------------------------------------
# Target for deployment (host, account, application)
# -----------------------------------------------------------------------------
#  - host: The target platform to deploy to (e.g. https://hana.ondemand.com)
#  - account: The account to deploy to
#  - application:
#     - Name/ID of the application to deploy (non-empty, alphanumeric, lowercase letters, starting with a letter, max. 30 characters).
#     - If not specified, the maven project name in lowercase letters will be used.
host=https://hanatrial.ondemand.com
# MaxDB account
account=p1742770407trial
application=abendrot

# -----------------------------------------------------------------------------
# SCN user (and password)
# -----------------------------------------------------------------------------
#  - user: SCN user (as registered at http://scn.sap.com/)
#  - password: Password of SCN user. If not specified, it will be queried on the commandline each time needed.

# MaxDB user
user=P1742770407
password=THIS_IS_NOT_A_PASSWORD

# -----------------------------------------------------------------------------
# Optional settings
# -----------------------------------------------------------------------------
java-version=7

# Request specific URL prefix for deployed application component (optional).
#url=myappurl

# Define specific component name for deployed application (optional, defaults to "web").
#component=myappcomp

# The logging level of the server process(es) (optional, defaults to "error").
# Allowed values are: error|warn|info|debug
#severity=debug

# Minimum count of server processes, on which application can be started (optional, defaults to 1).
#minimum-processes=1

# Maximum count of server processes, on which application can be started (optional, defaults to 1).
#maximum-processes=1

# Specifies whether to start/stop an application synchronously (optional, defaults to false).
# Allowed values are: true|false
synchronous=true

# -----------------------------------------------------------------------------
# Manually define WAR file to deploy
# -----------------------------------------------------------------------------
# The WAR file to be deployed is autodetected from maven project settings, but can also be set manually.

# Option 1: Specify name of WAR
# - Define name of WAR file in "target" directory of project (without ".war").
#war.name=abendrot

# Option 2: Specify full path and name of WAR (including ".war")
# source=C:\\Users\\i051108\\Documents\\GitHub\\abendrot\\abendrot-web\\target\\abendrot-web-0.1.3-SNAPSHOT.war

Adapt this nwcloud.properties to your context. Then, launch for example :

$ mvn com.sap.research:nwcloud-maven-plugin:1.0.1.RELEASE:status
In my case, this returned Status: STARTED

$ mvn com.sap.research:nwcloud-maven-plugin:1.0.1.RELEASE:status
(...)
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building abendrot-web 0.1.7-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- nwcloud-maven-plugin:1.0.1.RELEASE:status (default-cli) @ abendrot-web ---

init:

password:
[INFO] Trying to automatically retrieve password from servers defined in Maven\'s \'settings.xml\'.
[INFO]  - Matching server found. Password extracted.

status:
     [java]
     [java] Requesting status for:
     [java]    application: abendrot
     [java]    account    : p1742770407trial
     [java]    host       : https://hanatrial.ondemand.com
     [java]    SDK version: 2.1.0
     [java]    user       : P1742770407
     [java]
     [java] Status: STARTED
     [java]
     [java] URL: https://abendrotp1742770407trial.hanatrial.ondemand.com
     [java]
     [java] Access points:
     [java]   https://abendrotp1742770407trial.hanatrial.ondemand.com
     [java]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.005s
[INFO] Finished at: Fri Feb 15 20:01:45 CET 2013
[INFO] Final Memory: 11M/309M
[INFO] ------------------------------------------------------------------------

To avoid having to type the full plugin identity before the goal (groupID:artifactID:version:goal e.g. com.sap.research:nwcloud-maven-plugin:1.0.1.RELEASE:status), you may want to " (...) search in settings.xml for the pluginGroups tag and insert com.sap.research as an artifact group that contains plugins.", as quoted from the nwcloud-maven-plugin documentation.

<pluginGroups>
    <!--pluginGroup
     | Specifies a further group identifier to use for plugin lookup.
    -->
    <pluginGroup>com.sap.research</pluginGroup>
</pluginGroups>
After that, just type
$ mvn nwcloud:status

Finally, Add this xml fragment to the <build><plugins> section of pom.xml:

<plugin>
  <groupId>com.sap.research</groupId>
  <artifactId>nwcloud-maven-plugin</artifactId>
  <version>1.0.1</version>
  <executions>
    <execution>
      <id>after.deploy</id>
      <phase>deploy</phase>
      <goals>
        <goal>stop</goal>
        <goal>deploy</goal>
        <goal>start</goal>
      </goals>
    </execution>
  </executions>
</plugin>

With all this, a maven deploy will automatically trigger the upgrade of the application in the cloud!. e.g.

$ mvn clean deploy -DaltDeploymentRepository=[your_repo_id]::default::[your_repo_url]

cf. Maven Deploy Plugin for -DaltDeploymentRepository syntax. If you do not know what that means, and have no time for a maven tutorial right now, enter :

$ mvn clean deploy -DaltDeploymentRepository=my_repo::default::file:///tmp/my_repo
Maven will 'deploy' the build results to the file system in the /tmp/my_repo directory (of the current drive, if you're on Windows), then nwcloud-maven-plugin will 'deploy' - same name, two different things - the war build result to the cloud. Here is a sample maven ouput:

Configure maven-git-commit-id-plugin as described in section "The easier way: generate git.properties" of the README. Cf. xml snippet:

<plugin>
  <groupId>pl.project13.maven</groupId>
  <artifactId>git-commit-id-plugin</artifactId>
  <version>2.1.0</version>
  <executions>
    <execution>
      <goals>
        <goal>revision</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <!-- forces the plugin to generate the git.properties file -->
    <generateGitPropertiesFile>true</generateGitPropertiesFile>

    <!-- The path for the to be generated properties file, it's relative to ${project.basedir} -->
    <generateGitPropertiesFilename>src/main/resources/git.properties</generateGitPropertiesFilename>
  </configuration>
</plugin>

Add a GitRepositoryState java class to hold git properties. Grab code from here

Add a index.jsp java server page to display a Github ribbon. The ribbon points back to abendrot sources in Github. Moreover, the ribbon points to the very commit that has been build to produce the application (not sure to be crystal clear ... anyhow, you got it). Moreover, if you have deployed from a directory where there are uncommited changes to github, the ribbon will not be deployed at all. Grab code from here

Rename index.html to helloworld.html. Now, index.jsp is the default landing page of abendrot web application.

Do not forget to add abendrot/src/main/resources/git.properties to .gitignore. The file will be generated at each build, it must not be kept as a source file.

First of all, to perform a release, it is mandatory to store the HANA Cloud account password outside the project directory, in the user home (~/.m2/settings.xml) as described in the Automate Section above.

Before we start, it may be useful to read this page from Sonatype: "Maven Tips and Tricks: Using GitHub".

Performing a release with the maven-release-plugin is usually a hassle. There are always details you did not think of that blow up the whole process. This is especially true if it is the first time, or if you do it seldomly, or if your are behind a ?#! proxy.
For this very reason the release process MUST be automated.
Furthermore, it is far easier to put in place at the start of a project, and to continously operate forward on, than to add it at the end, usually under deadline pressure from guys with suits.

Add <scm> and <distributionManagement> sections to your pom.xml. Open the accordion below to look at mine. Cut, adapt to your context, and paste into your pom.xml. As before, in case you do not have a maven repository where to deploy through HTTP, use your file system, replace http://.../repositories/[releases|snapshots] with something like file:///tmp/my_repo/[releases|snapshots]

<scm>
    <connection>scm:git:https://github.com/cthiebaud/abendrot.git</connection>
    <url>scm:git:https://github.com/cthiebaud/abendrot.git</url>
    <developerConnection>scm:git:https://github.com/cthiebaud/abendrot.git</developerConnection>
    <tag>HEAD</tag>
</scm>

<distributionManagement>
    <repository>
        <uniqueVersion>false</uniqueVersion>
        <id>beh_releases</id>
        <url>http://buildeventhub.net:8081/nexus/content/repositories/releases/</url>
        <layout>default</layout>
    </repository>
    <snapshotRepository>
        <uniqueVersion>true</uniqueVersion>
        <id>beh_snapshots</id>
        <url>http://buildeventhub.net:8081/nexus/content/repositories/snapshots/</url>
        <layout>default</layout>
    </snapshotRepository>
</distributionManagement>

In order to perform a fully automated & unattended release, to avoid to be prompted for username and password during the process, we need to instruct maven where to find our credentials.

  1. In general, maven stores credentials in ~/.2/settings.xml, cf. http://maven.apache.org/settings.html#Servers.
  2. Encryption is recommended, but not mandatory, cf. http://maven.apache.org/guides/mini/guide-encryption.html.
  3. Finally, a piece of glue between maven and git is required: the project.scm.id property, cf. http://maven.apache.org/plugins/maven-release-plugin/faq.html#credentials.
Here is my configuration, for your reference:

In ~/.2/settings.xml
<servers>
  <server>
    <id>beh_releases</id>
    <username>deployment</username>
    <password> ... </password>
  </server>
  <server>
    <id>beh_snapshots</id>
    <username>deployment</username>
    <password> ... </password>
  </server>
  <server>
    <id>github</id>
    <username>cthiebaud</username>
    <password> ... </password>
  </server>
</servers>
In pom.xml
<properties>
  <project.scm.id>github</project.scm.id>
</properties>

Ready to go ?

Ensure that your project directory is clean. That means that

  1. you have pulled the last vesion from Github,
  2. all your modifications have been commited and pushed to Github, and
  3. there are no local files that are not explicitely declared in a .gitignore file.
The easiest way to get into this state is to perform a fresh git clone into a new directory. e.g.

$ # git clone git@github.com:whatever folder-name
$ git clone https://github.com/cthiebaud/abendrot.git abendrot-release
Cloning into abendrot-release...
remote: Counting objects: 565, done.
remote: Compressing objects: 100% (379/379), done.
remote: Total 565 (delta 223), reused 489 (delta 147)Receiving objects:  99% (560/565), 2.93 MiB | 605 KiB/s
Receiving objects: 100% (565/565), 3.24 MiB | 619 KiB/s, done.
Resolving deltas: 100% (223/223), done.

$ cd to the new directory

$ cd abendrot-release/

Run a dry test. Loop until successful.

$ mvn clean deploy
Results:

Ask yourself:

  1. the version of the release? => -DreleaseVersion= ? parameter
  2. the tag of the release? => -Dtag= ? parameter
  3. the version of the next development iteration ? => -DdevelopmentVersion= ? parameter

Run prepare phase of the release process, e.g.:

$ mvn release:prepare --batch-mode -DreleaseVersion=0.0.3 -Dtag=abendrot-0.0.3 -DdevelopmentVersion=0.0.4-SNAPSHOT
Results:

In case something goes wrong during the release:prepare phase, rollback to the initial state with:
$ git reset --hard HEAD~1
$ mvn release:clean
  1. git reset --hard HEAD~1 will wipe for the eternity the local commit of the version upgrade in the the pom.xml just done by maven-release-plugin, and
  2. mvn release:clean will remove temporary work files (release.properties, etc.) left by the maven-release-plugin in the project directory

Run perform phase of the release process, e.g.:

$ mvn release:perform --batch-mode
Results:

Check the results: the binairies have been deployed to the binary repository, the application is running the new version, the sources have been tagged, and you are ready for the next development iteration.

Binaires. Verify that the war has been deployed to Nexus. Look for it on your maven deployment repository (or on your file system if you have used the file:// trick). E.g. @ abendrot nexus instance:

Application. Verify that the application has been redeployed. Go to your SAP HANA Cloud Application, and Click on the Github ribbon. E.g. @ abendrot application on the cloud:

Sources. The Github ribbon points directly to the last commit before the build. In that case, this is an automatic commit made by the maven-release-plugin on your behalf. E.g. @ abendrot sources on Github:

The very commit made during the writing of this tutorial is still available on Github here. The maven release plugin has tagged the sources, hence the sources snapshot is still available at Github, look for abendrot-0.0.3.zip on the abendrot tag page.

Well, here are some more human URLs that will redirect to the real urls :

You sure be thinking as well "your tutorial is OK, but going through all these just to push a mere "Hello, World!" to the cloud ... isn't it mega-supra-hyper overkill?"

Stay tuned, I'll try to find time to add meat to the tutorial using HANA Cloud Services:

  • Connectivity Service
  • Mail Service
  • Document Service

Tschüß!