2009
10.30

Rocky Road Ahead -> Defensive Programming Required!

You have been warned.

Old programmers tend to revert to printf() when it is time to find where the bugs are. It is much nicer to have a debugger handy. However, while trying our first Google Wave Robot, I longed for a better comprehension of the events passed to the robot and started printing the received events directly in the wave. This is when I found out that minor changes, that looked otherwise inconspicuous, would greatly affect the robot’s behaviour. In fact, small changes would stop the robot altogether.

As it turns out, there exist currently calls to the Google Wave Java API that throws exceptions, although the signatures do not report any. If an exception is raised in the printing while trying to debug a piece of code, then the robot appears unresponsive. For more specifics, look at bugs:

Therefore, I propose here a set of functions to print an instance of RobotMessageBundle received in the robot processEvents() call. NOTE: be careful in using these functions only in situations where receiving new submitted blips are not the trigger of submitting newer blips. This would be an unwanted recursive situation.

The following example is safe since the debug print happens only on WAVELET_SELF_ADDED events:

   Wavelet wavelet = bundle.getWavelet();
   if( bundle.wasSelfAdded() ) {
      Blip blip = wavelet.appendBlip();
      TextView textView = blip.getDocument();
      textView.delete();

      printBundle(bundle,textView,null);
   }

Here are the printing/debugging functions:

   public void printBundle(RobotMessageBundle bundle, TextView printTextView, String prefix) {
      if( null == prefix ) {
         prefix = "";
      }

      // is new wave
      try {
         printTextView.append(prefix+"bundle.isNewWave() "+bundle.isNewWave()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"bundle.isNewWave() "+exceptionToString(e)+" \n ");
      }

      // was self added
      try {
         printTextView.append(prefix+"bundle.wasSelfAdded() "+bundle.wasSelfAdded()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"bundle.wasSelfAdded() "+exceptionToString(e)+" \n ");
      }

      // was self removed
      try {
         printTextView.append(prefix+"bundle.wasSelfRemoved() "+bundle.wasSelfRemoved()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"bundle.wasSelfRemoved() "+exceptionToString(e)+" \n ");
      }

      // robot address
      try {
         printTextView.append(prefix+"bundle.getRobotAddress() "+bundle.getRobotAddress()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"bundle.getRobotAddress() "+exceptionToString(e)+" \n ");
      }

      // Events
      try {
         List events = bundle.getEvents();
         printTextView.append(prefix+"bundle.getEvents() "+((events==null)?"null":"list of "+events.size()+" events")+" \n ");
         if( null != events ) {
            for(Event event : events) {
               printBundleEvent(event, printTextView, prefix+"   ");
            }
         }
      } catch(Exception e) {
         printTextView.append(prefix+"*** Error on printing event: "+e.getMessage()+" \n ");
      }
   }

   public void printBundleEvent(Event event, TextView printTextView, String prefix) {
      if( null == prefix ) {
         prefix = "";
      }

      // Event type
      try {
         EventType eventType = event.getType();
         printTextView.append(prefix+"Event.getType() "+((eventType==null)?"null":eventType.name())+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getType() "+exceptionToString(e)+" \n ");
      }

      // button name
      try {
         printTextView.append(prefix+"Event.getButtonName() "+event.getButtonName()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getButtonName() "+exceptionToString(e)+" \n ");
      }

      // changed title
      try {
         printTextView.append(prefix+"Event.getChangedTitle() "+event.getChangedTitle()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getChangedTitle() "+exceptionToString(e)+" \n ");
      }

      // changed title
      try {
         printTextView.append(prefix+"Event.getCreatedBlipId() "+event.getCreatedBlipId()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getCreatedBlipId() "+exceptionToString(e)+" \n ");
      }

      // removed blip id
      try {
         printTextView.append(prefix+"Event.getRemovedBlipId() "+event.getRemovedBlipId()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getRemovedBlipId() "+exceptionToString(e)+" \n ");
      }

      // modified by
      try {
         printTextView.append(prefix+"Event.getModifiedBy() "+event.getModifiedBy()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getModifiedBy() "+exceptionToString(e)+" \n ");
      }

      // changed version
      try {
         printTextView.append(prefix+"Event.getChangedVersion() "+event.getChangedVersion()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getChangedVersion() "+exceptionToString(e)+" \n ");
      }

      // time stamp
      try {
         printTextView.append(prefix+"Event.getTimestamp() "+event.getTimestamp()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getTimestamp() "+exceptionToString(e)+" \n ");
      }

      // blip
      try {
         printTextView.append(prefix+"Event.getBlip() "+event.getBlip()+" \n ");
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getBlip() "+exceptionToString(e)+" \n ");
      }

      // Added participants
      try {
         Collection participants = event.getAddedParticipants();
         printTextView.append(prefix+"Event.getAddedParticipants() "+
               ((participants==null)?"null":"collection of "+participants.size()+" strings")+" \n ");
         if( null != participants ) {
            for(String participant : participants) {
               printTextView.append(prefix+"   "+participant+" \n ");
            }
         }
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getAddedParticipants() "+exceptionToString(e)+" \n ");
      }

      // Removed participants
      try {
         Collection participants = event.getRemovedParticipants();
         printTextView.append(prefix+"Event.getRemovedParticipants() "+
            ((participants==null)?"null":"collection of "+participants.size()+" strings")+" \n ");
         if( null != participants ) {
            for(String participant : participants) {
               printTextView.append(prefix+"   "+participant+" \n ");
            }
         }
      } catch(Exception e) {
         printTextView.append(prefix+"Event.getRemovedParticipants() "+exceptionToString(e)+" \n ");
      }
   }

   public String exceptionToString(Exception e) {
      return "ERROR:"+e.getClass().getName()+"("+e.getMessage()+")";
   }

No Comment.

Add Your Comment