/* (non-Javadoc)
   * @see org.eclipse.wst.jsdt.debug.core.jsdi.ThreadReference#resume()
   */
  public void resume() {
    if (isSuspended()) {
      try {
        if (state != EVENT_RESUME) {
          // XXX only send an request if we were not resumed by an event
          CFRequestPacket request = new CFRequestPacket(Commands.CONTINUE, id);
          String step = resolveStepKind();
          if (step != null) {
            request.setArgument(Attributes.STEPACTION, step);
          }

          CFResponsePacket response = crossfire().sendRequest(request);
          if (response.isSuccess()) {
            state = RUNNING;
          } else if (TRACE) {
            Tracing.writeString(
                "THREAD [failed continue request] " + JSON.serialize(request)); // $NON-NLS-1$
          }
        }
      } finally {
        clearFrames();
        state = RUNNING;
      }
    }
  }
 /* (non-Javadoc)
  * @see org.eclipse.wst.jsdt.debug.core.jsdi.ThreadReference#suspend()
  */
 public void suspend() {
   if (isRunning()) {
     CFRequestPacket request = new CFRequestPacket(Commands.SUSPEND, id);
     try {
       CFResponsePacket response = crossfire().sendRequest(request);
       if (response.isSuccess()) {
         // XXX catch in case the last resume failed
         state = SUSPENDED;
       } else if (TRACE) {
         Tracing.writeString(
             "THREAD [failed suspend request]: " + JSON.serialize(request)); // $NON-NLS-1$
       }
     } finally {
       clearFrames();
     }
   }
 }
 /* (non-Javadoc)
  * @see org.eclipse.wst.jsdt.debug.core.jsdi.ScriptReference#source()
  */
 public synchronized String source() {
   if (source == null) {
     CFRequestPacket request = new CFRequestPacket(Commands.SCRIPTS, context_id);
     request.setArgument(Attributes.INCLUDE_SOURCE, Boolean.TRUE);
     request.setArgument(Attributes.URLS, Arrays.asList(new String[] {url}));
     CFResponsePacket response = crossfire().sendRequest(request);
     if (response.isSuccess()) {
       List list = (List) response.getBody().get(Attributes.SCRIPTS);
       if (list != null && list.size() > 0) {
         initializeScript((Map) list.get(0));
       }
     } else if (TRACE) {
       Tracing.writeString(
           "SCRIPTREF [failed source request]: " + JSON.serialize(request)); // $NON-NLS-1$
     }
   }
   return source;
 }
 /* (non-Javadoc)
  * @see org.eclipse.wst.jsdt.debug.core.jsdi.ThreadReference#frames()
  */
 public synchronized List frames() {
   if (frames == null) {
     CFRequestPacket request = new CFRequestPacket(Commands.BACKTRACE, id);
     request.setArgument(Attributes.FROM_FRAME, new Integer(0));
     request.setArgument(Attributes.INCLUDE_SCOPES, Boolean.TRUE);
     CFResponsePacket response = crossfire().sendRequest(request);
     if (response.isSuccess()) {
       frames = new ArrayList();
       List frms = (List) response.getBody().get(Attributes.FRAMES);
       if (frms != null) {
         Map fmap = null;
         for (int i = 0; i < frms.size(); i++) {
           fmap = (Map) frms.get(i);
           // XXX hack to prevent http://code.google.com/p/fbug/issues/detail?id=4203
           if (fmap.containsKey(Attributes.URL)) {
             frames.add(new CFStackFrame(virtualMachine(), this, fmap));
           } else if (TRACE) {
             Tracing.writeString(
                 "STACKFRAME [got bogus stackframe infos]: "
                     + fmap.values().toString()); // $NON-NLS-1$
           }
         }
       }
     } else {
       if (TRACE) {
         Tracing.writeString(
             "STACKFRAME [backtrace request failed]: " + JSON.serialize(request)); // $NON-NLS-1$
       }
       if (frames != null) {
         frames.clear();
       }
       return Collections.EMPTY_LIST;
     }
   }
   return frames;
 }