A Legacy Notes Developer's journey into madness.

Getting a handle on Scope using Java

Devin Olson  June 4 2013 06:54:15 AM

XPages gives us some wonderfully cool pre-built containers into which we can throw various variables, and retrieve them later at our convenience.


The containers to which I'm referring are the SCOPE containers, specifically applicationScope, sessionScope, viewScope, and requestScope.   Using SSJS, we can reference these containers at will by using their respective names:



// put "bass" into viewScope using the key "fish"
viewScope.put("fish", "bass");

. . .

// retrieve the variable later in the code (or in an entirely different code block
var myFish = viewScope.get("fish");


This is really very powerful, and allows us to do all kinds of way cool things.


But what about Java?   In other posts I have harped on about how important it is to learn Java.  So if you create some Java code to handle a bunch of your business logic (either POJO or Beans), would it not be useful to be able to access these Scope containers?

Each of these Scope containers implements the Map interface ( "is a" Map applies), and using Maps in Java is easy.  Using them is so easy that I'm not even going to bother explaining how to use them.  Read the docs and figure it out.  

What I am going to tell you is how I access them.  Because the hardest part about using a Map is finding the Map.   (Hmmm -could there be a not-so hidden meaning there?)   This is a helper function I have in my core XSP Java library.   I hope it helps you out.  

Anyway, here is the code:



package com.learningxpages.demo;

import java.util.Map;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

public class Core {
 public static enum SCOPE {
         Application, Session, View, Request;

         @Override
         public String toString() {
                 return this.name();
         }

         public String getInfo() {
                 return this.getDeclaringClass() + "." + this.getClass() + ":" + this.name();
         }
         
 }; // SCOPE


 @SuppressWarnings("unchecked")
 public static Map getScopeMap(FacesContext context, Core.SCOPE scope) {
         try {
                 if (null == context) {
                         throw new IllegalArgumentException("FacesContext is null");
                 }
                 if (null == scope) {
                         throw new IllegalArgumentException("Scope is null");
                 }

                 ExternalContext ec = context.getExternalContext();
                 switch (scope) {
                 case Session:
                         return ec.getSessionMap();

                 case Application:
                         return ec.getApplicationMap();

                 case View:
                         return context.getViewRoot().getViewMap();

                 case Request:
                         return ec.getRequestMap();

                 default:
                         return null;
                 } // switch

         } catch (Exception e) {
                 System.out.println("*");
                 System.out.println("EXCEPTION in Core.getScopeMap()");
                 if (null != scope) {
                         System.out.println("Scope:" + scope.name());
                 }
                 e.printStackTrace();
         } // try

         return null;
 } // getScopeMap(FacesContext, Scope)
 
} // Core




Hope this helps!
-Devin.

(Crosspost from Spanky’s Place) Installing and Configuring IBM Domino 9 Social Edition on CentOS 6 Enterprise Linux

Devin Olson  April 30 2013 07:36:25 AM

This is is a copy of my blogpost



Since the official release of IBM Notes and Domino 9.0 Social Edition a few weeks ago, I have been "chomping at the bit" wanting to release a set of instructions / videos on how to install it on a Linux machine.



During the beta program I had the opportunity to "play" with it quite a bit, and let me tell you this release is exceptionally good.   It is also by far the easiest and most hassle-free version I have ever installed on a Linux machine -but there are still a few gotchas and watch-outs to be wary of.



I have written an instructional document entitled Installing and Configuring IBM Domino 9 Social Edition on CentOS 6 Enterprise Linux and posted it to dropbox.  I hope it helps alleviate some of the fear and confusion with regards to using Linux as your Domino server platform.     The document is aimed at YellowHeads (having some experience with Domino installations on Windows) who are thinking about stepping into the world of Linux.  The document is focused on 64 bit Linux, but calls out differences from 32 bit installations where necessary.  Even though it is aimed specifically at CentOS 6, the instructions should work for any RHEL or Debian-based (with some changes to handle DEB vs. RPM) linux version  -although I must point out that the only supported Linux distributions are RHEL 6 and SUSE 11.



I have also cut a series of 9 videos wherein I walk through the instructions step-by step and demonstrate how easy it really is to perform the installation.  They are available on my YouTube channel, although I'm hoping I can talk David Leedy into including them on Notes In 9.  






Hope this helps!


-Devin

Dell Service Tag via WMIC Command

Devin Olson  April 26 2013 08:38:36 AM


Let me say up front that this post has NOTHING to do with Lotus, XPages, or software development in any way.   But it is too good a tip to not post about.


I recently needed to get the service tag for one of my Dell laptops.  The problem is that the sticker on the bottom has worn off, so I can't read the service tag there.   Dell has a utility that you can run from their website to automatically detect the service tag, but this laptop had a non-functioning network card (part of the reason I needed the service tag).  But it isrunning Windows 7, which means I have Windows Management Instrumentation Command-line (WMIC) at my disposal.  

I'm not going to get into all the details on how to use WMIC (you can check out the link yourself), but I will say that it is an extremely cool and powerful little utility.   I used it to find the Dell Service Tag on my Alienware M11x R2 laptop.   The steps are as follows:


  1. Open a command window

  2. Enter this command: wmic csproduct get vendor, name, identifyingnumber



That's it.  Your service tag, model, and machine vendor will be displayed on the next line.


Hope this helps!
-Devin.  

Bug in DD-WRT on a Netgear WNDR3700 Router

Devin Olson  April 23 2013 08:10:54 AM


Yesterday I tried to install dd-wrt (v24 SP1) on my Netgear WNDR3700 v2 router.   The installation was a breeze.   Then I tried to configure it.


That is when the trouble began



There is a bug in the CSJS sent to the browser for the web administration interface in this version of DD-WRT.   I honestly don't know if it is in older versions, nor do I know if this issue exists in the firmware for any other model router.   But for my router this problem exists, and it is really frustrating.  

There is a CSJS function called to_apply() that is called whenever the Apply Settings button is clicked.

Here is the button:    

The problem is that the to_apply() function doesn't seem to exist in any of the code sent to the browser, nor can it be found in any of the referenced script libraries.  This means that clicking the button does nothing.  Your changes are not saved or applied.   I had similar problems with the code referenced by the Save button.  That code exists, but would fail and my saves would not "take".  

Essentially I was left with a bricked router.  It had this awesome new firmware on it, but I was unable to save any configuration settings, which meant it was pretty much useless.  

I managed to find a Forum entry from another user having the same problem (thanks to my iPad and Verizon 4G LTE), although this person is using a different version router (WNDR3700 V4).   And fortunately for me, his/her solution worked.

Hack Solution:

  1. Use a MODERN browser that has web-development capability (such as Chrome, Firefox, or Safari).  

  2. Sign into the Router's web administration interface, and make the changes you need

  3. Right-Click on the Apply Settings button, and choose Inspect Element (or whatever your browser's version happens to be)

  4. Change the Onclick code from  onclick="to_apply(this.form);"  to onclick="applytake(this.form);"

  5. Click the button.  Your changes will be saved and applied

  6. Reboot the Router




Hope this helps!
-Devin.







 

Regex Reminder: Match the End of a String

Devin Olson  April 9 2013 02:35:11 PM

Regular Expression for matching the end of a string (usually in Java)


I am posting this here because I'm tired of having to think this through every time I need it.  Perhaps it will be of some use to somebody else.

^.*substring$


When searching any string using a RegEx Matches Pattern construct, the above pattern breaks down as follows:

  • ^  match the beginning of the string

  • .  match any single character

  • *  match the preceding match character (in this case, any character), zero or more times.  

  • substring this is the substring you want to match.  Make sure all control characters are escaped.

  • $  match the preceding match instructions against the end of the string.


Also, if you want to perform a CASE-INSENSITIVE match (without using a Java Pattern Object),
you can add the (?i) control flag to the beginning of your regular expression:

(?i)^.*substring$




Hope this helps!
-Devin.

eclipse Frustrations (why do I suddenly have 18K+ errors?)

Devin Olson  March 14 2013 08:59:38 AM
Yesterday I had the incredibly frustrating experience of having eclipse break -and I had no idea why.   I spent several hours trying to figure it out before giving up and walking away.  

I had previously (with the help of Declan Lynch) set up a new installation of the eclipse IDE so I could do some XPages Plug-In development using the OpenNTF XPages Extension Library, and it was working great.   I saved my stuff and shut down eclipse.  

Later on I launched eclipse and found myself looking at a sea of red decorators, there were over 18,000 errors showing in my console.  

Now we all know how the "What Changed?" game works.  You get a call from a stupid end user who is having a problem with their computer.  So you ask the question "What did you change?", and the inevitable answer is always some variation of "nothing", or "I didn't do anything".   Which of course we as computer people know is complete crap.   Obviously they changed something, otherwise the darn thing wouldn't be broken.  

So I wracked my brain trying to figure out what had changed -and could not come up with anything.  I had not touched eclipse, nor had I touched any of the files that eclipse needed for my environment.  In the interim I had been working on a completely different machine.  So  I really had changed nothing.

Yet it was still broken.  Try as I might I couldn't get it working.  (Yes, I JFGI'd it, and no, I couldn't figure out the problem).   I knew that some required resources were not available -the IDE was complaining that it couldn't resolve the import com.ibm.xsp.library.AbstractXspLibrary (actually it couldn't even resolve com.ibm.xsp), but even though I KNEW the resources were there I couldn't get it to work.  It was late in the day and I was frustrated and angry so I just shut it down and walked away (after appropriate bitching on http://www.facebook.com/default.xsp, of course).

This morning my boss pinged me and helped me identify and fix the problem.   The fix was so incredibly simple that I just had to post it here.  

You see, I installed the latest version of eclipse Juno:  Eclipse Java EE IDE for Web Developers.  Version: Juno Service Release 2 Build id: 20130225-0426, and it seems there is a problem with this version in that it occasionally  forgets the target platform.  

Absolutely maddening.  

Here is how to fix this, should it happen to you.  





1) Open your eclipse window preferences
2) Expand Plug-in Development and click on Target Platform.  Then select your platform and click the reload button.  Then click the OK button.


That's it.  Eclipse will rebuild your workspace and you should be good to go.


Hope this helps!
-Devin.

Domino 8.5.3: Problem and solution to ’formId’ is null or not an object or TypeError: ’undefined’ is not an object

Devin Olson  January 19 2013 10:32:23 AM
I've been working on a new project for a little while now.  It was working perfectly my development environment (Domino 9 Beta server), and the time had come to put a limited access version into production for additional testing.  Production is running 8.5.3

Yes, I can hear the rumblings now.  But please understand that there is NO WAY we are going to run a Beta  release in a production environment, but we will likely be a first adopter once the release goes gold.  

Anyway, we set up the test application on the production server, configured the ACL, and started playing with it.  At which point it promptly broke.   When certain buttons (not all of them) were clicked, a dialog box would pop up giving an error -the error varied depending on what browser was being used (Safari, FF, Opera, MSIE), but the error was usually some variation of:

Error: 'formId' is null or not an object


- or -

TypeError: 'undefined' is not an object (evaluating '_cl.formId')



This issue wasn't happening on ALL object clicks, only those which were calling XSP:partialRefreshGet() or XSP:partialRefreshPost().


It turns out that In Domino 8.5.3 there is an known issue in the implementation of XSP:partialRefreshGet() and XSP:partialRefreshPost().

The second argument to both of these methods is the "options" parameter. This parameter is SUPPOSED to be OPTIONAL, but the issue in 8.5.3 can cause, if the second argument is not present, a failure to properly determine the client side identity of the element ID specified in the first argument.  Which results in the nasty dialog warning on the browser.  The target ID for the partial refresh being passed through the AJAX call back to the browser doesn't exist -hence the dialog error.  

This issue never showed up in development or testing because I added the calls to XSP.partialRefreshGet() to the development version AFTER having upgraded the development server to 9 beta.  The good news is this issue is obviously resolved in version 9.   The bad news is that until I put in a solution we can't roll to production.  

Fortunately, the solution is really, really simple.   Simply add an empty second parameter to the calls.  

OLD CODE:

XSP.partialRefreshGet("#{id:myWayCoolElementID}");

NEW CODE:

XSP.partialRefreshGet("#{id:myWayCoolElementID}", {});

And voilĂ , the code now works as designed.  

Peace,

-Devin.

Stupid equality test -my most common Java bug.

Devin Olson  December 10 2012 04:01:59 PM
I was first introduced to Java (as a Programming Language) around 1997 or 1998, and I've been working with it on a semi-regular basis since around 2001.  

Since July of this year I have been working with it on a daily basis.  

But even with being "elbow deep" in the language all this time, I continue to make this simple, stupid mistake.  

So I'm posting it here hoping that it will help me remember, and perhaps help others as well.  


(myString == anotherString)  

IS NOT EQUIVALENT to

(myString.equals(anotherString))




Sigh.  

-Devin.

How to Crash an XPages server with 1 line of code

Devin Olson  November 29 2012 08:37:24 AM

NOTICE:  I have been notified that an SPR has now been created for this issue and it is being worked on.  Kudos to the team at IBM for jumping on this so quickly.  


Thanks also to NTF for testing / verifying the problem exists in the lotus.domino.Document object itself.  You rock, my friend.



Yesterday I was doing some testing and I crashed my server.  

So I restarted the server, checked the logs, checked my code, made some adjustments to try and identify the cause of the crash, and resumed my testing...and crashed my server.  

So I restarted the server, checked the logs, checked my code, made some adjustments to try and identify the cause of the crash, and resumed my testing...and crashed my server.  

Rinse...repeat...rinse...repeat.    

We've all been there, we all know the frustration of trying to find the cause of such a problem.  This one was a doosie -nothing was showing up in log.nsf -not even a panic notation.   The console helped me (my development server runs in a console window on Linux, the console remains open even after a server crash) to figure out which NSD file to reference.  

There was a generic notation telling me to attach the NSD log file along with my normal log file when submitting a bug report, which doesn't really apply in this case as this is a DEVELOPMENT server -crashes are (while not really welcomed) an expected part of the development process.  In almost all cases a server crash on a development server is due to a bug in the DEVELOPER's code; NOT the application environment itself.  Sending the logs to IBM for analysis would be akin to calling out the Cumberland Fire Department to help turn off my gas stove.

Which meant I had to go through the NSD logs myself.   If you have never had the pleasure of pouring through one you have no idea of what you are missing.  They will cure insomnia better than an entire bottle of Vick's Nyquil  -instant snoresville.  Don't misunderstand me, these logs are extremely valuable and contain a ton of important and pertinent information -but there is simply so much that processing one "by hand" is exhausting.  

I did eventually figure out the cause of my crashes, and in this case it is NOT caused by a bug in my code.   The problem was caused by the Document.hasItem() method -or perhaps the SSJS to Java translation / conversion of the method.   Hopefully my explanation (as it follows) and SOLUTION will help you to avoid this kind of error in your own environments.  

First of a bit of an explanation of how XPages work is in order.   In XPages all running code is Java.   You may recall one of my previous posts where I where I went off on a bit of a rant about how important it is that you learn Java to write good XPages.  This is a perfect example of why understanding Java can help.  As you'll discover my solution is NOT Java -writing Java is not as important as understanding.  

Ok, back from the rabbit trail.  Three critical points to understand are:  
1.        In XPages all running code is Java.  All of the XML and SSJS you create when you write an XPage is either converted to Java code during the build process or interpreted so it can interact with the Java objects at run-time.  Wrapper code is generated for your SSJS to interact with.
2.        Domino Java objects are true Java objects, and don't need to be converted.
3.        When your SSJS interacts with a Domino Java object, it does so via the generated wrapper code from point 1 above.


What this means the awesome STRONG type-checking native to Java (and therefore the Domino Java objects) is, through necessity, somewhat short-circuited by the SSJS to Java conversion during the build.  In most cases the run-time checks which are built into the code will handle type or null checking just fine, but every once in a while a coding pattern can occur which has not been accounted for -which can in turn lead to the aforementioned server-crash nastiness.  

In this case the problem stems from a combination of the lotus.domino.Document object, it's implementation of the hasItem() method, and SSJS to Java translation.   The method signature for hasItem() is:

public
boolean hasItem(String name) throws NotesException


When you call this method you must pass in a String value.  If you don't pass a String the compiler will complain.  If you pass in null, the code will compile just fine, but when it runs it will break and throw a NotesException error -which is normal expected behavior.  

This object and it's code is wrapped by the NotesXSPdocument object -which you reference in your SSJS.   When you define a document data source for an XPage or custom control, that data source handle is a NotesXSPdocument object.  This object has a hasItem() method, with the following signature:

hasItem(fieldName:string) : boolean


The thing that must be remembered here is that this is JavaScript, not Java.   And JavaScript (even SSJS) is the exact opposite of a strongly typed language.  Yes, it has built in typeof and instanceof methods, and has classes and objects -but you can change the type of any object at any time.  When you write your SSJS and call document.hasItem(myVariable), you could make myVariable anything you want: a hat or a brooch or a pterodactyl.   When the code gets built and the corresponding Java code is created certain wrapper functionality will be generated to convert whatever you pass in (via the SSJS argument) to a Java String object.   And this is where things break down.  

I honestly don't know if this is how the internally built code works or not; I don't have any special "inside knowledge" -this is merely my opinion on how this process could work. If you pass in a variable which at run-time happens to be null, the Java code will try to figure out it's String representation. There is a toString() method in the java.lang.Object class which returns a String object, and all other Java objects (even your custom ones) ultimately descend from this class; which means that calling this method from any Java object is generally a safe thing to do.   Unless of course the thing from which you are trying to convert to a String is null.  null is not an object, and therefore has no toString() method.  My guess here is that the internal code is not doing a test for null (and returning an empty string), but is instead simply calling the toString() method.  

As I said, I don't know how the internal conversion is actually performed, but I do know what happens when you pass a null to this method -the server kills itself.    

Don't believe me?   Check out the following code:  


WHAT FOLLOWS IS FOR ILLUSTRATIVE PURPOSES ONLY
DO NOT PUT IT ON A SERVER
IF YOU DO YOUR SERVER WILL CRASH,  
YOUR ADMINISTRATORS WILL BE VERY ANGRY AND VIOLENCE WILL FOLLOW.  

SERIOUSLY,

DO NOT DO THIS


You've been warned.  



var
hasItem = currentDocument.hasItem(null);

That single line of code, if placed in an XPage or Custom control, will cause the server to immediately crash.  

I have created a sample NSF you can use to play with, assuming you have a safe development environment you can repeatedly destroy.   You can find this on my downloads page:    http://www.azlighthouse.com/downloads.html

The good news is that there is a workaround in place that has been in my toolbox for some time.  Using my @IsBlank function as a wrapper for the argument is really easy, and completely solves the problem.  You can find this function in the ssjsTools library in the sample NSF, or just grab it from my previous "XPages SSJS Function: @IsBlank" blog entry.  

The code to implement this solution is as simple as:  

var
itemname = null;
var
hasItem = currentDocument.hasItem(@IsBlank(itemname)? "": itemname);


Ok, that is enough for today.

Hope this helps!
-Devin.  

"You don’t need to know Java to write XPages" and other fables

Devin Olson  October 11 2012 09:19:14 AM
Since the advent of XPages several years ago, I've heard the following mantra more times than I care to remember:

"You don't need to know Java to write XPages"

To which I say HORSE SHIT!!

While you may technically be able to build an XPages application (or several) without knowing Java, you will never be able to build a good one.  I can already sense the naysayers starting to grumble; I'm sorry if you don't like hearing this, but it nevertheless remains the TRUTH.  Urban VIII and the Jesuits didn't like hearing about heliocentrism either.  

The underlying nature of XPages built on JSF means that unless you are writing Java code, EVERYTHING you create in your XPages application must be interpreted and processed at run-time.  All that cool SSJS you write and all those neato controls that you drag onto your XPage are ultimately converted into Java.  All of that conversion takes time to complete, and consumes resources on the server.  Yes, IBM did and awesome job putting all this black magic real-time interpretation / language translation / object mapping uber cool mojo together, and yes it works extremely well; but it still takes time and resources.  When you consider the impact of all those little moments and put a real load on the server, those little moments begin to add up.  

If you have, even at a very basic fundamental level, some knowledge of Java and how the language works you will instinctively begin to build better XPages.  Even if you don't actually write any Java code, a grasp of how things work "under the hood" will help.  

Once you start writing your own Java code and incorporating it into your XPages, they will (unless you write complete crap) perform better, scale better, be more efficient, end world hunger and cause peace to break out everywhere.  

Tim Tripcony wrote an excellent blog post just the other day called pragmatic reasons every Domino developer should learn Java.  I encourage you to go read it.  Now, I like Tim very much (and consider him a good friend), but he is sometimes a bit too nice.  Let me see if I can make the point more simply:

If you don't lean Java you will lose your job and your children will starve.

Take a course (or two), read a book (or two), and invest in yourself and your career.  If you can, try to learn Java OUTSIDE of an XPages environment.  Trust me on this.  I used to teach Java, and even though I've done very little with it since 2002, that experience has made my personal transition from legacy Domino development to XPages much easier.  




SOURCE CONTROL

"DDE has built in design locking and replication, and that is good enough"

To which I say EVEN MORE HORSE SHIT!!

While you may technically be able to build your XPages application without a good source control system in place, you will eventually run into problems with corrupted design notes, conflicts, and other pain-in-the-ass things.   Eclipse makes it INCREDIBLY EASY to add and use a Source (or Version) control system.  It doesn't matter what one you use so much as you USE ONE.  I could rant about this all day, but I have work to do, so I'll leave you with a few links that you should go and read.  Some of them are old, but they are (IMHO even more so now) still extremely relevant.

Jeff Atwood: Check In Early, Check In Often (August 2008)

Rands In Repose: What To Do When You're Screwed (July 2004)

Notes In 9: Xpages, Designer - SOURCE CONTROL!! (January 2012)

Hope this helps,
-Devin.