/*
 * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * This source code is provided to illustrate the usage of a given feature
 * or technique and has been deliberately simplified. Additional steps
 * required for a production-quality application, such as security checks,
 * input validation and proper error handling, might not be present in
 * this sample code.
 */


package com.sun.tools.example.debug.gui;

import java.io.*;
import java.util.*;

import com.sun.jdi.*;
import com.sun.tools.example.debug.event.*;
import com.sun.tools.example.debug.bdi.*;

public class ContextManager {

    private ClassManager classManager;
    private ExecutionManager runtime;

    private String mainClassName;
    private String vmArguments;
    private String commandArguments;
    private String remotePort;

    private ThreadReference currentThread;

    private boolean verbose;

    private ArrayList<ContextListener> contextListeners = new ArrayList<ContextListener>();

    public ContextManager(Environment env) {
        classManager = env.getClassManager();
        runtime = env.getExecutionManager();
        mainClassName = "";
        vmArguments = "";
        commandArguments = "";
        currentThread = null;

        ContextManagerListener listener = new ContextManagerListener();
        runtime.addJDIListener(listener);
        runtime.addSessionListener(listener);
    }

    // Program execution defaults.

    //### Should there be change listeners for these?
    //### They would be needed if we expected a dialog to be
    //### synchronized with command input while it was open.

    public String getMainClassName() {
        return mainClassName;
    }

    public void setMainClassName(String mainClassName) {
        this.mainClassName = mainClassName;
    }

    public String getVmArguments() {
        return processClasspathDefaults(vmArguments);
    }

    public void setVmArguments(String vmArguments) {
        this.vmArguments = vmArguments;
    }

    public String getProgramArguments() {
        return commandArguments;
    }

    public void setProgramArguments(String commandArguments) {
        this.commandArguments = commandArguments;
    }

    public String getRemotePort() {
        return remotePort;
    }

    public void setRemotePort(String remotePort) {
        this.remotePort = remotePort;

    }


    // Miscellaneous debugger session preferences.

    public boolean getVerboseFlag() {
        return verbose;
    }

    public void setVerboseFlag(boolean verbose) {
        this.verbose = verbose;
    }


    // Thread focus.

    public ThreadReference getCurrentThread() {
        return currentThread;
    }

    public void setCurrentThread(ThreadReference t) {
        if (t != currentThread) {
            currentThread = t;
            notifyCurrentThreadChanged(t);
        }
    }

    public void setCurrentThreadInvalidate(ThreadReference t) {
        currentThread = t;
        notifyCurrentFrameChanged(runtime.threadInfo(t),
                                  0, true);
    }

    public void invalidateCurrentThread() {
        notifyCurrentFrameChanged(null, 0, true);
    }


    // If a view is displaying the current thread, it may
    // choose to indicate which frame is current in the
    // sense of the command-line UI.  It may also "warp" the
    // selection to that frame when changed by an 'up' or 'down'
    // command. Hence, a notifier is provided.

    
public int getCurrentFrameIndex() { return getCurrentFrameIndex(currentThreadInfo); }
/****** public int getCurrentFrameIndex() { return getCurrentFrameIndex(currentThreadInfo); } ******/
public int getCurrentFrameIndex(ThreadReference t) { return getCurrentFrameIndex(runtime.threadInfo(t)); } //### Used in StackTraceTool. public int getCurrentFrameIndex(ThreadInfo tinfo) { if (tinfo == null) { return 0; } Integer currentFrame = (Integer)tinfo.getUserObject(); if (currentFrame == null) { return 0; } else { return currentFrame.intValue(); } } public int moveCurrentFrameIndex(ThreadReference t, int count) throws VMNotInterruptedException { return setCurrentFrameIndex(t,count, true); } public int setCurrentFrameIndex(ThreadReference t, int newIndex) throws VMNotInterruptedException { return setCurrentFrameIndex(t, newIndex, false); } public int setCurrentFrameIndex(int newIndex) throws VMNotInterruptedException { if (currentThread == null) { return 0; } else { return setCurrentFrameIndex(currentThread, newIndex, false); } } private int setCurrentFrameIndex(ThreadReference t, int x, boolean relative) throws VMNotInterruptedException { boolean sameThread = t.equals(currentThread); ThreadInfo tinfo = runtime.threadInfo(t); if (tinfo == null) { return 0; } int maxIndex = tinfo.getFrameCount()-1; int oldIndex = getCurrentFrameIndex(tinfo); int newIndex = relative? oldIndex + x : x; if (newIndex > maxIndex) { newIndex = maxIndex; } else if (newIndex < 0) { newIndex = 0; } if (!sameThread || newIndex != oldIndex) { // don't recurse setCurrentFrameIndex(tinfo, newIndex); } return newIndex - oldIndex; } private void setCurrentFrameIndex(ThreadInfo tinfo, int index) { tinfo.setUserObject(new Integer(index)); //### In fact, the value may not have changed at this point. //### We need to signal that the user attempted to change it, //### however, so that the selection can be "warped" to the //### current location. notifyCurrentFrameChanged(tinfo.thread(), index); } public StackFrame getCurrentFrame() throws VMNotInterruptedException { return getCurrentFrame(runtime.threadInfo(currentThread)); } public StackFrame getCurrentFrame(ThreadReference t) throws VMNotInterruptedException { return getCurrentFrame(runtime.threadInfo(t)); } public StackFrame getCurrentFrame(ThreadInfo tinfo) throws VMNotInterruptedException { int index = getCurrentFrameIndex(tinfo); try { // It is possible, though unlikely, that the VM was interrupted // before the thread created its Java stack. return tinfo.getFrame(index); } catch (FrameIndexOutOfBoundsException e) { return null; } } public void addContextListener(ContextListener cl) { contextListeners.add(cl); } public void removeContextListener(ContextListener cl) { contextListeners.remove(cl); } //### These notifiers are fired only in response to USER-INITIATED changes //### to the current thread and current frame. When the current thread is set automatically //### after a breakpoint hit or step completion, no event is generated. Instead, //### interested parties are expected to listen for the BreakpointHit and StepCompleted //### events. This convention is unclean, and I believe that it reflects a defect in //### in the current architecture. Unfortunately, however, we cannot guarantee the //### order in which various listeners receive a given event, and the handlers for //### the very same events that cause automatic changes to the current thread may also //### need to know the current thread. private void notifyCurrentThreadChanged(ThreadReference t) { ThreadInfo tinfo = null; int index = 0; if (t != null) { tinfo = runtime.threadInfo(t); index = getCurrentFrameIndex(tinfo); } notifyCurrentFrameChanged(tinfo, index, false); } private void notifyCurrentFrameChanged(ThreadReference t, int index) { notifyCurrentFrameChanged(runtime.threadInfo(t), index, false); } private void notifyCurrentFrameChanged(ThreadInfo tinfo, int index, boolean invalidate) { ArrayList<ContextListener> l = new ArrayList<ContextListener>(contextListeners); CurrentFrameChangedEvent evt = new CurrentFrameChangedEvent(this, tinfo, index, invalidate); for (int i = 0; i < l.size(); i++) { l.get(i).currentFrameChanged(evt); } } private class ContextManagerListener extends JDIAdapter implements SessionListener, JDIListener { // SessionListener @Override public void sessionStart(EventObject e) { invalidateCurrentThread(); } @Override public void sessionInterrupt(EventObject e) { setCurrentThreadInvalidate(currentThread); } @Override public void sessionContinue(EventObject e) { invalidateCurrentThread(); } // JDIListener @Override public void locationTrigger(LocationTriggerEventSet e) { setCurrentThreadInvalidate(e.getThread()); } @Override public void exception(ExceptionEventSet e) { setCurrentThreadInvalidate(e.getThread()); } @Override public void vmDisconnect(VMDisconnectEventSet e) { invalidateCurrentThread(); } }
Add a -classpath argument to the arguments passed to the exec'ed VM with the contents of CLASSPATH environment variable, if -classpath was not already specified.
Params:
  • javaArgs – the arguments to the VM being exec'd that potentially has a user specified -classpath argument.
Returns:a javaArgs whose -classpath option has been added
/** * Add a -classpath argument to the arguments passed to the exec'ed * VM with the contents of CLASSPATH environment variable, * if -classpath was not already specified. * * @param javaArgs the arguments to the VM being exec'd that * potentially has a user specified -classpath argument. * @return a javaArgs whose -classpath option has been added */
private String processClasspathDefaults(String javaArgs) { if (javaArgs.indexOf("-classpath ") == -1) { StringBuffer munged = new StringBuffer(javaArgs); SearchPath classpath = classManager.getClassPath(); if (classpath.isEmpty()) { String envcp = System.getProperty("env.class.path"); if ((envcp != null) && (envcp.length() > 0)) { munged.append(" -classpath " + envcp); } } else { munged.append(" -classpath " + classpath.asString()); } return munged.toString(); } else { return javaArgs; } } private String appendPath(String path1, String path2) { if (path1 == null || path1.length() == 0) { return path2 == null ? "." : path2; } else if (path2 == null || path2.length() == 0) { return path1; } else { return path1 + File.pathSeparator + path2; } } }