docs: Object getValue(
        MatchSpaceKey msg,
        Object contextValue)
    throws MatchingException, BadMessageFormatMatchingException
    {
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
        tc.entry(
          cclass,
          "getValue",
          "msg: " + msg + "contextValue: " + contextValue);    
      // The value which we'll return    
      Boolean resultBool = Boolean.FALSE; 
  
      // May need to call MFP multiple times, if our context has multiple nodes
      if(contextValue != null)
      {
        // Currently this must be a list of nodes
        if (contextValue instanceof SetValEvaluationContext)
        {
          SetValEvaluationContext evalContext = (SetValEvaluationContext)contextValue;
          
          // Get the node list
          ArrayList wrappedParentList = evalContext.getWrappedNodeList();
          // If the list is empty, then we have yet to get the document root
          if(wrappedParentList.isEmpty())
          {
      	    //Set up a root (document) context for evaluation
          	Object docRoot = Matching.getEvaluator().getDocumentRoot(msg);
              
            // Create an object to hold the wrapped node
            WrappedNodeResults wrapper = new WrappedNodeResults(docRoot);
            // Set the root into the evaluation context
            evalContext.addNode(wrapper);
          } 
          
          // Iterate over the nodes
          Iterator iter = wrappedParentList.iterator();
  
          while(iter.hasNext())
          {
            WrappedNodeResults nextWrappedNode = (WrappedNodeResults)iter.next();       
            Object nextParentNode = nextWrappedNode.getNode();
            
            String debugString = ""; 
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              tc.debug(this,cclass, "getValue", "Evaluation context node: " + nextWrappedNode);  
            
            // If no cached value we'll need to call MFP
            Boolean tempBool = nextWrappedNode.getEvalBoolResult(id.getName());
              
            if(tempBool == null)
            {
              // Call MFP to get the results for this node
              tempBool = (Boolean) msg.getIdentifierValue(id,
                                                          false,
                                                          nextParentNode, 
                                                          false); // false means dont return a list
  
              // Add result to cache for next time
              nextWrappedNode.addEvalBoolResult(id.getName(), tempBool);
              
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                debugString = "Result from MFP ";            
            }
            else
            {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                debugString = "Result from Cache ";        
            }   
            
            // Useful debug
            if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
            {
              String asString = ", type: Boolean - <" + tempBool + ">";
  
              tc.debug(this,cclass, "getValue", debugString + "for identifier " + id.getName() + asString);
            }   
            
            if(tempBool.booleanValue())
            {
              resultBool = Boolean.TRUE;
              break;
            }     
   
          } // eof while
        } // eof instanceof XPathEvaluationContext
      } // eof contextValue not null
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
        tc.exit(this,cclass, "getValue", resultBool);
      return resultBool;
    }