Skip to Content
Technical Articles
Author's profile photo Snezhana Zakrajsek

Development process in SAP BTP Neo environment without the Java tools for Eclipse

As you might already know, as of 25 March 2021, the Java tools for Eclipse that work with the SAP BTP SDK for the Neo environment are no longer supported. As of 17 June 2021, the Java tools for Eclipse are removed from the SAP Development Tools site.

This means that if you were using the the Java tools for Eclipse, you will need to change your development process. From now on, you will use IDE of your choice and the console client that is part of the SAP BTP SDK for the Neo environment.

The following blog post will help you to get familiar with this development process. It is not a new process – it has always existed and some of you might already use it.

 


If you see a similar error message in Eclipse while trying to add a new cloud server, it is because the Java tools for Eclipse that work with the SAP BTP SDK for the Neo environment are no longer supported. They were available for installation and usage after end of support, until they stopped working properly.

If you are no longer able to install the Java tools for Eclipse that work with the SAP BTP SDK for the Neo environment, it is because they are removed from the SAP Development Tools site.

Development environment

Your development environment depends on what you want to achieve. Here is a sample table with actions and tools, which support these actions:

Working locally

Tools

 Action Tools
Develop & build – IDE & build tools of your choice
SAP BTP SDK
Run Console client (part of SAP BTP SDK)
Debug – IDE of your choice
Console client (part of SAP BTP SDK)
Profile – Eclipse IDE (Oxygen or newer)
SAP JVM Tools for Eclipse
SAP JVM

The local server

In order to run the application locally, you need to install a local SAP BTP server; this is done with the console client command neo install-local. By running this command, you install a server runtime in a local folder called server, which by default is located in your SAP BTP SDK installation directory.

In order to configure and manage your local application (e.g. add destination, get application logs, etc.), you might need to work directly with some files in the server folder.

Some of the more interesting files within the server folder are:

Purpose Location File
Get logs /server/log/
Debug app
/server/bin/
– setenv.sh
– setenv.bat
Add app authentication /server/config_master/com.sap.security.um.provider.neo.local/ – neogroups.json
– neousers.json
Manage destinations
/server/config_master/service.destinations/destinations/

Note: the com.sap.security.um.provider.neo.local folder does not exist upon initial local server installation; you need to create the folder and required files inside if your scenario needs them.

Working on the cloud

Tools

 Action Tools
Run – Console client (part of BTP SDK)
Debug – Eclipse IDE (Oxygen or newer)
SAP JVM Tools for Eclipse
Profile – Eclipse IDE (Oxygen or newer)
SAP JVM Tools for Eclipse

The cloud server

In the cloud scenario you do not have access to a server folder. You can configure and manage your application (e.g. add destination, get application logs) via console client commands.

Development process

Let’s go through a sample development process by building a simple Java web application.

Prerequisites

You can use IDE and build tools of your choice for developing the Java application. In the blog post, we will use Eclipse IDE and Maven.

We will also use Linux, Mac OS X, or other Unix based OS; if you are using Microsoft Windows – pay attention to the additional notes on each step.

  • IDE of choice; for the purposes of the blog post: Eclipse IDE
  • Build tool of choice; for the purposes of the blog post: Maven
  • SAP BTP SDK; for the purposes of the blog post: Java Web Tomcat 8, version 3.129.5

Create and build Java web project

  1. Create new Java web project using Maven
    mvn archetype:generate -DgroupId=com.sap.sample -DartifactId=sample-web-app -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
  2. Create PublicServlet.java file under /sample-web-app/src/main/java/com/sap/sample/

    cd sample-web-app
    mkdir -p "./src/main/java/com/sap/sample/"
    touch "./src/main/java/com/sap/sample/PublicServlet.java"
  • And update its contents
    package com.sap.sample;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class PublicServlet extends HttpServlet {
    
      private static final long serialVersionUID = 1L;
    
      @Override
      public void doGet(HttpServletRequest request, HttpServletResponse response) throws 
      ServletException, IOException {
        response.getWriter().println("<p>Hello!</p>");
      }
    }
  • Update the sample-web-app/src/main/webapp/WEB-INF/web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://Java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    
      <display-name>Hello!</display-name>
    
      <servlet>
        <servlet-name>PublicServlet</servlet-name>
        <servlet-class>com.sap.sample.PublicServlet</servlet-class>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>PublicServlet</servlet-name>
        <url-pattern>/public</url-pattern>
      </servlet-mapping>
    
    </web-app>
  • Add dependency to Servlet 3.1 API in the pom.xml
    <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
    </dependency>​
  • Build the project using Maven
    mvn clean install

Run the application locally

This is the documentation describing how to run applications locally.

We have developed and built the Java application. Let’s run it locally.

Procedure

  1. Run the project on a local SAP BTP server
    # install local server; the server will be located in the <SDK installation folder>/server by default
    neo install-local​
    
    # start local server
    neo start-local
    
    # deploy the sample application and check http://localhost:8080/sample-web-app/public
    neo deploy-local --source <path to the sample-web-app folder>/sample-web-app/target/sample-web-app.war​
  2. Check that the application is running on http://localhost:8080/sample-web-app/public

Debug the application locally

This is the documentation describing how to debug applications locally.

We have developed, built and run the Java application locally. Let’s debug it locally.

Note: you can use IDE of your choice; for the purposes of the blog post we are using Eclipse IDE.

Prerequisites

  • You should have already installed a local server and run the application on it.

Procedure

  1. Enable remote debugging of the local SAP BTP server: open /<SDK installation folder>/server/bin/setenv.sh and add in the end of the file:
    CATALINA_OPTS="-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n"

    Note for Microsoft Windows users: check documentation for this step.

  2. Restart the local SAP BTP server
    # stop the local server
    neo stop-local​
    
    # start the local server
    neo start-local​
  3. Import the project in the IDE.
    Project%20imported%20in%20Eclipse%20IDE
  4. Attach a remote Java debugger from within the IDE on localhost:5005
    Remote%20debug%20configuration%20in%20Eclipse%20IDE
  5. Put a debug breakpoint on the PublicServlet.java doGet() method and hit http://localhost:8080/sample-web-app/public
    Debug%20the%20locally%20deployed%20application%20from%20within%20Eclipse%20IDE

Profile the application locally

This is the documentation describing how to profile applications locally.

We have run the Java web application locally. Let’s profile it with SAP JVM Profiler.

Note: if you want to profile your application using SAP JVM Profiler, you must use SAP JVM, SAP JVM Tools for Eclipse and thus Eclipse IDE (Oxygen or newer).

Procedure

Follow the procedure as described in the documentation.

 

Environment variables and system properties locally

We have a Java web application, which reads environment variables and system properties. Let’s run the Java web application locally and set the required environment variables and system properties.

Procedure for system properties

  1. Read the system property in your Java web application
    System.getProperties().getProperty("custom.system.property")​
  2. Add the system property in the end of the /<SDK installation folder>/server/props.ini file
    -Dcustom.system.property=my.system.property​
  3. Deploy the application locally and restart the local SAP BTP server if already started

Procedure for environment variables

  1. Read the environment variable in your Java web application
    System.getenv("CUSTOM_ENVIRONMENT_VARIABLE")​
  2. Add the environment variable in the end of the /<SDK installation folder>/server/bin/setenv.sh file
    export CUSTOM_ENVIRONMENT_VARIABLE="MY_ENVIRONMENT_VARIABLE"​

    Note for Microsoft Windows users: add the environment variable in the  /<SDK installation folder>/server/bin/setenv.bat file and using the set CUSTOM_ENVIRONMENT_VARIABLE=”MY_ENVIRONMENT_VARIABLE” syntax.

  3. Deploy the application locally and restart the local SAP BTP server if already started

Run the application on the cloud

This is the documentation describing how to run applications on the cloud.

We have developed and run the Java application locally. Let’s run it on the cloud.

Procedure

  1. Deploy the application on the cloud
    neo deploy --host <host> --account <subaccount_name> --application <application_name> --source <path to the sample-web-app folder>/sample-web-app/target/sample-web-app.war​ --user <email_or_user>  ​

Debug application on the cloud

This is the documentation describing how to debug applications on the cloud.

We have deployed the Java application on the cloud. Let’s debug it on the cloud.

Note: if you want to debug the application on the cloud, you must use SAP JVM Tools for Eclipse and thus Eclipse IDE (Oxygen or newer).

Procedure

Follow the procedure as described in the documentation.

Profile the application on the cloud

This is the documentation describing how to profile applications on the cloud.

We have deployed the Java application on the cloud. Let’s profile it on the cloud.

Note: if you want to profile the application on the cloud, you must use SAP JVM Tools for Eclipse and thus Eclipse IDE (Oxygen or newer).

Procedure

Follow the procedure as described in the documentation.

 

Environment variables and system properties on the cloud

This is the documentation describing how to set environment variables and system properties when deploying application on the cloud.

We have a Java web application, which reads environment variables and system properties. Let’s set the environment variables and system properties and run the Java web application on the cloud.

Procedure for system properties

  1. Read the system property in your Java web application
    System.getProperties().getProperty("custom.system.property")​​
  2. Deploy the application on the cloud and set the required system property via the “–vm-arguments” parameter
    neo deploy --host <host> --account <subaccount_name> --application <application_name> --vm-arguments "-Dcustom.system.property=my.system.property" --source <path to the war file>​ --user <email_or_user>​

Procedure for environment variables

  1. Read the environment variable in your Java web application
    System.getenv("CUSTOM_ENVIRONMENT_VARIABLE")​​
  2. Deploy the application on the cloud and set the required environment variable via the “–ev” parameter
    neo deploy --host <host> --account <subaccount_name> --application <application_name> --ev CUSTOM_ENVIRONMENT_VARIABLE=MY_ENVIRONMENT_VARIABLE --source <path to the war file>​ --user <email_or_user>​

Use SAP BTP SDK API in the web project

Until now, we have developed a simple Java application, which does not take advantage of any SAP BTP APIs. Let’s change that.

Add SAP BTP API as Maven dependency

This is a blog post describing how to build Java web applications with Maven.

This are all SAP BTP artifacts on Maven Central.

  1. Add the SAP BTP SDK API as a dependency in the In the /sample-web-application/pom.xml

    		<dependency>
    			<groupId>com.sap.cloud</groupId>
    			<artifactId>neo-java-web-api</artifactId>
    			<version>3.129.5</version>
    			<scope>provided</scope>
    		</dependency>

    Note: the artifactId and version depend on the kind and version of the SAP BTP SDK.

Add destination locally

We have developed the Java application. Let’s add a destination in the existing servlet.

Note: when working locally, you must add all destinations as files with no extension in the /server/config_master/service.destinations/destinations/ folder.

  1. Add destination called outbound-internet-destination in the /server/config_master/service.destinations/destinations/ folder
    Name=outbound-internet-destination
    URL=https\://help.sap.com/doc/8cd05d3af14a42f7a53c0609acf55826/Cloud/en-US/terms_of_use.html
    ProxyType=Internet
    Type=HTTP
    Authentication=NoAuthentication
    TrustAll=true
    CloudConnectorVersion = 2​
  2. Update the PublicServlet.java code to locate the destination and print its properties
    package com.sap.sample;
    
    import java.io.IOException;
    
    import javax.annotation.Resource;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.sap.cloud.account.TenantContext;
    import com.sap.core.connectivity.api.configuration.ConnectivityConfiguration;
    import com.sap.core.connectivity.api.configuration.DestinationConfiguration;
    
    public class PublicServlet extends HttpServlet {
    
    	private static final long serialVersionUID = 1L;
    
    	@Resource
    	private TenantContext tenantContext;
    
    	@Override
    	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		try {
    			// Look up the connectivity configuration API
    			Context ctx = new InitialContext();
    			ConnectivityConfiguration configuration = (ConnectivityConfiguration) ctx
    					.lookup("java:comp/env/connectivityConfiguration");
    
    			// Get destination configuration
    			String destinationName = "outbound-internet-destination";
    			DestinationConfiguration destConfiguration = configuration.getConfiguration(destinationName);
    
    			if (destConfiguration == null) {
    				response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
    						String.format(
    								"Destination %s is not found. Hint:" + " Make sure to have the destination configured.",
    								destinationName));
    				return;
    			}
    
    			String url = destConfiguration.getProperty("URL");
    			String proxyType = destConfiguration.getProperty("ProxyType");
    
    			response.getWriter().println("<p>Destination: " + url + "</p><p>Proxy type: " + proxyType + "</p>");
    		} catch (Exception e) {
    			// Connectivity operation failed
    			String errorMessage = "Connectivity operation failed with reason: " + e.getMessage();
    			response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorMessage);
    		}
    	}
    }
  3. Update the sample-web-app/src/main/webapp/WEB-INF/web.xml to declare the JNDI lookup for the destination:
    <resource-ref>
      <res-ref-name>connectivityConfiguration</res-ref-name>
      <res-type>com.sap.core.connectivity.api.configuration.ConnectivityConfiguration</res-type>
    </resource-ref>​
  4. Build the application, deploy it on the local server and request http://localhost:8080/sample-web-app/public. It should print the destination properties. 

Add authentication locally

This is the documentation describing authentication in Neo environment.

We have developed the Java application. Let’s add a second servlet in it, which will be secured with a basic authentication.

  1. Create ProtectedServlet.java file under /sample-web-app/src/main/java/com/sap/sample/
    package com.sap.sample;
    
    import java.io.IOException;
    import java.security.Principal;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.sap.security.um.service.UserManagementAccessor;
    import com.sap.security.um.user.PersistenceException;
    import com.sap.security.um.user.UnsupportedUserAttributeException;
    import com.sap.security.um.user.User;
    import com.sap.security.um.user.UserProvider;
    
    public class ProtectedServlet extends HttpServlet {
    
    	private static final long serialVersionUID = 1L;
    
    	@Override
    	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		try {
    			response.getWriter().println("<p>Welcome " + getUserAttributes(request.getUserPrincipal()) + "</p>");
    		} catch (Exception e) {
    			response.getWriter().println("Protected operation failed with reason: " + e.getMessage());
    		}
    	}
    
    	/**
    	 * Get name and e-mail user attributes and return them as condensed string.
    	 */
    	private String getUserAttributes(Principal principal)
    			throws PersistenceException, UnsupportedUserAttributeException {
    		// Get user from user storage based on principal name
    		UserProvider userProvider = UserManagementAccessor.getUserProvider();
    		User user = userProvider.getUser(principal.getName());
    
    		// Extract and return user name and e-mail address if present
    		String firstName = user.getAttribute("firstname");
    		String lastName = user.getAttribute("lastname");
    		String eMail = user.getAttribute("email");
    		return (firstName != null && lastName != null ? firstName + " " + lastName + " [" + principal.getName() + "]"
    				: principal.getName()) + (eMail != null ? " (" + eMail + ")" : "");
    	}
    }
  2. Add the second servlet and a security configuration in the sample-web-app/src/main/webapp/WEB-INF/web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://Java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    
    	<display-name>Hello!</display-name>
    
    	<servlet>
    		<servlet-name>PublicServlet</servlet-name>
    		<servlet-class>com.sap.sample.PublicServlet</servlet-class>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>PublicServlet</servlet-name>
    		<url-pattern>/public</url-pattern>
    	</servlet-mapping>
    
    	<servlet>
    		<servlet-name>ProtectedServlet</servlet-name>
    		<servlet-class>com.sap.sample.PublicServlet</servlet-class>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>ProtectedServlet</servlet-name>
    		<url-pattern>/protected</url-pattern>
    	</servlet-mapping>
    
    	<!-- Secure application -->
    	<login-config>
    		<auth-method>BASIC</auth-method>
    	</login-config>
    	
    	<security-constraint>
    		<web-resource-collection>
    			<web-resource-name>Protected Area</web-resource-name>
    			<url-pattern>/protected/*</url-pattern>
    		</web-resource-collection>
    		<auth-constraint>
    			<role-name>Everyone</role-name>
    		</auth-constraint>
    	</security-constraint>
    	
    	<security-constraint>
    		<web-resource-collection>
    			<web-resource-name>Public Area</web-resource-name>
    			<url-pattern>/*</url-pattern>
    		</web-resource-collection>
    	</security-constraint>
    	
    	<security-role>
    		<description>All SAP BTP users</description>
    		<role-name>Everyone</role-name>
    	</security-role>
    
    </web-app>​
  3. Add the neousers.json file in /server/config_master/com.sap.security.um.provider.neo.local/
    The file contains two users with role Everyone: first user with id john and password johndoe, and second user jane with password janedoe.
    Note: create the com.sap.security.um.provider.neo.local folder, if not already created.

    {
      "Users": [
        {
          "UID": "john",
          "Password": "{SSHA}Ub53I5XdyH/Nh3gr3pUQ6vPyjYPPRVKF",
          "Roles": [
            "Everyone"
          ],
          "Attributes": [
            {
              "attributeName": "firstname",
              "attributeValue": "John"
            },
            {
              "attributeName": "lastname",
              "attributeValue": "Doe"
            },
            {
              "attributeName": "email",
              "attributeValue": "john.doe@sap.com"
            }
          ]
        },
        {
          "UID": "jane",
          "Password": "{SSHA}/obq802EmKc+rc4/fjU/XzbvBiaHtNIH",
          "Roles": [
            "Everyone"
          ],
          "Attributes": [
            {
              "attributeName": "firstname",
              "attributeValue": "Jane"
            },
            {
              "attributeName": "lastname",
              "attributeValue": "Doe"
            },
            {
              "attributeName": "email",
              "attributeValue": "jane.doe@sap.com"
            }
          ]
        }
      ]
    }

    Note: SSHA is a password storage scheme, the salted version of the SHA-1. When developing locally, you can use the slappasswd utility – an OpenLDAP password utility for Linux, Mac OS X, or other Unix based OS, which generates such hashes: “slappasswd -h {SSHA} -s <password>“.
    There are also few online web pages, which can generate LDAP SSH password hash; just have in mind that this approach is appropriate for testing purposes only.

  4. Build the application, deploy it on the local server and request http://localhost:8080/sample-web-app/protected. It should ask you to log in; usernames and passwords are as follow: is john with password johndoe; jane with password janedoe. 

 

Wrap up

In this blog post we were able to develop, run, debug, profile and configure an application locally and on the cloud without using the Java tools for Eclipse that work with the SAP BTP SDK for the Neo environment.

I hope the blog post helped you to set up and start the development process using the console client that is part of the SAP BTP SDK for the Neo environment.

Assigned Tags

      6 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Jaron Frenk
      Jaron Frenk

      Just read your blogpost. We have a problem with regards to tomcat 9. Can you verify that this also works with tomcat 9? We cannot get local authentication going with the NEO tomcat 9 SDK.

      Author's profile photo Dobromir Zahariev
      Dobromir Zahariev

      Hello Jaron,

      yes, I can confirm that CLI tools are part of all Neo SDKs - including the Tomcat 9 based one.

      Best Regards

      Author's profile photo Karsten Voigt
      Karsten Voigt

      Hi

       

      Thanks for your post, but this is not a usable development process. Each simple code modification requires a complete build and deployment to a local server. I guess this approach requires two to four times more development effort. Isn't there a way for automatic publishing changes?

       

      There can I find further documentation on this "new" development approach?

       

      Thanks.

      Regards

      Karsten

      Author's profile photo Dobromir Zahariev
      Dobromir Zahariev

      Hello Karsten,

      As far as I know no other option.

      Best regards

      Author's profile photo Ralf Riedel
      Ralf Riedel

      Hi Snezhana,

      for the local dev approach, how can I change the logging settings?

      I've found a logback.xml in server\bin\logback-config. Is this the intended place to setup logging for local development? Is there a way to change logging settings for a running tomcat instance?

      Thanks in advance!

      Ralf

      Author's profile photo Dobromir Zahariev
      Dobromir Zahariev

      Hello Ralf,

      as the runtime is basically a Tomcat server with some additional libraries, the approach for setting log levels in local Neo Server should be the same as local Tomcat server.

      With google search about "tomcat change log level without restart" I found  several articles that explain possible approach that involves Mean tab on JConsole.

      I hope this will help.

       

      Best regards