Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

Inside SAP, some cool guys (michael.spahn, radu-florian.atanasiu and sudheer.tammana) have been brewing a special blend of Spring Roo add-ons, making it very easy and comfortable for you to use Spring Roo with SAP NetWeaver Cloud; helping you to integrate SAP NetWeaver Gateway entities with Spring Roo generated entities and to kick-start your business application within minutes.

In this blog post, I’ll show you how to use the add-ons. You’ll learn to leverage the add-ons for your own projects and to add some more flavor... let’s say Google Maps. You might wonder, where do I find this great blend and much more? Visit SAP NetWeaver Cloud Labs and also learn more about the crowd behind the add-ons.

Before you get started

Get yourself familiar with Spring Roo. There are loads of tutorials and books out there. I personally find the book "Getting Started with Roo" by Josh Long and Steve Mayzak a quick read and a good start into the world of Spring Roo. Set up Spring Roo and perform the steps described under "Try Spring Roo" to get your first Spring Roo application up and running, and to see if all is set up correctly. (Comment: I use Spring Roo standalone version 1.2.2.RELEASE for Mac OS X, but there is also an excellent Eclipse-based IDE - STS. It’s your decision... the tutorial works with both.).

After being used to Spring Roo, it’s time to set up the SAP NetWeaver Cloud add-ons. Follow the steps described here (for the SAP NetWeaver Cloud Addon for Spring Roo) and here (for the SAP NetWeaver Gateway Connectivity Addon for Spring Roo) to install the necessary add-ons.

For the last step, you have two options: Option 1, you use an existing SAP NetWeaver Gateway system providing the services for SAPs famous flight demo (We use one flight data service in our sample application.). SAP, for instance, provides you access to such a system (read-only access):

Base-URL: http://gw.esworkplace.sap.com/sap/opu/odata/IWBEP/RMTSAMPLEFLIGHT_2/
User: GW@ESW
Password:ESW4GW

Option 2, set up your own SAP NetWeaver Gateway system hosting the flight demo. Using an existing SAP NetWeaver Gateway system might be fine for the start, but if you want to have the full experience, you should set up your own system. Read my blog post on how I set up a SAP NetWeaver Gateway system on my Mac. Was quite fun. :wink:

The Sample Application

Now let's talk about the sample application for this rather technical tutorial (In comparison to my blog post on responsive design, I didn't spend much time on making the user interface pretty.) I chose a very simple but common scenario: Imagine, you develop a Line-of-Business (LoB) application, called TravelLocs. The application is used to maintain a list of preferred travel agencies. We assume that preferred is primarily defined by the location of the agency. So, wouldn’t it be nice if the user sees the agency’s location on a map to make the decision if it's a preferred one? I'm also a big fan of APIs (see also steinermatt blog post) and think we should make all information accessible via a simple REST API, e.g. to use it for a widget or in a dashboard. That’s all our simple application does.

Now let’s have a look into the data sources: For such an application, often, some data already exists in one or the other, e.g. ERP, system. In our case, we assume that you have read-only access to the famous SAP flight demo and the service TravelAgenciesCollection via SAP NetWeaver Gateway. The service returns a list of travel agencies containing the following information:

TravelAgencies
Travel Agency ID
Name
Street
Region
Postal Code
PO Box

For the application, we need to gather some additional information, which we cannot store in the e.g. ERP system. Instead, we use SAP NetWeaver Cloud to store it, and link it to the data provided by the Gateway service. To make it simple, we only store two more attributes per agency: a description and a flag, indicating if it’s a preferred agency:

TravelAgenciesEx
Description
Preferred

Building the Application

Enough preparation, let’s get our hands dirty and get the application up and running. Figure 1 summarizes the necessary steps for building our application. I omit the console output for each step and only give the commands you should execute in the Roo shell.


Figure 1. The building blocks of our application.

Open the command line (under Windows) or terminal (under Mac OS X), create a new folder, enter the folder, open the Spring Roo shell, create a new project and enable persistency, as follows:

>> mkdir demo
>> cd demo
>> roo.[sh|bat]
roo> // Creating project demo
roo> project --topLevelPackage com.sap.nwcloud --projectName demo
roo> // Enabling persistency using eclipse link with in-memory store
roo> persistence setup --provider ECLIPSELINK –-database HYPERSONIC_IN_MEMORY

>> Step 1: Consuming Gateway services and accessing the travel agencies collection

Next, we are integrating Gateway and accessing the list of travel agencies stored in the ERP system. By just entering the following commands into the Roo shell, you’ll see the magic happening:

roo> // Setting up Gateway connectivity
roo> gateway setup
roo> // Defining odata endpoint; we use SAPs demo system
roo> gateway define odata_endpoint --Name flightdemo --URL http://gw.esworkplace.sap.com/sap/opu/odata/IWBEP/RMTSAMPLEFLIGHT_2/
      --USER GW@ESW --PASSWORD ESW4GW

A note on proxies: If you’re behind a proxy you must set the proxy by specifying it in the gateway define command, like this:

roo> // Defining odata endpoint; we use SAPs demo system
roo> gateway define odata_endpoint --Name flightdemo --URL http://gw.esworkplace.sap.com/sap/opu/odata/IWBEP/RMTSAMPLEFLIGHT_2/
     --USER GW@ESW --PASSWORD ESW4GW --HTTP_PROXYHOST proxy --HTTP_PROXYPORT 8080

For my TechEd 2012 demo, I used a local Gateway instance (option 2) with the following parameters:

roo> // Defining local odata endpoint
roo> gateway define odata_endpoint --Name flightdemo --URL http://192.168.240.130:8042/sap/opu/odata/IWBEP/RMTSAMPLEFLIGHT_2/
     --USER DEVELOPER --PASSWORD ch4ngeme

Back to the necessary commands (the two above are only for clarification).

roo> // Mapping the (remote) entity TravelAgencyCollection
roo> // Read-only access if you use SAPs demo system
roo> gateway entity --namespace flightdemo --remoteEntitySet TravelAgencies
roo> // Creating the web UI; scaffolding
roo> web mvc setup
roo> // We only allow read-only access; no editing operations allowed
roo> web mvc scaffold --class ~.web.TravelAgencyController --backingType ~.domain.TravelAgencies     --disallowedOperations delete,update,create
roo> // Exiting Roo shell
roo> quit

Wasn’t this fast and easy? :wink: Let’s run the application locally

>> mvn jetty:run

and see how it looks-like: http://localhost:8080/demo. When you’re done enjoying the Gateway integration, exit jetty and enter the Roo shell again.

>> Step 2: Adding an entity for storing our extension data: TravelAgenciesExt

Now, we add the entity storing all our extension data, i.e. the description and the flag, indication if it’s a preferred agency.

roo> // Defining entity TravelAgenciesExt
roo> entity jpa --class ~.domain.TravelAgenciesExt
roo> field string --fieldName description
roo> field bool --fieldName preferredAgency
roo> // Generating the web UI; scaffolding for extension table
roo> web mvc scaffold --class ~.web.TravelAgencyExtController --backingType ~.domain.TravelAgenciesExt
roo> // Exiting Roo shell
roo> quit

And again, let’s see how it looks-like:

mvn jetty:run

>> Step 3: Linking entity TravelAgencies with TravelAgenciesExt

Since the Gateway add-on is still under heavy development, the way entities are linked surely changes in the future and I currently have to use a hack which only works for add and delete but not for edit. In the future, no hack will be necessary. The guys (michael.spahn, radu-florian.atanasiu and sudheer.tammana) behind the add-on are currently discussing several options. Maybe you like to join the fun? :wink:

roo> // -> Linking TravelAgenciesExt  with TravelAgencies  uni-directional
roo> field reference --class ~.domain.TravelAgenciesExt --fieldName travelAgency --type ~.domain.TravelAgencies --cardinality ONE_TO_ONE
roo> // Exiting Roo shell
roo> quit

Open file TravelAgenciesExt.java and add the highlighted lines to apply the hack:

package com.sap.nwcloud.demo.domain;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.CascadeType;          // <- added
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;
@RooJavaBean
@RooToString
@RooJpaActiveRecord
public class TravelAgenciesExt {
    private String description;
    private Boolean preferredAgency;
    @OneToOne(cascade={CascadeType.ALL}) // <- added
    private TravelAgencies travelAgency;
}

And again, you got it, right? :wink: . Let’s see the application in action:

mvn jetty:run

>> Step 4: Adding a map to show the location per travel agency

First of all, it’s good if you know something about Java Server Pages (JSP), because we have to edit the show view of travel agencies; but luckily, we can use Roo’s command for embedding external web applications to generate most of the code needed. We only have to do some little pluming. So let’s add a static Google map to our application:

roo> // Embedding an external web application, in our case Google maps
roo> web mvc embed map --location "3355 Las Vegas Boulevard South Las Vegas, NV 89109, USA"
roo> // Exiting Roo shell
roo> quit

And again, let’s enjoy the map

mvn jetty:run

exit jetty and let the pluming start. Open the following two files in a text editor: src/main/webapp/WEB-INF/views/embed/google_maps.jspx

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:embed="urn:jsptagdir:/WEB-INF/tags/embed" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
<jsp:output omit-xml-declaration="yes"/>
<util:panel id="title" title="Google Maps">
<embed:map id="map_null" location="3355 Las Vegas Boulevard South Las Vegas, NV 89109, USA" z="h/nSUqa1znHt/kCaJ/F3jA8l5gE="/>
</util:panel>
</div>

and src/main/webapp/WEB-INF/views/travelagencieses/show.jspx

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:page="urn:jsptagdir:/WEB-INF/tags/form" version="2.0">
    <jsp:directive.page contentType="text/html;charset=UTF-8"/>
    <jsp:output omit-xml-declaration="yes"/>
    <page:show create="false" delete="false" id="ps_com_sap_nwcloud_domain_TravelAgencies" object="${travelagencies}" path="/travelagencieses" update="false" z="70w+D+ckNDIcZk4lb/wh8YOQaGQ=">
        <field:display field="travelAgencyID" id="s_com_sap_nwcloud_domain_TravelAgencies_TravelAgencyID" object="${travelagencies}" z="x623CUzDnS6OwyKzBifTLkfwIDg="/>
        <field:display field="name" id="s_com_sap_nwcloud_domain_TravelAgencies_Name" object="${travelagencies}" z="XbIvQVLg3bbNKYVxKV5iNdxaUIs="/>
        <field:display field="street" id="s_com_sap_nwcloud_domain_TravelAgencies_Street" object="${travelagencies}" z="jOAMP1fxIFuj2oHKAuAUloMYmSY="/>
        <field:display field="region" id="s_com_sap_nwcloud_domain_TravelAgencies_Region" object="${travelagencies}" z="fKBTys1jKvaPz+vjpZ3M00dSB1g="/>
        <field:display field="postalCode" id="s_com_sap_nwcloud_domain_TravelAgencies_PostalCode" object="${travelagencies}" z="2FMk3lyGEENeg1L4paIACDGD/yI="/>
        <field:display field="POBox" id="s_com_sap_nwcloud_domain_TravelAgencies_POBox" object="${travelagencies}" z="Dh7C1yMf6ytqHZTJwsiCYX4TZXw="/>
        <field:display field="languageCode" id="s_com_sap_nwcloud_domain_TravelAgencies_LanguageCode" object="${travelagencies}" z="TSh5FMx9zLSwimji4VbpoCnhRIc="/>
        <field:display field="mimeType" id="s_com_sap_nwcloud_domain_TravelAgencies_MimeType" object="${travelagencies}" z="1sWn9OexhqbhtpDoFNNo34OPxrQ="/>
        <field:display field="localCurrencyCode" id="s_com_sap_nwcloud_domain_TravelAgencies_LocalCurrencyCode" object="${travelagencies}" z="GDanAoNVby9aT3j4SOnLT2J1n+I="/>
        <field:display field="telephoneNumber" id="s_com_sap_nwcloud_domain_TravelAgencies_TelephoneNumber" object="${travelagencies}" z="rRhtJrBZdGgKlLI/NAdK+cqn1FQ="/>
        <field:display field="URL" id="s_com_sap_nwcloud_domain_TravelAgencies_URL" object="${travelagencies}" z="S9KHXeZOfXpPlktKN54WmNkNuLw="/>
        <field:display field="country" id="s_com_sap_nwcloud_domain_TravelAgencies_Country" object="${travelagencies}" z="je079YHOFOXPjqlXzJpnJQ9+W3Y="/>
        <field:display field="city" id="s_com_sap_nwcloud_domain_TravelAgencies_City" object="${travelagencies}" z="TuLO2nPa0ymI5QTBL6w39i8rIz8="/>
    </page:show>
</div>

copy the coding from google_maps.jspx to show.jspx. Don’t forget to update the location and save show.jspx. show.jspx now looks as follows:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
// Copy part below and remove comment
<div xmlns:embed="urn:jsptagdir:/WEB-INF/tags/embed" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:page="urn:jsptagdir:/WEB-INF/tags/form" version="2.0">    <jsp:directive.page contentType="text/html;charset=UTF-8"/>
    <jsp:output omit-xml-declaration="yes"/>
    <page:show create="false" delete="false" id="ps_com_sap_nwcloud_domain_TravelAgencies" object="${travelagencies}" path="/travelagencieses" update="false" z="70w+D+ckNDIcZk4lb/wh8YOQaGQ=">
        <field:display field="travelAgencyID" id="s_com_sap_nwcloud_domain_TravelAgencies_TravelAgencyID" object="${travelagencies}" z="x623CUzDnS6OwyKzBifTLkfwIDg="/>
        <field:display field="name" id="s_com_sap_nwcloud_domain_TravelAgencies_Name" object="${travelagencies}" z="XbIvQVLg3bbNKYVxKV5iNdxaUIs="/>
        <field:display field="street" id="s_com_sap_nwcloud_domain_TravelAgencies_Street" object="${travelagencies}" z="jOAMP1fxIFuj2oHKAuAUloMYmSY="/>
        <field:display field="region" id="s_com_sap_nwcloud_domain_TravelAgencies_Region" object="${travelagencies}" z="fKBTys1jKvaPz+vjpZ3M00dSB1g="/>
        <field:display field="postalCode" id="s_com_sap_nwcloud_domain_TravelAgencies_PostalCode" object="${travelagencies}" z="2FMk3lyGEENeg1L4paIACDGD/yI="/>
        <field:display field="POBox" id="s_com_sap_nwcloud_domain_TravelAgencies_POBox" object="${travelagencies}" z="Dh7C1yMf6ytqHZTJwsiCYX4TZXw="/>
        <field:display field="languageCode" id="s_com_sap_nwcloud_domain_TravelAgencies_LanguageCode" object="${travelagencies}" z="TSh5FMx9zLSwimji4VbpoCnhRIc="/>
        <field:display field="mimeType" id="s_com_sap_nwcloud_domain_TravelAgencies_MimeType" object="${travelagencies}" z="1sWn9OexhqbhtpDoFNNo34OPxrQ="/>
        <field:display field="localCurrencyCode" id="s_com_sap_nwcloud_domain_TravelAgencies_LocalCurrencyCode" object="${travelagencies}" z="GDanAoNVby9aT3j4SOnLT2J1n+I="/>
        <field:display field="telephoneNumber" id="s_com_sap_nwcloud_domain_TravelAgencies_TelephoneNumber" object="${travelagencies}" z="rRhtJrBZdGgKlLI/NAdK+cqn1FQ="/>
        <field:display field="URL" id="s_com_sap_nwcloud_domain_TravelAgencies_URL" object="${travelagencies}" z="S9KHXeZOfXpPlktKN54WmNkNuLw="/>
        <field:display field="country" id="s_com_sap_nwcloud_domain_TravelAgencies_Country" object="${travelagencies}" z="je079YHOFOXPjqlXzJpnJQ9+W3Y="/>
        <field:display field="city" id="s_com_sap_nwcloud_domain_TravelAgencies_City" object="${travelagencies}" z="TuLO2nPa0ymI5QTBL6w39i8rIz8="/>
    </page:show>
     // Copy part below and remove comment
     <util:panel id="title" title="Google Maps">
        <embed:map id="map_null" location="${travelagencies.street}, ${travelagencies.postalCode}, ${travelagencies.city}" z="T5ZT89GAHaWeY8anHet5nJokHZ4="/>
    </util:panel>
</div>

Next, open file src/main/webapp/WEB-INF/views/menu.jspx and remove

<menu:category id="c_embedded" z="LRTVSLfH1//iHuBP77kc72qGGb8=">
          <menu:item id="i_embedded___embedgoogle_maps_id" messageCode="global_generic" url="//embed/google_maps" z="Z96lgV9WfBw9BFHEEdRejIjpw6Q="/>
</menu:category>

Finally, delete folder src/main/webapp/WEB-INF/views/embed/.

Run jetty again and enjoy the location of the agency on a map (see under agencies -> show)

mvn jetty:run

>> Step 5: Enabling JSON support for our two entities

Next, my favorite step, let’s APIfy our application and add a REST API.

roo> // Enabling json for all enitites
roo> json all
roo> // Updating the controllers
roo> web mvc json all
roo> // Exiting Roo shell
roo> quit

Again, start the application and test the Rest API. I prefer using curl to test my REST services. If your operation system doesn’t support curl out-of-the-box, simply download it here:

curl -i -H "Accept: application/json" http://localhost:8080/demo/travelagencieses
curl -i -H "Accept: application/json" http://localhost:8080/demo/travelagenciesexts

>> Step 6: Deploying to SAP NetWeaver Cloud

Finally, let’s bring our application in the cloud.

roo> // Enabling NW Cloud deployment
roo> nwcloud enable-deploy
roo> // Enabling NW Cloud persistency
roo> nwcloud enable-jpa
roo> // Exiting Roo shell
roo> quit

Package the application by calling Maven,

>> mvn clean package

open file "nwcloud.properties", and set your SCN user and password

# -----------------------------------------------------------------------------
# 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.
user=myscnuser
#password=myscnpassword

define your deployment target

# -----------------------------------------------------------------------------
# Target for deployment (host, account, application)
# -----------------------------------------------------------------------------
#  - host: The target platform to deploy to (e.g. https://netweaver.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://netweaver.ondemand.com
account=myaccount
#application=myapp

and specify the location of the command-line deployment tool.

# -----------------------------------------------------------------------------
# Location of Neo SDK
# -----------------------------------------------------------------------------
#  - Download Neo SDK from: https://tools.netweaver.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:\\Program Files\\Neo-SDK

If you’re behind a proxy and auto-detection of proxy settings from environment variables should not work, remember to set your proxy settings manually:

# 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.
#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" -Dhttp.proxyUser=proxyuser -Dhttp.proxyPassword=proxypassword -Dhttps.proxyUser=proxyuser -Dhttps.proxyPassword=proxypassword

Save the file, and ... finally deploy and run the application in the SAP NetWeaver Cloud by calling Maven, again:

>> mvn nwcloud:deploy nwcloud:start

Great, we made it. Welcome to SAP NetWeaver Cloud :smile: . Now it’s your turn, start exploring Spring Roo, the add-ons and join the project under SAP NetWeaver Cloud Labs...

One final word: If you really want to leverage the power of Spring Roo, you must understand the underlying technologies very well. Spring Roo helps you to speed up the kick-start and automates many steps, but you must often dig deep for the last 10 percent. Have this in mind.

8 Comments