Posts Tagged: ‘OSGi’

Schulungsangebot – Spring Boot & Domino: REST APIs

14. Februar 2019 Posted by Sven Hasselbach

Kurs „Spring Boot & Domino: REST APIs“

Für große Anwendungen ist eine REST Schnittstelle heutzutage unverzichtbar. Doch mit den Bordmitteln sind schnell Grenzen erreicht und auch die Einbeziehung von Entwicklern ohne Domino-Hintergrundwissen gestaltet sich schwierig

Spring Boot ist der Defacto-Standard für Unternehmensanwendungen im Java-Umfeld und eine robuste wie auch flexible Alternative zu existierenden Frameworks des Domino-Umfelds.

Der Kurs vermittelt die nötigen Kenntnisse, um eine Spring Boot-basierte REST API zu entwickeln und diese als OSGi Plugin zu deployen. Ergänzt wird der Kurs durch langjährige Praxiserfahrung im täglichen Einsatz. Themen wie Token-Authentifizierung, Caching-Strategien für Hochperformante Anwendungen, Multi-Threading-Support, automatisierte Dokumentation dank Swagger uvw. werden im Kurs ausführlich behandelt.

Als Startpunkt für eigene Entwicklungen ist der verwendete Source Code Lizenzfrei enthalten.

Dauer: 3 Tage / Preis 3.500 € zzgl. MwSt. (Unabhängig von der Teilnehmerzahl)

Zielgruppe: Anwendungsentwickler Lotus Notes / Domino. Webentwicklungs- und Java- kenntnisse vorausgesetzt.

Bei Interesse oder Fragen bitte eine Mail an mich (freelancer AT hasselba.ch) oder das Kontaktformular nutzen.

Domino & Spring Boot: How does it work

1. Juni 2018 Posted by Sven Hasselbach

The example Spring Boot Plugin I have published two days ago is a full working example to run a 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 on 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.

 

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.

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.

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: 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.

XPages: A ClientSide State

13. September 2015 Posted by Sven Hasselbach

I have created a ClientSide State for XPages, which allows horizontal scaling of XPages applications with a single click.

After installing the OSGi Plugin on the servers and the DDE, you can activate it with a single click:

2015-09-13 20_41_02-XPage Properties Editor - ClientStateDemo - IBM Domino Designer

Then, the State of the XPages application is stored on client side (in the field „$$clientstate„), and not on the server anymore. The State is AES-128 encrypted and uses some random bytes for a higher security.

2015-09-13 20_52_11-Quelltext von_ http___localhost_ClientStateDemo.nsf_Test.xsp

You can find the code on GitHub.

P.S.

Parts of the code are shamelessly stolen from Jesse.

Rest & Security: More about the DominoStatelessTokenServlet

25. Februar 2015 Posted by Sven Hasselbach

During the last days I have refined the DominoStatelessTokenServlet a little bit. It is now a pre-beta release, and I think it is time to explain some details about it. While it is still a proof-of-concept, it demonstrates how a stateless authentication can easily be implemented. A lot of testing is still required until it is ready for production use, but I think it provides really cool things for the domino environment.

First, it fixes the problematic 200er HTTP response code when an authentication was not successfull. Then it introduces a higher security level for web based applications, because the authentication token is only transferred in the HTTP headers: A CSRF attack as shown here is not possible anymore. The authentication works accross multiple servers / clusters, which can become interesting for example when you want to share the authentication securely between a Bluemix hosted application and your companies hosted infrastructure; the token is created from a server running in your company, and is then used to identify a user in the cloud-based application (It’s a real authentication, not a “misused authorization” like OAuth).

The token can also be safely stored in an mobile app: When the device gets lost, the user credentials are not compromised. And it allows to create different tokens for different applications for the same user (currently not implemented).

As a short demonstration, I have added a Angular JS example (with a hardcoded token) to  show how it works in practise: An AJAX request is sent to the servlet, and the JSON response contains the name of the current Domino user.

The HTML page is not really complicated, it will just show the returned username:

<!doctype html>
<html ng-app>
   <head>
      <title>Hello AngularJS</title>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
      <script src="hello.js"></script>
   </head>
   <body>
      <div ng-controller="Hello">
         <p>Hello {{greeting.username}}!</p>
      </div>
   </body>
</html>

The “Hello” controller which performs the AJAX request adds the “X-AUTH-TOKEN” to the HTTP headers of the request:

function Hello($scope, $http) {

   // add a valid token to the headers
   $http.defaults.headers.common['X-AUTH-TOKEN'] = 
     'MTQyNDI2OTE0NDgxNCFUVGVzdFVzZXIwMQ==!HyC1mnvvdaneLaW0Wn48kZ1MaTrdowr1e4nWBRWRX8Y=';

   // load the data
   $http.get('http://localhost/token/validate/').
      success(function(data) {
         $scope.greeting = data;
      });

}

And this is the result:

StatelessToken 01 - Validate Token

The Token consist of two parts: The data part, and the Hmac hash of the data. Both are Base64 encoded, and when the data part is decoded, you can currently see the username and the timestamp of the token generation:

  • Encoded
MTQyNDI2OTE0NDgxNCFUVGVzdFVzZXIwMQ==
  • Decoded
1424269144814!TTestUser01

Because the data are hashed it is not possible to modify them. The timestamp is validated from the servlet; as soon it is too old, it is not longer valid.

To create a token, the servlet must be currently opened with the username and the password as URL parameters:

http://localhost/token/create/?username=TTestUser01&password=test01

In the response, the newly generated token is added to the HTTP headers:

StatelessToken 02 - Create Token

In the servlet configuration (web.xml), a backend user is defined on whose behalf a lookup to the NAB is made to verify the provided HTTP password.  The password for the hash is also stored there, and the maximum age of the token.

HowTo: Vaadin on Domino (4)

26. Januar 2015 Posted by Sven Hasselbach

Now, let’s access some Domino resources.

I have created a database named “VaadinResources.nsf“, containing a normal image resource, and an image added via package explorer to the “WEB-INF” folder:

Screenshot - ImageResource

Screenshot - WEB-INF Resource

Vaadin provides stream resources, which allows creating of dynamic resources. These resources handle “InputStream” objects, which we can grab from Domino via Java NAPI.

To do this, it is first required to add some plug-ins to the dependencies of the “HelloVaadin” plug-in:

Screenshot - Dependencies

  • com.ibm.domino.napi
  • com.ibm.domino.commons
  • com.ibm.commons

Then we can import the “NAPIUtils” class to the project and add a new method “loadBinaryFile” to it:

/**
 * loads given file from a database and returns the Inputsstream
 * 
 * @param serverName
 *            the server to use
 * @param dbPath
 *            the database path
 * @param fileName
 *            the file to load
 * @return the file data as InputStream
 * 
 */
static public InputStream loadBinaryFile(final String serverName, final String dbPath,
        final String fileName) {

    NotesSession nSession = null;
    NotesDatabase nDatabase = null;
    NotesNote nNote = null;

    try {
        nSession = new NotesSession();

        // open database
        try {
            nDatabase = nSession.getDatabaseByPath(serverName + "!!" + dbPath);
        } catch (NotesAPIException e) {
            e.printStackTrace();
        }
        nDatabase.open();

        // load existing data
        nNote = FileAccess.getFileByPath(nDatabase, fileName);

        // get Filedate and return String
        InputStream is = FileAccess.readFileContentAsInputStream(nNote);

        return is;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // recycle NAPI objects
        recycleNAPIObject(nNote, nDatabase, nSession);
    }
    return null;
}

A new class “DominoImageSource” which implements the “StreamResource.StreamSource” interface uses this method to pipe the “InputStream” object returned from the Domino Java NAPI:

package ch.hasselba.vaadin;

import java.io.InputStream;
import ch.hasselba.napi.NAPIUtils;
import com.vaadin.server.StreamResource.StreamSource;

@SuppressWarnings("serial")
public class DominoImageSource implements StreamSource {
    
    private String fileName;
    private String serverName;
    private String dbPath;
    
    public DominoImageSource(final String serverName, final String dbPath, 
            final String fileName){
        super();
        this.serverName = serverName;
        this.dbPath = dbPath;
        this.fileName = fileName;
    }
    public InputStream getStream () {    
        return NAPIUtils.loadBinaryFile( this.serverName, this.dbPath, this.fileName );
    }
}

Now, we can create a new Application named “ResourceUI” which displays these two resources:

package ch.hasselba.vaadin;

import com.vaadin.server.StreamResource;
import com.vaadin.server.StreamResource.StreamSource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Image;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

@SuppressWarnings("serial")
public class ResourcesUI extends UI  {

    @Override
    protected void init(VaadinRequest request) {
        
         VerticalLayout layout = new VerticalLayout();
         setContent(layout);
         layout.setSizeFull();
         
         // Create an instance of our stream source.
         StreamSource webinfResource = new DominoImageSource ( 
                 "Dev01", "VaadinResources.nsf" , "/WEB-INF/WEB-INFResource.png");
         
         StreamSource imageResource = new DominoImageSource ( 
                 "Dev01", "VaadinResources.nsf" , "ImageResource.gif");

         // Create an image component that gets its contents
         // from the resource.
         layout.addComponent(new Image("WEB-INF Resource", 
                 new StreamResource(webinfResource, "image01.png")));
         layout.addComponent(new Image("Image Resource", 
                 new StreamResource(imageResource, "image02.gif")));
        
    }
}

Again, no rocket science and self-explaining code. When we open the application, the resources are loaded from the database and displayed in the browser:

Screenshot - Resource Application

As soon we are changing the images in the database (and the cache is expired), the new image will appear in our Vaadin application.

HowTo: Vaadin on Domino (3)

25. Januar 2015 Posted by Sven Hasselbach

Let’s create another application, based on Vaadin’s AddressBook example. You can download the source code directly or grab the code from the repository; it is a single class file named “AddressbookUI” only.

After importing (or manually creating) the class in the HelloVaadin plug-in, the servlet configuration in “web.xml” must be updated:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="2.5" 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_2_5.xsd">

  <display-name>Addressbook</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    
    <servlet>
        <servlet-name>AdressbookServlet</servlet-name>
        <servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
        <init-param>
            <param-name>UI</param-name>
            <param-value>ch.hasselba.vaadin.AddressbookUI</param-value>
        </init-param>
    </servlet> 

    <servlet-mapping>
        <servlet-name>AdressbookServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
</web-app>

The “<param-value>” must contain the complete class name, I have additionally changed the name of the servlet and updated the path in the “plugin.xml“:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>

     <extension
         point="com.ibm.pvc.webcontainer.application">
      <contextRoot>
         /addressbook  
      </contextRoot>
      <contentLocation>
         WebContent
      </contentLocation>
   </extension>

</plugin>

To connect the example to a Domino environment, the “createDummyDatasource” method of the class must be replaced:

@SuppressWarnings("unchecked")
private static IndexedContainer createDummyDatasource() {

    // Domino objects
    Session session = null;
    Database db = null;
    View view = null;
    Document doc = null;
    Document tmpDoc = null;

    // initialize IndexedContainer
    IndexedContainer ic = new IndexedContainer();

    // add fieldnames as properties
    for (String p : fieldNames) {
        ic.addContainerProperty(p, String.class, "");
    }

    // get all users from NAB
    try{
        // init Domino objects
        session = ContextInfo.getUserSession();
        db = session.getDatabase(session.getServerName(), "dummynames.nsf");
        view = db.getView( "People" );

        // process all documents in view
        doc = view.getFirstDocument();
        while (doc != null) {

            // create a new item
            Object id = ic.addItem();

            // add field values to the item
            ic.getContainerProperty(id, FNAME).
                setValue(doc.getItemValueString("FirstName"));
            ic.getContainerProperty(id, LNAME).
                setValue(doc.getItemValueString("LastName"));

            // grab next document
            tmpDoc = doc;
            doc = view.getNextDocument(tmpDoc);
            recycle( tmpDoc );
        }
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        recycle( doc, tmpDoc, view, db, session );
    }
    return ic;
}

/**
* recycle Domino objects
*
* @param objs
*     lotus.domino.Base objects to recylce
*/
private static void recycle(Base... objs){
    try{
        for( Base obj:objs ){
            if( obj != null )
                obj.recycle();
        }
    }catch(Exception e){}
}

Because this is not rocket science I won’t get into the details.

To prevent anonymous access, I have added a simple redirection in the “init” method:

protected void init(VaadinRequest request) {
        
    if( ContextInfo.isAnonymous() ){
         getPage().setLocation("/names.nsf?login=1&redirectto=" + 
             request.getContextPath() );
         return;
    }
        
    initLayout();
    initContactList();
    initEditor();
    initSearch();
    initButtons();
}

When opening the application as an anonymous user you will be automatically redirected to the Login Screen:

00 - Login

After signing in, domino redirects back to the addressbook example, and the list of persons in your “names.nsf” is shown up:

00 - Addressbook

HowTo: Vaadin on Domino (2)

24. Januar 2015 Posted by Sven Hasselbach

When running your own servlet, you eventually want to access the Domino environment. To do this, some changes has to be made to the HelloVaadin plug-in.

1. Open the “MANFIFEST.MF” and open the “Dependencies” tab

2. Add the plug-in “com.ibm.osgi.domino.core” to the list of required plug-ins

01 - Dependencies - Add OSGi Plugin 00

01 - Dependencies - Add OSGi Plugin

01 - Dependencies - Add OSGi Plugin 02

Save the “MANIFEST.MF

3. Now we can use “com.ibm.domino.osgi.core.context.ContextInfo” to access the Domino environment in HelloVaadinUI

package ch.hasselba.vaadin;

import lotus.domino.Database;
import lotus.domino.NotesException;
import lotus.domino.Session;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI; 
import com.vaadin.ui.VerticalLayout;
import com.ibm.domino.osgi.core.context.ContextInfo;

@SuppressWarnings("serial")
public class HelloVaadinUI extends UI {
    
    public static class Servlet extends VaadinServlet {
    }
    
    @Override
    protected void init(VaadinRequest request) {
    
        VerticalLayout layout = new VerticalLayout();
        setContent(layout);
        layout.setSizeFull();
        
        String dbPath = "";
        String userName = "";
        String queryString = "";
       
        try {
            
            // get the current database
            Database db = ContextInfo.getUserDatabase();
            if( db != null )
                dbPath = db.getFilePath();
            
            // get the current session
            Session session = ContextInfo.getUserSession();
            if( session != null )
                userName = session.getEffectiveUserName();
            
            // get the query string
            queryString = ContextInfo.getServerVariable("QUERY_STRING");
            
        } catch (NotesException e) {
            e.printStackTrace();
        }
        
        Label label = new Label();
        label.setValue("<h1>Hello " + userName + "!</h1>");
        label.setContentMode(ContentMode.HTML);
        
        Label labelDB = new Label();
        labelDB.setValue("<p>DB Path: " + dbPath + "</p>");
        labelDB.setContentMode(ContentMode.HTML);
        
        Label labelQuery = new Label();
        labelQuery.setValue("<p>Query: " + queryString + "</p>");
        labelQuery.setContentMode(ContentMode.HTML);
        
        layout.addComponents(label, labelDB, labelQuery);
    }

}

4. When opening the application inside the names.nsf, the result looks like this:

04  - Result

HowTo: Vaadin on Domino

24. Januar 2015 Posted by Sven Hasselbach

This example requires a valid XPages Plugin Development Environment. The execution environment used is the XPages Domino JRE.

1. Create a new plug-in project and select “Equinox” as OSGi framework

01 - New Plugin Project

2. Set the name of the activator class to “ch.hasselba.vaadin.Activator

02 - Activator Class

3. Open the MANIFEST.MF file

03 - Manifest

4. On Tab “Overview“, activate the option for lazy loading and the singleton property

04 - Singleton

5. Go to “Dependencies” tab and add the required plugin “com.ibm.pvc.webcontainer

05 - Dependencies - Required Plugins 01

When entering “pvc“, you can easily find the plugin from the list:

05 - Dependencies - Required Plugins 02

6. Then, add  “javax.servlet” and “javax.servlet.http” to the list of imported packages

06 - Dependencies -ImportedPackages

7. Now, download the Jar files for Vaadin. The files can be found here (the All-in-One archive is the right one).

8. Import the Jars to the project

08 - Import - Vaadin Jars 01

08 - Import - Vaadin Jars 02

The required Jars are:

  • vaadin-client-7.3.8.jar
  • vaadin-client-compiled-7.3.8.jar
  • vaadin-client-compiler-7.3.8.jar
  • vaadin-push-7.3.8.jar
  • vaadin-server-7.3.8.jar
  • vaadin-shared-7.3.8.jar
  • vaadin-themes-7.3.8.jar

08 - Import - Vaadin Jars 03

9. Do this with „jsoup“ and „org.json“ libaries too:

09 - Import - Other Jar

10. Now, go to the “Runtime” tab and add the classpathes (don’t forget to move the “.” to the top of the list)

10 - Runtime - Classpath 02

10 - Runtime - Classpath

The symbol of the filetypes have now changed:

10 - Runtime - Classpath 03

11. On tab “Overview“, click on “Extensions” to open the Extension tab

11 - Overview - Extensions

Click on “Yes” to open the “Extension” tab:

11 - Overview - Extensions 02

12. Here, you have to add the extension point “com.ibm.pvc.webcontainer.application

12 - Extension - Add 01

12 - Extension - Add 02

13. Open “plugin.xml”

13 - Plugin_XML

14. … and configure the extension point:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>

     <extension
         point="com.ibm.pvc.webcontainer.application">
      <contextRoot>
         /helloVaadin  
      </contextRoot>
      <contentLocation>
         WebContent
      </contentLocation>
   </extension>

</plugin>

contextRoot defines the URL pattern where the Vaadin servlet is reachable.  contentLocation is a folder where the required web.xml configuration file can be found.

Save the “plugin.xml” file.

15. Create the folder “WebContent“…

15 - Folder 01

15 - Folder 02

16. … and then a second folder “WEB-INF” inside of “WebContent

17. Create the “web.xml” file in this folder, the tree should look like this:

17 - WebFolder Structure

18. The “web.xml” contains the configuration of the servlet:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="2.5" 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_2_5.xsd">

  <display-name>HelloVaadin</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    
    <servlet>
        <servlet-name>HelloVaadinServlet</servlet-name>
        <servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
        <init-param>
            <param-name>UI</param-name>
            <param-value>ch.hasselba.vaadin.HelloVaadinUI</param-value>
        </init-param>
    </servlet> 

    <servlet-mapping>
        <servlet-name>HelloVaadinServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
</web-app>

The <init-param> tag inside <servlet> defines our UI class of our application. We will create this class later. The <servlet-mapping> defines a mapping inside the webapplication path.

This means, if you would add a url-pattern like “/helloVaadinServlet/*” to the Vaadin servlet, the URL to reach the application is

http://example.com/helloVaadin/helloVaadinServlet/

The “/helloVaadin/” part is the defined in the contextPath parameter in the web application. When using another pattern as “/*“, an additional mapping for the Vaadin resources is required:

<servlet-mapping>
        <servlet-name>HelloVaadinServlet</servlet-name>
        <url-pattern>/VAADIN/*</url-pattern>
</servlet-mapping>

19. Go to “Build” tab, and include the “Web-Content” folder:

19 - Build - Add WebContent 01

The following line should now appear in the build.properties file which includes the folder in the final Jar.

19 - Build - Add WebContent 02

20. Create the Vaadin servlet class “ch.hasselba.vaadin.HelloVaadinUI”

20. Servlet Class 01

20. Servlet Class 03

21. Add the following code to the class

package ch.hasselba.vaadin;

import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI; 

@SuppressWarnings("serial")
public class HelloVaadinUI extends UI {
    
    public static class Servlet extends VaadinServlet {
    }
    
    @Override
    protected void init(VaadinRequest request) {
    
        HorizontalLayout layout = new HorizontalLayout();
        setContent(layout);
        layout.setSizeFull();

        Label label = new Label();
        label.setValue("<h1>Hello Vaadin!</h1>");
        label.setContentMode(ContentMode.HTML);
        layout.addComponent(label);
        layout.setComponentAlignment(label, Alignment.TOP_CENTER);
    }

}

22. At the end, organize the manifest. Open tab “Overview” and start the “Organize Manifest Wizard

22 - Overview - Organize Manifest 01

22 - Overview - Organize Manifest 02

This updates the manifest and adds all resources for the Vaadin application.

22 - Overview - Organize Manifest 03

Last but not least, save all project files.

25. Create a Feature Project named “HelloVaadinFeature” and click on “Next

Feature 00

27. Select the “HelloVaadin” Plug-In

Feature 02

28. On the “Plugins” tab, check the option “Unpack the plug-in archive after the installation“:

Feature 03

Save the file and…

29. … create the Update Site “HelloVaadinUpdateSite

UpdateSite 01

UpdateSite 02

Add the feature…

UpdateSite 03

UpdateSite 04

… and build the site:

UpdateSite 05

30. Import it to the Update Site on the Domino server and restart the HTTP task

31. That’s it! Open the URL in the browser and enjoy.

99 - Hello Vaadin