Today’s basic XPages coding adventure sees our hero start from the depths of dodgy and make his way towards the light – quite refreshing really, because most of the time I’m moving in the other direction.

The Problem

The problem is a typical situation that everybody sees from time to time – a checkbox in a form table that shows a few extra rows if you check it.  Simple stuff, really.

Picture of a checkbox that is used to hide some additional fields

Too easy!

Everything is in the Extension Library Form Layout Rows for convenience, and the date fields are Dojo Date Text Boxes.  Start Date is mandatory, with a validateRequired validator on it to handle this.

Starting off, feeling lazy, I went with the simple solution.  Partial refresh from onClick in the checkbox, with the rendered property on the last two form layout rows setting the visibility depending on the value of the checkbox control.  Voila – it worked.  Too easy!

Until I tested it properly.  What if your user, bless them, decides to check the Create Repeats checkbox before setting a date?  I know this seems completely illogical, but who are we to judge?

InvalidError

The Dojo Date Text Box does some nice helpful client side validation, which prevents anything server-side going ahead…..which of course prevents your server side rendering from bringing up the additional rows.  Oh no!  Your checkbox stays checked too, which means that your user is now stuck.  The only way they can get the repeat fields to appear is to fill in the date, uncheck the checkbox and check it again, no doubt while reaching new heights of righteous indignation and venting to your manager.

OK, so maybe we should do this better.

Client Side!

Doing this on the client side is the obvious solution here, and it is of course the right way to do anything like this when you’re not being dodgy and lazy.  display: none.  Thanks Captain Obvious.

However, it is better to use classes for this, so I set up a couple of simple classes in my CSS:

.repeatInvisible {
     display: none;
}
.repeatVisible {
}

Why did I create a blank style for the visible case?  Don’t worry, there’s method to the madness here.

First up, we need to set the styleClass on the hidden form rows to make sure the initial value of the class gives the right value when the XPage is first rendered:

var hideStyle = getComponent("repeats").getValue() == "Y" ? "repeatVisible" : "repeatInvisible";
return "lotusFormFieldRow " + hideStyle;

Next, the onChange event on the checkbox – client side script.  There’s a little gotcha here – Form Layout Rows render as a <tr> tag with your class applied, but no id attribute.  You can’t use dojo.byId(“#{id:formRow8}”) here, so you need to find the rows that have your custom classes on them and manipulate the styles from there.  This is why you need the blank class – so that you’ve still got something there to identify your rows if you need to hide them again.

var repeats = dojo.byId("#{id:repeats}");

if(repeats.checked){
   dojo.query(".repeatInvisible").forEach(function(node, index, nodelist){
      dojo.toggleClass(node, "repeatInvisible");
      dojo.toggleClass(node, "repeatVisible");
   });
}else{
   dojo.query(".repeatVisible").forEach(function(node, index, nodelist){
      dojo.toggleClass(node, "repeatInvisible");
      dojo.toggleClass(node, "repeatVisible");
   });
}

There are obviously lots of other ways to get at the classes and change them, but I like the way dojo makes things simpler here and allows you to hide any number of rows in one hit.  Pedants will point out that you probably don’t even have to use a conditional statement on the checkbox – you could just add an additional dummy class to the rows to make the search work and toggle the classes without checking the state.  True, but I wanted to make sure there was no way possible that you could somehow get out of whack and start toggling them in the reverse order.  I don’t actually know how that could happen, but computers have a talent for the unexpected – especially when I’m writing the code.

Lastly, you can remove any client side code or partial refresh stuff from your onChange event if you’re not doing anything further – you’re home and hosed!

Advertisements
Posted by: Brendan Long | September 30, 2014

They’re offering me developers? Great! What do I do now?

This one is a bit of a call for advice to the community – what would approach would you take if you were in my rather small shoes?

I’m an internal Notes development guy at a software development company that develops large-scale software in a completely different platform.  I’m trying to get a move on with a slow but determined migration across to XPages for the suite of internal business applications that I support, but day to day bugs and enhancements in my old-skool portfolio along with a stack of non-development tasks (in a small company, you sometimes need to wear a few extra hats, after all) tend to get in the way of real progress. My work has been piling up for a while now.

Management have grown frustrated noticed my lack of progress and have offered assistance. In what is a very pleasing and somewhat unexpected move, they have offered me the services of a couple of young, enthusiastic developer types to do a little bit of Domino work for me when they are ‘on the bench’.

Sounds awesome, right?

Of course it does, and it most certainly is, but it does put me in a position where I have to work out how to get the best possible value out of this situation – for me, and for them too.  It’s not often you get to introduce new developers to the Domino world, and I really want them to:

  • do good work
  • learn something useful for themselves
  • bring some ideas to the table to help me learn too
  • like the platform

The last one is important to me.  I don’t want this to be a bummer for them, and on a selfish note, it might be the only chance I get to convince the hardcore snooty Oracle developer types in my office that ‘Lotus Development’ isn’t some third-rate kludge-a-palooza that is only practiced by useless hacks like me.  I want them to be pleasantly surprised.

The Pitch

So, to my first task – to give them an introduction to the platform that highlights the possibilities.  I’m thinking that I will leverage a few of the presentations I have seen recently about the current direction of Domino – especially the idea that Domino is basically a very secure NoSQL database (that’s got to be cool, right?) that you can build on using modern technologies in the front and back ends – java and javascript frameworks FTW!  These guys are likely to be java developers who have done a bit of JSF (Oracle ADF in this case), so some of the concepts might actually be more relevant to them than they are to me.  I’m also hoping they are front end JS dabblers who can teach me a thing or two and come up with something pretty snappy if they are given some freedom in the browser.  Fingers crossed.

The Learning Curve

The next thing I’m going to have to try to do is find a way to get them up to speed quickly.  Training is probably not an option here and I don’t think I’m going to be allowed to factor in much time for study, so I think it will be a case of buying everybody a copy of Mastering XPages, pointing them at a few of the better online resources, and giving them a good small startup project that lets them get stuck in quickly.  I’m a bit worried about this to be honest, but if I ask for two months of training per resource and a budget with actual numbers in it the whole initiative will be in the can faster than I can say “best practice”.  It’s the deep end or nothing, and I hope it’s not a recipe for disaster.

I’ll have to document requirements in a much more useful way than the sparse notes that I’m used to, but I’m also determined to keep things fairly agile rather than writing a detailed spec where possible.  I still think I’ll find myself losing a fair chunk of my coding time to do a bit of BA work here, but that will be worth it.  Who knows, if I find that these guys really are a level above me in the coding stakes I might be setting myself up for a new career.

The Techo Stuff

Lastly, of course, is the great big choice I need to make about where to take this in terms of technology choices.  What makes this interesting for me is that I’m a dabbler at best, or in some cases a complete noob in some of the technologies that seem to be hitting the top of the charts in XPages land right now.  I want them to use modern tech, but I need to make sure I pick stuff that has a shelf life because I will be supporting this stuff once the guys move on to greener pastures.  I’m also trying to keep an eye towards technologies that give us an option to migrate more readily if, well, you  know, IBM decides Domino is about as useful as they think Notes is right now.

In short, I need to back the winning horse, but I might be using last year’s form guide.

The first choice is easy though.  Domino is non-negotiable, because we have quite a few applications that are tightly integrated and some of the ones we won’t be touching in the first wave rely on others for their data – using good old DBLookups and the like.  All that old stuff just works, so we won’t be breaking it just yet.

Next up – the front end choices.  It seems to me that bootstrap on XPages is now the de-facto standard, and much more likely to bring nods of anticipation from my new guys than if I introduced them to OneUI.  That said, I’m hoping that this choice won’t introduce a degree of risk for them – I’m not really up with the status of things like Bootstrap4XPages and I’m hoping that it is production-ready and RAD-friendly.  Sniffing the breeze in the yellowverse suggests to me that it is, so if the guys look even remotely interested when I drop the word bootstrap, I’ll try to go that way.  I’m also open to them bringing in extra front end javascript goodness, jquery of course and some extra stuff if they have some skills there.  It looks like the really cool kids on the block are starting to play with AngularJS, and I’m tempted to drop that one in there as well to see what they think, but I’m wondering if that might be one bridge too far for this stage of the game.

Back end, and I think it’s going to be java all the way.  One of the selling points I used to get these guys locked in is that it will give them a chance to practice java on a smaller scale application, and this should be a winner for me.  I’d love to build a bit a library of java classes and beans that covers all the applications and standardises everything, and I’m hoping these guys will start dragging me over the line on this.

Lastly, source control.  I’m lost here.  The only source control I have ever had is the fear of embarrassment and re-work.  That usually suffices when you’re a one man band, but we might need to do a little bit better in this situation.  I doubt that I’ll get much time to set this up though, so we might have to fly by the seat of our pants for starters.

Ready, Set, Go!

The last hurdle is handing over the reins and letting go.  That’s not easy when you’re used to eating your own dog food and secretly afraid that people will laugh at you, but I’m brimming with optimism right now and I hope I can make it work.  Wish me luck (after you drop a few pearls of wisdom in the comments, that is)!

Posted by: Brendan Long | September 29, 2014

Book Review: JavaScript Enlightenment by Cody Lindley

Like many ex-Domino cowboys, I’m not too proud to admit that my JavaScript skills are somewhat rudimentary.  I’ve been doing ‘just enough to get it working’ for a while now, from the old-skool Domino web stuff that I used to do to the XPages SSJS that I’m now working in.  It’s not pretty.  If I had to pick one word to describe my level of proficiency, I would probably agonise for a few seconds and then settle for ‘sucks’.  I get it working, and hope I’m the only one who is ever going to read the code.  I fully expect that if some hotshot young coder from uni ever comes along to refactor my work they will be peppering my code with snarky comments like //Ermigerd, this guy really is a N00b!.

Oh, the shame.

So, in recent times I’ve decided to get serious about learning.  XPages looks to be exploding beyond it’s current boundaries very quickly right now (more about that in my next blog post) and so I really have to lift my game to get on board.  I’m a bit of a book guy when it comes to study, but after a couple of aborted attempts at picking a javascript book that I like with Eloquent JavaScript and Crockford’s ‘Good parts’, I stumbled across a book called JavaScript Enlightenment by Cody Lindley, and I thought I would recommend it for any other folks out there who haven’t quite had that lightbulb moment with JavaScript.

Unlike many JavaScript books, this one attacks the problem from the underlying concepts of the language, explaining JavaScript objects first, and using this concept to build a deeper understanding of some of the  concepts that I have always struggled to get my head around – prototypes, inheritance, and of course, objects and constructors.  The material is further explained by fantastic code examples that cut to the core of the subject at hand without introducing too many unrelated concepts – something I don’t always see in typical coding texts.  My only criticism of the book is the excessive use of the word ‘grok’ which grates on me a little, but I think that might just be a measure of the relative difference in coolness between the author and myself.  Finally, the best thing about the book is that it is short and concise, packing all of this into less than 200 pages.

For the first time ever I feel like I ‘get’ JavaScript objects, and I’m hopeful that a better understanding of the fundamentals will be invaluable when I start diving into frameworks and other cool JavaScript related stuff.  I also feel like I’m better prepared to dive back in for another look at Mr. Crockford’s best bits, so to speak, so I think that will be my next port of call.  I still haven’t got to the point where I’m not embarrassed by my own code, but I feel like I’m on the way.

Posted by: Brendan Long | June 1, 2014

OneUI, Radio Groups, and CSS Specificity

Using OneUI might be a little passe these days, but I’m all for the easy cop-out if I’m trying to get something out quickly.  However, OneUI sometimes brings a few CSS quirks along to XPages that you need to wrestle with and work around.

For example, try sticking a Radio Button Group or a Checkbox Group inside a table with the oneUI style of .LotusTable.  LotusTable adds a top border to your table rows which looks kinda nice, but just when you’re congratulating yourself on making your table look 2012-cool with zero effort, you notice something:

RadioGroupBorder

The radio button has a little top border.  Nobody wants to see that.

Why, oh cruel and heartless browser?

This happens because the Radio Button Group is rather unfortunately rendered as a table, and the oneUI stylesheet contains the usually helpful line:

.lotusTable td { border-top: 1px solid #EEEEEE;}

Which is, of course the rule that puts the borders on your table rows.  Seeing as the Radio Group table is still nested inside the .lotusTable table, it all flows downhill, so to speak.

No problem.  Just add a class with some CSS, right?

Wrong.  As it turns out, you can’t add a class to the table in question because it is rendered by XPages without any style information.  Adding a class to the radio group applies that class to the <fieldset> tag that XPages uses as a container for the table, but this is then over-ridden by CSS.

The solution to this one comes from remembering one of those helpful CSS things that nobody ever bothers to remember – specificity.  If more than one CSS rule applies to a particular element, the rules duke it out using the following scoring system to decide on the winner:

  • ID Selectors (“#myDiv”) are worth 100 points.
  • Class selectors (“.lotusTable”) are worth 10 points
  • HTML tag selectors (div) are worth 1 point.

So, the easy thing to do would be to throw a panel around the radio button group with a set id, but I prefer to avoid adding extra tags if I can.  All you need to do is beat the offending rule’s score by one, so the following rule will do the trick:

.lotusTable fieldset td {
border-top: none;
}

The bonus here is that this will also work for checkbox groups, as they also use the ‘table in a fieldset’ markup.  Happy days!

Posted by: Brendan Long | October 31, 2013

doc.getItemValue – not risky anymore

This one is a bit of a pleasant surprise for me, so I thought I’d share.  I found myself looking at Chris Toohey’s (excellent) blog for a tip, and stumbled across a comment that suggested that if you call doc.getItemValue(“noWay”);

in SSJS OR LotusScript, and the item doesn’t exist, the method is friendly enough to return an empty java.util.Vector (or in the case of LS, an array).

I had no idea.  I’ve been doing the good old defensive if (doc.hasItem(“noWay”)) check since forever, and now it looks like I don’t have to worry about it anymore.

Posted by: Brendan Long | September 24, 2013

How a Crappy Administrator Does Upgrades

Everybody knows that Notes upgrades are easy. Ridiculously easy. So easy, in fact, that IBM don’t seem to think anybody needs documentation anymore. However, when you’re a bumbling, way-too-part-time Notes Administrator with sole responsiblity for the corporate servers, upgrades can be a tricky business. Assuming that you’re like me and you’re too lazy to ever reach a point where you understand the risks in detail, how do you know when to pull the trigger?

My tried and true method for timing an upgrade is to wait for the point in time when my desire for shiny new features finally overcomes my fear of blowing up the mail server and facing the pitchforks, and then to jump in both feet first with my eyes closed and hope for the best. Usually this is hastened along a little by the traditional glowing reports from the usual suspect bloggers, and in this case I had a few extra spurs, namely:

  • The 8.5.3 version of iNotes doesn’t work well (and when I say well, I mean ‘at all’) on newer versions of firefox and nobody likes you when you tell them to use a different browser.
  • My old boss beat me to the upgrade and he has heaps more users and a mountain of bureaucracy to overcome, and he has been bagging me about it relentlessly.

So, it’s upgrade time.

I started on Sunday morning with a fresh VMWare snapshot. Let’s face it, your snapshot is going to be completely worthless as soon as one email hits the server post-upgrade, but it’s still worth having, if only because it gives you something to wave in front of the risk-averse management types who know you’re a cowboy at heart. I found a little bit of doco (OK, I was being snide before) on the IBM domino wiki, some of it for Notes 9, and some of it for 8.5, and I figured they were close enough.

So, admin server first. I disabled the services, rebooted, installed the software, ran a couple of tasks and then rebooted. Up she came, and I prepared to send the triumphant mail to our important client types telling them that everything was back up. In an ironic twist, my Notes client choked on the email because my second directory wasn’t available in Directory Assistance and it didn’t recognise the important client types.  My worst nightmare – a real problem requiring troubleshooting!  A few hopeful restarts followed by a bit of frantic googling and a few show xdir reload commands later, and I was in trouble. I was forced to actually read the error message on the console – something I haven’t had a great deal of success with in the past, to be honest – but this time around I was pleased to see that the server could tell me how to fix things. The error said:

“error opening Directory Assistance Database da.nsf – Function only supported for transaction logged databases”

and as it turned out, that’s exactly what the problem was. I have no idea whatsoever how or why, but my da.nsf had transaction logging disabled. I re-enabled it, restarted, and everything came up nicely. Phew!

On to the clustered app server, and I’m pleased to say that this one went over without a hitch.

Next up: Traveler. I was hoping for a repeat of my first Traveler install, where I blindly threw it at the server and hoped for the best and it.just.worked. I’m pleased to say that’s pretty much what happened, but I will say that the traveller install was quite slow, and I had to do a hail Mary restart when it didn’t seem to initialise properly the first time.  It’s probably in the doco somewhere.  My personal highlight though was reading the informational messages that Traveler pops up as it goes through the process of upgrading itself. First it tells you things are going along swimmingly, doing step 10 of 20, and then the next minute it says “Step 1 of 2016”.  Woah, looks like we’re in for a long night!  Fortunately things sped up not long after. On my final restart I saw a few worrying warning messages on my server console, but I figured I’d ignore those for a little while and see if they go away. Job done.

I’ve still got one more (DRP) server to do, and then I’m left with the unspeakable. Sametime entry. I hear Sametime 9 is coming out soon, and the reports of the likely architecture are looking decidedly tl:dr to me. Hopefully IBM make a liar out of me and it’s as easy as it has always been.

UPDATE: Two days on, and I have converted the design of a few mail files. It seems to be playing nicely with my 8.5.3 client base in my pilot group, so I’m hoping to unleash iNotes at least by the end of this week, and then it’s on to the bumbling client rollout.

Posted by: Brendan Long | September 13, 2013

Checking a File Upload Control – Server Side

In my latest escapade, I’m looking to provide an avatar-like feature on a staff record so that staff can upload a self-portrait.  I’m pretty sure most of the staff at my company, myself included, will be unable to resist the urge to change their photo to something immature, but I digress.  Avatars it is.

So, I’m displaying an image from a “Photo” field in the document, and providing a File Upload control for the user to change the image.  Pretty simple stuff.

My first question was around making sure that you only ever have one photo in the photo field, so that we can just upload the first attachment.  A bit of googling took me to a great answer by Mark Leusink on StackOverflow that makes use of the method NotesXSPDocument.getAttachmentList(“rtitem”).  This returns a list of attachments of type DominoDocument.AttachmentValueHolder – this has a property called getState() that tells you if the file is being added by the file upload control.  Brilliant!


var attList = document1.getAttachmentList("Photograph");

for(var i=0; i<attList.size(); i++) {
var att = attList.get(i);

          if (att.getState()==0) {      //STATE_INDOCUMENT: this is the 'old' file: remove it
                document1.removeAttachment("Photograph", att.getName() );
          } else if (att.getState()==1) {       //STATE_ADDED: this is the new file
               //leave it
          }
}

I popped this into the querySave event for my data source, and it works well – but I was rather unimpressed when I discovered that the code dutifully cleared my photo field even when there wasn’t a file in the File Upload.  Of course it did.  Silly me.

So, I needed to check the file upload first and only clear things out if there was a new image on the way.  This turned out to be a little more difficult than I expected.  You can validate the file upload easily enough in client side JS, but I didn’t really want to add client side code or an extra control to act as a flag – that seems too much like the old skool hidden computed fields stuff that we did with Notes client apps.  I wanted to do it on the server side instead.

I went diving, and found a few possible solutions, but nothing that I really liked.  Then I realised that a nice simple solution was staring me in the face – I could use the code I had just discovered to do the check, like so:


var attList = document1.getAttachmentList("Photograph");
var uploading = false;

//First pass - check to see if we are uploading a file
for (var i=0; i<attList.size(); i++){
     var att = attList.get(i);
     if (att.getState()==1){
          uploading = true;
     }
}

//Second pass - if we are uploading, remove everything except the one we are uploading
if (uploading == true){

     for(var i=0; i<attList.size(); i++) {
          var att = attList.get(i);

          if (att.getState()==0) {      //STATE_INDOCUMENT: this is the 'old' file: remove it
               document1.removeAttachment("Photograph", att.getName() );
          } else if (att.getState()==1) {       //STATE_ADDED: this is the new file
               //leave it
          }
     }
}

This is all pretty simple stuff, but it reminds me that I need to put more time into learning about the various methods and properties available in the dim, dark corners of the object model.  I find myself pining for an XPages version of the old-school LotusScript poster that everybody had up on their wall back in the day.  Sure, the 2013 version might be as big as the side of a barn, but I’d still be tempted to find a big enough wall if such a thing existed.

Posted by: Brendan Long | July 30, 2013

Fun with repeat controls – column totals

Last week I had the opportunity to delight in what is perhaps the most enjoyable scenario for any crusty old Notes developer switching over to XPages – I created a view with a DBColumn in one of the columns, using a repeat control.  It’s probably a little bit ho-hum in the brave new world of java with a side serve of beans, but  I’m new enough to the game that it still feels cool.  I’m like a guy admiring his new mullet in the mirror, I suppose.

Anyway, I digress.  To make things a little more interesting, I needed to have column totals at the bottom, and the view could be filtered with a few fields at the top.  The formula for one of the columns was a little complex, with a nice smattering of ‘if this value then use that field, else use the other field’ thrown in for good measure, so it wasn’t going to be a simple case of a DBLookup to grab the values I needed.

Running Total

After a bit of thought, I decided the best approach would be to keep a running total by updating a variable in requestScope each time a new row was computed by the repeat control.  Pretty straightforward.  In the repeat control’s collection formula I would start off with something like:

//Reset the total for the blah column
viewScope.put("blahTotal", 0);

and then in the computed field in the table cell in the repeat control I would include:

viewScope.put("blahTotal", viewScope.get("blahTotal") + newVal);

and then finally, in the computed field in the footer row for the table:

viewScope.get("blahTotal");

Simple, right?

But it’s never that simple

My big voila! moment was somewhat soured when I opened up the xpage.  For some reason, my totals were double what they should have been.  It was pretty obvious that due to the foibles of the JSF life cycle, my computed fields were computing twice.

I threw in some debugging messages into a sessionScope variable, and added an Edit Box with the same formula for good measure, and found out something interesting.  My computed fields computed twice, but the edit boxes computed only once.  Even more interesting, the control was computing twice in the same cycle.

For example, if I had three row values: 1, 2 and 3, I would have expected my sessionScope variable to show 1-2-3-1-2-3-1-2-3-1-2-3, as the controls were computed each time the page was rendered.  However, my sessionScope variable reported 1-1-1-2-2-2-3-3-3, which told me that the controls were computing multiple times in the same JSF phase.  Strange.

To make matters worse, I tried stripping my page back to just the repeat control table, and the computed field was still doubling up, but if I used a brand new page with a basic view, I was able to get a fairly similar scenario to work properly.  I was in danger of falling into my bad habit of investigation procrastination and blowing a few days on this thing, so I needed to snap out of it and ask for some help.

Hello StackOverflow!

I was a little stumped, so I posted up a question on StackOverflow.  I didn’t get an answer to explain why my computed field was computing twice, but I did get some advice that put me out of my misery.  Instead of agonising about why the computed field was firing multiple times, I could just use a formula that only stored the value once for each row, regardless of how many times JSF decided to compute it.  Java HashMaps are ideal for this, as you can store a set of document unids along with their corresponding column values.  Much more robust.

My StackOverflow saviour posted up a funky java class that would have done the job nicely, but I copped out and just used the approach with a HashMap in requestScope.

Problem solved!

So, the improved code looks a little something like this.  In the repeat control’s collection formula we need to initialise our HashMap:

requestScope.put("blahColumn", new java.util.HashMap());

In the computed field in the repeat control, we add (or over-write) a value for the document in question:

var subTotal:java.util.HashMap = requestScope.get("forecastColumn");
subTotal.put(entry.getUniversalID(), newVal);

and lastly, the computed field for the total:

//Start with a 0 value just in case
var subTotal = 0;

//The column values are stored in a java HashMap in requestScope
var colVals:java.util.HashMap = requestScope.get("blahColumn");
var iterator:java.util.Iterator = colVals.entrySet().iterator();

//Sum the values in the HashMap
while (iterator.hasNext()){
var nextEntry = iterator.next();
subTotal = subTotal + nextEntry.getValue();
}

return subTotal;

and we’re done.  You could obviously turn this into a funky reusable function or java class given a little bit of time, but for now I’m pretty happy with the minimal code solution because my view only has a couple of columns with totals.  And I’m lazy.

So what did I learn here?

  • The JSF life cycle does some mysterious things in the background, and sometimes you’ve just got to suck it up and accept that.  Don’t try to understand it.  It just does.
  • Sometimes it’s better to come up with a robust solution so you don’t have to spend hours trying to work out what JSF is doing to your page.
  • Even if you’re not up to your neck in java, it’s worth knowing about a few handy java classes that you can use to save time.

and lastly, StackOverflow is a great resource when you’re stuck.

 

 

Posted by: Brendan Long | March 29, 2013

The perils of the Social Media Hiatus

Way back around Christmas time I decided to take my now annual twitter and blog reading hiatus, mainly as a means of escaping the dreaded New Years Eve.

Get Anti-social.  Screw Business*

In a way, this is always a good thing for me, just like any week spent away from technology tends to be a good thing.  Sometimes you need to clear your head, and I’ve found that a week away from electronics of any kind works better than anything else I can think of.

However, when combined with a powerful procrastinatory (is that a word?  It should be) streak and a packed work calendar, getting back on the social horse can prove to be a difficult task.  My social media hiatus stretched from weeks into a few months, and I’m still finding it difficult to make the time, despite the fact that it’s a really exciting time in the Notes world, with Notes 9 out in the wild and the blogs buzzing.

What this really brings home for me is that ‘getting social’ is something that takes a proper commitment, and it’s not always a natural or easy thing to do for some, myself included.  I guess it’s worth considering the benefits vs the effort required, and if the little voice in my head that keeps telling me that I’m missing out on something right now is anything to go by, I think it’s worth the effort to get myself back into gear.

Hopefully.

*This was almost the title for my blog.  In hindsight, I’m glad I didn’t go there for fear of being woken up by IBM hired goons in the middle of the night.

Posted by: Brendan Long | March 6, 2013

Gotcha! applicationScope on Multiple Replicas

Like all XPages converts, I found it mildly exciting when I first learned about scoped variables.  Being able to store all of your keyword type data that rarely changes in applicationScope and recall it quickly is an enormous improvement over using @DbLookup.  Apart from the obvious improvements to application performance, you also avoid wasting an afternoon typing out hundreds of DBLookup and DBColumn forumlas on your form.

I’m not saying I’ve ever done that myself, of course.

Anyway, applicationScope is cool, but there is one gotcha that you need to keep in mind when you’re working on an application that will be released into the real world.  It’s fairly obvious, but it is worth keeping in mind.

applicationScope variables are not replicated between servers.  Not even clustered servers.

This is one of those things that can bite you when you have just breezed through an effortless UAT phase and launched your application onto the production server cluster.  You’re really hoping to wow the users with a bug-free, rock solid application with a spanking new UI, but then somebody changes one of those values that rarely change, and the next thing you know half of your users are booking into the training course on the Gold Coast and the other half are going completely nuts because the only option they get is the alternative session in Melbourne.  In July.

Playing It Safe

Once you know about this, there are oodles of ways to keep things matching.  Here’s my current approach.

Store all of your keyword values on a single document, or a collection of dedicated documents.  When the keywords are saved, load the values into applicationScope along with a sequential version number that will be checked for currency.  Store this number on the Configuration document and in applicationScope.

Once you’ve got your version number stored, it is merely a case of checking the document when you open up any XPage.  If the version number in applicationScope differs from the one in the setup document, we have to update.  Simple!

function initAppScope() {
//Initialise application scope variables from the keyword document
//Need to do this in two scenarios - applicationScope has no values (new day) or setup document has been
//updated (possibly on another server)
var viewSetup:NotesView = database.getView("LookupSetup");
var docSetup:NotesDocument = viewSetup.getDocumentByKey("Setup");

if (null == docSetup) {
errorNoSetupDoc();  //sends an email to the application administrator instructing them to panic
return null;
}

if (docSetup.getItemValueString("setupVersion") !== applicationScope.get("setupVersion")){
applicationScope.put("setupVersion", docSetup.getItemValueString("setupVersion"));

//Initialise the rest of your values here

}

Of course, this works best if your replication schedules are frequent, or your servers are clustered.  If not, you might still get caught waiting for changes to replicate to other servers and you might need to think about having a more robust solution if this is crucial.  In my case, I’m dealing with clustered servers and nobody would ever arrange a company event on the Gold Coast.  I’m pretty safe.

Older Posts »

Categories