Package org.fusesource.ide.launcher.debug.model

Source Code of org.fusesource.ide.launcher.debug.model.CamelDebugTarget$ThreadGarbageCollector

/*******************************************************************************
* Copyright (c) 2014 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.fusesource.ide.launcher.debug.model;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.fusesource.ide.camel.model.RouteContainer;
import org.fusesource.ide.camel.model.io.XmlContainerMarshaller;
import org.fusesource.ide.commons.util.CamelUtils;
import org.fusesource.ide.commons.util.Strings;
import org.fusesource.ide.launcher.Activator;
import org.fusesource.ide.launcher.debug.model.exchange.BacklogTracerEventMessage;
import org.fusesource.ide.launcher.debug.model.exchange.Header;
import org.fusesource.ide.launcher.debug.util.CamelDebugRegistry;
import org.fusesource.ide.launcher.debug.util.CamelDebugRegistryEntry;
import org.fusesource.ide.launcher.debug.util.CamelDebugUtils;
import org.fusesource.ide.launcher.debug.util.ICamelDebugConstants;
import org.fusesource.ide.launcher.util.CamelDebugContextEditorInput;

/**
* Camel Debug Target
*
* @author lhein
*/
public class CamelDebugTarget extends CamelDebugElement implements IDebugTarget {

  // associated system process (VM)
  private IProcess fProcess;
 
  // containing launch object
  private ILaunch fLaunch;
 
  // JMX connection info
  private String jmxUri;
  private String jmxUser;
  private String jmxPass;
 
  private JMXServiceURL url;
  private JMXConnector jmxc;
  private MBeanServerConnection mbsc;
 
  // terminated state
  private boolean fTerminated = false;
 
  // processing state
  private boolean fProcessingActive = true;
 
  // program name
  private String fName;
 
  // camel context
  private String camelContextId;
  private String contentType;
 
  // the currently suspended node's id
  private String suspendedNodeId;
 
  // threads
  private HashMap<String, CamelThread> threads = new HashMap<String, CamelThread>();
 
  // event dispatcher
  private EventDispatchJob dispatcher;
  private ThreadGarbageCollector garbageCollector;

  /**
   * the debugger facade
   */
  private CamelDebugFacade debugger;
 
  /**
   * Constructs a new debug target in the given launch for the
   * associated Camel VM process.
   *
   * @param launch containing launch
   * @param process Camel VM
   * @param jmxUri jmx uri to send requests to the VM
   * @param jmxUser user name for jmx auth
   * @param jmxPass password for jmx auth
   * @exception CoreException if unable to connect to host
   */
  public CamelDebugTarget(ILaunch launch, IProcess process, String jmxUri, String jmxUser, String jmxPass) throws CoreException {
    super(null);
    this.fLaunch = launch;
    this.fTarget = this;
    this.fProcess = process;
    this.jmxUri = jmxUri;
    this.jmxUser = jmxUser;
    this.jmxPass = jmxPass;
   
    // retrieve the context id
    initCamelContextId();
   
    // start connector job
    JMXConnectJob conJob = new JMXConnectJob();
    conJob.schedule();
   
    this.dispatcher = new EventDispatchJob();
    this.dispatcher.schedule();
   
    this.garbageCollector = new ThreadGarbageCollector();
    this.garbageCollector.schedule();
   
    DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
  }
 
  /**
   * retrieves the camel thread for the given id
   *
   * @param uniqueId
   * @return
   */
  public CamelThread getThreadForId(String uniqueId) {
    CamelThread t = null;
    if (threads.containsKey(uniqueId)) {
      t = threads.get(uniqueId);
    } else {
      t = new CamelThread(this, uniqueId);
      threads.put(uniqueId, t);
    }
    return t;
  }
 
  /**
   * returns the id of the node which is currently suspended
   *
   * @return
   */
  public String getSuspendedNodeId() {
    return this.suspendedNodeId;
  }
 
  /**
   * generates a unique key for the thread
   *
   * @param msg  the message to take data from
   * @return  a unique key or null if msg was null
   */
  public String generateKey(BacklogTracerEventMessage msg) {
    if (msg == null) return null;
    if (msg.getMessage().getHeaders().size()>0) {
      for (Header h : msg.getMessage().getHeaders()) {
        if (h.getKey().equalsIgnoreCase("breadcrumbid")) {
          // there is a breadcrumbId - use that as key
          return h.getValue();
        }
      }
    }
    // otherwise use the exchange id
    return msg.getExchangeId();
  }
 
  /**
   * retrieves the camel context id
   */
  private void initCamelContextId() {
    this.camelContextId = null;
   
    String filePath = CamelDebugUtils.getRawCamelContextFilePathFromLaunchConfig(getLaunch().getLaunchConfiguration());
    if (filePath != null) {
      File f = new File(filePath);
      if (f.exists() && f.isFile() && CamelUtils.isCamelContextFile(filePath)) {
        XmlContainerMarshaller m = new XmlContainerMarshaller();
        RouteContainer c = m.loadRoutes(f)
        if (c != null) {
          this.camelContextId = c.getCamelContextId();
        }
        if (CamelUtils.isBlueprintFile(filePath)) {
          this.contentType = ICamelDebugConstants.CAMEL_CONTEXT_CONTENT_TYPE_BLUEPRINT;
        } else if (CamelUtils.isSpringFile(filePath)) {
          this.contentType = ICamelDebugConstants.CAMEL_CONTEXT_CONTENT_TYPE_SPRING;
        }
      }
    }
  }
 
  /**
   * establish JMX connection to process
   *
   * @return
   */
  private boolean connectToVM() {
    try {
      if (this.url == null) this.url = new JMXServiceURL(this.jmxUri);
      if (!Strings.isBlank(this.jmxUser)) {
        // credentials defined - so use them
        Map<String, Object> envMap = new HashMap<String, Object>();
        envMap.put("jmx.remote.credentials", new String[] { this.jmxUser, this.jmxPass });
        this.jmxc = JMXConnectorFactory.connect(this.url, envMap);
      } else {
        // no need for using credentials if no user is defined
        this.jmxc = JMXConnectorFactory.connect(this.url);
      }
      this.mbsc = this.jmxc.getMBeanServerConnection();  
      return true;
    } catch (IOException ex) {
      //ignore
    }
    return false;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
   */
  public IProcess getProcess() {
    return fProcess;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
   */
  public IThread[] getThreads() throws DebugException {
    return threads.values().toArray(new IThread[threads.size()]);
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
   */
  public boolean hasThreads() throws DebugException {
    return true; // WTB Changed per bug #138600
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDebugTarget#getName()
   */
  public String getName() throws DebugException {
    if (fName == null) {
      fName = String.format("Camel Context at %s", jmxUri);
    }
    return fName;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
   */
  public boolean supportsBreakpoint(IBreakpoint breakpoint) {
    if (breakpoint.getModelIdentifier().equals(ICamelDebugConstants.ID_CAMEL_DEBUG_MODEL)) {
      String file = CamelDebugUtils.getRawCamelContextFilePathFromLaunchConfig(getLaunch().getLaunchConfiguration());
      if (file != null) {
        File f = new File(file);
        IMarker marker = breakpoint.getMarker();
        if (marker != null && marker.getResource() != null) {
          return f.getPath().equals(marker.getResource().getLocation().toFile().getPath());
        }
      }
    }
    return false;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
   */
  public IDebugTarget getDebugTarget() {
    return this;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
   */
  public ILaunch getLaunch() {
    return fLaunch;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ITerminate#canTerminate()
   */
  public boolean canTerminate() {
    return getProcess() != null && getProcess().canTerminate();
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ITerminate#isTerminated()
   */
  public boolean isTerminated() {
    return fTerminated || (getProcess() != null && getProcess().isTerminated());
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ITerminate#terminate()
   */
  public void terminate() throws DebugException {
    fTerminated = true;
    DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(this);
    try {
      if (fProcess != null && !fProcess.isTerminated()) {
        disconnect();
        fProcess.terminate();
      }
    } catch (DebugException ex) {
//      Activator.getLogger().error(ex);
    }
    closeRemoteContextEditor();
    fireTerminateEvent();
    // clean up the jobs
    this.dispatcher.cancel();
    this.garbageCollector.cancel();
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ISuspendResume#canResume()
   */
  public boolean canResume() {
    return !isTerminated() && isSuspended();
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
   */
  public boolean canSuspend() {
    return !isTerminated() && !isSuspended();
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
   */
  public boolean isSuspended() {
    return this.fProcessingActive == false;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ISuspendResume#resume()
   */
  public void resume() throws DebugException {
    this.fProcessingActive = true;
    fireResumeEvent(DebugEvent.CLIENT_REQUEST);
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.ISuspendResume#suspend()
   */
  public void suspend() throws DebugException {
    this.fProcessingActive = false;
    fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
   */
  public void breakpointAdded(IBreakpoint breakpoint) {
    if (supportsBreakpoint(breakpoint)) {
      try {
        if (breakpoint.isEnabled() && this.debugger != null) {
          if (breakpoint.getMarker().getType().equals(ICamelDebugConstants.ID_CAMEL_CONDITIONALBREAKPOINT_MARKER_TYPE)) {
            this.debugger.addConditionalBreakpoint(CamelDebugUtils.getEndpointNodeId(breakpoint), CamelDebugUtils.getLanguage(breakpoint), CamelDebugUtils.getCondition(breakpoint));
          } else if (breakpoint.getMarker().getType().equals(ICamelDebugConstants.ID_CAMEL_BREAKPOINT_MARKER_TYPE)) {
            this.debugger.addBreakpoint(CamelDebugUtils.getEndpointNodeId(breakpoint));           
          }
        }
      } catch (CoreException e) {
      }
    }
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
   */
  public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
    if (supportsBreakpoint(breakpoint)) {
      this.debugger.removeBreakpoint(CamelDebugUtils.getEndpointNodeId(breakpoint));
    }
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
   */
  public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
    if (supportsBreakpoint(breakpoint)) {
      try {
        if (breakpoint.isEnabled()) {
          breakpointAdded(breakpoint);
        } else {
          breakpointRemoved(breakpoint, null);
        }
      } catch (CoreException e) {
      }
    }
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
   */
  public boolean canDisconnect() {
    return true;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDisconnect#disconnect()
   */
  public void disconnect() throws DebugException {
    if (this.debugger != null) {
      this.debugger.disableDebugger();
      this.debugger.resumeAll();
      for (CamelThread t : threads.values()) t.terminate();
      this.debugger = null;
    }
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
   */
  public boolean isDisconnected() {
    return this.debugger == null;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
   */
  public boolean supportsStorageRetrieval() {
    return false;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
   */
  public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
    return null;
  }

  /**
   * Notification we have connected to the VM and it has started.
   * Resume the VM.
   *
   * @param createEditorInput  flag if the editor input should be created
   */
  public void started(boolean createEditorInput) {
    fireCreationEvent();
    installDeferredBreakpoints();
    if (createEditorInput) {
      createRemoteDebugContextEditorInput();
    }
    try {
      resume();
    } catch (DebugException ex) {
      Activator.getLogger().error(ex);
    }
  }
 
  /**
   * resumes all threads
   */
  public void resumeAllThreads() {
    try {
      for (CamelThread t : threads.values()) {
        t.resume();
      }
      this.resume();
    } catch (DebugException ex) {
      Activator.getLogger().error(ex);
    }
  }
 
  /**
   * Install breakpoints that are already registered with the breakpoint
   * manager.
   */
  private void installDeferredBreakpoints() {
    IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(ICamelDebugConstants.ID_CAMEL_DEBUG_MODEL);
    for (IBreakpoint bp : breakpoints) {
      if (bp instanceof CamelEndpointBreakpoint) {
        CamelEndpointBreakpoint ceb = (CamelEndpointBreakpoint)bp;
        // first get the file path from the launch config
        String fileUnderDebug = CamelDebugUtils.getRawCamelContextFilePathFromLaunchConfig(getLaunch().getLaunchConfiguration());
        // then get the project for the file
        IProject p = CamelDebugUtils.getProjectForFilePath(fileUnderDebug);
        // only add breakpoints for if project matches
        if (p.getName().equals(ceb.getProjectName())) {
          breakpointAdded(bp)
        }       
      }
    }
  }
 
  /**
   * returns the debugger facade
   *
   * @return
   */
  public CamelDebugFacade getDebugger() {
    return this.debugger;
  }
 
  /**
   * returns a dump of all messages waiting in the node
   *
   * @param endpointNodeId
   * @return
   */
  public String getMessagesForNode(String endpointNodeId) {
    return this.debugger.dumpTracedMessagesAsXml(endpointNodeId);
  }
 
  /**
   * Notification a breakpoint was encountered. Determine
   * which breakpoint was hit and fire a suspend event.
   *
   * @param nodeid the id of the node
   */
  private void breakpointHit(String nodeId, BacklogTracerEventMessage msg) {
    boolean bpFound = false;
    String id = generateKey(msg);
    CamelThread t = getThreadForId(id);
   
    // determine which breakpoint was hit, and set the thread's breakpoint
    IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(ICamelDebugConstants.ID_CAMEL_DEBUG_MODEL);
    for (int i = 0; i < breakpoints.length; i++) {
      IBreakpoint breakpoint = breakpoints[i];
      if (supportsBreakpoint(breakpoint)) {
        if (breakpoint instanceof CamelEndpointBreakpoint) {
          CamelEndpointBreakpoint bp = (CamelEndpointBreakpoint)breakpoint;
          if (bp.getEndpointNodeId().equals(nodeId)) {
            t.setBreakpoints(new IBreakpoint[]{breakpoint});
            t.breakpointHit(nodeId, msg);
            this.suspendedNodeId = nodeId;
            bpFound = true;
            break;
          }
        }
      }
    }
   
    // we process breakpoints reported by runtime even if not set in the UI when
    // the thread is in stepping mode, because in stepping mode the next node will
    // be always a breakpoint regardless if set in UI or not
    if (!bpFound && getThreadForId(generateKey(msg)).isStepping()) {
      t.setBreakpoints(new IBreakpoint[0]);
      t.breakpointHit(nodeId, msg);
    }
  }
 
  /**
   * closes the remote context in editor
   */
  private void closeRemoteContextEditor() {
    if (getLaunch() == null || getLaunch().getLaunchConfiguration() == null) return;
    CamelDebugRegistryEntry entry = CamelDebugRegistry.getInstance().getEntry(getLaunch().getLaunchConfiguration());
    if (entry == null) return;
    CamelDebugContextEditorInput input = entry.getEditorInput();
    CamelDebugRegistry.getInstance().removeEntry(getLaunch().getLaunchConfiguration());
    IWorkbench wb = PlatformUI.getWorkbench();
    if (wb != null) {
      IWorkbenchWindow[] wbw = wb.getWorkbenchWindows();
      if (wbw.length > 0) {
        final IWorkbenchPage page = wbw[0].getActivePage();
        if (page != null) {
          final IEditorPart ep = page.getActiveEditor();
          if (ep != null && ep.getEditorInput() instanceof CamelDebugContextEditorInput) {
            CamelDebugContextEditorInput ip = (CamelDebugContextEditorInput)ep.getEditorInput();
            IFile f = (IFile)input.getAdapter(IFile.class);
            IFile fIp = (IFile)ip.getAdapter(IFile.class);
            if (fIp.getFullPath().toFile().getPath().equals(f.getFullPath().toFile().getPath())) {
              Display.getDefault().asyncExec(new Runnable() {
                @Override
                public void run() {
                  page.closeEditor(ep, false)
                }
              });
            }           
          }
        }
      }
    }   
  }
 
  /**
   * creates the remote editor input
   *
   * @param contextId
   */
  private void createRemoteDebugContextEditorInput() {
    try {
      // create the editor input
      CamelDebugContextEditorInput input = new CamelDebugContextEditorInput(debugger, getLaunch().getLaunchConfiguration());
      // and save it in the registry
      CamelDebugRegistry.getInstance().createEntry(this, this.camelContextId, input, getLaunch().getLaunchConfiguration());
    } catch (Exception ex) {
      Activator.getLogger().error(ex);
    }
  }

  /**
   * update the editor input to contain latest changes
   */
  public void updateEditorInput() {
    CamelDebugRegistryEntry entry = CamelDebugRegistry.getInstance().getEntry(getLaunch().getLaunchConfiguration());
    if (entry != null) {
      CamelDebugContextEditorInput input = entry.getEditorInput();
      input.refresh();
    }
   
//    closeRemoteContextEditor();
  }
 
  /**
   * Listens to events from the CAMEL VM and fires corresponding
   * debug events.
   */
  class JMXConnectJob extends Job {
   
    private static final long CONNECTION_TIMEOUT = 60 * 1000; // 60 seconds timeout
   
    public JMXConnectJob() {
      super("Connect to Camel Debugger...");
      setSystem(false);
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
     */
    protected IStatus run(IProgressMonitor monitor) {
      monitor.beginTask("Connect to Camel VM...", 1);
     
      final long startTime = System.currentTimeMillis();
      boolean connected = false;
     
      // run until connected or timed out
      while (!connected && System.currentTimeMillis()-startTime <= CONNECTION_TIMEOUT && !monitor.isCanceled()) {
        try {
          if (connectToVM()) {
            // connected to the camel vm
            CamelDebugTarget.this.debugger = new CamelDebugFacade(CamelDebugTarget.this, mbsc, camelContextId, contentType);
            connected = true;
            started(true);
            if (CamelDebugTarget.this.debugger.isEnabled() == false) CamelDebugTarget.this.debugger.enableDebugger();
          }
        } catch (Exception ex) {
          Activator.getLogger().error(ex);
          // runtime not yet up...wait a bit and retry
          try {
            Thread.sleep(500);
          } catch (InterruptedException e) {
            monitor.setCanceled(true);
          }
        }
      }
     
      if (!connected) {
        try {
          abort("Unable to connect to Camel VM", new Exception("Unable to connect to Camel Debugger"));
        } catch (DebugException ex) {
          Activator.getLogger().error(ex);
        }
      }
     
      monitor.done();
     
      return connected == true ? Status.OK_STATUS : Status.CANCEL_STATUS;
    }
  }
 
  /**
   * Listens to events from the CAMEL VM and fires corresponding
   * debug events.
   */
  class EventDispatchJob extends Job {
   
    public EventDispatchJob() {
      super("Camel Debug Event Dispatch");
      setSystem(true);
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    protected IStatus run(IProgressMonitor monitor) {
      while (!isTerminated() && !monitor.isCanceled()) {
        // check for suspended breakpoints
        if (CamelDebugTarget.this.debugger != null && !isSuspended()) {
          try {
            Set<String> suspendedBreakpoints = CamelDebugTarget.this.debugger.getSuspendedBreakpointNodeIds();
            if (suspendedBreakpoints != null && !suspendedBreakpoints.isEmpty()) {
              // we need to suspend the debug target
              suspend();
             
              for (String nodeId : suspendedBreakpoints) {
                BacklogTracerEventMessage evMsg = CamelDebugUtils.getBacklogTracerEventMessage(getMessagesForNode(nodeId));
                String id = generateKey(evMsg);
                CamelThread t = getThreadForId(id);
                 
                // now we can access the stack frames
                String endpointId = t.getTopStackFrame() != null ? ((CamelStackFrame)t.getTopStackFrame()).getEndpointId() : null;
                if (nodeId.equals(endpointId)) {
                  // its the same breakpoint we already hit for that exchange - ignore it
                  continue;
                }
               
                if (!t.isSuspended()) {
                  // process the breakpoint
                  breakpointHit(nodeId, evMsg);
                 
                  // now resume
                  resume();
                }
              }
            }
            // wait a bit to keep jmx traffic lower - if we are too fast sometimes a breakpoint is
            // hit but no message dump is available yet -> bad coding on camel side?
            Thread.sleep(2000);
          } catch (Exception ex) {
            Activator.getLogger().error(ex);
          }
        }
      }
      return Status.OK_STATUS;
    }
  }
 
  class ThreadGarbageCollector extends Job {
   
    private final long THREAD_LIFE_DURATION = 5*30*1000; // 5 minutes
   
    public ThreadGarbageCollector() {
      super("Thread CleanUp Service");
      setSystem(true);
    }
   
    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    protected IStatus run(IProgressMonitor monitor) {
      while (!isTerminated() && !monitor.isCanceled()) {
        try {
          // check all threads
          for (CamelThread t : threads.values()) {
            // we clean all threads not suspended in the last x seconds and state running
            if (t.isSuspended() == false && (System.currentTimeMillis() - t.getLastSuspended()) > THREAD_LIFE_DURATION) {
              t.terminate();
            }
          }
          Thread.sleep(60000); // run every 60 secs
        } catch (InterruptedException ex) {
          Activator.getLogger().error(ex);
        } catch (DebugException de) {
          Activator.getLogger().error(de);
        }
      }
      return Status.OK_STATUS;
    }
  }
}
TOP

Related Classes of org.fusesource.ide.launcher.debug.model.CamelDebugTarget$ThreadGarbageCollector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.