Debugging made easier

This tip is for those people who are using the Debug Toolbar from Mark Leusink. One of the nice things about this toolbar is the embedded logging. You can use logging by means of calling methods on a managed bean ( dbar ) or in your java code you can use the methods info,error,debug or warn. Each method writes log line to the debug (or the log db ) with the corresponding level.

Because in my current project I use this way of logging a lot and because I’m a lazy programmer I started to use code templates. In the Eclipse client it   is possible to predefine certain lines of code which are added to your editor when you type a shortcut followed by the key combo ctrl space.  The most common is the following: syso. This will be translated to System.out.println(). Obviously typing syso and hitting ctrl+space is lots quicker than typing the full line of code.

So I defined 4 new templates. dInfo, dError, dBug, dWarn. The steps to create a new template are :

1) File -> Preferences and type templates in the search box and click on Java ->Editor->Templates

templates_1

2) Press the new Button.

templates_4

3) Fill in a name (dBug, dInfo,dError or dWarn ) and past the following code

templates_3

DebugToolbar.get().info(this.getClass().toString()+”: “);

This will get an instance of the DebugToolbar class and add an info message to the log which contains the current class we are working in. *

4) Click ok, Apply, Ok and see if it works

5) Type dInfo ( or any of the other templates you created ) and hit ctrl+space. The code should be auto completed with the content you have specified in the previous step.

I hope you like this little tip. It makes your life as a developer a little easier !

 

 

 

*keep in mind that the ‘this’ keyword  wont work when you use it in a static method..

 

Hi,

after some down time I’m back again doing some xpages and I already seem to have forgotton to many things. I have the following code:

A datasource:

<xe:objectData var="league" ignoreRequestParams="true"
scope="request">
<xe:this.saveObject><![CDATA[#{javascript:leagueService.set(league)}]]></xe:this.saveObject>
<xe:this.createObject><![CDATA[#{javascript:
return leagueService.get(viewScope.currentKey);}]]></xe:this.createObject>
</xe:objectData>

and a couple of comboboxes

<xp:comboBox id="idLeagueList" value="#{viewScope.currentKey}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript: return eu.jeroensomhorst.cms.util.JSFUtil.asSelectItem(leagueService.getAll(season),true);}]]></xp:this.value>
</xp:selectItems>

<xp:eventHandler event="onchange" submit="true" refreshMode="complete">
</xp:eventHandler>
</xp:comboBox>

<xp:listBox id="lstAvailableTeams">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:eu.jeroensomhorst.cms.util.JSFUtil.asSelectItem(teamService.getAll());}]]></xp:this.value>
</xp:selectItems>
</xp:listBox>

as you can see nothing to fancy. But the problem is as that whenever I do change the value of the idLeagueList combobox and execute the changelistener ( aka it updates the viewscope ). It always retrieves the previous data. I thought I had sorted that out ages ago but apparently not. Can anyone help me out here?

Design patterns in xPages: The repository Pattern (some sort..)

For my current home project I’m busy exploring the Java side of xPages more and more because of my general love for this language. The project involves a little website that should display the current standings and results of hockey teams ( wheelchair hockey ) during the season.

A little feature list

– Support for seasons: Create seasons add teams to a season
– Support for teams: basic crud actions
– Support for competition days and games: basic crud actions
– A list of current standings and results: Realtime calculations for teams etc.

I wanted to use the objectdata datasource for this one. So I searched a bit on the net, remembered the splendid presention from Thimo Janssen and wrote a little code.

Because I didn’t want to fill my pojo’s with the code about how to read and save them I decided to write something called a Repository class. A Repository class is a class that knows all about saving/retrieving an object to and from an datasource for instance a Domino database!

This way we can keep the Object (pojo) itself neat and clean. Now for some code:

I’ll start by showing you the code for the xPage

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
	xmlns:xc="http://www.ibm.com/xsp/custom"
	xmlns:xe="http://www.ibm.com/xsp/coreex">

	<xp:messages id="messages1"></xp:messages>
	<xp:this.data>
		<xe:objectData var="season" scope="request"
			saveObject="#{javascript:seasonService.set(season)}"
			createObject="#{javascript:seasonService.get(param.id);}">

		</xe:objectData>
	</xp:this.data>

	<xp:label for="txtDescription">
		<xp:this.value><![CDATA[#{javascript:if(season.isNew())
	return "Nieuw seizoen";

return "Seizoen aanpassen";
 }]]></xp:this.value>
	</xp:label>
	<ul>

		<xp:inputText value="#{season.description}" id="inputText1">
			<xp:eventHandler event="onkeypress" submit="true"
				refreshMode="complete" disableValidators="true">
				<xp:this.script><![CDATA[return (event.keyCode==13);]]></xp:this.script>
				<xp:this.action>
					<xp:saveDocument var="season"></xp:saveDocument>
				</xp:this.action>
			</xp:eventHandler>
		</xp:inputText>

		<xp:repeat id="seasonlist" value="#{seasonService.all}"
			var="season">
			<li>
				<xp:image id="isCurrentSeason">
					<xp:this.url><![CDATA[#{javascript:var path = "/icons/vwicn032.gif";

if(applicationScope.currentSeason == season.getKey()){
	path ="/icons/vwicn031.gif";
}

var url:XSPUrl = new XSPUrl(database.getHttpURL());
url.setPath(path);
return url.toString();}]]></xp:this.url>
					<xp:eventHandler event="onclick" submit="true"
						refreshMode="partial" refreshId="seasonlist" execMode="partial">
						<xp:this.action><![CDATA[#{javascript:applicationScope.put("currentSeason",season.getKey());
}]]></xp:this.action>
					</xp:eventHandler>
				</xp:image>
				<xp:link text="#{season.description}">
					<xp:this.value><![CDATA[#{javascript:return "/Administrator.xsp?p=season&id="+season.getKey();}]]></xp:this.value>
				</xp:link>
			</li>
		</xp:repeat>
	</ul>

	<xc:ccCompetitieDagenList></xc:ccCompetitieDagenList>
</xp:view>

In the above piece of code you can see the createObject and saveObject properties who are both using the same object called  “seasonService”. This service is the so called Repository class. As said this object is responsible for retrieving and saving an object to the database ( in this case Domino ).

Lets have a look at the code of the Repository Object.

package eu.jeroensomhorst.hockeymanager.services;

import java.util.Vector;

import lotus.domino.Document;

import lotus.domino.Database;
import lotus.domino.NotesException;
import lotus.domino.ViewEntry;
import eu.jeroensomhorst.cms.util.DominoUtil;
import eu.jeroensomhorst.domino.api.ViewEntryEx;
import eu.jeroensomhorst.hockeymanager.model.Entity;
import eu.jeroensomhorst.hockeymanager.model.Season;

public class SeasonService extends AbstractService {

	private static final long serialVersionUID = -7353982216625578326L;

	public SeasonService() {
		super.FORM = "Season";
	}

	protected final Season fromEntry(ViewEntry entry) {
		ViewEntryEx vex = new ViewEntryEx(entry);
		System.out.println("Retrieve season from entry");

		Season s = new Season();
		s.setDescription((String) vex.getColumnValue("Description"));
		s.setKey((String) vex.getColumnValue("Key"));

		try {
			entry.recycle();
		} catch (NotesException e) {

		}
		return s;
	}

	public boolean delete(Entity t) {
		// TODO Auto-generated method stub
		return false;
	}

	public Season get(String key) {

		if (key != null && !"".equals(key)) {
			Vector<String> viewKey = new Vector<String>();
			viewKey.add("Season");
			viewKey.add(key);

			try {
				ViewEntry entry;
				entry = DominoUtil.getEntryByKey(".AllDocuments", viewKey);
				return this.fromEntry(entry);
			} catch (NotesException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		return new Season();
	}

	public Entity set(Entity t) {
		System.out.println("Saving entity");
		if(t instanceof Season){
			Season season = (Season) t;
			Database db = DominoUtil.getCurrentDatabase();
			Document doc = null;
			if(season.isNew()){
				try{
				doc = db.createDocument();
				doc.replaceItemValue("Form","Season");
				doc.computeWithForm(true,false);
				doc.replaceItemValue("Description",season.getDescription());
				doc.save(true,false);
				season.setKey(doc.getUniversalID());
				}catch(NotesException e){

				}finally{
					try {
						doc.recycle();
					} catch (NotesException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}else{
				db = DominoUtil.getCurrentDatabase();
				try{
					doc = db.getDocumentByID(season.getKey());
					doc.replaceItemValue("Description",season.getDescription());
					doc.save(true,false);		
				}catch(NotesException e){

				}finally{
					try {
						doc.recycle();
					} catch (NotesException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

			}
		}
		return t;
	}

}

The most important parts for now are the GET and the SET methods. As you can see the GET method is capable of retrieving an entry by Key or create a new object (and what you also see is that when an object by key is not found a new object is created… #bug!). If no key is provided a new empty instance of the season class is returned.

When a key is provided the code will do a getentrybykey search on a predefined view. With this retrieved entry the season object is constructed using the fromEntry method. The fromEntry method is there because on another place in the code we want to retrieve data using a view entry as well. Namely the getAll Method. This retrieves ALL season objects using a predefined key / view name and from every viewentry a season object is constructed. Because I’m lazy and don’t want to write / update the same code on several places I created the fromEntry method.

Secondly the SET method. The set Method accepts an Entity object ( because we defined an interface for the repository object. We will talk about them later in another post.. maybe ). At the beginnning we check if the given object is of type Season. If so we create or update the datastore ( aka the notesdocument ). The update takes place only when the object is not new in other words when a key ( uniqueid ) is provided in the object. If the object doesn’t have such a key we assume the object is new and create a new document and save it. When the save succeeds the universalid of the document is saved into the season object. At last the season object is returned.

This code is not perfect. For instance what to do when the update/save of the season creates an error? Should we throw an error or should we return a null reference to tell the ui the code made a booboo? Anyways.. all comes to an end so this will conclude this little post about Java and xPages. I will , when the project progresses add some more info about Java and xPages. In the meantime. Stay tuned!

 

My thoughts about the org.opentf.domino api milestone 2.5

A few months ago there was a little fuzz going on in the openntf / domino community. There where some guys who wanted to go where IBM didn’t want to go. Updating the JAVA api that was available to us notes developers.

Since that moment there have been a few releases of the org.openntf.domino api and I decided to take a look and work with it on a little home project. One of my biggest hobbies is playing Wheelchair floorball. Every year it is a little challenge to keep track of the results, the current standings and so on because everything is kept in excel sheets that are downloadable from the official website. I want to have it on a website which gives me a direct overview of where my team is standing in the competition and for other people to see if their team is winning.  So why not create a xpage application from it. From the start I made the decision to use the new org.openntf.domino api to see how it works.

My first impression is.. wow. 

Of course there is the obvious ‘where did my .recycle’ go. The API takes care for that of us. Somehow ( have to check the source for it ) it keeps track of every object you create and recycle’s it when needed.

Secondly there is the iterator support on collections. If you have a NotesDocumentCollection or a ViewEntryCollection you are able to iterate over it using the usual iterator’s as many java developers are accustomed to.

Because I’m still playing around with the new JAVA api I will keep it at these two points. When my project has advanced a bit more I will write another blog about it.

oh btw.. there is a small thing I would like to be added to the API.

ViewEntry.getColumnValue(String name);

In a view you can add the programmatic name. The xsp wrapper of a viewentry is able to retrieve the data from a column by name. For some reason this Api won’t allow it. I think that it would be really nice asset because it makes the code a bit more readable (and that’s what it is all about.. ) see for yourself:

public class SomeFactory{

 public Vector<Some> getSome(){
     View vw = DominoUtil.getCurrentDatabase().getView(".AllDocuments");
     ViewEntryCollection coll = vw.getAllEntriesByKey("Some");
     Iterator<ViewEntry> it = coll.iterator();
     Vector<Some> l = new Vector(coll.getCount());
     While(it.hasNext()){
	l.add(fromEntry(it.next()));
     }
     return l;
  }

  private Some fromEntryOld(ViewEntry entry){
    Some s = new Some();
    entry.setProperty(entry.getColumnValue(11));
    entry.setNextProperty(entry.getColumnValue(14);
    entry.setAnotherProperty(entry.getColumnValue(1));
    return s;
  }
  private Some fromEntry(ViewEntry entry){
    Some s = new Some();
    entry.setProperty(entry.getColumnValue("Property"));
    entry.setNextProperty(entry.getColumnValue("NextProperty");
    entry.setAnotherProperty(entry.getColumnValue("AnotherProperty"));
    return s;
  }
}

This could be possible because inside the viewentry object you can call its parent. Retrieve all the column names and chekc if the given column was found in the namesvector. If so retrieve its index and do a simple getColumnValues().get(index);

ViewPanel vs. Dijit.Tree part 3… or not

I planned to write the 3th parth in these series in the next couple of days but something unfortunate has happened. By windows 7 install decided to crash. And ofcourse I didn’t backup my domino 9 beta data directory.. So the work I had done was lost. I appologize for this :(.

The upcoming weeks I will use to prepare a new box with domino 9 and to prepare for the 3th part of this series.

Software installation and %temp%

I justed reïnstalled my windows 7 notebook. One of the many drivers I need to install are the drivers for my nvidia graphics card.

When started it askes the user where to extract the setup files. So I set the directory to %temp%/nvidia .  The etraction process began and after it completed the installer returned with an error stating it could’nt find the installation files.

I was wondering two things

1) Why does the installer have to ask me where to put the extracted files if we the OS offers a TEMP directory

2) And secondly if you change the default path, why did the installation program got lost?

I see this much to often. Software that isn’t using the %temp% directory when it should be. If more software would utilize this shortcut it would be much much easier to keep your pc neat and clean..

>> EOF

CSS layouts

A quick post from me about layouts. If you are as lazy as I am and don’t want to use the application layout all the time but also dont want to burn up precious hours only finetuning CSS you could take a look at this page: http://layouts.ironmyers.com. It features a enormous amount of ready to use CSS layouts.

Easy to retrieve, easy to change. Have fun!

Enable autogrow feature of CKEditor

In a xPage project the customer asked us if the following would be possible: ” When the content of the richtext editor exceeds the height of the richtext editor we want to have it expanded” . And this is ofcourse possible!

The richtexteditor is based on the CKEDITOR plugin ( since 8.5.2 ). There is a plugin which does exactly that what the customer wanted. The Autogrow plugin. To enable it in your xpage you simple have to define it as an extraplugin using a dojo attribute. See the following line of code:

<xp:inputRichText value="#{document1.body}" id="rtNode">
 <xp:this.dojoAttributes>
  <xp:dojoAttribute name="extraPlugins" value="autogrow"></xp:dojoAttribute>
 </xp:this.dojoAttributes>
</xp:inputRichText>

This way you can add extra plugins you want to load in the ckeditor. If you want to have multiple plugins being loaded you only need to separate the plugin names with a comma. I haven’t found out yet how to add plugin settings using this attribute. 🙁

update: I tested it today on 8.5.3 fp1 and 9 and both seem to work perfectly.

ViewPanel vs. Dijit.Tree part 2

In this article I will describe how I converted. We will concentrate on how to use a restService control and how to get the data needed to load the first categories in the tree.

This in This
viewpanel grid

In the previous part of the series I explained a bit about how to create a simple dijit.tree and how it works. Now in this part I will explain how I used the restservice component from the extLib to generate a JSON structure which is compatible with the dijit.tree.

note: for these series you will need a copy of the fakenames.nsf file.

For those who are not familiar with the RestService control from Extlib. This control gives you the ability to create fairly easy an restfull service. I contains lots of default service types but for this tutorial we are going to write the Get method ourselves.We start by placing the following control on our xpage.

<xe:restService id="restService">
</xe:restService>

Configure the rest control

When we open up the properties pane we will see that the control offers a great deal of properties. The first one we will look at is the pathInfo property.

pathinfo

This property will tell the service when it should be rendering. A rest service typicaly is accessed by an http get, post, put or delete call. Therefore it needs an url identifier. Lets say we named the xpage api.xsp. And we define /names/  as the pathInfo. This way we can access the restService with the following url

http://yourdomain/database.nsf/api.xsp/names/

Now lets try it. You will notice that the service returns an empty string page ( among some header information). This is ofcourse because we told the service when to render but we didn’t tell it what to render. For this series it is enough to add the code that should be used in the Get call.

In the properties list expand the following path basic / service.  There are lots of properties but for now the following are the most important.

Property Description
doGet SSJS code that is being executed when the user does a get on the rest service
contentDisposition content disposition header
contentType Defines how the response ( which you will receive from the service)  is being formatted. Aka: which headers are being send out

Lets fill the doGet method. Open up the SSJS editor of this property and add the following code:

if(!isCategory(context.getUrl())){
	return getCategories();
}else{
	return getCategoryContent(context.getUrl());
}

Now add a SSJS library to your application and add the following lines of code:

function isCategory(url:XSPUrl){
	return false;
}

function getCategories(url:XSPUrl){
	var v:NotesView = getPeopleView();
	var nav:NotesViewNavigator = v.createViewNav();
	nav.setCacheGuidance(25,NotesViewNavigator.VN_CACHEGUIDANCE_READALL);

	var entry:NotesViewEntry = nav.getFirst();
	var nEntry:NotesViewEntry = null;
	var list:org.json.simple.JSONArray = new org.json.simple.JSONArray();

	while(entry != null){
		nEntry = nav.getNextCategory();

		if(entry.isCategory()){
			var values = entry.getColumnValues();
			var json:org.json.simple.JSONObject = new org.json.simple.JSONObject();
			json.put("$ref",values.get(0));
			json.put("name",values.get(0));
			json.put("children",false);
			list.add(json);
		}

		try{
			entry.recycle();
		}catch(e){

		}
		entry = nEntry;
	}
	try{
		nav.recycle();
		v.recycle();
	}catch(e){

	}

	return list.toJSONString();
}

function getPeopleView(){
	var v:NotesView = database.getView("(CountPeople)");
	v.setAutoUpdate(false);
	return v;
}

As you can see this code is fairly easy. It first checks if the request made is a category only request (currently it defaults to true ). Next on it will retrieve all categories from the view on the first level. ( See fakenames.nsf for details of the view ). Last but not least add this library to your xPage.

When we visit http://yourdomain/database.nsf/api.xsp/names/ you will get a result which looks like like:

[{"name":"A","children":false,"$ref":"A"},{"name":"B","children":false,"$ref":"B"},{"name":"C","children":false,"$ref":"C"},{"name":"D","children":false,"$ref":"D"},{"name":"E","children":false,"$ref":"E"},{"name":"F","children":false,"$ref":"F"},{"name":"G","children":false,"$ref":"G"},{"name":"H","children":false,"$ref":"H"},{"name":"I","children":false,"$ref":"I"},{"name":"J","children":false,"$ref":"J"},{"name":"K","children":false,"$ref":"K"},{"name":"L","children":false,"$ref":"L"},{"name":"M","children":false,"$ref":"M"},{"name":"N","children":false,"$ref":"N"},{"name":"O","children":false,"$ref":"O"},{"name":"P","children":false,"$ref":"P"},{"name":"Q","children":false,"$ref":"Q"},{"name":"R","children":false,"$ref":"R"},{"name":"S","children":false,"$ref":"S"},{"name":"T","children":false,"$ref":"T"},{"name":"U","children":false,"$ref":"U"},{"name":"V","children":false,"$ref":"V"},{"name":"W","children":false,"$ref":"W"},{"name":"X","children":false,"$ref":"X"},{"name":"Y","children":false,"$ref":"Y"},{"name":"Z","children":false,"$ref":"Z"}]

Creating the dijit.tree

With this response we can start to customize the dijit control we saw in party 1. Open up the xPage where you pasted the dijit.tree code from part 1 on. Or create a new xPage with the code from part 1. We have to make the following adjustments to the code.

    dojo.addOnLoad(function() {

// Create a data store to retrieve data from
var store = new dojox.data.JsonRestStore({ target: "api.xsp/names/",labelAttribute:"name"});

// secondly we create a treeModel. A treemodel are the classes / datastructure 
// on which the tree is running
        var treeModel = new dijit.tree.ForestStoreModel({
            store: store,
            rootId: "undefined",
            rootLabel: "alphabet",
            childrenAttrs: ["children"]
        });

// Last but not least we create a new instance of our tree. 
        new dijit.Tree({
            model: treeModel
        },
        "treeOne");
    });

As you can see we replaced the store with an instance of JSONRestStore. Since we retrieve our data from a RestService we need to have a correct way to interact with it. A JSONRestStore retrieves its data a restfull way. This means it will read /api.xsp/names/ and when we click a node it will read /api.xsp/names/A till Z ( depends on the node ofcourse ).

Next we create a new TreeModel. In this model we define the rootId ( undefined since there is none..) and we set the default name of the root. The last attribute tells the tree at which attribute name in the JSON it should check for children.

This concludes the second part of this series. We have a nice little dijit tree which only shows the first categories as nodes. I showed you how to create a simple RestService using the RestService control and some lines of SSJS and how we can use this data to populate a dijit.tree.

In the next part I will explain how we can change the SSJS so it will retrieve leaves ( aka content of a category ) when the tree needs it and I will show you how to add lazy loading.

update: Changed code for the getCategories call . It should be isCategory = false 

xPages and Beer 12-06-2013

Yesterday I attended a new edition of the xPages and Beer sessions. xPages and Beer is an initiative started by some very great xPages developers to share their knowledge for anyone who wants to attend.

The very first edition started with around ~10 people and yesterday a stunning crowd of 20! people where attending. It realy shows that gatherings like these are wanted by the community. During the session we saw three presentations done by different people

Peter Pennings – Ilionx : Mobile xPages.

During his presentation Peter talked about an application he  created for the newest blackberry. The idea behind the application was that it retrieved it’s data from ‘a’ source and saved it locally on the phone to update it the next the time the user wanted or came online ( if I understood correctly ). Althrough the application itself was not made with the mobile xPage controls (which I actually hoped to get some more information about ) the data is being retrieved using an call to a xAgent. This realy shows the power of xPages.

Thimo Jansen – Defrog: xe:ObjectData ( link )

The second, and for me personally the most interesting session, was about the use of the xe:Object data. xe:ObjectData were introduced in the extension library quit some time ago. xe:ObjectData is a new type of datasource. Instead of using a document or a view you can now use a Pojo as the model of your xpage. I’ve used them in the past but didn’t quit understand the need for them because sooner or later the data is saved to a notesdocument anyway. Now with the presentation from Thimo I’m eager to use them again in future projects!

Mark Leusing: Debugging / Debug toolbar (link)

During the last presentation Mark talked about his debug toolbar (which every xpage developer should be using.. !) and about java  / ssjs debugging in general. Now with the remote debugging capabilities  in Notes 9 and the debugtoolbar at hand there really shouldn’t be a reason for a developer to use print! ( so called poor man’s debugger ) statement anymore.

Many thanks to every one for organising this event and see you next time!

update: Added links to a presentation about debug toolbar and xe:objectdata