Monday, December 29, 2014

Using Domino Designer's 'Sign Design' to solve strange Java exceptions

Today, I reached out to another XPages developer who works on the same project in order to help me get past a strange error I was getting. The issue was that Java code within an XPages application that previously worked fine started failing, even though it had not been altered. He had experienced this issue before and knew what to do to fix it. The fix I am about to describe was new to me, so I felt it was worth sharing here.

The exception I was getting was this:
javax.servlet.ServletException: java.lang.Error: Unresolved compilation problem:  

When I first got the error, I naturally thought that it was something that I had changed. I didn't know what to make of an unresolved compilation problem, it seemed a bit generic, like the check engine light on your car. Even after I was able to isolate the line causing the problem, it made no sense because it was run of the mill Java code, the kind of snippet you use and reuse. In this case, it was a variable resolver that gets a handle to the current session.  

My coworker suggested performing a "Sign Design" on the whole application. To do this, right click on the application name, then click "Application", and then "Sign Design". Sure enough, this fixed the issue, no more Java exceptions. This is one of those fixes that is worth trying when nothing else is making sense. Of course this issue is most likely to happen for applications where work is shared by a team of developers, as is the case here. The downside of this fix of course, is that you lose some of the history, and it looks like you touched every design element.
The way to find the option to Sign Design is to right-click on the application title, and choose Application, and then choose Sign Design.

PS:  I want to wish Best Wishes for 2015 to all who stumble across my ramblings.

Sunday, October 19, 2014

Quick Tip: Forcing a CSS override

If you are using OneUI in your XPages application, then you know sometimes it just doesn’t do what you want it to do. Trying to get it to behave can be frustrating, this tip will help when OneUI overides your custom style for reasons unknown.

The Problem

In my case, I was trying to make the labels of a radio button group appear disabled. Only the buttons themselves would look disabled, but the labels looked the same as when the control was enabled.
I don't feel that there is enough distinction between Enabled on the left, and Disabled on the right.
The radio button group control does attempt to make it easy by having a property to enter the styleClass for when the control is disabled or enabled.

XPages makes it easy for you to specify a disabled styleClass
This works fine for most of the CSS, except for some reason the color is overwritten as shown in the left picture below. I spent a lot of time playing with multiple CSS selectors with no success until I discovered how to force the CSS to override.
For some reason the "color" is overwritten by OneUI

The Solution

The way to override is to add “!important” after the attribute you don’t want to be overwritten. In my case, the only attribute that wasn’t behaving was the color. After I added !important, it worked exactly like I wanted. In the right picture above shows what this one change gives you.

Here is the Before code:

.radio-disabled {
font-size:14pt;
font-family:Calibri;
color: #AFAEB5;
}

Here is the After code:
.radio-disabled {
font-size:14pt;
font-family:Calibri;
color: #AFAEB5 !important;
}

The Finished Result

Enabled on the left, disabled on the right. It is easy to distinguish which is which.

Final Thoughts

Perhaps this is old news to some who read this. Though, in my office, none of the four XPages developers knew about this before. I hope that this helps other XPagers who wrestle with OneUI.

I will add that, this should be something that is used sparingly. In my case, only the specific class of “.radio-disabled” is using it. I can see that you could really mess your UI by overusing !important. Here is a related article called “Don’t Use !important” that explains some of the pitfalls.

Thursday, October 9, 2014

My First Experience Using the JSON-RPC Service.

This is one of those posts, where I am writing to my future self so that I can remember all that I learned about using the JSON-RPC service.

If you are an XPages developer who is interested in learning about this tool then I first suggest checking out the following resources:
  • This email response to a question by Tim Tripcony is sheer brilliance. I had to read and re-read this several times to really understand it, but that speaks all about me and nothing about how Tim explains things.  A big thanks to David Leedy for making it available to all.
  • Keith Strickland has written a very helpful blog post on JSON-RPC way back in June 2011. It was Keith who first turned me on to the Remote Service control when I found his answer to this Stack Overflow question.


How I and why I used the JSON-RPC control

I needed to run a server based Java method that called a process and returned a result. My requirements stated that I need to try this process twice in a single event, and tell the user if the first try has failed. The way that Java works is to always one return value, so the intermediary messages would never be returned. In order to accomplish what I needed, I knew that clientside javascript was my best bet. In order to call a serverside java method from clientside JS, I decided to use an JSON-PRC call.


How to create the JSON-RPC service

1) Pull the tool from the pallet under “Data Access”. It is just called “Remote Service”.



2) Give the service a serviceName and/or a pathInfo. I believe that the service may be referred to as either.



3) Create the methods that you need to run. This will involve adding optional arguments and adding SSJS code to run in the script property. The script property doesn’t use the standard script editor that is usually used when you can enter serverside javascript.



4) The finished result

Using the Remote Service

It took me a while to understand that the service doesn’t return a value initially, it returns an object that contains a callback method. The callback method actually returns the value. Thanks to Toby Samples who answered my Stack Overflow question helping me with this.

Here is the code where I call my remote service methods:

Code Explanation:
  1. First the code shows the user a message that the process is starting
  2. Next, a value needed in one of the messages is pulled from a hidden input
  3. The RPC method is called, the object returned is assigned to the var “deferred”
  4. The callback of the object is called to get the result of the ‘first’ method
  5. If the ‘first’ method returns true, the user gets a success message
  6. If the ‘first’ method fails, the user gets a ‘retrying’ message, and the second method is called and the resulting object is assigned to a var “insideDeferred”
  7. If the result of the ‘second’ is true, the user gets a success message
  8. If the result of the ‘second’ method is false, the user gets a ‘try later’ message.

A slight problem

This code all worked great, except… it ran so fast that the ‘trying again’ message appeared too quick for a user to read. I spent a lot of time trying to figure out a way to use timers to slow it down. Eventually I decided that I was spending too much time on this, and used an simple alert for that message, which fulfills my requirement and allowed me to get moving with the rest of the project.


Parting Thoughts

Now that I understand how the Remote Service is used, I am sure I will find more uses for it.  It is an important tool in any XPages developers toolbox.  I can also see it being an important part of web applications that use a Domino backend and frontend Javascript frameworks like Angular JS.

Wednesday, August 20, 2014

Trouble Using the Jar Design Element in XPages

It has been a while since posting, I have not forgot about blogging, but really have not done anything blog worthy.  In one of my projects, we have to talk to a mainframe application (not the tables) and perform various tasks.  The mainframe connection is made through Hostbridge technology, and packaged for me by our java developer in a jar that I can interact with using the java beans I use for business logic in my application.

As we are in proof of concept mode, the java developer sends me the jar every time he makes a change and I place it in my NSF using the new Jar design element. Unfortunately, so far it hasn't been as easy doing this as I expected.  I dropped the jar file in, and then was able to write code to call the public methods using the java bean.  So far so good, after adding the proper imports the code compiled fine.

At runtime, it would choke and give me a NoClassDefFoundError exception. This of course is really confusing because to me, the time to decide that you can't find the class should be compile time. I tried several times cleaning and rebuilding the application before turning to Stack Overflow with this question: http://stackoverflow.com/questions/25371817/the-contents-of-jar-file-not-found-using-jar-design-element-of-designer-9

I recieved two helpful answers from Stephan Wissell and Frantisek Kossuth.  The first thing I tried was removing the application, re-adding and verifying the build path which Stephan suggested.  This worked, and I was able to continue on without getting the same exception.

The next day it was necessary to change the package name we were using inside the jar.  I was able to fix my own java code by correcting the import and again it compiled fine.  Unfortuately at runtime,  I started getting the same NoClassDefFoundError exception again.  This time nothing I tried worked.  I spent a long time checking build paths, and trying to use the WebContent/WEB-INF/lib instead of the jar element.  I did discover along the way that the jar element actually places the file in the the lib folder on its own.  I also discovered that the Package Explorer makes it appear that the file is not there, but if you use the Navigator instead you can see that the jar file is present in that folder.

Franitisek in his answer, linked to another Stack Overflow question, one that I discovered before I asked my question.  In that question, the person who answered Panu Haaramo made a comment on his answer directing the OP to this blog post: http://lotusandjava.blogspot.com/2012/10/xpage-javalangnoclassdeffounderror.html

In this post, the author remarked that the only thing that worked was renaming the class.  So instead of renaming any classes, I decided to rename the jar file using the right-click menu option rename.  I did not rename using the O/S or have the java developer send me a new jar.  To my amazement, this worked, and the exception went away and I am now back in business.  I probably spent at least 4 hours at work today struggling with this issue, so I am hoping this post will save someone that trouble.

The bottom line

If you are getting a NoClassDefFoundError exception and using jars, try renaming the jars using the right click menu. It is easy, and it just might work. (You can always rename them back later, although I haven't actually tried that yet)

If someone at IBM sees this post, this might be something to look into fixing in the next release. :)


PS.  I am looking forward to attending MWLUG next week, hope to see some of you there.

Tuesday, June 24, 2014

Integrating Datepick.js into your XPage

No, Datepick.js is not another Javascript framework; it is simply a super awesome jQuery plug-in that I recently discovered, and put to use in my latest XPages project. 

There are many calendar plugins to use with jQuery.  Here is an article where someone decides which are the top ten. I entertained using some of these, specifically #1 and #6 in the list, until I discovered "jQuery Datepicker" by Keith Wood, which for some reason was not on this list. Once I discovered this one, I knew straight away that my search was over.  In this post, I will show you how I used jQuery Datepicker (datepick.js) within an XPage. 

Generally, this calendar is used like most datepickers, where it is shown via a button and then hidden again. However, i
n my use case, I wanted a full month calendar that was always visible in the left side navigation as shown below.  Below is the 'finished' result.

This is the finished result. The random number is there so I know it refreshes, but later will be meaningful content.
















How I made it work

The first step is to download the source and copy it to your WebContent folder in your application. I recommend creating a "js" subdirectory and placing the files in there.  You then need to reference the files in your XPage using the <script> tag.

Step 1:  Download and add to page

The second step is to create a place to put the calendar and give it a class. I created a panel and gave it a class of ".calHere". 
Step 2 - Add a class where to put the calendar
The third step is to create code to launch and process the calendar.  In the onClientLoad event of the panel, I have the following code. 
Step 3 - Format the calendar and figure out what to do with result

Code Explanation 

First it launches the calendar, and then assigns a function to the calendar's onSelect event.  Finally, it also prevents the user from selecting weekends, which is something in my specific requirements.   

Here is how I went about updating the backend data with the value selected in the calendar:
  1.  I first format the Javascript Date using moment.js, as very useful utility for all things time.
  2.   Then update a hidden input control in the content panel with the formatted date.  I make use here of Marky Roden's X$ function for selecting Domino ID's in jQuery.
  3.   Lastly, I force a partial refresh of the content panel using the built-in XSP object.
I am very pleased with how this came out.  I highly recommend that everyone at least become aware of Keith Wood's jQuery Datepicker.  The datepicker has every imaginable way that it can be customized both in functionality and style.  I wish I discovered this a long time ago.   

Monday, June 9, 2014

Force your expired XPage to return to the login page

One of things that I have found annoying about XPages apps is that an application page left open in the browser for a long time will act like it is usable, but in fact the session has timed out and the page is unusable. When you try to actually submit anything the page will fail, and you will have to re-login.  I work for a bank now, where they are very concerned with security so I wanted my application to work similar to most financial websites.  In addition, I find a page you can't use a very poor user experience.  I had some time while the project is ramping up, so I decided to do something about it.

In this post, I will go over a simple way to force the page to redirect to the login page after the session expires.  I was actually surprised when I researched this that I couldn't find anyone who had already done it.  I put this Stack Overflow question in, and Stephan Wissel answered it and pointed me in the right direction.  He reinforced what I suspected that I would have to do this entirely in the client.

What does it do, how does it work

The concept here is pretty simple, when you load a page it sets a timer.  Whenever you submit anything to the server, or switch tabs in the application the timer is reset.  The timer accepts two parameters, the time to wait, and the page to redirect to.  The function does NOT log you out, that is what happens automatically by the server, this simply makes the client aware of what already happened.  In my case, I redirect to the application home page, so that after the login is re-entered it goes where I want it to.  It would be easy to just make the function refresh the current page.

var timeoutID; 
function setAutoRefresh(refreshTime, relativePath) { 
        if(timeoutID){ 
                window.clearTimeout(timeoutID); 
        } 
        timeoutID = window.setTimeout(function(){ location.replace(relativePath);}, refreshTime); 
} 


The same function will work for setting and resetting the timer.   Not sure why you would, but if you wanted to, you could have any number of timeouts on a page by giving them different variables.

You call the function like this:
var pathArray = window.location.pathname.split( '/' ); 
var path = "/" + pathArray[1] + "/" + pathArray[2]; 
//returns relative path to application home, example: "/atm/atm.nsf" 
//1860000 represents 31 minutes, one minute after session timeout 
setAutoRefresh(1860000, path); 

I made my timer set to one minute after the default 30 minute session logout.  The way this is written now, if the time was set less then it would redirect to the page and skip the login page which to me defeats the purpose. One warning, if you miss resetting the timer then the page could redirect unexpectedly.  In my application, I call the function from the onClientLoad of my layout custom control once and then in each button that perform updates. Note:  If you are not using a layout custom control, then you will have to put this in the onClientLoad of every XPage.  

Potential Enhancements

The code I wrote is pretty basic, maybe too basic.   Here are a two ways that you could make it more robust:
  • When the timer is up, you could create an ajax call to ping the server, and then redirect the page if you get returned a "Not Authorized" message.  If the session is still active you could reset the timer.  With this method, you could load it once, and just have it run every ten minutes, and never have to worry about it.  
  • Another enhancement, would be not reset the timer when you switch tabs or submit anything, but instead reset if based on a mouse moving event.  I considered this but thought it overkill for the application I am writing and didn't want to be calling the function non-stop. 
If anyone had any better ways of doing this, or anything to add, please comment.



August 2016 Edit:  


For some strange reason David Leedy is unable to comment on my blog so I am adding his comment here.

I'm adapting this code for my day job and also a future MWLug presentation and maybe even NotesIn9. I had problems with the code as it seemed to hardcode in the level of folder nesting. I ended up using this:
var thisUrl = window.location.href;
var lastSlash = thisUrl.lastIndexOf("/");
var dbPath = thisUrl.substring(0, lastSlash);
var finalPath = dbPath + "?Logout&redirectto=" + dbPath + "/sessionExpired?OpenPage";



console.log("dbPath : " + dbPath);
console.log("FinalPath : " + finalPath);

//1 minute = 60,000 milliseconds
setAutoRefresh(60000,finalPath); 

Thanks to both you Steve, and Daniel for this post and comment! 

Wednesday, May 21, 2014

Angular JS - Another Tool in your XPages Toolbox - Part 2

In my previous post, I shared my reason for wanting to try to learn how to use Angular within an XPage.  In this post, I will show you how I used Angular to duplicate the functionality of a Dojo data grid on the same page.

My Existing XPage

In my existing XPage, I use the Extension Library REST service control to return data based on what the current user has rights to see.  The REST service use a formula for "keys" which filters the data based on the first column.  The REST service outputs JSON which is read by the Dojo Data Grid.
Dojo DataGrid 
There are two thing that have always bugged me about the Dojo grid that I created.  The first was that I could never get column sorting to work.  It seemed to have a conflict with the user of the keys property that I could not overcome.  The second thing that bugged me was that I could not get the grid to behave in a responsive manner.  When I shrink the screen, the Dojo grid would not shrink with it. I accept that it is possible that in both cases I was doing something wrong there, but I did spend a lot of time trying to get those things to work.

Grid using Angular

Since I duplicating what I did with Dojo, I used an Angular plug-in called ng-grid.  I used the very same JSON data to display the grid inside a <div>.
Grid using Angular
The Angular Grid not only looks good, but the column sorting works as well.  This grid is naturally responsive and solves my two big gripes with the Dojo grid. 

Look, I'm responsive

The 'How To' Section

Before I go through my steps, let me say that this is not a beginners guide to Angular, to really understand it.
There is a lot of information out on the web on Angular. I highly recommend Mark Roden's latest series on Angular which takes a methodical approach that is easy to follow.

1)  First you have to load the library on your page.  After downloading Angular from Google, I copied the library in a folder I created under the "Web Content" subdirectory.

2)  I then referenced the library using a <script> tag in only the page where I used Angular.  Use Firebug to check that you loaded everything correctly.
3) I then create a Controller file and call it grid-controller and place it is a subdirectory under the "Angular" folder under "Web Content".   Repeat step 2 for the controller file, making sure to account for the subdirectory in your script tag.

4) Normally for a page using Angular, you will add an attribute to the <html> tag of "ng-app" telling Angular that you are using it on the whole page.   In my case, I added the "ng-app" attribute to a <div> on my page.  I actually used a <xp:panel>, and set the tagName to render as a <div>. I did it this way because I wanted to show how you would use an XPage control where you also decide whether to render the grid based on certain conditions.  The easiest route though, is to pass HTML through like in the second example below.

This is all the code needed on the custom control.  Note: Once div is nested in the other.
This is how it would look if you pass the HTML straight through

5) Angular also needs you to specify the name of the Controller to use for a specific element.  A normal Angular application might use several controllers throughout the page to connect the data to the display.  You tell Angular which one for a specific section by using the ng-controller attribute. In my case, I am only using a single controller that I set in the same <div>.  Besides setting the style, that is all I have on the custom control.

6)  In my controller, I need to tell where to get the model (data) to send to the view (XPage).  As I stated above, I am using the same JSON data as the Dojo Grid.  To access the JSON, I use $http.get() method to read the URL of my REST Service.  Remember, you can the pathInfo attribute in your REST service, which allows you to see the JSON in a URL. I set my pathInfo to "restData".  The result is set to a variable called $scope, which acts as your return value of the controller.

The Controller which in Angular connects the data and the display
From line 8 to the end is specific to the ng-grid plug-in which I explain below. Everything outlined up to this point is all you need to test out Angular in your XPage.  Before I added the grid to my demo, I was able to display the whole list using ng-repeat. I was also able to reference the data is $scope using direct references like this {poDoc[0].Status}}  The controller returns an array in this case. I could have done anything you can do in Angular to the data. I encourage you to give it a try.

The last part of the code refines the $scope to sets options and format for the grid.  In order to get the grid to work it had to be in its own <div> that was a child of the <div> where I set the ng-app and ng-controller.  The grid is not part of core Angular so in order to use it I did had to download and a separate javascript and css file. To find ng-grid look here, note that it has a dependency on jQuery. It gets a thumbs up in my book.

Where to from here

I am really intrigued by Angular, so I will continue to experiment with it.  Next, I would like to enhance the example here to allow the grid to launch documents and perform searching/filtering.  If the result is worth sharing then I will make a part 3 of this series.

Sunday, May 18, 2014

Angular JS - Another Tool in your XPages Toolbox - Part 1

Around this time last year Twitter Bootstrap was becoming the big thing in the XPage Community, and a year later it is widely adopted and has become another tool in your XPages toolbox.  Not that they are that similar but it seems that Angular.JS is now becoming the next big thing for 2014.

For the last several months I have observed with high interest as Mark Roden, Mark Barton, Jeff Byrd and perhaps others from the community have discussed Angular and other noun.js frameworks (backbone, ember, etc).  One common theme that I have noticed is the enthusiasm of eliminating everything front end that XPages provides and only using Domino for the security model and to serve up pages and JSON data.

I must admit that I am a little bothered inside when I try to understand what they are advocating. What bothers me is that I like XPages and what it brings to the table.  I like my XPages toolbox, and while I am always interested in a shiny new tool, I am not interested in trading it for another toolbox.

I totally respect those guys reasons for advocating their approach to front end javascript frameworks, and I am glad they are pushing the envelope in that area, and grateful they are sharing their knowledge.  When I say I am bothered it has more to do with my opinion that you can have both.  I would be lying if I didn't say the investment in time I have made to learning the whole XPages platform didn't have something to do with it.

To be clear, Marky is not saying everyone should follow his path, but as one of the leading bloggers in our community there is a certain pressure to follow the leader.  Speaking of leaders in our community, there is tangible vacancy as we all mourn the loss of Tim Tripcony.  It saddens me that I won't see Tim comment on this post as he sometimes did with others I wrote.

Given this background, I have set out to learn Angular.JS by creating a proof of concept for using it within an XPage.  I have decided to duplicate the functionality of a Dojo Data Grid using Angular.  In this two part blog series, I will show you how I used an Angular.JS within an existing Xpage.

Disclaimer:  

There is always a chance that after time passes, and I become more comfortable with the Angular framework and what all it can do, that I will agree and even advocate with what Marky and others have proposed.  I reserve the right to change my mind.

Learning Angular:

I really can't say that I know Angular that well, as I write it is only 7 days since I first dug into it.

Here is what I did to get up to speed:
  • First I read Marky Roden's blog series, which inspired me to dig deeper.  
  • I next turned to one of favorite resources, lynda.com and watched the course "Up and Running with Angular.JS" by Ray Villalobos.  Ray is one of the my favorite instructors on lynda.com and has a great website with the most awesome URL for a web developer - iviewsource.com
  • After I finished the course, I read Marky's blog post again, as well as those from Mark Barton and Jeff Byrd
With this background, and the assurance from Marky that is was possible, I dove right in my goal of making Angular work within a <div> of an existing XPage.  In part 2, I will share how and what I did.  I will even show how what I added was better than what I used before.

Sunday, April 6, 2014

New Opportunities

It might be a while before I have another blog post.  Two days ago was my last day working for Harmons Grocery.  It has been an awesome 20 months for me.  I feel proud of the work I accomplished here, and feel that I have made a difference.  What more can you want from a job?

The vast majority of my time here was spent on two large projects that improved the way that Harmons runs their business.  I really appreciated the opportunities to develop in XPages; while here, I feel like I have gone from an XPages newbie to a seasoned Xpages developer.  Of course, there is much more that I want to learn going forward.  I have a long list in my Connect 2014 notebook of topics to learn this year.

In the next few days I have lots of work to do getting prepared for a cross country move.  It will probably be a month or more until I check in again.  I am looking forward to blogging about XPages from a different angle that will come from a change in surroundings.  It is very encouraging to me when people tell me that they enjoy my blog and to keep it up.  

Thursday, March 20, 2014

Opening Documents when Using a Dojo TreeGrid

In my last post I referenced some of the styling challenges I faced when using a Dojo Tree Grid.  At the end of this post I will document them so that I would not forget what went into fixing them.  It was also a challenge to figure out who to open documents in a TreeGrid.  Thankfully this challenge was fixed much more easily and quicker than the styling issue.   In this post I will explain how to open documents using a Dojo TreeGrid.

When using a Dojo TreeGrid, you create a Panel that contains the grid.  The code for the grid itself is contained in a Output Script.  There are no extension library controls for the TreeGrid.  You create this in a similar manner to how you would an EXTJS grid.  For a comprehensive blog series on all things Dojo Grid please visit Brad Balassatis' blog

To make the Grid entries clickable, you have to add an event to the Panel that contains the TreeGrid.  This event must be manually added as follows.

1) Go to the All Properties of the Panel
2) Create a new attribute (attrs)
3) Name the attribute "onclick"
4) Enter the value as clientside javascript (more on this below)



The part that is somewhat confusing is that the value must be properly formatted javascript that is static text. If you compute the value then you do NOT have clientside javascript as a choice.  I believe that I found that this only worked when it didn't contain any carriage returns.  

The javascript code I used is as follows:
var grid = dijit.byId('#{id:treeGrid}'); var index = grid.selection.selectedIndex; var item = grid.getItem(index); var unid = item["id"]; var url = "/po/po.nsf/New_PO.xsp?doc=" + unid;if(unid.toString().length == 32){ window.document.location.href = url;}

The first line gets an handle to the grid.  The second line gets a handle to the grid index where your mouse is. The third line is getting the "id" of the row where your mouse is.  The fourth line is building a URL string using the id that you obtained.   

The fifth line is key.  Because each row has an "id", sometimes the id is the category value, and sometimes the id is the UNID of the document in that category.  I had no success trying to change the label of "id", it just breaks the grid.  The if statement checks if "id" is equal to 32, which is the length of a UNID.  If the "id" is not the UNID then it does nothing.  

The last thing I did was to change the pointer to a hand.  I did this by adding a second event attribute to the panel and calling it "onmouseover" and giving it a value of $('#treeGrid').css('cursor', 'pointer');

The only negative here was that the hand cursor is there even for the category rows that do not open.  I also see a potential bug here is you had a category size exactly equal to 32.

The Grid Styling Fix

The styling fix turned out to be that I was not using a theme that extended WebStandard.  Adding WebStandard fixed the styling issue but broke other things.  The fix is to add the dojo.css to your page as the first stylesheet and then also give the containing panel a class of "view-panel".  Thanks again to Brad Balassatis for figuring this out for me.

If your Dojo Tree Grid looks like this then use the fix above to correct the look.

This looks much better

One More Thing

I tried to make a Dojo TreeGrid using a view with two categories but was unable to get it to work.  If anyone knows how to do this, I would love to hear it.

Tuesday, March 11, 2014

How to Load a Different Theme for a Specific XPage

You would think that what I am about to describe would be something that it easy and straightforward but it is certainly not. In the post I am going to go over the two best ways to use a different theme for a specific XPage(s) in your applications.

This post is based on my own experiences, and experiences gained from this Stack Overflow question that I asked.   Thanks to Toby Samples and Tim Tripcony for your answers which are paraphrased below.

The Problem

For whatever reason, whether you are having CSS conflicts or a different reason and you want to use a different theme for a certain page and leave the rest of the application alone.  The assumption here is that you have a theme that you like for the majority of your application.  You have already set that theme in the XSP Properties of the application.

Fix #1

Set the session variable in each XPage to set the theme.  When you set the theme name in the XSP Properties, you are actually setting a session variable called "xsp.theme" that tells the XPages machine what theme to load.  If you want to load a different theme it is a simple fix, just set the variable to another theme.  To make this work, the catch is that you have to set this on every XPage in the application.   The code will look something like this:  context.setSessionProperty("xsp.theme", "alt-theme"); You would place this code in an event in each XPage.  I don't know which event would be the best, but start with BeforeRenderResponse.  The code that you place in the other XPages would set the xsp.theme property back to the name of the primary theme.

Fix #2

Use a complementary NSF to hold the XPage that use the alternative theme.  The fact that the application is split into two NSF's will be seamless to the users.  Tim Tripcony make a compelling argument to the benefits of this approach.  The chief benefit in my opinion is that you leave the rest of your application alone.   This approach seems like the easiest to implement if you are pressed for time.

What Approach did I go with?

I was going to go with Fix#1 but before I got a chance to do that, my friend Brad Balassaitis emailed me that he had figured out why I was have CSS conflicts and how to fix them and thus eliminated my need to use an alternative theme. Thanks again, Brad.

Monday, February 10, 2014

Using an EXTJS RowExpander in XPages

If you are an XPages Developer, or better put, a Web Developer who creates world class applications using XPages, then you should either be using EXTJS or it should be on your radar.  If you want to see a comprehensive blog series on EXTJS then start here on Mark Roden's blog.  Mark also gave a presentation at IBM Connect 2014 that showed off some of the really cool things you could accomplish with EXTJS.

Of the features that Marky very briefly touched on during his Connect session was the ability to add a RowExpander to display more information about the row above.  This feature is great when you have more information to display than the available screen real estate will allow.   In this post, I will show how I used a Row Expander in an EXTJS grid within an XPage.

The Problem

In my Purchase Order application, I needed to display Line Item information in a grid.  At a minimum the line items had 11 columns, and some types had 15 columns.  In addition, I also needed to display the quantity that each store ordered, as well as something called "Shippers" which are tied to individual line items. Shippers are a box that contains a variety of different product UPC's in case you are wondering.  I did not want force the user to have to click on each line item and open another page just to see this information.

The Solution

I used the Row Expander plug in to display my store quantity and shipper information.   The Row Expander simply adds a column with a +/- that allows you to display additional information.  The table in brown, shows store quantity, and the table in blue shows Shippers.  (All of this will be immediately apparent to users of this system)

The Finished Result
(The second line item contains Shippers, the first does not)

How I did it

To use the Row Expander, you can only provide it straight HTML, no facets here.  You have to build the HTML yourself, and then make sure it is dynamic.  It is sort of like the way that you did things using traditional Domino web development.  I designed both tables differently due to the fact that 'Shippers" are separate documents, and the Store Quantities are part of the line items.  


Building Store Quantity Table

Think of the Store Quantity as information that I couldn't have fit in the columns due to space.  This is the table with the Brown headers above.  In this case I built that table using JSFiddle until it looked how I wanted it.  The actual numbers are pulled from a view using the REST service, just as you would for any column.  Note:  I used a Rest Service of type "ViewJsonService" that uses a categoryFilter to only pull data relating to the current document.
 
Columns used in the table are read from the REST Service
Once the data is pulled from the view into the Rest Service, you can read into the table you created by placing the name is curly braces.  Don't judge me on the use of the <style> tag for this usage.  The data is always fresh because it pulls from the view at runtime.
All of this code builds the first table, with the exception of the last fourth of the final row.

Building the Shipper Table

Think of the Shipper table as any other data you want to put in the row expander.  In my case, the Shipper is a separate document, so the contents of each are not included on the Line Item documents.  I guess I could have built some multi-value fields and place the shipper details in those fields, but that sounded really painful. What I decided was that after the creation/editing of the Shippers, I would dynamically build the table and save it to the related Line Item.  

Upon completion of a new or edited Line Item, I run a java method I wrote that is shown below to created the table and write it to the parent document.   I then display the table HTML in the view that the Rest Service pulls from.   I then pull the column in the Rest Service, and display it in the Row Expander.  In the above screenshot, the column is "ShipperHTML".

There is nothing really hard about the java code to created the table.  I will point out that I used StringBuffer to build the table, which is more efficient than using a String.  The rest of the code should be straightforward, even if you don't know java well.  This method lives in a managed bean that I use to track the progress of the each Line Item as it is being created or edited.  I call the createShipperTable() method from the method that saves the Line Item to the backend document.

Java method to build Dynamic Table

Conclusion

The Row Expander is just one of the many useful features of EXTJS.  I hope this post is helpful if you ever need to use it.  I also hope my need to use application specific references didn't take away from the understand of how it works. 

Saturday, February 1, 2014

My Thoughts on IBM Connect 2014

As the snow falls where I am the day after arriving back, here are my thoughts on IBM Connect 2014.  If you read my pre-conference post, you will know that this was my first LS/Connect in 15 years.   Having missed the last 14 years I was very excited to get to go again. Despite the long gap, it was all very familiar.

My personal goals for this conference was to of course, learn about the latest and greatest in the world of Domino/XPages, but my primary goal was to meet as many people as possible.  In both respects, I think the conference was a big success.

Thoughts on the General Sessions

I have to admit that I hadn't heard of American Authors prior to knowing they were going to play at Connect. My wife is a fan of them, so she was excited I would get to see them.  They were great, I loved the energy, and I plan on buying their latest album.  

The next hour or so of the OGS, wasn't really all that interesting to me live, but that is not all bad. Twitter was abuzz with mockery and jokes, which made it all bearable.  I think Kathy Brown, and David Leedy cracked me up the most.  The OGS is not really for technical people like myself.  It did get a lot more interesting when Luis Benitez did his demonstration of the Mail next mail client.  

The best general session by far was on Tuesday.  I loved the message that Scott Adams presentted.  I have already watched it again with my wife and daughters. The direct link is here, kudos to IBM for making that available.

They made us wait until the end to see Scott of course, but I thought the speakers before that were really good.  The CEO of Kenexa was really good, and I plan to watch that one again too.  I also want to say that upon reflection, I really like the theme of the conference which was "Energizing Life's Work".  Personally I have had a similar philosophy especially in the last 18 months.  In hindsight, I think the best thing to have happened me was having trouble finding work in the summer of '12  It lit a fire under me that wouldn't have happened otherwise.  All that to say is that I approve of that message and do feel energized with the work I do.  We all have to work, I am blessed to be doing something I love.

Thoughts on Breakout Sessions

Here are the highlights of the sessions in which I learned the most (in no particular order).  

1)  XPages Performance and Scalability by Tony McGuckin and Martin Donnelly

I had been exposed to this material before, but in this session it began to really make more sense to me.  I took 4 pages of notes in this two hour session  Here are some hightlights:
  • "XPages is much more feature rich than even the latest JSF" - Tony
  • Performance and Scalability need to be built in from the start
  • "You develop performance, you don't get it for free" - Martin
  • Once a week use the XPages toolbox to profile your application
  • Each control with a rendered property gets executed 4 times for every submit
  • Consider using the Dynamic Content control for hide-when functionality
  • For best scalability, keep pages on disk, this is the new default in 9.0.1

2) Be Open, REST services and Web Services by Bernd Hort

In this hour long session, Bernd covered lots of great info on these two topics with highlights being
  • Java 6 built into designer has all you need to use Web Services
  • Host your own WSDL files in case the provider moves or put security on them
  • RESTclient is a very useful Firefox add-on
  • "Jersey" is a utility to map json to objects

3)  ExtJS in XPages by Marky Roden

In this session, Marky opened developers eyes to the possibilities that are available using ExtJS.  Even though I have used ExtJS for six months, I still came away have learned some really cool tricks
  • Show the user something is happening when loading large amounts of data, use a progress bar
  • Using HTML5 local storage, you can poll the server for updates and cache results and only update results if data changed <- AWESOME
  • Use a Buffered Reader, which builds and destroys grid set and you can't tell it is happening.

4) Bootstrap4Xpages by Mark Leusink and Phillipe Riand

I almost didn't go to this session, since I have used bootstrap extensively but I am really glad that I did. Mark really built something that will make Bootstrap easier to implement for XPages developers
  • This runs as a server plugin, so all applications on the server have access to it
  • You can add your own components to what is 'out of the box'
  • Includes a really awesome file upload control
  • You should avoid using dojo controls when using this

5) XPages Mobile Development in 9.0.1 and Beyond by Tony McGuckin and Eamon Muldoon

The XPages team in Ireland had been working hard on improving mobile development.  
  • The Single Page Application wizard makes the development process much easier. 
  • The built-in managed bean called deviceBean gives you info on what device is accessing the app
  • onOrientationChange() event that can run serverside code on every orientation change 
  • onResize() event that also can run serverside code on every resize
  • FUTURE:  Built-in support for Responsive Web Design
  • FUTURE:  Support for Progressive Enhancement (gestures and behavior)

6) IBM Worklight: Going from XPages Mobile to Native Mobile Applications by John Jardin and Marky Roden

This session talked about the need for native applications.  They then did a demonstration of the features of Worklight until close to the end when some this amazing happened.  

They took a plain XPages mobile application and made it into a native mobile application.  John Jardin figured out that you can display the application in a iFrame and using Worklight you can have the application work as a native app on iOS or Android.  You can even use Worklight to bypass iTunes or Google Play. This is the single coolest thing I saw at IBM Connect 2014.  Kudos to John Jardin who figured this out. I wish that I stood up and clapped but it took me a few seconds to grasp what I had witnessed.  

7)  Meet the XPages Developer Birds of a Feather 

This was an hour long Q & A session with the Dublin XPages development team.   I learned quite a bit of what the community is asking for.  For example, I knew before that Designer used an older version of Eclipse, I just didn't realize how many people are really bothered by that.  I guess I never considered Designer to be a big problem, and I realize now that I am in the minority.  Besides that were lots of other good topics discussed.  I thought the IBM team handled things well, as did the audience.  I will say that I have a ton of respect for the team that gave us XPages and in addition I really respect them making themselves available in the way they did.     

Other noteworthy sessions that I attended and really liked:
  • Localization of XPages by Brad Balassaitis and Kathy Brown
  • Build Apps Rapidly by Leveraging IBM Collaboration by Henning Schmidt and Niklas Heidoff
  • IBM Domino 2013 and Beyond 
  • Xpages and the SBT by Martin Donnelly and Padraic Edwards
  • IBM Worklight for XPages Developers by Mat Newman
  • XPages 9 Circles by Paul Withers and Mike McGarrell
  • Open Social - Extending your Arsenal by Ryan Baxter and Yun Zhi Lin
  • Domino Designer by Kathy Brown and Julian Robichaux

What I didn't like about IBM Connect 2014

This will be a short section, because there wasn't much that I didn't like.  If I had to focus on one gripe it would be the scheduling of XPages related sessions.   There were some times, when there was nothing really of interest to me being presented, and other times, when there were two, and sometimes three interesting XPages/Mobile/App Dev sessions going on at the same time.   


Fulfilling My Primary Goal

When it comes down it, all of technical things I learned at the conference, I could have done on my own by hours of personal study.  My primary goal was to meet like minded people and turn online acquaintances into friends.  I am usually reserved but I promised myself to take every opportunity to reach out to everyone I came across but especially those I have followed online.  It was a little difficult at first, but after a few times it became second nature.  I met so many that awesome people that I can't list them all so I better not try. It was a limiting staying away from the Dolphin and Swan but I feel like I made the best of each chance I had. Despite being excited to see my family, I was sad to leave having made so many friends.  I hope to not have to wait 15 years to return.

It was great meeting Chris Toohey, and talking about things we had in common since I was raised in his native Pennsylvania 
Marky Roden, Brad Balassaitis, and Tim Tripcony at the PSC Party
Frank Santorelli and Mike Davis from Cincy who I enjoyed spending time with at Hollywood studios. Here we are in line for the Toy Story ride.

Wednesday, January 15, 2014

IBM Connect 2014

This year I have the privilege of being able to attend IBM Connect 2014.    This will be my third 'Sphere that I have attended, and the first this century.  My last Lotusphere was in 1999, and before that 1996. Back then there were loads of people, and it was very hard to score a ticket.

When I went in 1996, I had just started working with Notes just a month or two before, and my manager comes to me and hands me a ticket and says, 'Guess what, you are going to Orlando'.   He had bought the ticket for himself, but had a conflict, and I got to go.  Everything was so new that year, I just remember taking tons and tons of notes (no pun intended).  I remember well all the cheering and clapping when the features of Notes 4 were revealed.  Good times.

In 1999, I got to go again and learned a ton more.  I think that was the year that Notes 5 was introduced to great fanfare.  That was also the year that I almost accidentally knocked over Ray Ozzie.  I was entering a door and it was sunny and I couldn't see someone about to come out due to the reflection, and I nearly knocked him over with the door.  Thankfully Ray was nimble of feet and jumped out of the way just in time. Lotusphere was always fun for meeting people all over the world, I remember hanging that year with several Norwegians and Brits.  Good times again.

For many years after that, I was either an hourly contractor or worked at a company that didn't put value in conferences.  If I was to attend Lotusphere it would have to be on my own $.  With my current job, I am a salaried employee, and at a company that puts value in training, so I am able to go this year.

In addition to the sessions, I hope to meet lots of people.  I have tried to be more active in the Notes community, and hope to meet many that I have interacted with on Twitter, Stack Overflow, or blogs (there's or mine).   If you see me, please come by and say Hi.  If you have a get together, I am open to invites, I am @szavocki on twitter.

My Connect 2014 Schedule (subject to change):


Life is full of conflict

I know that time conflicts are inevitable, but there are several sessions that I really wanted to attend that I can't due to conflicts.  These sessions are ones I can't attend due not being able to be in two places at once.

  • Creating a Great XPages User Interface (really hoping they add a second Sunday session for this one)
  • Creating State of the Art Web Applications with REST services
  • End-to-End Quality Processes for Top Notch XPages apps
  • Improving your IBM Designer Experience
  • IBM Domino App Dev: Today and Tomorrow
  • Rapid XPages Dev using the Application Layout Control
  • Creating a Mobile Application Framework with XPages (This one pains me the most)

Free Certifications

In addition to the sessions, I also plan on taking two certification tests since they are offered for free.  I am already an 8.5 Application Developer, so I plan on taking the update test to make me a Certified Application Developer in Notes 9.   I also plan on taking the Notes Admin Test LOT-406, which if I pass will make me and Advanced Certified Application Developer in Notes 9.  Right now, I am studying for both tests.  I hope to take the first on on Monday, and the second on Wednesday.  

Again, I hope to meet many of you that I have come to know virtually these last few years since I decided to become more involved.  See you all in 11 days.

Tuesday, January 7, 2014

Creating a PDF dynamically from an XPage - Part 3

In this my third post on how to dynamically create a PDF from an Xpage, I am going to explain my use of tools for creating the XSL stylesheet.  Part 1 is here, and Part 2 is here.

Overview

The XSL stylesheet is what is used to layout the design of the data onto the page.  It reads an XML file, and transforms it using the XSL with the result being a PDF document.

In the past, I have used this flowchart that I made.  This post will focus on the stylesheet creation in the big gray box.

You can create your own XSL stylesheets without using a tool, but it is like writing java without an IDE.   There are several tools that I know of to create XSL for you.  Most of these tools do much more that just XSL and that is reflected in the price.  This page links to companies that make these tools.  The prices for these range from $400 to ~$1000 for a single user license.   There is also a inexpensive solution to use which is called FO Designer which is about $60.  We went with FO Designer, with the thinking being that this tools just does what we want without paying for features we wouldn't use.  I will save my commentary of it for the opinions sections at the end.

The FO Designer works this way.  You visually layout on the screen your form, then you push a button to generate the XSL-FO.  I would then copy the generated FO into a stylesheet within Domino Designer.  I would then refresh my page, and test the PDF.  The tool had a way to test PDFs but I needed it to work within Domino, and I didn't consider the tools PDF generation a true test.

FO Designer

The Opinion Section

This section is named such so I can tell you what I really think.  Here are the major obstacles that I faced.

1) FO Designer might have been great in the year 2000, but it is inadequate now.  I regret thinking that I could make it work.  I wish I pushed for one of the modern higher $$$ options.  It doesn't seem to support tables, and vertical lines don't render.  It has no undo, and is very clunky to use.  When you create an element and set the Xpath to "absolute", and then copy and paste that element it resets to "relative" which causes the PDF creation to fail in Domino.

2) PDF creation in Domino is an all or nothing proposition.  If there is any part of the code not exactly 100% perfect then the PDF creation will fail, and you won't know why.  I found myself having to examine the generated XSL in sublime text prior to copying into my application.

The Recommendation Section

If you find yourself needing to create PDF's this way then I recommend the following.

1) Choose one a different tool than FO Designer.  It will cost you or your company more money, but it will save a lot of frustration.  I can't offer a recommendation as I haven't tried the others.

2) Test your work NOT in Domino, but using web based tools like this one http://www.utilities-online.info/foprender/#.UsxyvPRDuSo   This tool will give you a hint of what is wrong, when something is wrong, as opposed to just not working.   Once it looks right here, then you can copy it into Domino and test it there.

3) The XSL will transform a single XML file.  If you have multiple document that need to be combined into a single XML file, I found the following to be a quick and easy way to do it.

  • In your java method that generated the XML, do a lookup and get a handle to the related documents
  • Loop through the related documents, and copy the values you want on the PDF onto the main document
  • Once the items are copied to the main document then run the generateXML() method
  • Don't save the main document with all the new values on it, you want the PDF to only have the latest data each time you create it.
As for me, we are putting this part of the project on hold.  I hope we come back to it, as I have invested a lot of time and effort in getting this far.  In another sense I am relieved to move on.