Domino Access Service – Posting a document

Introduction

In our app described in previous posts I have included an interface to post a new document using Domino Access Services. Here is how I did it.

HTML structure

The main part of the ‘form’ is the HTML structure.

form

Since we use Bootstrap I included form-groups to layout the fields. In my example I still use XPages, but the inputfields you can replace with HTML input elements.

<form role=”form”>

<h2>Registration</h2>
<div id=”entryForm”>
<div class=”form-group”>
<xp:label value=”Firstname:” id=”label2″></xp:label>
<xp:inputText id=”inpFirstname” styleClass=”firstName”>
<xp:this.attrs>
<xp:attr name=”placeholder” value=”Enter firstname”></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class=”form-group”>
<xp:label value=”Lastname:” id=”label3″></xp:label>

<xp:inputText id=”inpLastname” styleClass=”lastName”>
<xp:this.attrs>
<xp:attr name=”placeholder” value=”Enter lastname”></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class=”form-group”>
<xp:label value=”Email:” id=”label1″></xp:label>
<xp:inputText id=”inpEmail” styleClass=”email” type=”email”>
<xp:this.attrs>
<xp:attr name=”placeholder” value=”Enter email”></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<div class=”form-group”>
<xp:label value=”Password:” id=”label4″></xp:label>
<xp:inputText id=”inpPassword” type=”” styleClass=”wannebepassword”>
<xp:this.attrs>
<xp:attr name=”placeholder” value=”Enter password”></xp:attr>
</xp:this.attrs>
</xp:inputText>
</div>
<xp:button value=”Submit” id=”button1″ styleClass=”btnRegister btn btn-default”>
</xp:button>
</div>
</form>
<div id=”formResponse”></div>

JavaScript

On the onClientLoad event of the XPage I have included the following script.

Parameters

Keep in mind to include the form name in the URL parameter (?form=Person) since you cannot include that pair in the JSON object that is send to Domino Access Service.

The &computewithform=true parameter ensures the HTTPPassword field will be translated with the @Password function.

<xp:eventHandler event=”onClientLoad” submit=”false”>
<xp:this.script>
<![CDATA[$(document).ready(function() {
$(“.wannebepassword”).attr(“type”, “password”);
$(“.btnRegister”).click(function(e) {
var firstName = $(“.firstName”).val();
var lastName = $(“.lastName”).val();
var email = $(“.email”).val();
var password = $(“.wannebepassword”).val();
var newName = $(“.firstName”).val() + ” ” + $(“.lastName”).val();
if (newName !== ” “) {
var newPersonObj = {
FirstName: firstName,
LastName: lastName,
FullName: newName,
InternetAddress: email,
HTTPPassword: password,
Form: “Person”
};
$.ajax({
url: ‘http://server/fakenames40k.nsf/api/data/documents?form=Person&computewithform=true&#8217;,
type: ‘POST’,
data: JSON.stringify(newPersonObj),
dataType: ‘xml’,
accepts: {
xml: ‘text/xml’,
text: ‘text/plain’
},
contentType: “application/json”
}).done(function(data, textStatus, jqXHR) {
var newPersonLocation = jqXHR.getResponseHeader(“Location”);
$(“#entryForm”).hide();
$(“#formResponse”).html(‘Registration successfull.<br/><a class=”btn btn-default” href=”‘ + newPersonLocation + ‘”>Check it out!</a>’);
}).fail(function(jqXHR, textStatus, errorThrown) {
alert(“Registration has failed:” + errorThrown);
console.log(‘Registration has failed.’);
});
} else {
alert(“Please enter a name”);
}
return false;
});
});]]>
</xp:this.script>
</xp:eventHandler>

Password attribute

XPages does not allow you to define the password type as attribute. I found the answer from Tim Tripcony on Stackoverflow helpful to define a work-around.

Wrap up

That is about it!

This is just a simple example. Probably you would normally include some more validation (avoid double entries) but you get the idea.

Adding search to our app

Introduction

In this post I will demonstrate how to apply a search to our application described in previous posts, in which we read the JSON from Domino Access Service and parse it with the Jackson library to display it thereafter with a Repeat control.

Since I am using in our application the Application Layout control with a responsive Bootstrap UI (shameless pitch to glory the persons who delivered this great functionality to XPages) which includes a searchBar section and scrolling through 40K of person records is not something you want to anguish your thumb with, a search functionality gives the advantage to skip scrolling through unnecessary documents.

searchBar section

Here is how I set up the searchBar section in the Application Layout control:

searchbar

As you can see I have defined a result page for the search, called search.xsp.

Here is how the search bar will look like for the user:

searchbox

XPage search

beforePageLoad event

The beforePageLoad event has slightly changed compared with event in our initial XPage. This time we search for the search parameter defined in the searchBar section:

var query = context.getUrlParameter(“search”);
var persons = new Array();
persons = personsBean.getPersons(“http://dev1/fakenames40k.nsf/api/data/collections/name/people?count=25&search=” + query);
viewScope.put(“names”,persons);

Next is the result list. I have added an additional list item and added the active class:

This item will display the search query we have provided:

acgtive

The Repeat control has also changed slighty. The rows property has been adjusted. We calculate the number of documents returned by the full text search.

<![CDATA[#{javascript:database.updateFTIndex(true);
var query:string = context.getUrlParameter(“search”);
var vw:NotesView = database.getView(“people”);
var totNums:Integer = vw.FTSearch(query).toFixed();
return totNums}]]>

Also the text that indicates where we are in the result set has been modified:

Tip: since we are actually performing FT searches here perhaps it is better to put the counted results already from our initial call in a scope variable and re-use it =(

The button in our infinite scroll function/custom control has also been adapted. Here is the code:

Here is what the end result looks like after a search:

endresult

Infinite scroll for our Domino Access Services & Jackson app

Introduction

In a previous post I demonstrated how to process JSON data from Domino Access Services with the Jackson library. In this post I follow up on that and demonstrate how you can apply an infinite scroll function to it so you can navigate through the presented list in a mobile app kinda way:

app

Class DASRest

Include Serializable

Since we are going to add more Java objects to our list we will use a scope variable to store the values in. Because of the usage we need to include serializable in our DASRest class:

package com.quintessens.FakeNames;

import java.io.Serializable;
import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.map.ObjectMapper;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

public class DASRest implements Serializable {

private static final long serialVersionUID = 1 L;

public static Person[] getPersons(String url) {
Person[] persons = null;
try {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(url);
String json = service.accept(MediaType.APPLICATION_JSON).get(String.class);
ObjectMapper mapper = new ObjectMapper();
persons = mapper.readValue(json, Person[].class);

} catch (Exception e) {
System.out.println(“catch…”);
e.printStackTrace();
}
return persons;
}
}

Managed Bean

We will also register our class as a Managed Bean in the faces-config.xml file:

<?xml version=”1.0″ encoding=”UTF-8″?>
<faces-config>
<managed-bean>
<managed-bean-name>personsBean</managed-bean-name>
<managed-bean-class>com.quintessens.FakeNames.DASRest</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>

beforePageLoad event

In the beforePageLoad event of the XPage where we will display the result list we will make the initial call to the Domino Access Service and collect the fist set of documents:

var persons = new Array();
persons = personsBean.getPersons(“http://dev1/fakenames40k.nsf/api/data/collections/name/people?count=25&#8243;)
viewScope.put(“names”,persons);

As you can see we still use the fakenames application. The received result we place in a viewScope variable. Now we need to bind this variable to a repeat control.

Repeat Control

Our repeat control looks pretty straight forward. I included already some mark-up since we will utilize Bootstrap for our UI presentation:

<ul class=”list-group”>
<xp:repeat id=”rptPersons” indexVar=”persIndex” var=”persData”>
<xp:this.value>
<![CDATA[#{javascript:viewScope.get(“names”)}]]>
</xp:this.value>
<xp:this.rows>
<![CDATA[#{javascript:var vw:NotesView = database.getView(“people”);
return vw.getAllEntries().getCount().toFixed();}]]>
</xp:this.rows>
<li class=”list-group-item”>
<xp:text escape=”true” id=”computedField1″ value=”#{javascript:return persData.name}”>
</xp:text>

</li>
</xp:repeat>
</ul>

Infinite Scroll

My infinite scroll function is inspired by the excellent snippet from Frank Kranenburg and available on OpenNTF.

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<xp:view xmlns:xp=”http://www.ibm.com/xsp/core&#8221; xmlns:xe=”http://www.ibm.com/xsp/coreex”&gt;

<!– make sure ‘add rows’ component is hidden –>
<style>
.infiniteScroll {
display: none;
}
</style>

<xp:button value=”Label” id=”button2″ styleClass=”infiniteScroll”>
<xp:eventHandler event=”onclick” submit=”true” refreshMode=”partial” refreshId=”#{javascript:compositeData.repeatId}”>
<xp:this.action>
<![CDATA[#{javascript:var repeater = compositeData.repeatControlId;

var counter = getComponent(repeater).getRowCount();
var numb = compositeData.increment;
var url = compositeData.baseURL;

var scope = compositeData.scopeVarName

var currPersons = viewScope.get(scope);
var morePersons = personsBeanTest.getPersons(url + counter + “&count=” + numb);
var allPersons = currPersons.concat(morePersons);

viewScope.put(scope,allPersons);

}]]>
</xp:this.action>
</xp:eventHandler>
</xp:button>

<!– small script to check if we need to auto-click the ‘add rows’ button –>
<xp:scriptBlock id=”scriptBlock1″>
<xp:this.value>
<![CDATA[$(window).scroll(function(){
if($(window).scrollTop() == $(document).height() – $(window).height()) {
$(“.infiniteScroll”).click();
}
});]]>
</xp:this.value>
</xp:scriptBlock>
</xp:view>

Under the event handler of the button we collect the current array with objects from the viewscope, we make a new call to Domino Access Services with our current position and we join the received next set of objects with the current set and then we write things back to the viewscope.

We then partial refresh the design element (a panel) that contains both the repeat control and the infinite scroll.

I defined some properties for the custom control in case I might re-use it for other views…

infscroll

That is basically it! On my Xpage I included some text to indicate where we are in the view and that there are more documents available:

<xp:text escape=”true” id=”computedField2″><xp:this.value><![CDATA[#{javascript:var vw:NotesView = database.getView(“people”);
var currNums:Integer = getComponent(“rptPersons”).getRowCount();
var totNums:Integer = vw.getAllEntries().getCount().toFixed();

return “Displaying rows ” + currNums + ” out of ” + totNums;
}]]></xp:this.value></xp:text>

Processing JSON data from Domino Access Services with Jackson

Introduction

In order to separate the data model from the business logic you could use Domino Access Services as your default data provider and process the JSON client- or server-side.

In this blog I demonstrate how you can use the Jackson library to process the incoming JSON and bind it to a repeat control.

About Jackson

Jackson is a multi-purpose Java library for processing JSON data format. Jackson aims to be the best possible combination of fast, correct, lightweight, and ergonomic for developers.

Find out more about the library here.

Sample – Fakenames application

In this example we will use the infamous fakenames application from codestore (grab it while it still out there). I have altered the data in my example a bit more so it contains company and job title information.

If you happen to have a script who can fill in the database with more sensible data please drop a line here.

People view

We will use the people view as our data-source  and access it via Domino Access Service. The  URI for the view is something as followed (depending on your installation):

http://server1/fakenames.nsf/api/data/collections/name/people

XPage

We will use and XPage to display the data from the view. The xpage contains a repeater and a couple of fields e.g.:

<?xml version=”1.0″ encoding=”UTF-8″?>
<xp:view
xmlns:xp=”http://www.ibm.com/xsp/core&#8221;
xmlns:xc=”http://www.ibm.com/xsp/custom”&gt;

<xp:panel>
<xp:repeat id=”rptPersons” rows=”10″ var=”persons”
value=”#{javascript:com.quintessens.FakeNames.DASRest.getPersons(‘http://server1/fakenames.nsf/api/data/collections/name/people?count=100&#8242;)}”>
<xp:panel id=”personsPanel”>
<h1>
<xp:text escape=”true” id=”computedField1″
value=”#{javascript:persons.getName()}”
>
</xp:text>
</h1>
<h3>
<xp:text escape=”true” id=”computedField2″
value=”#{javascript:persons.getCompanyname()}”
>
</xp:text>
</h3>
<xp:text escape=”true” id=”computedField3″
value=”#{javascript:persons.getJobtitle()}”
style=”font-style:italic”>
</xp:text>

</xp:panel>
</xp:repeat>
<xp:pager layout=”Previous Group Next”
partialRefresh=”true” id=”pager1″ for=”rptPersons”>
</xp:pager>
</xp:panel>
</xp:view>

Note I call in the repeater control a method getPersons in the class DASRest and provide an URL of the data-source.

I add the count parameter to get more initial results than set in the server configuration.

I also have added a pager control to navigate through the returned collection.

DASRest class

The DASRest class looks as followed:

package com.quintessens.FakeNames;

import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.map.ObjectMapper;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

import com.quintessens.FakeNames.Person;

public class DASRest {

public static Person[] getPersons(String url) {
Person[] persons = null;
try {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(url);
String json = service.accept(MediaType.APPLICATION_JSON).get(String.class);
ObjectMapper mapper = new ObjectMapper();
persons = mapper.readValue(json, Person[].class);
} catch (Exception e) {
e.printStackTrace();
}
return persons;
}
}

Jersey

This class uses the Jersey library to setup a client to contact the Domino Access Service.

Developing RESTful Web services that seamlessly support exposing your data in a variety of representation media types and abstract away the low-level details of the client-server communication is not an easy task without a good toolkit. In order to simplify development of RESTful Web services and their clients in Java, a standard and portable JAX-RS API has been designed.

The received JSON is then converted into a Java object. I find this a good site to learn more about mapping JSON and Java.

Person class

The class also uses a Person class. In this class we specify which fields we want to map and how they should look like:

package com.quintessens.FakeNames;

import javax.xml.bind.annotation.XmlRootElement;

import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;

@XmlRootElement
@JsonIgnoreProperties(ignoreUnknown = true)
public class Person {
private String name;//$17
private String companyName;
private String jobtitle;

@JsonProperty(“$17″)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@JsonProperty(“CompanyName”)
public String getCompanyname() {
return companyName;
}
public void setCompanyname(String companyname) {
this.companyName = companyname;
}
public String getJobtitle() {
return jobtitle;
}
public void setJobtitle(String jobtitle) {
this.jobtitle = jobtitle;
}
}

As you can see @JsonProperty(“$17″) makes the code a bit more user-friendly. In this case it maps the programmatic column name with a variable name.

The result

The following image shows the result of the code above:

jackson

As you see the markup is still basic but you can easily beautify it with Bootstrap or preferred CSS framework of choice.

The purpose of this blog was to demonstrate separating the data model and the business logic. You could have received the same result just using a repeat control and server-side javascript. But since the JSON & Java combination is more hype in the Domino world I guess it is interesting to take a look at the possibilities.

Wrap up

Some thoughts I have after this experiment:

  • What about the other documents?

In my example I make a call to DAS and include the count = 100 parameter. The number 100 is the limit that is set on my server. I have not figured out yet how to load a next set of documents and include it to the existing collection (please drop a note in case you have an answer to this).

  • What about performance?

Is Domino Access Services faster than e.g. defining my own data provider e.g. via a viewnavigator? I don’t know. In case you have suggestions on the preferred or fastest way to provide the data then let me know.

  • What about the language?

Java is not my native language in the Domino world. But the example above is understandable for a lot of us I would think. But who died out of a bit of curiosity?

Thanks for reading. Happy coding!

Born social – Create a Social Notes application from scratch

Introduction

A long time ago (it seems) I had the idea to prepare integration of Connections with Xpages development via the SBTSDK. I thought this would be a good way to learn Connections and it’s API more in details. By setting up custom controls you would be able to build mash-up apps piece by piece.

However there seemed to be little interest for this in the market (correct me if I am wrong) so I continued with other technologies.

Lately Mark Roden posted a couple of posts on his blog regarding the social business toolkit so I hop on to this and post my previous work. Hopefully it can help someone getting started.

Downloads

Born Social – the doc

The document Born Social describes how to setup your server, development environment and application to get started developing with the SBTSDK.

It also provide code samples of custom controls to display information from IBM Connections.

born social

Previous Posts on SBT SDK

Perhaps it helps to read some previous posts I wrote on the SBT SDK.

Born Social – the app

The following file contains an NSF file with all the code, custom controls and some sample xpages.

born social app

Summary

I hope the provided samples and guidance will help you to get started with the SBT SDK.

At IBMConnect at the IBM developers booth I asked what the upcoming plans where for SBT SDK and if we could get more controls for XPages but the answer was that IBM had received very few questions for application development with Connections :-/

Perhaps if more people debunk this mind-set at IBM, perhaps by sharing their samples, interest will grow.

My reflections of IBMConnectED

Yes, or ofcourse, I attended the IBMConnectED 2015 event in Orlando. First start with a summary of sessions I attended:

XPages Performance and Scalability
IBM Domino Applications on Cloud
IBM’s Mobile Collaboration Strategy and Portfolio
IBM ConnectED – A New Way to Engage
IBM Domino – 2015 and Beyond
IBM Domino Applications in Bluemix
The Future of Web Development – Write Once, Run Everywhere with AngularJS and Domino
Mastering Your Logs
IBM Domino App Dev Futures
There’s an API for That! Why and How To Build on the IBM Connections Platform
Yes! You CAN Use Those Cool New Frameworks in Your Mobile Domino Apps!
Considerations for the Cloud
Be Open – Use WebServices And REST In XPages Applications
IBM Domino Application Development – CHALK201
App Throwdown Winner’s Circle
GURUpalooza!
Responsive Application Development for XPages
Build Your Own Apps in Minutes Leveraging IBM Bluemix and IBM Connections
ConnectED Closing Session

That sounds like a lot but have we actually learned or heard something new out there?

IBM killed the master-classes

A class given by an expert to highly talented students

A class may be seen as a course of instruction. In previous editions a master-class tend to be a deep-dive into a subject, where you were taught from a beginner’s level to an expert level. A typical master-class extended the hour, due to the complexity or diversity of the subject.

Often this setup was already worth to attend the conference. However at the 2015 edition subjects where squeezed into a 45 minute time-frame and sometimes presented by an IBM-er so it became a sales pitch in disguise (IBM Domino Applications on Cloud).

When talking with other attendees I heard similar disappointments about the masterclass setup.

Oh my God they (almost) killed the Notes client

Lot’s of Verse at the conference, but the Notes client was mentioned very little. You might wonder if there is a roadmap for Notes?

If you look at the following picture you would think a new edition of the Notes client would appear in 2015:

ibm-connect-2013-messaging-and-collaboration-roadmap-43-638

 

So IBM Verse = Notes Next? I wonder why IBM is not able to tell about their plans for Verse on premise and if it is going to be the future Notes client and how native Notes applications will be delivered in this Verse client. I assume via the Notes browser plugin but the fact that IBM simply ignores these kind of important questions is a slap in the face of current customers to my opinion.

Application development on Bluemix

One of the scarce announcements on the event was the future delivery of XPages and Connections development on the cloud aka Bluemix. This is great and exciting news to my opinion! I understand IBM Notes team can not keep up with bringing new internet related services into their platform but by bringing the platform into an environment that is based on open standards like Bluemix those services will become available for us developers.

Exciting news! I was expecting to have Notes as a data-source in Bluemix but with XPages as a runtime environment this will bring the platform much closer to us.

Meet the developers

The opportunity to meet the developers behind the different products in the Connections portfolio is excellent so I stepped in with some questions of my own.

  • No we are not thinking about a development client for Connections, either make development in Connections easier than it is today :-/
  • No we are not thinking about an admin client for Connections, either try Domain Patrol Social by Infoware or the Connections Administration Toolkit by TimeToAct.
  • No clear roadmap for the social business toolkit. IBM is waiting for requests.

Nevertheless I got help/guidance with other development questions and it was nice to meet the IBM developers who normally help you on StackOverflow.

Application development future

There were some sessions about app dev futures but mainly they were summaries of the recent activities. OK you had Bluemix ofcourse and about responsive design via the Extension Library but nothing about a roadmap or exciting ideas for the Domino Designer client during this event.

Encryption in XPages

This was promised and demonstrated during the App Dev future session. Great & finally!

I would have rather heard about activities on features we do not have today:

  • secured local storage & synchronization (Darwino/Unplugged)
  • more mobile controls (the next billion web users are gonna be mobile http://time.com/3589909/internet-next-billion-mobile/)
  • technologies/modules behind Verse
  • Verse theme for app dev

Just to name a few.

Best session

A bit of a sensitive topic since people were throwing on stage what session they thought to be best. So I rather prefer to highlight the session I enjoy most.

Most enjoyable session

As criteria for my nomination I choose:

  • Presentation skills/confidence of the speaker
  • Topic skills of the speaker
  • Personal reflections of the speaker on the topic
  • Real world examples on the topic
  • Funny quotes / remarks on the topic

And the winner is….

Considerations For The Cloud – BP207
Best Practices
Chris Miller (Connectria)

Although I am not an admin guy (anymore) Chris managed to teach me a lot on moving to the cloud in a fast tempo with a lot of funny references.

Cookiegate, Project Chrome & more

I did not understand the twitter stream about people not having a Pretzel cookie in their lunch-box since I had one in mine. Or was I not to pick up a lunchbox with the label IBM-ers only on it?

Project Chrome held the twitter stream for a while. I am not aware of the outcome. Either that journalist is not to be taken serious any more or an amount of IBM-ers will face the beginning 2015 with a new perspective. Hopefully IBM is wise enough to send out the right type of people and within the Connections portfolio we do not suffer the consequences of it.

It was announced that you could pick up or register for a free certification voucher during IBMConnectED because there wouldn’t be a certification lab at the conference. I would like to thank Daniel Brix for chasing IBM ICS support together and to manage to register myself for such a voucher.

Counting the Notes client phrase

Out of curiosity I counted Tuesday the phrase “Notes client” in presentations. This was rare.

notes client counter

The session from Chris Miller came out as the winner in this ‘challenge’.

Final thoughts

I enjoyed my conference and be able to meet a lot of people with similar interests. From a developer perspective I think the conference was nevertheless a bit poor. I thought IBM would focus in this ConnectED version more on technology and less on softer sections like adaption. The app dev sections were too scarce to my opinion.

The move to more sessions in Swan with smaller rooms caused that some rooms were full and people could not attend it. It happened for me once for the session on internet security. You happen to pay an considerable amount of money for an event in, what IBM calls an intimate setting, and you cannot attend a session. How poor for return for your investment!

Should Notes client customers be uncomfortable about IBM Verse? From what I understood IBM Verse is just a different rendering machine for your inbox adding to features from Connections and Analytics. So it should not be a replacement for the Notes client. But the fact that IBM could not tell anything on the Notes client should worry you. IBM spilled another year on the Notes client roadmap it seems.

Jeff Schick may call he “loves the Notes client”. Is he willing to tell this hooked on a lie detector?