/*
 * Copyright (c) 1998, 2008, 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.tty;

import com.sun.jdi.*;
import com.sun.jdi.request.StepRequest;
import com.sun.jdi.request.MethodEntryRequest;
import com.sun.jdi.request.MethodExitRequest;
import java.util.*;
import java.io.*;


class Env {

    static EventRequestSpecList specList = new EventRequestSpecList();

    private static VMConnection connection;

    private static SourceMapper sourceMapper = new SourceMapper("");
    private static List<String> excludes;

    private static final int SOURCE_CACHE_SIZE = 5;
    private static List<SourceCode> sourceCache = new LinkedList<SourceCode>();

    private static HashMap<String, Value> savedValues = new HashMap<String, Value>();
    private static Method atExitMethod;

    static void init(String connectSpec, boolean openNow, int flags) {
        connection = new VMConnection(connectSpec, flags);
        if (!connection.isLaunch() || openNow) {
            connection.open();
        }
    }

    static VMConnection connection() {
        return connection;
    }

    static VirtualMachine vm() {
        return connection.vm();
    }

    static void shutdown() {
        shutdown(null);
    }

    static void shutdown(String message) {
        if (connection != null) {
            try {
                connection.disposeVM();
            } catch (VMDisconnectedException e) {
                // Shutting down after the VM has gone away. This is
                // not an error, and we just ignore it.
            }
        }
        if (message != null) {
            MessageOutput.lnprint(message);
            MessageOutput.println();
        }
        System.exit(0);
    }

    static void setSourcePath(String srcPath) {
        sourceMapper = new SourceMapper(srcPath);
        sourceCache.clear();
    }

    static void setSourcePath(List<String> srcList) {
        sourceMapper = new SourceMapper(srcList);
        sourceCache.clear();
    }

    static String getSourcePath() {
        return sourceMapper.getSourcePath();
    }

    static private List<String> excludes() {
        if (excludes == null) {
            setExcludes("java.*, javax.*, sun.*, com.sun.*");
        }
        return excludes;
    }

    static String excludesString() {
        StringBuffer buffer = new StringBuffer();
        for (String pattern : excludes()) {
            buffer.append(pattern);
            buffer.append(",");
        }
        return buffer.toString();
    }

    static void addExcludes(StepRequest request) {
        for (String pattern : excludes()) {
            request.addClassExclusionFilter(pattern);
        }
    }

    static void addExcludes(MethodEntryRequest request) {
        for (String pattern : excludes()) {
            request.addClassExclusionFilter(pattern);
        }
    }

    static void addExcludes(MethodExitRequest request) {
        for (String pattern : excludes()) {
            request.addClassExclusionFilter(pattern);
        }
    }

    static void setExcludes(String excludeString) {
        StringTokenizer t = new StringTokenizer(excludeString, " ,;");
        List<String> list = new ArrayList<String>();
        while (t.hasMoreTokens()) {
            list.add(t.nextToken());
        }
        excludes = list;
    }

    static Method atExitMethod() {
        return atExitMethod;
    }

    static void setAtExitMethod(Method mmm) {
        atExitMethod = mmm;
    }

    
Return a Reader cooresponding to the source of this location. Return null if not available. Note: returned reader must be closed.
/** * Return a Reader cooresponding to the source of this location. * Return null if not available. * Note: returned reader must be closed. */
static BufferedReader sourceReader(Location location) { return sourceMapper.sourceReader(location); } static synchronized String sourceLine(Location location, int lineNumber) throws IOException { if (lineNumber == -1) { throw new IllegalArgumentException(); } try { String fileName = location.sourceName(); Iterator<SourceCode> iter = sourceCache.iterator(); SourceCode code = null; while (iter.hasNext()) { SourceCode candidate = iter.next(); if (candidate.fileName().equals(fileName)) { code = candidate; iter.remove(); break; } } if (code == null) { BufferedReader reader = sourceReader(location); if (reader == null) { throw new FileNotFoundException(fileName); } code = new SourceCode(fileName, reader); if (sourceCache.size() == SOURCE_CACHE_SIZE) { sourceCache.remove(sourceCache.size() - 1); } } sourceCache.add(0, code); return code.sourceLine(lineNumber); } catch (AbsentInformationException e) { throw new IllegalArgumentException(); } }
Return a description of an object.
/** Return a description of an object. */
static String description(ObjectReference ref) { ReferenceType clazz = ref.referenceType(); long id = ref.uniqueID(); if (clazz == null) { return toHex(id); } else { return MessageOutput.format("object description and hex id", new Object [] {clazz.name(), toHex(id)}); } }
Convert a long to a hexadecimal string.
/** Convert a long to a hexadecimal string. */
static String toHex(long n) { char s1[] = new char[16]; char s2[] = new char[18]; /* Store digits in reverse order. */ int i = 0; do { long d = n & 0xf; s1[i++] = (char)((d < 10) ? ('0' + d) : ('a' + d - 10)); } while ((n >>>= 4) > 0); /* Now reverse the array. */ s2[0] = '0'; s2[1] = 'x'; int j = 2; while (--i >= 0) { s2[j++] = s1[i]; } return new String(s2, 0, j); }
Convert hexadecimal strings to longs.
/** Convert hexadecimal strings to longs. */
static long fromHex(String hexStr) { String str = hexStr.startsWith("0x") ? hexStr.substring(2).toLowerCase() : hexStr.toLowerCase(); if (hexStr.length() == 0) { throw new NumberFormatException(); } long ret = 0; for (int i = 0; i < str.length(); i++) { int c = str.charAt(i); if (c >= '0' && c <= '9') { ret = (ret * 16) + (c - '0'); } else if (c >= 'a' && c <= 'f') { ret = (ret * 16) + (c - 'a' + 10); } else { throw new NumberFormatException(); } } return ret; } static ReferenceType getReferenceTypeFromToken(String idToken) { ReferenceType cls = null; if (Character.isDigit(idToken.charAt(0))) { cls = null; } else if (idToken.startsWith("*.")) { // This notation saves typing by letting the user omit leading // package names. The first // loaded class whose name matches this limited regular // expression is selected. idToken = idToken.substring(1); for (ReferenceType type : Env.vm().allClasses()) { if (type.name().endsWith(idToken)) { cls = type; break; } } } else { // It's a class name List<ReferenceType> classes = Env.vm().classesByName(idToken); if (classes.size() > 0) { // TO DO: handle multiples cls = classes.get(0); } } return cls; } static Set<String> getSaveKeys() { return savedValues.keySet(); } static Value getSavedValue(String key) { return savedValues.get(key); } static void setSavedValue(String key, Value value) { savedValues.put(key, value); } static class SourceCode { private String fileName; private List<String> sourceLines = new ArrayList<String>(); SourceCode(String fileName, BufferedReader reader) throws IOException { this.fileName = fileName; try { String line = reader.readLine(); while (line != null) { sourceLines.add(line); line = reader.readLine(); } } finally { reader.close(); } } String fileName() { return fileName; } String sourceLine(int number) { int index = number - 1; // list is 0-indexed if (index >= sourceLines.size()) { return null; } else { return sourceLines.get(index); } } } }