Posts Tagged: ‘rest’

Migrating OSGi Plugins to standalone applications

13. Januar 2020 Posted by Sven Hasselbach

I have created an example project for migrating an OSGI-based Spring Boot application into an standalone application:

https://github.com/hasselbach/domino-springboot/blob/maven/domino-springboot.plugin

The application runs in the JVM of the Notes Client, only a user id is required, not a complete server installation (and ID). The benefit is that you can run as much JVM instances you want (which allows a better resource management and deployment) and it is easier to integrate the applications into existing CD environments. Also, Non-Domino developers can use their preferred IDE and are able to use existing / standard knowledge when developing Java applications.

When using the Java NAPI, you need to remove the spring-boot-devtools dependency because of problems with the class loader and DLLs.

HCL, Domino & node.js

23. Juni 2018 Posted by Sven Hasselbach

I am very happy to hear that HCL invests in Domino and improves the existing technology stack. But as a German, I have to be sceptical (it’s in our genes), because I can not see any advantage in the integration of node.js applications on top of Domino. I have written a demo two years ago, just to prove that it would be possible.

One of the main reasons is that I have switched my application architecture, which means that Domino is nothing more than a great NoSQL-Datacontainer. While the existing REST APIs were absolutly not fitting my requirements (too slow, painfull output and not expandable), I have pursued „my own way“ by using Spring Boot as my preferred technology. This made me independent from IBMs release cycles, and since the Java 8 upgrade I am happy, because I was able to add the missing parts which where never delivered by IBM.

Token authentication? Solved by creating my own solution. Performance? Boosted with Memcache. Memory limitations? Also solved with Memcache. Delay of agent execution? Solved with Spring Boot. I have dropped the Designer and using Eclipse directly, especially development/maintenance of legacy Java agents makes a lot of more fun. Code analysis / quality? Maven, JUnit & SonarQube are your friends. SSL encryption? Nginx. And the list grows and grows…

My point is that beeing independet from IBMs releases allows me to be extremly flexible – which IBM is not. Just have a look at Bootstrap and XPages: I have created my own renderers, and I can switch to the latest version with a few clicks (as long as there is no fundamental change in the structure). I am not dependent that – maybe – in the future someone will adopt the version to the XPages Extension library. If one of my customers wants to use it, OK, no problem.

That‘s what my customers love: The sky (aka budget) is the limit.

And here comes the problem I see with the node.js integration: The release cycles are extremely short. Just have a look at the release list:

https://nodejs.org/en/download/releases/

In the last 8 monthes there where 10(!) new versions for Carbon (V8, LTS). 26 versions since 2016 for Boron (V6, LTS). And that’s only node.js – the core of the whole thing. Don’t forget the packages and their dependencies. Let’s skip the fundamental problems with the NPM ecosystem: If it is required to get the latest updates, „npm update -g“ and everything is fine.

But waiting for Big Blue for a hot fix? If the „Domino NPM Package“ is not updated, but depends on an older version, you maybe cannot update the whole application. Ever had problems withthe old Jar files of the Domino JVM? Or was it required to downgrade of the Eclipse Maven Plugin to run with Domino’s JRE 6? Just think about it…

Don‘t get me wrong: This is not against the technology. I am using JavaScript for more than 15 years and have build some node.js applications and React Native apps in the last years, but I am not a fan of JavaScript because of the chaotical language concept, and the pain when trying to find syntax errors in scripting languages in general, or the missing type safety (something which is not required in compiler languages). But you can build great and high performant applications, and ES6 was a big step forward.

In my eyes there is no reason for tying node.js with Domino. My advice is to build REST interfaces on top of Domino (and reuse the existing business logic), and access it with a separate application based on [enter your preferred technologie here] with a backend connector. The frontend can be realised by a web development team / company. This takes a lot pressure off the existing Domino environment (from the management perspective): You can build new applications with the current hipster technology, can find developers and administrators, and the costs for moderinzation are not as high as a migration. After taking this path, some customers who abandoned Domino years ago, are investing again in the product.

So far I am still open for a big surprise and hopefully HCL can convince me of the contrary.

P.S.

I am still developing XPages applications, in my eyes a great technologiy, but it was never adopted by the developers as it should. With node.js, you have a new learning curve: Dojo/jQuery is NOT JavaScript.

Domino & Spring Boot: An example project

30. Mai 2018 Posted by Sven Hasselbach

I have uploaded an example for running Spring Boot applications on top of Domino. You can find it here:
https://github.com/hasselbach/domino-springboot

This solution is running for years in productive environments.

Hopefully I will find some time to explain how it works.

Speaking at Social Connections 11 about Connections APIs

24. Mai 2017 Posted by Henning Schmidt

Only one more week until Social Connections 11 is going to take place in Chicago. I am really happy to be selected as a speaker for this event! I will be speaking about the IBM Connections REST APIs and will show in many live examples how to use them, what to keep in mind an what […]

High Performance REST Applications (4) – Looking into OSGi

4. Mai 2017 Posted by Sven Hasselbach

Before going any deeper into the the servlet project, let’s have a look at the imported projects and talk about some OSGi basics.

First you will notice that for every cloned repository three Eclipse projects have been imported:

  1. A plugin project
  2. A feature project
  3. An updatesite project

The plugin project contains the code and all the relevant resources of the servlet. It defines extension points provided or describes which extension points are used by the plugin.
A feature project is basically a list of plugins and other features which can be understood as a logical separate unit. And an updatesite contains all features you need.

Using an UpdateSite is the preferred way to deploy plugins to Domino. It has a „Build All„-Button which builds all plugins from all features in your updatesite project, and creates the JARs to import into an UpdateSite in Domino.

Update Site „Build All“-Button

A plugin is mainly described by two files: the MANIFEST.MF (stored in the /META-INF folder) and a plugin.xml in the root.

plugin.xml & MANIFEST.MF

The MANIFEST.MF contains meta informations about the Plugin, like the name, imports and exports, other required bundles, the Activator class, the Execution environment and many more.

For example the Domino REST servlet plugin requires the concurrent plugin:

Required Bundles: „ch.hasselba.concurrent.plugin“

If the bundle is loaded, but the requirements are not fullyfied, the bundle won’t start.

The plugin.xml is optional for OSGI bundles, but we need this file, because it describes the extension point used by our plugin:

plugin.xml – Extension Point

Our servlet plugin uses the com.ibm.pvc.webcontainer.application extension point to run a JEE application. The parameter contextRoot is the path our servlet listens (which means it will be reachable at http://example.com/ec2017), and the contentLocation parameter is the path to the static files of the plugin and our web.xml.

WebContent folder

An Activator class is the class executed when a bundle is started or stopped (or the other possibilities a lifecyle of a bundle can have). It is also a good idea to store the BundleContext in the Activator to communicate with the OSGi environment.

Last but not least, there is a build.properties file: This file is for Eclipse and contains all relevant information to build the bundle. This means that if you add a JAR file the plugin requires, you have to add the JAR to both – the MANIFEST.MF and the build.properties (if the classes of the JAR file are used in the project).

In the Domino REST Servlet project, the spymemcached.jar is used, that’s why it is added to the build path and the manifest:

build.properties – spymemcached JAR

MANTIFEST.MF – spymemcached JAR

You have to keep this in your mind, because if you write some code, it is not enough just to add the required JAR to the build path, it also has to be exported in your bundle / plugin.

In the next post, let’s have a look into web.xml, and then go into the real „High Performance“ solution.

High Performance REST Applications (3) – Importing the Starter Project

24. April 2017 Posted by Sven Hasselbach

Now you can import the projects required from Git.

First, go to „File > Import…

Import Project

Then select „Projects from Git“

Projects from Git

and „Clone URI“ to clone an existing repository:

Clone existing respository

To get the URI, you have to open https://github.com/hasselbach/ and select the repository „ch.hasselba.concurrent„. Click the „Clone or download„-Button and copy the URI from the opening box:

Get the repository URI

Paste the URI into the location in Eclipse

Add the URI to Eclipse

In the next dialog, you can choose the branch to import. In this case, only „master“ exists

Select the branch to import

Now you have to choose a local destination where the cloned repository will be stored

Select the local destination

Select „Import existing Eclipse projects„…

Import existing projects

… and select all projects of the repository:

Select all projects

With „Finish„, the sources are downloaded. In the „Project Explorer„, you can see the three imported projects. And you can see the original repository name and the current branch you are working on:

Repository & Branch

The JRE used for the project can be seen if you expand one of the projects. „Sometimes“ this changes magically, and the build will fail – that is one of the first things you have to check if you have errors in a OSGi project.

JRE / Target used for this project

Now, do the same for the „domino-rest-servlet“ repository. But instead importing the „master“ branch, select the „highperformance“ branch only.

Import HighPerformance Branch

That’s it. In the next post, we have take a look in what you have downloaded.

High Performance REST Applications (2) – Dev Environment

23. April 2017 Posted by Sven Hasselbach

Before you can start developing a Servlet as an OSGi Plugins, you must set up a development environment first. To do this, download Eclipse IDE (Eclipse IDE for Java EE Developers) and XPages SDK from OpenNTF (The XPages SDK is a helper to create the JRE environment and the Target Platform). For development it is the best to have a (local) development server, because during development you might want to restart and/or modify it, and debugging is a lot easier if have control over the whole server.

After unpacking Eclipse and the XPages SDK, you have to install it and set up the JRE and the Target Platform. Go to „Help > Install New Software“. With „Add…“, you can add the UpdateSite of the XPages SDK to Eclipse:

Install New Software

Add Update Site

Click on „Local…“, and choose the folder „org.openntf.xsp.sdk.updatesite“ from the unpacked archive. Then give it a name for identification. You can choose whatever you want.

Choose the XPages SDK UpdateSite

Now, choose the plugin, click „OK“, accept the license, allow the installation from unsigned content and restart Eclipse after installation is complete.

Install the Plugin

Next step ist to configure the JRE: Go to „Help > Preferences“, „XPages SDK“, and choose the pathes were your Domino Server is installed. Also choose „Automatically create JRE for Domino“:

Then apply it.

If you have FP8 installed, you don’t need the next step: Change the Complier compliance level to 1.6. Again, apply the setting and allow a full rebuild of the Workspace.

Change the compliance level

Switch the default JRE to the newly created XPages Domino JRE:

Now you have to add the target platform: Enter „target“ in the search field, select the „Target Platform“, and click on „Add“. Choose the „Domino Install Target“, create it and choose it as active platform.

Target Definition: „Domino Install Target“

OK, that’s it. You have a working IDE and you are ready to import the starter project from GitHub.

High Performance REST Applications (1) – Intro

21. April 2017 Posted by Sven Hasselbach

This is a new serie about developing high performance REST applications on top of Domino. It will contain my presentations from SNoUG and EntwicklerCamp this year and describes all required steps to develop, build and deploy these servlets on a basic level.

The code used in this serie is already available at GitHub:

(The high performance part is in a branch of my example Domino REST Servlet described earlier in this blog.)

The serie will start with setting up the development environment, explaining OSGi plugin basics and will then go over how to implement the REST API. Some details about concurrency developments and their problems will also be included. Hopefully it is easy to understand.

Don’t hold back to ask a question in the comments or to contact me directly. I have kicked out the buggy comment plugin last month, so you should be able to post them even when I have updated my wordpress installation.

Relax and enjoy the upcoming posts.

Re: Domino REST performance analysis

16. März 2017 Posted by Sven Hasselbach

I have created a Quick-n-Dirty performance test for Csaba’s „10K record test“:

Loading time 200 ms overall, 60 ms TTFB.

Do you want to know how this works? Feel free to come to SNoUG next week or to Rudi’s EntwicklerCamp and join my sessions about „High Performance REST Applications“.

Domin & REST: Debug your Plugin

7. März 2017 Posted by Sven Hasselbach

When developing OSGi Plugins, you should have your own development server running on your local machine. Not only because of the faster deployment of changes (a new version of a plugin must always deployed with a HTTP restart), but because of the Java debugging posibilities: Only one Eclipse instance can connect to the JVM, and every request processed by the server will start the debugger. If multiple users a accessing the server while you are debugging, your Eclipse will try to debug every incoming request, and this can lead into a confusing situation for all.

To enable debugging, you first have to add two parameters to the notes.ini:

JavaEnableDebug=1
JavaDebugOptions=transport=dt_socket,server=y,suspend=n,address=8000

This starts the debugging on port 8000. Feel free to change the value to every port you want. Because of security reasons you should not start debugging on a productive machine.

After restarting the domino server, you can connect to the JVM in your Eclipse IDE by creating a new JVM remote debugging session. Create a new debug configuration…

… choose (1) „Remote Java Application„, (2) give a name to it, (3) select the plugin project, (4) enter the port the server listens, and click on (5) „Apply„.

If you want to connect to your server, you need to start debugging by clicking on the project:

After setting a breakpoint and sending a request to the servlet, Eclipse switches to the Debug perspective where you can look what happens with your servlet.

Sometimes you are connecting to the „wrong“ JVM, because a Java agent is running and/or a DOTS task does it’s job. It’s better to disable these tasks on your development server.

During debugging you are able to hotswap your code, but keep in mind that after a restart of the HTTP JVM all your changes are no longer „installed“. You have to build a new plugin or replace your code during runtime again.

In the next blog post, let’s talk about our development tools.

Domino & REST: More about Jackson

3. März 2017 Posted by Sven Hasselbach

When creating a REST API servlet, Jackson provides a huge list of possibilities to manipulate the JSON data, mostly using annotations.

Let’s demonstrate some of them with this little class, which has only two properties:

public class Demo {

    private String foo;
    private String bar;

    public String getFoo() { 
        return foo;
    }
    public void setFoo(String foo) {
        this.foo = foo;
    }

    public String getBar() { 
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }
}

The playground converts the content string to a POJO and back to a string:

String content = "{ \"foo\": \"bar\" }";
 
 // init the ObjectMapper
 ObjectMapper mapper = new ObjectMapper();
 
 // build the Object
 Demo test = null;
 try {
     test = mapper.readValue(content, Demo.class);
 } catch (Exception e) {
     e.printStackTrace();
 }

 // and now convert it back to a String
 String data = null;
 try {
     data = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(test);
 } catch (Exception e) {
     e.printStackTrace();
 }

 System.out.println( data );

If we run this code, the result is not really spectacular:

{
 "foo" : "bar",
 "bar" : null
}

So let’s ignore the property foo by adding the annotation @JsonIgnoreProperties to the Demo class:

@JsonIgnoreProperties({"foo"})
public class Demo { ... }

Now, foo is no longer in our resulting JSON:

{
    "bar" : null
}

The property bar is null, and we don’t like nulled properties in our JSON. That’s why we add another annotation, @JsonInclude:

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Demo { ... }

After removing the previously added @JsonIgnoreProperties annotation, our result looks like this (the empty property bar was skipped):

{
    "foo" : "bar"
}

What happens if we change our content string, and add an unknown property?

String content = "{ \"foo\": \"bar\", \"undefined\": \"property\" }";

An error occurs because Jackson does not know how to handle the new property:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "undefined" (class ch.hasselba.JacksonPlayground.Demo), not marked as ignorable (2 known properties: "foo", "bar"])
 at [Source: { "foo": "bar", "undefined": "property" }; line: 1, column: 31] (through reference chain: ch.hasselba.JacksonPlayground.Demo["undefined"])
 at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
 at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:817)
 at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:954)
 at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1315)
 at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1293)
 at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:249)
 at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
 at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3560)
 at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2576)
 at ch.hasselba.JacksonPlayground.App.main(App.java:24)
null

But there are two annotations to the rescue, @JsonAnyGetter@JsonAnySetter. By changing our Demo class and adding the following lines of code…

private Map<String, Object> others = new ConcurrentHashMap<String, Object>();

@JsonAnyGetter
public Map<String, Object> getOthers() {
    return this.others;
}

@JsonAnySetter
public void addOther(final String name, final Object value) {
    this.others.put(name, value);
}

… Jackson now puts all the unknown/undefined properties in the others map (uses the method defined by @JsonSetter). And then it uses the method with the @JsonGetter annotation when producing the JSON from the Demo instance.

{
  "foo" : "bar",
  "bar" : null,
  "undefined" : "property"
}

What if we want to handle multiple „Demo“ objects in a JSON Array?

String content = "[ { \"foo\": \"bar\" }, {\"foo\": \"bar2\" } ]";

In this case we change our reading routine to work with lists:

// build the Object
List<Demo> test = null;
try {
    test = mapper.readValue(content, mapper.getTypeFactory()
            .constructCollectionType(List.class, Demo.class));
} catch (Exception e) {
    e.printStackTrace();
}

In the result all entries are now contained in the list of Demo objects:

[ {
 "foo" : "bar",
 "bar" : null
}, {
 "foo" : "bar2",
 "bar" : null
} ]

Back to our RestApiApplication, have a look at this line:

objMapper.setSerializationInclusion(Include.NON_EMPTY);

This removes all empty properties globally from the generated output of our the servlet. So there is no need to add the @JsonIgnore annotation to any class. You can modifiy the globally used ObjectMapper in your servlet with multiple option, more will follow in another blog post.

Domino & REST: Accessing Domino’s Environment / Check Authentication

2. März 2017 Posted by Sven Hasselbach

If we want to access Domino’s Environment, it is the ContextInfo class which gives us all we need. Everything you need to do to use the class is described in an earlier blog post.

The class gives mainly access to the following methods:

Method Description
getDataDirectory() Path to notes data directory
getEnvironmentString(String envName) Returns the environment variable
getServerDatabase() The actual database as NAPI object, if any
getServerVariable(String varName) Variables from the Request, i.e. „QUERY_STRING“
getUserDatabase() The actual database as Domino Java object, if any
getUserSession() The session of the actual user performing the request (
isAnonymous() true if the current user is Anonymous

Keep in mind that the incoming request is independently of any underlying Notes database. In our example, the URI http://your.server/dominorestservlet/helloworld/ does not run inside of a NSF, that’s why the getServerDatabase() and the getUserDatabase() methods returns null.

As a consequence, our servlet does not have any access restriction and is reachable as anonymous. If you want to access a database programatically, the „normal“ Domino access control is intervening again, but we can do the access check by ourself.

To prevent the access to the servlet, I have added a „checkAuthentication“ method to the RestApiServlet class. This method checks if the current user is a) not anonymous and b) a member of the group RESTAPIAccessAllowed. The method throws a NotAuthenticatedException which let’s the servlet return a HTTP 403.

Domino & REST: Consuming JSON

1. März 2017 Posted by Sven Hasselbach

Consuming JSON is as easy as pie: Just create a new method to the RestApiServlet,  add a @POST annotation, and declare the object you want to the parameters of the method:

    @POST
    @Path("/helloworld/")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response postHelloWorld(HelloWorld helloWorld) {
        return Response.ok(helloWorld, MediaType.APPLICATION_JSON).build();
    }

In this example we are using the same URI „/helloworld/„; because we now are using another HTTP method, there is no conflict between the two methods.

Have a look at the parameter of the postHelloWorld method: It is the HelloWorld class which now instantiated and filled automatically from the POSTed JSON data! We can access the object in Java, and in this short example the result is directly returned back in the response.

If we now send a JSON request with a „message“ field…

curl -i -X POST -d "{\"message\": \"foo\"}" \ 
    -H "Content-Type: application/json" \
    http://your.server/dominorestservlet/helloworld/

… the response contains the message we have posted:

Domino & REST: A basic Servlet

28. Februar 2017 Posted by Sven Hasselbach

To have a good starting point when creating RESTful applications on top of Domino, I have created a „Hello World“ example of a JEE Application, based on Apache Wink & Jackson 2.5.0.

The Jackson AnnotaionProcessor is registered into Apache Wink application and is enabled by default, the JAXB processor is also included as the secondary AnnotationProcessor. The benefit of this is that only one global ObjectMapper instance is created and is reused, wich allows a better performance as when you create an own instance of an ObjectMapper for every request.

The servlet is deployed as a Plugin, so you need a working XPages plugin development environment first before you can build it (I won’t get in the details at this time). The code of the servlet can be found in the domino-rest-servlet.plugin project.

First have a look into plugin.xml: This file contains the extension point used by the plugin, which means that this tells the Domino server what is inside and what to do next with the plugin. The extension point is of type „com.ibm.pvc.webcontainer.application“ and allows to run our own JEE application, independently of the XPages runtime. The contextRoot is the URI part on which our application „listens“. The contentLocation is where files are searched when accessed from the browser, and points to the WebContent folder (as you already know, it is the same as in XPages projects when using the package explorer view). Here you can store static files and/or resources if required.

The web.xml file is the servlet configuration and the place where the servlet is registered. With servlet-mappings you can define URI pathes *inside* of the JEE application.

In this example, every request is mapped to the RestServlet servlet when it is send to „http://your.server/dominorestservlet/„. It will be now processed by the class ch.hasselba.dominorestservlet.RestApiApplication, which „knows“ the RestApiServlet because of the @Path annotations.

Our „Hello World“ example is registered for the URI „/helloworld/“ and only for HTTP GET requests. As soon you are opening „http://your.server/dominorestservlet/helloworld/„, an instance of HelloWorld is created and transformed to JSON. The result looks like this:

{"message":"Hello World!"}

During the next blog posts, I will expand this example and explain step by step how a seamless integration in the Domino environment works.

You can find the code here: https://github.com/hasselbach/domino-rest-servlet

Domino & REST: Listeners for Initialization & Destroying of a Servlet

27. Februar 2017 Posted by Sven Hasselbach

If you need to know when your Servlet is initialized or destroyed, you can use a ServletContextListener in your application.

First, create the class AppServletContextListener and implement the javax.servlet.ServletContextListener interface. This provides two methods for capturing the events: contextInitialized and contextDestroyed:

package ch.hasselba.servlet;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class AppServletContextListener
               implements ServletContextListener{

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        System.out.println("ServletContextListener destroyed");
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        System.out.println("ServletContextListener started");
    }
}

The ServletContextEvent allows you to access the ServletContext if required.

Now you have to register the listener in your web.xml:

<web-app>
     <listener>
         <listener-class>
             ch.hasselba.servlet.AppHttpSessionListener
         </listener-class>
    </listener>
</web-app>

As soon as you start or stop the HTTP task, the Listener is called, and you can execute some application specific code (i.e. shutdown threads, bring out the garbage, etc.)