John M. Wargo

Twitter Feed

johnwargo: Here we go - First-time smartphone buyers favor Android over iOS: http://t.co/mQwxRHDP
johnwargo: Ummm, eating a handful of Dark Chocolate M&M's So good!
johnwargo: Working on the book's preface, hard 2 keep myself from saying 'the book you hold in your hand' since many won't ever actually hold the book
johnwargo: When sending an email to a group, why is it that Lotus Notes is smart enough to not send me a copy if I'm in the group but Outlook isn't?
johnwargo: Staying at a hotel without a gym. Ugh. I didn't even think to check to see if they had one, assumed they did.
Home
Mobilizing Domino Data Using REST: Part 1 PDF Print E-mail
User Rating: / 3
PoorBest 
Wednesday, 19 January 2011 08:00

The first part of a series on mobilizing IBM Lotus Domino data for mobile platforms that don’t directly support XML-based Web Services (like Android and the iPhone).

Introduction

Back when I worked for Research in Motion, I presented topics at Lotusphere and the View Developer Conference on how to connect to Domino databases from rich client applications on BlackBerry. Research in Motion had some pretty cool tools at the time (MDS Studio) that made it painfully easy – I could build a BlackBerry application that talked to a Domino Web Service in about 3 minutes.

Beginning with BlackBerry Device Software 4.2, Research in Motion added the ability to connect to Web Services from a BlackBerry Java application (using JSR 172), so I added building a BlackBerry Java application to my set of demos. I then wrote a series of articles on this site that documented the whole process. Here are links to the articles:

Domino & BlackBerry Java Applications Part 1

Domino & BlackBerry Java Applications Part 2

Domino & BlackBerry Java Applications Part 2.5

Domino & BlackBerry Java Applications Part 3

After I left Research in Motion, I continued to present at the same conferences and added the Midwest Lotus User Group (MWLUG) conference to my standard tour. Because of the Web Services capabilities of Microsoft Visual Studio, it was pretty easy to add a demo of a Windows Mobile application to my presentations as well.

The iPhone and Android platforms were released without the ability to connect to XML-based Web services, so I had to find a different way for those platforms to connect to Domino. Android includes the JSON libraries from json.org, and there were several versions of JSON libraries for the iPhone platform up there as well, so I decided I’d use REST and JSON to accommodate Android and iPhone. At Lotusphere 2010, while recovering from pneumonia, I added an Android demo to the presentation and was even able to show an almost complete (I never finished it) iPhone example as well. At the conference I promised I’d publish an article here demonstrating how I built the Android application, so here it begins (finally). This article is the first part of a new series that’s all about how to use REST and JSON to mobilize Domino data on Android. There’ll be two articles in this series here, plus I’ll eventually publish an article in the View illustrating the iPhone application.

The Sample Application

In case you missed the first part of this series, the application we’re building here allows a mobile user to lookup contacts in the Domino Directory. The assumption here is that most every Domino customer has some extra database of contacts and mobile users will need the ability to lookup contact information. This is the same process as demonstrated in the original series; it’s just modified so it leverages JSON instead of Web Services.

About REST

REST stands for Representational State Transfer and essentially it’s a form of Web Service where parameters for a request are sent on the URL to the server and the server’s response is returned in the body of the HTTP response typically in XML or JSON format although it could be in any format. RESTful Web Services are much easier to use then XML Web Services since it’s so much less work to call the service and there’s much less overhead when the data is returned as JSON rather than XML.

About JSON

JSON stands for JavaScript Object Notation and it’s a way of representing data in a textual format that’s easy to parse and manipulate. To quote json.org (www.json.org):

“JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

JSON is built on two structures:

* A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.

* An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

These are universal data structures. Virtually all modern programming languages support them in one form or another. It makes sense that a data format that is interchangeable with programming languages also be based on these structures.”

In JSON, an array looks like this:


And an Object looks like this:


You’ll see how these apply in the following section.

*JSON Images shamelessly ‘borrowed’ from www.json.org.

Designing the JSON Agent

In the Web Services version of the agent I created for the BlackBerry and Windows Mobile versions of the mobile application, I created a single service that supported two operations: GetUserList and GetUserDetails. Since the needs for this application were for there to be the same two operations and each operation would be called by a URL, it would seem to make sense to make a separate Domino web agent for each operation. Unfortunately, that approach would require two agents and a bunch of duplicated code between them, so I decided to create a single agent that exposed the two operations through a single interface. So, there is going to be a single Domino agent called by the mobile application and different results would be returned to the calling program depending on what information is passed on the URL to the Domino server.

So, the URL a mobile application will be using to use the service will look like this:

http://server/database.nsf/domdirlookuprest?openagent&cmd=COMMAND&searchstr=SEARCHSTRING

Where the ‘cmd=’ and ‘searchStr=’ portions of the URL are places where the calling program can pass in parameters to control what the service returns.

To obtain a list of contacts whose last name begins with ‘war’, the mobile application will call the following URL:

http://server_name/bbnames.nsf/domdirlookuprest?openagent&cmd=list&searchstr=war

In this case, the cmd is ‘list’ and the searchStr is ‘War’ – when the agent runs on the Domino server, it will return the following JSON array (assuming that there are two contacts defined in the database whose last names begin with War):

["John Wargo", "Anna Wargo"]

Once a mobile application’s user selects a contact, the agent is called again with the following URL:

http://localhost/bbnames.nsf/domdirlookuprest?openagent&cmd=details&searchstr=john+wargo

In this case, the cmd is ‘details’ and the searchStr is my contact name. When the agent runs on the Domino server, it will return the following JSON object (notice that the first call, the call to get the list, returns a JSON array, while the second call (for the details) returns an object):

{
  "FullName" : "John Wargo", 
  "LastName" : "Wargo", 
  "FirstName" : "John", 
  "EmailAddress" : "jwargo@att.com", 
  "OfficePhone" : "330.123.4567", 
  "MobilePhone" : "330.987.6543"
}

That’s it, that’s all there is to the agent I’m showing you how to build in this article.

Probably asking yourself “Why not use the JSON capabilities already built into Domino to provide this functionality?” Well, Domino’s ability to generate JSON output is designed for rendering views in a format that’s easy for an application to process. Using the following URL:

http://server1/database.nsf.nsf/viewname?ReadViewEntries&OutputFormat=JSON

would cause the Domino server to render the view as JSON, it doesn’t help us here because we’re passing in search strings and trying to retrieve only one document. It could be done (I think) with a single category view, but taking that approach was much more work than I wanted to do.

Building the JSON Agent

Let’s dig into the agent. A sample database that contains this agent is attached at the bottom of this article.

It essentially begins with the standard stuff I put into any Domino agent:

Option Public
Option Declare
Option Base 1

Then I define some common variables I’ll need as I process the database view:

'Notes Objects
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim s As NotesSession
Dim tmpName As NotesName
Dim userView As NotesView
Dim userDoc As NotesDocument

'Other variables
Dim i As Integer
Dim jsonText As String

Finally some constants that are used to prepare the JSON text outputted by the agent:

Const amp = |&|
Const BR = |<br />|
Const comma = |, |
Const errorStr = |ERROR: |
Const quoteStr = |"|

It’s the Initialize subroutine where all of the processing happens. Remember, the service works by having essentially a single URL that’s called by the calling program. Parameters passed on the URL instruct the agent what to do. The Initialize subroutine essentially does nothing but parse the URL and call the appropriate subroutine depending on which command (‘list’ or ‘details’) is passed to the agent on the URL.
Since we’re trying to output JSON in this agent, Initialize begins with a print statement that causes Domino to skip the building of an HTML page to be sent to the calling program. If this wasn’t there, Domino would assume the agent was delivering HTML content and would prepend the beginning parts of a web page to the agent’s output.

Next, the agent gets a handle to the current Notes Session object, database object then the agent’s context (through set doc = s.DocumentContext). After that, the agent gets the URL string from the document context and parses it through repeated calls to the GetCmdLineValue function. Once it knows what command has been sent (list or details) and what search string to use, it calls the appropriate subroutine (GetContactList or GetContactDetails) to lookup the appropriate document(s) and output the necessary JSON text.

Sub Initialize()

  'Print out this line to force Domino to not write it's own 
  'HTML gunk at the beginning of the resulting page
  Print "Content-Type:text/html"
 
  Dim cmdName As String
  Dim queryStr As String
  Dim searchStr As String  
  Dim tmpStr As string
  Dim tmpInt As integer
 
  'Initialize our Notes session object
  Set s = New NotesSession
  'Then get a handle to the current database
  Set db = s.CurrentDatabase
  'Get a handle to the agent's context (header variables and so on)
  Set doc = s.DocumentContext  
 
  'Parse the command line and call the correct function
  queryStr = LCase(doc.Query_String_Decoded(0)) & amp
  cmdName = GetCmdLineValue(queryStr, "&cmd=", amp)
  searchStr = GetCmdLineValue(queryStr, "&searchstr=", amp)
  
  'Launch the appropriate function based upon what's passed in the URL
  If cmdName = "details" Then
    GetContactDetails(searchStr)
  Else
    If cmdName = "list" Then
      GetContactList(searchStr)
    Else
      'We have an invalid command passed on the Query_String, 
      'so return an error
      Print errorStr
    End If  
  End If
 
End Sub

The GetCmdLineValue function simply takes an input string and returns everything between the two delimiters.

Function GetCmdLineValue( textStr As String, delim1 As String, delim2 As String) As String

  Dim startPos As Integer  
  Dim tmpInt As Integer
  Dim valLen As Integer
 
  'find the first ocurrance of the delimeter
  tmpInt = InStr( textStr, delim1)
  'Only continue if we've found something
  If (tmpInt > 0) Then
    'Figure out where the value starts 
    startPos = tmpInt + Len(delim1)
    'Then look past there for the second delimeter
    valLen = InStr(startPos, textStr, delim2) - startPos
    'The value we're looking for is between the two delimeters
    GetCmdLineValue = Mid( textStr, startPos, valLen)
  Else
    GetCmdLineValue = ||
  End If   
End Function

The GetContactList subroutine uses the provided searchString to search the contents of the default Domino Directory $VIMPeopleByLastName view.  If it finds any documents, it builds a JSON array containing each contact name then prints the array; thereby sending the array information to the calling program.

sub GetContactList(searchStr As String)

  Const arrayStart = "["
  Const arrayEnd = "]"
 
  'Local Notes objects
  Dim ve As NotesViewEntry
  Dim vec As NotesViewEntryCollection
   
  'Other variables
  Dim numContacts As Integer
   
  'Open the view we're going to lookup against
  Set userView = db.GetView("($VIMPeopleByLastName)")
  If Not userView Is Nothing Then
    'Do we have a search string?
    If Len(Trim(searchStr)) > 0 Then
      'See if we can find any users by the search string
      Set vec = userView.GetAllEntriesByKey(searchStr)
    Else
      'Otherwise get all documents
      Set vec = userView.AllEntries
    End If
    'Now, if we have any entries - put them into the array
    If vec.Count > 0 Then
      'Get the number of contacts to use throughout the rest of the code
      numContacts = vec.Count
      'Start the Array JSON text
      jsonText = arrayStart
      'Process all of the entries in the View Entry Collection
      For i = 1 To numContacts
        Set ve = vec.GetNthEntry(i)
        If Not ve Is Nothing Then
          Set userDoc = ve.Document
          If Not userDoc Is Nothing Then
            Set tmpName = New NotesName(userDoc.FullName(0))
            If Not tmpName Is Nothing Then
              jsonText = jsonText & quoteStr & tmpName.Common & _
                quoteStr
            Else
              jsonText = jsonText & quoteStr & errorStr & _
                |Unable to obtain Contact Name| & quoteStr
            End If
          Else
             'Unable to get the document
             jsonText = jsonText & errorStr & _ 
              |Unable to open the contact document| & quoteStr
          End If
        Else
         'Unable to access the View Entry
          jsonText = jsonText & quoteStr & errorStr & _  
            |Unable to access the ViewEntry| & quoteStr
        End If
        'Add a comma if we need one (when there's more than 
        'one name being returned)
        If (i < numContacts) Then
          jsonText = jsonText & comma
        End If
      Next i
      'Write our resulting JSON results to the browser
      Print jsonText & arrayEnd
   Else
      'We got nothing, so return an empty array to the 
      'calling program
      Print arrayStart & arrayEnd
    End If
  End If
End sub

The GetContactDetails subroutine uses the provided searchString to search the contents of the default Domino Directory $VIMPeople view.  If it finds a document (It should find only one unless there are more than one contacts in the database with the exact same name), it builds a JSON object that contains each of the fields retrieved from the document then prints the object, causing the object to be returned to the calling program.

sub GetContactDetails(searchStr As String)

   Const jsonStart = |{|
  Const jsonEnd = |}|
 
  'Do we have a search string?
  'the calling program should check, but have to make sure
  If Len(Trim(searchStr)) > 0 Then
    'Open the view we're going to lookup against
    'this is a different view because we're searching against
    'the full name where above we're using last name  
    Set userView = db.GetView("($VIMPeople)")
    'Make sure we have the view
    If Not userView Is Nothing Then
      'Try to get the user document using abbreviated full name as a key 
      'This should work because the view is sorted that way.
      Set userDoc = userView.GetDocumentByKey(searchStr)
      If Not userDoc Is Nothing Then 
        'Start the JSON text we'll be returning
        jsonText = jsonStart
        'Populate the result fields 
        Set tmpName = New NotesName(userDoc.FullName(0))
        jsonText = jsonText & |"FullName" : | & quoteStr & _ 
          tmpName.Abbreviated & quoteStr & comma
        jsonText = jsonText & |"LastName" : | &  quoteStr & _ 
          userDoc.LastName(0) & quoteStr & comma
        jsonText = jsonText & |"FirstName" : | &  quoteStr & _ 
          userDoc.FirstName(0) & quoteStr & comma
        jsonText = jsonText & |"EmailAddress" : | &  quoteStr & _ 
          userDoc.InternetAddress(0) & quoteStr & comma
        jsonText = jsonText & |"OfficePhone" : | &  quoteStr & _ 
          userDoc.OfficePhoneNumber(0) & quoteStr & comma
        jsonText = jsonText & |"MobilePhone" : | &  quoteStr & _ 
          userDoc.CellPhoneNumber(0) & quoteStr & jsonEnd
        Print jsonText 
      Else
        Print errorStr & |Unable to open Contact Document|
      End If        
    Else
      Print errorStr & |Unable to open User View|
    End If
  Else
    Print errorStr & |Search String not provided|
  End If
End sub

Conclusion

That’s all there is to it. In the next installment, I’ll show you how to build an Android application that consumes the service. It only took me a year to deliver on my promise to publish this article. I wonder how long it will take me to publish the next one article. Stay tuned.

Attachments:
FileDescriptionFile size
Download this file (Domino REST.pdf)Domino REST.pdfThis article in PDF format.394 Kb
Download this file (rest_names.zip)rest_names.zipStandard Domino Directory Template including the DomDirLookupREST agent described in the article.2265 Kb
 
What does AT&T do? PDF Print E-mail
User Rating: / 2
PoorBest 
Monday, 17 January 2011 17:42

Another great article surfaced recently about AT&T and how it will be affected by Verizon getting the iPhone. The article is from PC World and it's called What does AT&T to when Verizon Starts Selling iPhones. It does a really good job highlighting the things that AT&T has done to deal with the network overload caused by iPhone users and at the same time preapre for Verizon getting the device as well.

People are going to switch, but AT&T's network has been built up to support the iPhone and, not mentioned much in many of the articles I've read, supports simultaneous voice and data. The Verizon iPhone, built on CDMA, is not going to be able to provide access to both voice and data. It's something AT&T's network supports but Verizon doesn't support until it gets to LTE. Why Apple would release a CDMA phone instead of LTE doesn't make sense to me considering people aren't going to be happy not browsing the web while talking on the phone.

When Apple comes out with a new version of the phone that runs LTE a few months later, Verizon customers will be dumping their CDMA phones and buying new LTE Phones. Good for Apple, Bad for Verizon customers.

 
The Verizon iPhone PDF Print E-mail
Monday, 17 January 2011 10:24

I've said this for a long time now and I'm speaking for myself, NOT my employer: The best thing that can happen to AT&T is for Verizon to get the iPhone. As I've written here before, Apple doesn't care about the network, they just don't. So, Verizon getting the iPhone is going to really show how good AT&T's network really is.

What's interesting is the "Verizon Deal May Expose iPhone Flaws" article in the New york Times. Like the wired article of last summer, it's a good, even, balanced & impartial look at the iPhone. Some parts of the article that struck me as interesting (and true):

Yet for all that it offers, the iPhone has always been plagued by serious drawbacks. The “phone” part of the iPhone has never worked very well, dropping calls with annoying regularity. Even when the phone works, the sound quality is often substandard. You would think in an age when fewer people are using landlines this would matter. Apparently not.

If I'm on the phone with someone and the call drops, when they call back I always ask them "you're on an iPhone, right?" I don't get dropped calls on my BlackBerry, so if two phones are on the same network and the calls drop more frequently for the one phone vs. the other, which is it? The phone or the network?  It's the phone.

Meanwhile, the iPhone’s lack of a raised keyboard makes it next to impossible to do serious e-mailing. And users have to worry constantly about battery life; if they’re not judicious, the iPhone’s battery can be drained by noon.

Yeah, how good is a phone if the battery won't last past noon?

“People so love their devices from Apple that they are willing to put up with the stupidities,” said Larry Keeley, president of the innovation and design firm Doblin. “For many users,” he added, “especially the ones Apple loves the most, the fact that the battery gets balky is how you convince yourself to get a new one.”

My oldest son, Amato, who is on my Verizon Wireless plan, told me recently that even though he was perfectly happy with his Android phone, if given the chance to switch to an iPhone, he would probably do it. “I can’t even say why,” he said. “I don’t even know if there is any real rationale behind that desire.”

True, very true - People are going to buy one no matter how good it is (or isn't).

Why not support Verizon's 4g network? That one makes no sense - right after the launch of LTE for Verizon (although Verizon's implementation of LTE isn't 4g, not yet).  Check out the quote:

At the Verizon Wireless-iPhone extravaganza on Tuesday — in which the two companies announced that the iPhone 4 would run on Verizon Wireless’s 3G network — Apple’s chief operating officer, Timothy D. Cook, was asked why Apple wasn’t going with the carrier’s faster, newer 4G LTE network. Mr. Cook replied that doing so required “design compromises” that Apple was unwilling to make.

They never make design compromises at Apple. They make consumer compromises. Yet consumers have always been willing to overlook those compromises so they can claim they own some of the coolest products on the planet.

I'm sticking with my BlackBerry, thank you. I use my iPhone for some apps (like the Sonos app) but for day to day business, nothing beats a BlackBerry.

 
Spam Tester PDF Print E-mail
Wednesday, 12 January 2011 14:49

I run a WordPress blog and setup the registration option so friends and family (especially my last remaining Aunt) can know when I post new items to the blog. I setup the system to notify me when someone registers and it's funny to see the different spammers register for the system. Usually the user name they enter doesn't look anything like the email address - that's usually a good clue for me that it's a spammer. You'd think that the user name someone selects would match their primary email address, but that's not what they usually do. I haven't tested this, but I'm sure the email addresses are bogus - too funny though how many of them end in .ru.

You've got to love it though when spammers register for your site and clearly identify themselves as spammers. Take a look at the following screen shot:

The person registered for the site and the email address they're using tells it like it is: someone testing some spamming software.

WordPress has a pretty cool system that blocks spammers from posting stuff to your blog. I use dto use the Nucleus CMS for my blog and one time I had hundreds of spam comments on all sorts of areas in my blog. With WordPress, blocking those guys is automatic, you enable the module and it keeps the bad stuff out.

You'll notice that I'm not doing what most people do and spell spam with all capital letters. A lot of folks out there think Spam is an acronym when really all it is is a tasty breakfast meat. It's just a word, nothing to get all capitalized about.

 
<< Start < 11 12 13 14 15 17 19 20 > End >>

Page 17 of 51

InformIT (Pearson Education)