node.js, domino-db & Docker (3): Adding domino-db

The express application is still the boilerplate created by express generator. Now let’s look into the existing code and use the domino-db package. First we have to understand express a little bit better. I won’t go deeply into details, because there are many tutorials available, and the documentation is really awesome.

Overview

Directory structure

/domino-express
   |-app
      |-app.js
      |-bin
         |-...
      |-public
         |-...
      |-routes
         |-...
      |-views
         |-...

app.js

This is the main application. It contains the configuration of the application and global modules (like used the middleware, global route handlers, etc.). At the moment we don’t need to change anything here.

/bin

This folder contains the starting script for the application.

/public

Contains publicly accessible static resources like images, stylesheets, etc.

/routes

The handling for existing routes, which means how the application should process incoming requests.

/views

Contains the templates for the generated output. We are using Jade as our template engine.

The boilerplate

The first thing to look at is the /routes/index.js file. Just open it in Atom, and see what the express generator created for us:

The first line loads the express package and gives access to it. The next line gives us access to the router, which then is used to define a handle for all incoming requests on the application root (http://localhost:3000/).

When this route is called, the defined function renders the response using the view template ‚index‘ (which can be found in the /views folder). The variables used in the template are contained in the object handed over as second parameter.

The last line exports the router instance and gives access to it outside of our module. Just for a better understanding: Everything in this file (aka module) is private, and here it is defined what is public to the rest of our express application. For more details, have a look here: https://www.sitepoint.com/understanding-module-exports-exports-node-js/

Change to ES6

After changing everything as proposed by the editor, the code should now look like this:

const express = require('express');

const router = express.Router();

/* GET home page. */
router.get('/', (req, res) => {
  res.render('index', { title: 'Express' });
});

module.exports = router;

Now we add the requirement for the domino-db package:

const { useServer } = require('@domino/domino-db');

The curly brackets notation is used to „import“ only the useServer element from the domino-db package.

Then we add the configuration for our Domino backend (shamelessly copied from the example in the dev pack):

const serverConfig = {
  hostName: 'your.server.com', // Host name of your server
  connection: {
    port: '3002', // Proton port on your server
  },
};

const databaseConfig = {
  filePath: 'node-demo.nsf', // The database file name
};

const createOptions = {
  documents: [
    {
      Form: 'Contact',
      FirstName: 'Aaron',
      LastName: 'Aardman',
      City: 'Arlington',
      State: 'MA',
    },
    {
      Form: 'Contact',
      FirstName: 'Brian',
      LastName: 'Zelnick',
      City: 'Chelmsford',
      State: 'MA',
    },
  ],
};

And now we add the connection of the database query when our base path is accessed:

router.get('/', (req, res) => {
  useServer(serverConfig).then(
      async server => {
        const database = await server.useDatabase(databaseConfig);
        const response = await database.bulkCreateDocuments(createOptions);

        // Display the new document UNIDs
        const unids = response.documents.map(doc => doc['@unid']);
        res.render('index', { title: 'Express', result: `Documents created: ${unids}` });
  });
});

Before we get into the details of this code, let’s start our application with npm start.After accessing the URL of the application http://localhost:3000, nothing happens.

Just some console output tells us that we need some error handling when our Domino server is not reachble.

GET / - - ms - -
(node:13268) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): DominoDbError: gRPC client error

This topic and more details about the domino-db module will be covered in the next post.

Veröffentlicht unter ES6, Java Script, node.js | Verschlagwortet mit , , , , | Hinterlasse einen Kommentar

node.js, domino-db & Docker (2): Dev Environment

Before we can start to create a new app we first have to setup a development environment. While there are multiple IDE’s around, I have made most of my node.js development with Atom instead of an IDE like Eclipse or Visual Studio. Maybe this will change in the future, but for a better understanding, let’s start with Atom and do the required steps manually.

By default, there is no support for ES6, so we need to make an additional installation after installing the editor:

1. Download Atom from https://atom.io/

2. Go to Atom > Preferences

3. Install linter-eslint package

4. Additional packages must be installed (This happens multiple times):

5. In a console, go to the domino-express which we have created before:

cd domino-express/

6. Install eslint-config-rallycoding module

npm install --save-dev eslint-config-rallycoding

This step has to be done for every new project. The module is required to enable the ES6 support for every project, but only during development.

7. Create a file named .eslintrc in the project folder and add the following content:

{
   "extends": "rallycoding"
}

8. Change the dependency for the domino-db package:

"@domino/domino-db": "file:./domino-domino-db-1.0.0-package"

The path has to be changed because for the Docker setup it is in the /src folder, now it is in the project root.

9. Install the required npm modules

npm install

10. Restart Atom and open the project folder

11. If everything worked correctly, you should now see an error in the index.js file (maybe you have to open the file first):

12. When opening the file, you should see an error in the first line and an explanation about the problem:

13. Click on „Fix“, then var should change to let

14. An new problem occurs, because the variable is never changed. So the advice is to change it to const.

15. Done. Now we are ready for developing.

Veröffentlicht unter ES6, Java Script, node.js | Verschlagwortet mit , , , | Hinterlasse einen Kommentar

node.js, domino-db & Docker

Here is an example to create a express application with the new domino-db npm module and run it in a docker container. Requirements are that node.js & Docker is installed. Everything is done in the command line and a text editor.

1. Install Express application generator

npm install express-generator -g

2. Create a fresh application with stylus engine

express -c stylus domino-express

3. Go to the newly created folder

cd domino-express/

4. Create a folder for the application

md app/

5. Copy all files to the app folder, only package.json should be left

6. Copy the domino-domino-db-1.0.0-package folder into the project folder

7. Create a file .dockerignore and with the following content:

node_modules
npm-debug.log

8. Create the Dockerfile with the following content:

FROM node:8

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

# create a folder for the local domino-db package
RUN mkdir -p /src
COPY ./domino-domino-db-1.0.0-package /src/domino-domino-db-1.0.0-package

# install & rebuild
RUN npm install
RUN npm rebuild

# If you are building your code for production
# RUN npm install --only=production

# Bundle app source
COPY ./app .

EXPOSE 3000
CMD [ "npm", "start" ]

9. The directory structure should look like this:

/domino-express
   |-app
      |-...
   |-domino-domino-db-1.0.0-package
      |-...
   |-.dockerignore
   |-Dockerfile
   |-package.json

10. Add domino-db to package.json

{
  "name": "domino-express",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.16.0",
    "http-errors": "~1.6.2",
    "jade": "~1.11.0",
    "morgan": "~1.9.0",
    "stylus": "0.54.5",
    "@domino/domino-db": "file:/src/domino-domino-db-1.0.0-package"
  }
}

11. Build the docker container (replace username with your docker id)

docker build -t {username}/domino-express .

12. Start the container

docker run -p 3000:3000 -d -it {username}/domino-express

13. Open it in your browser => http://localhost:3000

Veröffentlicht unter ES6, Java Script, node.js | Verschlagwortet mit , , | 7 Kommentare

Dropping Domino’s HTTP task (3): WebSSO Integration (Part 1)

To integrate the new HTTP stack into the existing environment, we can use LTPA tokens. These tokens are cookies which store the authentication information and allow to share them betweeen different participating Domino servers. A users must log on only once, and existing applications and data/views can be accessed without a relogin.

Validating an existing LTPA token with Spring can be done with our own PreAuthentificationFilter which checks for an existing LTPA token and extracts the authentication details from the cookie and creates a new Principal instance.


import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

public class LtpaPreAuthenticatedFilter extends AbstractPreAuthenticatedProcessingFilter {

   @Value("${ltpa.secret}")
   private String ltpaSecret;

   @Value("${ltpa.cookieName}")
   private String ltpaCookieName;

   @Override
   protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {

      Cookie[] cookies = request.getCookies();
      if( cookies == null ) {
         return null;
      }

      for( int i= 0; i<cookies.length ; i++ ){
         String name = cookies[i].getName();
         String value = cookies[i].getValue();

         if( ltpaCookieName.equalsIgnoreCase(name) ){
            DominoLtpaToken ltpaToken = new DominoLtpaToken( value, ltpaSecret );

            if( ltpaToken.isValid() ){
               return ltpaToken.getDistinguishedName();
            }
         }
      }

      return null;
   }

   @Override
   protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
      // is required to return an empty string
      return "";
   }

}

The filter implements two methods, one for extraction of the principal, and the other for the credentials (which we don’t have with LTPA tokens). In the getPreAuthenticatedPrincipal method, existinig LTPA tokens are searched, then the user extracted and the token validated.

The secret of the LTPA token and the name are stored in application.properties:

The second part is implementing a AuthenticationUserDetailsService. This service is for getting additional details for the authenticated user, for example the ACL roles or groups the user belongs to.

import java.util.Collection;
import java.util.HashSet;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

public class LtpaUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {

   @Override
   public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token)
      throws UsernameNotFoundException {

      String userName=(String)token.getPrincipal();

      Collection<GrantedAuthority> authorities = new HashSet<GrantedAuthority>() ;
      authorities.add(new LtpaUserAuthority());

      User user = new User(userName,"",authorities);

      return user;
    }

}

In our case, we are just adding an LtpaUserAuthority to the user information. Don’t worry about the usage of the LtpaUserAuthority. We come back to this in another post.

import org.springframework.security.core.GrantedAuthority;

public class LtpaUserAuthority implements GrantedAuthority {

   private static final long serialVersionUID = 1L;

   @Override
   public String getAuthority() {
      return "ROLE_USER_LTPA";
   }

}

In the last step we have to update the SecurityConfig.java to activate the filter:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Configuration
   @Order(1)
   static class DominoLtpaSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

      @Bean
      public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService() {
         return new LtpaUserDetailsService();
      }

      @Bean
      public PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() {
         PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();

         provider.setPreAuthenticatedUserDetailsService(authenticationUserDetailsService());
         provider.setUserDetailsChecker(new AccountStatusUserDetailsChecker());

         return provider;
      }

      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
         auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
      }

      @Bean
      public AbstractPreAuthenticatedProcessingFilter preAuthenticatedProcessingFilter() throws Exception {
         LtpaPreAuthenticatedFilter filter = new LtpaPreAuthenticatedFilter();
         filter.setAuthenticationManager(authenticationManager());
         return filter;
      }

      @Override
      protected void configure(HttpSecurity http) throws Exception {
         http.addFilter(preAuthenticatedProcessingFilter())
         .authorizeRequests()
         .antMatchers("/**").permitAll() ;
      }
   }
  ...
}

This includes the filter in any request. Now, the Principal contains the user name stored in the LTPA token.

Veröffentlicht unter Java, Server, Web | Verschlagwortet mit , , , | Hinterlasse einen Kommentar

Dropping Domino’s HTTP task (2): Running in User Context

To use the approach as an alternative to Domino’s HTTP task, we need support for the different user contexts, because using NotesFactory.createSession() just creates a session for the current Notes ID used.

This goal can be achived by using the Java NAPI and the following method:

import com.ibm.domino.napi.NException;
import com.ibm.domino.napi.c.NotesUtil;
import com.ibm.domino.napi.c.xsp.XSPNative; 

/**
* create a new Domino session for the give username
* @param userName
* String containing the canonical username
* @return
* lotus.domino.Session for the given username
* @throws NException
* @throws ServletException
*/
public static Session createUserSession(final String userName)
{
   Session session = null;
   try {
      long hList = NotesUtil.createUserNameList(userName);
      session = XSPNative.createXPageSession(userName, hList,
         false, false);

      return session;
   } catch (Exception e) {
      e.printStackTrace();
   }

   return session;
}

It is required to load the required njnotes.dll before this method can be used, otherwise the C-API references won’t work. This must be done after initiation of the NotesThread and (only once) per thread:

System.loadLibrary("njnotes");

It is also required to use the full hierarchical name for the session creation, otherwise readers / authors won’t work correctly (you can create a session for every user you want, even for not existing ones).

To get this work correctly, I have created a little helper class which memorizes if the Notes-relevant part was already initialized for the thread used:

public class Utils {

   private static final ThreadLocal<Boolean> isNotesInitialized = new ThreadLocal<Boolean>();

   public static void initNotes(){

      // check if the Thread is already initialized
      if( Boolean.TRUE.equals( isNotesInitialized.get() ) )
         return;

      // init Notes
      NotesThread.sinitThread();
      System.loadLibrary("njnotes");

      // mark as initialized
      isNotesInitialized.set( Boolean.TRUE );

   }

}

Now let’s activate Spring Boot Security on the new server by adding the required dependencies to the pom.xml:

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>

To use the authentication with the existing Domino environment, we can use our own AuthenticationProvider:

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import org.springframework.security.authentication.BadCredentialsException;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
      String name = authentication.getName();
      String password = authentication.getCredentials().toString();

      String realUser = validatePassword( name, password );

      if( Utils.isEmptyString( realUser ) ){
         throw new BadCredentialsException("Authentication failed for user = " + name);
      }

      return auth;
   }

   @Override
   public boolean supports(Class<?> authentication) {
      return authentication.equals(UsernamePasswordAuthenticationToken.class);
   }

   public String validatePassword( final String userName, final String password){
      // see https://github.com/hasselbach/domino-stateless-token-servlet/blob/master/src/ch/hasselba/servlet/DominoStatelessTokenServlet.java
      // and convert the username to the hierarchical one
   }
}

If the authentication was successfull, we can access the correct username from the Principal object. Just add it as a parameter to the controller method, and you get the hierarchical name.

@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message, Principal principal) throws Exception {

   Thread.sleep(1000); // simulated delay

   // init Notes
   Utils.initNotes();

   // create the session for the user
   Session session = (Session) Utils.createUserSession(principal.getName());

   return new Greeting("Hello, " + HtmlUtils.htmlEscape( session.getEffectiveUserName() ) + "!" );
}

Now let’s see this in action:

P.S.
I have ignored recycling and termination of the Notes threads for an easier understanding.

Veröffentlicht unter Java, Server, Web | Verschlagwortet mit , , , | 5 Kommentare

Dropping Domino’s HTTP task

Instead of waiting for updates of the Domino HTTP task any longer I was thinking about how to use modern HTTP technologies on top of Domino. But instead of implementing it in the Domino stack, I think I found a new way for developing and running my Spring Boot applications: Why not using the existing JVM, and run my application directly on it? This means full access to the Domino objects, and allows access to the latest available technologies: No more limitations because of the provided tech stack, Websockets, Async HTTP Request Processing, full JEE support, modern and better development tools, …

I am not talking about DIIOP or RPC, that’s something different, and more a crutch as a solution. I need full access, especially to NAPI for C-API calls for running the code in the user context I want.

First thing to do is downloading and installing Maven and Git. I am using older versions on my Winows 7 VM, because I am to lazy to upgrade them. Then I have cloned the Websockets example from Spring as a starting point for a quick testing scenario.

I have choosen Jetty as the webserver to use by adding the dependencies to the pom.xml:

<dependency>
   <groupId>org.eclipse.jetty.websocket</groupId>
   <artifactId>websocket-client</artifactId>
   <version>9.4.11.v20180605</version>
</dependency>

<dependency>
   <groupId>org.eclipse.jetty.websocket</groupId>
   <artifactId>websocket-server</artifactId>
   <version>9.4.11.v20180605</version>
</dependency>

<dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-client</artifactId>
   <version>9.4.11.v20180605</version>
</dependency>

Jetty provides support for WebSockets, http/2, the latest servlet container and many more features which on the wishlist of Domino developers for years.

For an easier maintainment, I am using properties in the pom.xml for referencing the Domino environment:

<properties>
   <java.version>1.8</java.version>
   <domino.directory>T:/IBM/Domino901</domino.directory>
   <domino.osgi.shared.directory>${domino.directory}/osgi/shared/eclipse/plugins</domino.osgi.shared.directory>
   <domino.osgi.rcp.directory>${domino.directory}/osgi/rcp/eclipse/plugins</domino.osgi.rcp.directory>
   <domino.version>9.0.1</domino.version>
   <domino.jarversion>9.0.1.20180115-1058</domino.jarversion>
</properties>

My installation of Domino server is on drive T, and the JAR version is the part of the file or folder name which depends on the current installation / feature pack.

Now, we can add the dependencies to the required Domino JARs:


<dependency>
   <groupId>com.ibm</groupId>
   <artifactId>domino-api-binaries</artifactId>
   <version>${domino.version}</version>
   <scope>system</scope>
   <systemPath>${domino.directory}/jvm/lib/ext/Notes.jar</systemPath>
</dependency>

<dependency>
   <groupId>com.ibm</groupId>
   <artifactId>commons</artifactId>
   <version>${domino.version}</version>
   <scope>system</scope>
   <systemPath>${domino.osgi.shared.directory}/com.ibm.commons_${domino.jarversion}/lwpd.commons.jar</systemPath>
</dependency>

<dependency>
   <groupId>com.ibm.domino</groupId>
   <artifactId>napi</artifactId>
   <version>${domino.version}</version>
   <scope>system</scope>
   <systemPath>${domino.osgi.shared.directory}/com.ibm.domino.napi_${domino.jarversion}/lwpd.domino.napi.jar</systemPath>
</dependency>

At this point it is time to start the project for the first time. To do this, it is required to use the Domino JVM instead of the installed one. And here comes a small drawback: When using the Server JVM you cannot run the Domino server in parallel. If so, the server will crash immediatly with a „PANIC!“ message. You could start every task manually – but not the database server itself (this means you can use replication and mail and everything, but you cannot connect to the server from another client).

So here is a workaround: Install the Notes client and use his JVM! Think as it of a massive Database driver to connect to the server (there is no need to start the client, we just need the JVM and the DLLs).

Start a console, and change the environment (dependent of your installation of Maven & the Notes client):

SET JAVA_HOME=T:\IBM\Notes901\jvm
SET Path=T:\IBM\Notes901;C:\apache-maven-3.3.9\bin;T:\IBM\Notes901\jvm\bin

Go to your project folder and start the server:

mvn spring-boot:run

After opening http://localhost:8080 in your browser and clicking the „Connect“ button, you can see the WebSocket connection in the Dev Console:

At this point, nothing really spectacular. But now let’s modify the GreetingController.java and add some Domino code:

@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {

   Thread.sleep(1000); // simulated delay

   // make to Domino Thread
   NotesThread.sinitThread();
   Session session = NotesFactory.createSession();

   return new Greeting("Hello, " + HtmlUtils.htmlEscape( session.getEffectiveUserName() ) + "!" );
}

Restart the Jetty server, and enter a name. Et voilà…

In the next post, let’s use the Java NAPI to create a „real“ Webserver.

Veröffentlicht unter Java, Server, Web | Verschlagwortet mit , , , , , | 8 Kommentare

You don’t know JS

Here is a must-read: The „You don’t know JS“ book series, a deep dive into the core mechanisms of the JavaScript language.  The online version is free.

Veröffentlicht unter Java Script | Hinterlasse einen Kommentar

HCL, Domino & node.js

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 with the old Jar files of the Domino JVM? Or was it required to downgrade 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 problematic 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.

Veröffentlicht unter ExtLib, Java Script, REST, Server, Spring, XPages | Verschlagwortet mit , , , | 4 Kommentare

Domino & Spring Boot: How does it work

The example Spring Boot Plugin I have published two days ago is a full working example to run Spring Boot applications directly in the Domino HTTP task. It is designed as an OSGi plugin and runs inside the servlet container, which means that the „normal“ features of the Domino HTTP task are available at runtime, for example the existing the user session is accessible via the ContextInfo object.

To complile and deploy the plugin, you first have to install the XPages SDK and create the missing feature project and update site project as described in one of my older posts.
After importing the plugin in the UpdateSite and restarting the HTTP task, the Spring Boot application is ready and will flood the console with a lot of debugging informations when the first request hits the application:

While the example is a really basic one I am using the same approach for years in production environment. The reason is that it was fundamental for the customer (which has abandoned Domino years ago) to have a modern and industry-wide standard framework: The application is now a Spring Boot application which has a NoSQL backend – the decision makers had some buzzwords, the term „Domino“ is no longer used and all participants are happy now.

How does it work?

First it is required that the main configuration is still in the web.xml file. This is required because of the old servlet container which is still only available in version 2.5; I was not successfull to implement the latest Spring Boot version 5, because it seems that a servlet container version 3.0 is required.

In the web.xml file, the servlet mapping is defined:

<servlet>
   <servlet-name>dominoSpringBootServlet</servlet-name>
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
   <load-on-startup>1</load-on-startup>
</servlet>

An additional configuration file dominoSpringBootServlet.xml contains the servlet specific configuration; both (the servlet name and the XML configuration) must have the same name, otherwise Spring Boot will not find the configuration file.

In this configuration file, the base package is defined, which tells the framework where to scan for Java classes and annotations:

<context:component-scan base-package="domino.springboot.plugin" />

The following line enables Spring Boot’s annotations:

<mvc:annotation-driven />

Now, the package domino.springboot is scanned for controllers and configuration classes, which I will describe in the next post.

 

Veröffentlicht unter Java, OSGi, Server, Spring, Web | Verschlagwortet mit , , | Hinterlasse einen Kommentar

Domino & Spring Boot: An example project

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.

Veröffentlicht unter Java, OSGi, REST, Spring, Web | Verschlagwortet mit , , , | 4 Kommentare