The examples in this post are based on Ivy configuration files included in the distribution and omit original copyright information for readability. Ivy is distributed under Apache License, Version 2.0.


Ivy in NWDS


When working on Java projects which rely heavily on the use of third-party libraries and/or frameworks (like various Spring modules, for example) one need some dependency management mechanism to allow for quick and reliable resolution of required JAR dependencies.

The Java community has long favored the use of Maven repositories for just this purpose. Even though the Eclipse IDE, on which the NWDS is based, could very well be updated to handle Maven based projects, it might be a bit cumbersome to setup and to use together with the usual projects (Java, dynamic web, EAR) build with NWDS.

There is another way. Ivy is a flexible and unobtrusive dependency manager based on Ant, the scripting language NWDS understands by default. So this is how one  might use Ivy for a simple Spring project.


Configure Ivy project


Let's assume that we want to use Spring's Rest Template from Spring Data REST project to access a RESTful resource. For this we would need "spring-data-rest-webmvc.jar", plus, possibly, a logging implementation, together with all required dependencies.


  • Download Ivy binary distribution and unzip in a temporary location.
  • Create a simple project in NWDS using "Genral" type.
  • Copy files "ivy.xml", "ivy-2.4.0.jar", "build.xml" to the location of the project (the actual version of the Ivy JAR may differ).
  • The project structure should look as following.



The "build.xml" file should be modified to contain the reference to the Ivy JAR and a slightly different target for retrieving the dependencies.


<project name="retrieve-ivy-deps" default="resolve-and-retrieve"  xmlns:ivy="antlib:org.apache.ivy.ant">
  <target name="init-ivy">
  <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant">
  <pathelement location="${basedir}/ivy-2.4.0.jar" />
  <target name="resolve-and-retrieve" depends="init-ivy" description="--> resolves dependencies declared in ivy.xml file">
  <delete dir="${basedir}/lib"/>
  <ivy:retrieve conf="compile"/>

The file "ivy.xml" is where the top-most artifacts needed for our project are declared. It specifies the "copmpile" configuration which will retrieve the artifacts themselves together with all required compile-time dependencies (as specified in the Maven repository).


<ivy-module version="1.0">
  <info organisation="some.organization" module="ivy-dependencies-manager" />
  <conf name="compile" description="jars required for compilation" />
  <dependency org="org.springframework.data" name="spring-data-rest-webmvc" rev="2.1.6.RELEASE" conf="compile->default"/>
  <dependency org="ch.qos.logback" name="logback-classic" rev="1.1.7" conf="compile->default"/>

The remaining file, "ivysettings.xml" just tells Ivy that we want to use default Maven central repository.


  <settings defaultResolver="chain" />
  <chain name="chain">
  <ibiblio name="central" m2compatible="true"></ibiblio>

Once the "resolve-and-retrieve" target in the "build.xml" is executed (from contextual menu in the "Outline" view). All the needed dependencies for our project are resolved and downloaded into "lib" directory.


Buildfile: ivy~libs\build.xml
[ivy:retrieve] :: Apache Ivy 2.4.0 - 20141213170938 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: file = ivy~libs\ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: some.organization#ivy-dependencies-manager
[ivy:retrieve] confs: [compile]
[ivy:retrieve] found org.springframework.data#spring-data-rest-webmvc;2.1.6.RELEASE in central
[ivy:retrieve] found org.springframework.data#spring-data-rest-core;2.1.6.RELEASE in central
[ivy:retrieve] found org.springframework#spring-tx;3.2.14.RELEASE in central
[ivy:retrieve] found org.springframework#spring-beans;3.2.14.RELEASE in central
[ivy:retrieve] found org.springframework#spring-core;3.2.14.RELEASE in central
[ivy:retrieve] found commons-logging#commons-logging;1.1.3 in central
[ivy:retrieve] found org.springframework.hateoas#spring-hateoas;0.16.0.RELEASE in central
[ivy:retrieve] found org.springframework#spring-aop;3.2.14.RELEASE in central
[ivy:retrieve] found aopalliance#aopalliance;1.0 in chain
[ivy:retrieve] found org.springframework#spring-context;3.2.14.RELEASE in central
[ivy:retrieve] found org.springframework#spring-expression;3.2.14.RELEASE in central
[ivy:retrieve] found org.springframework#spring-web;3.2.14.RELEASE in central
[ivy:retrieve] found org.springframework#spring-webmvc;3.2.14.RELEASE in central
[ivy:retrieve] found org.objenesis#objenesis;2.1 in central
[ivy:retrieve] found org.springframework.data#spring-data-commons;1.8.6.RELEASE in central
[ivy:retrieve] found org.slf4j#slf4j-api;1.7.12 in central
[ivy:retrieve] found org.springframework.plugin#spring-plugin-core;1.1.0.RELEASE in central
[ivy:retrieve] found org.atteo#evo-inflector;1.2 in central
[ivy:retrieve] found com.fasterxml.jackson.core#jackson-annotations;2.3.3 in central
[ivy:retrieve] found org.slf4j#jcl-over-slf4j;1.7.12 in central
[ivy:retrieve] found com.fasterxml.jackson.core#jackson-databind;2.3.5 in central
[ivy:retrieve] found com.fasterxml.jackson.core#jackson-core;2.3.5 in central
[ivy:retrieve] found ch.qos.logback#logback-classic;1.1.7 in central
[ivy:retrieve] found ch.qos.logback#logback-core;1.1.7 in central
[ivy:retrieve] found org.slf4j#slf4j-api;1.7.20 in central
[ivy:retrieve] :: resolution report :: resolve 487ms :: artifacts dl 16ms
[ivy:retrieve] :: evicted modules:
[ivy:retrieve] org.slf4j#slf4j-api;1.7.7 by [org.slf4j#slf4j-api;1.7.12] in [compile]
[ivy:retrieve] org.slf4j#slf4j-api;1.7.12 by [org.slf4j#slf4j-api;1.7.20] in [compile]
[ivy:retrieve] org.slf4j#slf4j-api;1.7.6 by [org.slf4j#slf4j-api;1.7.12] in [compile]
[ivy:retrieve] com.fasterxml.jackson.core#jackson-annotations;2.3.0 by [com.fasterxml.jackson.core#jackson-annotations;2.3.3] in [compile]
  |                  |            modules            ||   artifacts   |
  |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
  |      compile     |   28  |   0   |   0   |   4   ||   24  |   0   |
[ivy:retrieve] :: retrieving :: some.organization#ivy-dependencies-manager
[ivy:retrieve] confs: [compile]
[ivy:retrieve] 24 artifacts copied, 0 already retrieved (7231kB/93ms)

Just for illustration, Ivy just resolved and made available for us a whole dependency tree of JARs. Here the same tree as viewed in Maven project in IntelliJ.




General remarks


The "ivy-libs" project created above can be reused for resolving the dependencies for any number of Java projects in the NWDS.



Important: the mechanism described in this article is intended as an example only and should not be interpreted as a generally accepted or endorsed way of connecting to and working with a SAP back-end systems. In particular, additional security measures: securing access to the web application, securing transport of data obtained via RFC calls, even though not being addressed here, are absolutely essential to the real-world application. Another important consideration: the usage of a generic system user to connect to the back-end system and execute BAPIs, from outside an SAP managed landscape, is most likely a subject to a specific licensing restrictions. The same might be the case with the use of SAPUI5 libraries when the framework will be released.




With appearance of front-end tools like SAPUI5 (pure JavaScript), there is an alternative to the development of SAP compliant applications using standard IDEs like the popular NetBeans platform. This blog post will describe the way to set up a simple application using NetBeans which uses SAPUI5 demo kit, Jersey RESTful service and SAP JCo technology to execute RFC calls on the back-end system. The application is built and tested via Maven using an embedded Tomcat server.




  • Download and install locally a distribution of JCo connector available from SAP Marketplace which corresponds to your architecture. The code used here was tested with SAP JCo version 3.0.8 for Windows 7 (x64).
  • RFC enabled system user for connection to ABAP back-end system.
  • Familiarity with NetBeans platform and Maven build framework.
  • JavaScript libraries from SAPUI5 demo kit, the code is based on version 1.8.4.


Setting up


Create a simple Maven based web application project. In order to use SAP JCo libraries as Maven dependencies, install the sapjco JAR in your local repository. Here are the relevant contents of pom.xml file for the project.


        <!-- install sap-jco-3.0.8.jar in local repository ~.m2/repository/com/sap/sap-jco/3.0.8, for example -->
           <!-- other plugins: compile, war -->


Notice that we are using Tomcat Maven plugin to launch the web application in an embedded instance of Tomcat server.

The JARs from SAPUI5 demo kit go to WEB-INF/lib directory.



JCo service


SAP Java Connector (JCo) infrastructure allows to connect to a back-end ABAP system from any Java client. First we need to implement com.sap.conn.jco.ext.DestinationDataProvider describing the necessary connection properties.


public class JCoDataProvider implements DestinationDataProvider {
    public static final String RFC_SYSTEM_ID = "BACK_END_SYSTEM";
    private DestinationDataEventListener evtListener;
    private Properties props;
    public Properties getDestinationProperties(String name) {
        if (name.equals(RFC_SYSTEM_ID)) {
            if (props == null) {
                try {
                    props = new Properties();
                } catch (IOException ex) {
                    throw new RuntimeException("Cannot load JCo properties for destination " + name + ". " + ex.getMessage());
        } else {
            throw new IllegalArgumentException("Not configured for " + name);
        return props;
    public boolean supportsEvents() {
        return true;
    public void setDestinationDataEventListener(DestinationDataEventListener dl) {
        this.evtListener = dl;


This implementation just reads the properties from a flat properties file. See examples from the distribution of sapjco for more examples.

Out JCo manager then uses the specified data provider to connect to the back-end system and execute RFC calls using JCo API.


public class JCoManager {
    private static final String EXPORT_PARAMETERS_LIST = "export_parameters_list";
    private static final String TABLE_PARAMETERS_LIST = "table_parameter_list";
    public JCoManager() {
        if (!Environment.isDestinationDataProviderRegistered()) {
            Environment.registerDestinationDataProvider(new JCoDataProvider());
    private Map<String, JCoRecord> executeRfc(String bapi, Map<String, Object> inParams) {
        Map<String, JCoRecord> records = new HashMap<String, JCoRecord>();
        try {
            JCoDestination jcoDestination = JCoDestinationManager.getDestination(JCoDataProvider.RFC_SYSTEM_ID);
            JCoFunction jcoFunction = jcoDestination.getRepository().getFunction(bapi);
            if (jcoFunction == null) {
                throw new JCoRuntimeException(JCoException.JCO_ERROR_FUNCTION_NOT_FOUND, bapi);
            //see if we need to set the input parameters
            if (inParams != null) {
                //see if the function accepts any input parameters
                JCoParameterList jcoInParams = jcoFunction.getImportParameterList();
                if (jcoInParams == null) {
                    throw new JCoRuntimeException(JCoException.JCO_ERROR_CONFIGURATION,
                            "JCo function " + bapi + " does not have any input parameters");
                //loop through the supplied parameter map and set the function parametres
                for (Iterator<String> iter = inParams.keySet().iterator(); iter.hasNext();) {
                    String key = iter.next();
                    Object value = inParams.get(key);
                    try {
                        jcoInParams.setValue(key, value);
                    } catch (JCoRuntimeException e) {
                        throw new JCoRuntimeException(e.getGroup(), e.getKey(), "Problem setting input parameter "
                                + key
                                + " for bapi " + bapi + ". " + e.getMessage(), e);
            //execute call
            //set the export parameters
            JCoParameterList jcoOutParams = jcoFunction.getExportParameterList();
            if (jcoOutParams != null) {
                records.put(EXPORT_PARAMETERS_LIST, jcoOutParams);
            //set the table parameters
            JCoParameterList jcoTabParams = jcoFunction.getTableParameterList();
            if (jcoTabParams != null) {
                records.put(TABLE_PARAMETERS_LIST, jcoTabParams);
        } catch (JCoException e) {
            throw new JCoRuntimeException(e.getGroup(), e.getKey(), e.getMessage(), e);
        return records;
     * Executes STFC_CONNECTION BAPI. Can be used to check JCo connection to the
     * back-end.
    public String[] checkConnection(String requText) {
        String[] result = new String[2];
        Map<String, Object> inParams = new HashMap<String, Object>();
        inParams.put("REQUTEXT", requText);
        Map<String, JCoRecord> outRecords = executeRfc("STFC_CONNECTION", inParams);
        JCoRecord outParams = outRecords.get(EXPORT_PARAMETERS_LIST);
        result[0] = outParams.getString("ECHOTEXT");
        result[1] = outParams.getString("RESPTEXT");
        return result;


For our example we'll use STFC_CONNECTION BAPI for checking the connection to the back-end, it's called from checkConnection() method.


Jersey service


Create a simple Jersey resource and an implementation of com.sun.jersey.spi.inject.InjectableProvider to inject our JCo service as the singleton.

Here is the annotation used by the injectable provider.


public @interface SingletonComponent {


Here is the injectable provider itself.


public class SingletonComponentInjectableProvider implements InjectableProvider<SingletonComponent, Type>, Injectable<Object> {
    private Type type;
    public ComponentScope getScope() {
        return ComponentScope.Singleton;
    public Injectable getInjectable(ComponentContext ctx, SingletonComponent annot, Type type) {
        this.type = type;
        return this;
    public Object getValue() {
        Object obj = null;
        try {
            obj = ((Class) type).newInstance();
        } catch (InstantiationException ex) {
            throw new RuntimeException(ex);
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        return obj;


And here is the resource which uses our JCo service and exposes the results of RFC calls as JSON objects.


public class FlightResource {
    private JCoManager jCoManager;
    public Map check(@PathParam("echo") String echo) {
        Map map = new HashMap();
        String[] response = jCoManager.checkConnection(echo);
        map.put("str1", response[0]);
        map.put("str2", response[1]);
        return map;


Do not forget to configure Jersey servlet in web.xml file.




SAPUI5 front-end and testing


Create a simple HTML page with JS view and controller which allows to check the connection to the back-end.

Here is the details of the controller. It uses a JQuery driven AJAX call to our Jersey resource.


sap.ui.controller("flight.search", {
    check: function(echo){
      this._doAjax("/check/"+echo, null, "GET", false).done(function(data){
          console.log("Check connection returned: ", data);
          sap.ui.commons.MessageBox.alert(data.str2, null, data.str1);
    _doAjax: function(path, content, type, async) {
        var params = {
            url: "/rest" + path,
            dataType: "json",
            contentType: "application/json",
            context: this,
            cache: false
        params["type"] = type || "POST";
        if (content) {
            params["data"] = JSON.stringify(content);
        if (async === false) {
            params["async"] = async;
        return jQuery.ajax(params);


Here is the view.


sap.ui.jsview("flight.search", {
    getControllerName: function() {
        return "flight.search";
    createContent: function(ctrl) {
        var btn1;
        btn1 = new sap.ui.commons.Button({
            text: "Check"
        btn1.attachPress(function(evt) {            
        return [btn1];


We can run the server with mvn tomcat7:run command and access our application at localhost.


In this post I will show how we can setup and work with a popular code source and revision control tool -- TortoiseSVN -- together with the NetWeaver Developer Studio for AS version 7.0. Normally, you should take advantage of NetWeaver Developer Infrastructure (NWDI) when developing with Java in NWDS, which takes care of revision control for you (among other things). But to setup a fully functioning NWDI is not always an option. Sometimes you just need to be able to revert to or compare a file in your project with its version in the repository. Moreover, you are not always develop using Development Components (DCs) architecture required by NWDI. All this, naturally, might get you thinking about using an SVN repository to track changes to your NWDS projects. The problem is that, unlike the recent NWDS for AS 7.3, the older NWDS for AS 7.0 (in my case 7.0.25) is built on an old Eclipse version 2.1.2, which does not have many SVN plugins. The solution to the problem is to use an external SVN client to keep track of changes in the NWDS workspace, without Eclipse being aware of it.


Until recently, the problem with this solution was that SVN protocol required an .SVN folder with metadata being placed in every folder of the project. When working with some type of projects like WDJ (or with DCs in Local Development), NWDS has to copy some contents around (gen* and bin folders) and recreate some folders upon every build. This caused, SVN clients to complain (since .SVN folders were copied as well). Fortunately, the recent versions of SVN protocol specify one top-level .SVN folder containing all of the SVN metadata for the project. This made it a breeze to be able to use an external SVN client with any type of NWDS project.


Download and install Tortoise SVN client, it integrates seamlessly with Windows file explorer interface.


I assume we are going to create a new NWDS workspace under the path c:\svn\workspace. I also assume you have an SVN repository set up on a remote server. Use SVN Repo Browser from the context menu in c:\svn folder to browse to the root folder of the SVN repository where you want to import your workspace.



Create a remote folder workspace.



Once the workspace (remote) folder has been created, check it out to your local c:\svn\workspace directory. You should now have a SVN controlled workspace directory ready for NWDS projects.



Start NWDS with -data argument pointing to the c:\svn\workspace directory (copy NWDS shortcut, right click on the new shorcut, select Properties). NWDS will complete the setup for the new workspace. We will create a simple WDJ and Java projects for illustration purposes. Java project has a POJO (Person.java) and WDJ project imports this POJO as Java Bean Model and maps it all the way to the visual controller in the main Web Dynpro component. This is how the project files look in the Resource Perspective of the NWDS.



Notice that in the WDJ project we have bin, gen_ddic, gen_wdp folders that will be populated by WDJ at compile time (thus they should not be included in SVN).

Before we go futher, you can add some useful shortcuts to the context menu of TortoiseSVN by selecting TortoiseSVN --> Settings, then General --> Context Menu from the context menu. You can, for example, add Check for modifications to the context menu, since you'll probably use it often.



The first thing we want to do is to add .metadata folder in our workspace to SVN ignore list. This is were NWDS stores all the workspace metadata files and it could be quite voluminous and contain many subfolders. To do it, select c:\workspace\.metadata folder and select TortoiseSVN --> Add to ignore list --> .metadata.



Then add Java project to SVN control by selecting it and selecting TortoiseSVN --> Add... from context menu. You can deselect all of the .class files (or any other files or directories that you don't want to have under SVN control).




Do the same with WDJ project, I don't add any bin, gen_ddic, or gen_wdp folders to version control since they are automatically generated by WDJ.



To commit project files to SVN, select SVN Commit... from the context menu of workspace root folder, then select all but non-versioned (ignored) files and select Commit... from the context menu.



Enter the commit comment.



And TortoiseSVN commits the selected files to the remote repository.




If you decided not to add some folders to SVN, you should probably add them to the ignore list now. This can also be done for any non-versioned entires from the Commit... or Check for modifications screens as well. Do not forget to commit the changes to the ignore list.




As an exercise, let's try to modify one of our projects slightly and see if we can the difference with the committed version. We add a comment to the POJO in the Java project. If we then select the project and choose Check for modifications, we see that the Java class was modified and we can see where exactly if we select Compare with base from the context menu.




TortoiseSVN is a great tool, here I have just shown how easy it is to use it together with NWDS 7.0 to add version control to local projects (or DCs without NWDI). Also check out WinMerge, which works well with TortoiseSVN, to compare files.


Filter Blog

By date:
By tag: