Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/sun/tools/debug/RemoteClass.java

/*
 * @(#)RemoteClass.java	1.16 96/01/23
 *
 * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package sun.tools.debug;

import java.lang.Exception;
import java.io.*;

/**
 * The RemoteClass class allows access to a class in a remote Java
 * interpreter.  
 *
 * @see RemoteDebugger
 * @author Thomas Ball
 */
public class RemoteClass extends RemoteObject {
    String name;
    String sourceName;
    boolean intf;
    RemoteClass superclass;
    RemoteObject loader;
    RemoteClass interfaces[] = null;
    private RemoteField methods[] = null;
    private RemoteField instanceFields[] = null;
    private RemoteField staticFields[] = null;

    RemoteClass(RemoteAgent agent, int id) {
	super(agent, TP_CLASS, id, agent.classClass);
    }

    private void getClassInfo() throws Exception {
	if (interfaces == null) {
	    agent.getClassInfo(this);
	}
    }

    private void loadFields() throws Exception {
	if (staticFields == null || instanceFields == null) {
	    RemoteField fields[] = agent.getFields(id);

	    int nStaticFields = 0;
	    for (int i = 0; i < fields.length; i++) {
		if (fields[i].isStatic() == true) {
		    nStaticFields++;
		}
	    }

	    staticFields = new RemoteField[nStaticFields];
	    instanceFields = new RemoteField[fields.length - nStaticFields];
	    int iInst = 0;
	    int iStatic = 0;
	    for (int i = 0; i < fields.length; i++) {
		if (fields[i].isStatic() == true) {
		    staticFields[iStatic++] = fields[i];
		} else {
		    instanceFields[iInst++] = fields[i];
		}
	    }
	}
    }
    
    /** Returns the name of the class. */
    public String getName() throws Exception {
	getClassInfo();
	return name;
    }

    /** Returns the name of the class as its type. */
    public String typeName() throws Exception {
	getClassInfo();
	return getName();
    }

    /** Is this RemoteClass an interface? */
    public boolean isInterface() throws Exception {
	getClassInfo();
	return intf;
    }

    /** Return the superclass for this class. */
    public RemoteClass getSuperclass() throws Exception {
	getClassInfo();
	return superclass;
    }

    /** Return the classloader for this class. */
    public RemoteObject getClassLoader() throws Exception {
	getClassInfo();
	return loader;
    }

    /** Return the interfaces for this class. */
    public RemoteClass getInterfaces()[] throws Exception {
	getClassInfo();
	return interfaces;
    }

    /** Get the name of the source file referenced by this stackframe. */
    public String getSourceFileName() throws Exception {
	getClassInfo();
	return sourceName;
    };

    /** Get the source file referenced by this stackframe. */
    public InputStream getSourceFile() throws Exception {
	getClassInfo();
	return agent.getSourceFile(name, sourceName);
    };

    /** Return all the static fields for this class. */
    public RemoteField[] getFields() throws Exception {
	return getStaticFields();
    }

    /** Return all the static fields for this class. */
    public RemoteField[] getStaticFields() throws Exception {
	loadFields();
	return staticFields;
    }

    /** Return all the instance fields for this class.
     *  Note:  because this is a RemoteClass method, only the name and
     *         type methods will be valid, not the data.
     */
    public RemoteField[] getInstanceFields() throws Exception {
	loadFields();
	return instanceFields;
    }

    /**
     * Return the static field, specified by index.
     *
     * @exception ArrayIndexOutOfBoundsException when the index is greater than the number of instance variables
     */
    public RemoteField getField(int n) throws Exception {
	loadFields();
	if (n < 0 || n >= staticFields.length) {
	    throw new ArrayIndexOutOfBoundsException();
	}
	return staticFields[n];
    }

    /** Return the static field, specified by name. */
    public RemoteField getField(String name) throws Exception {
	loadFields();
	for (int i = 0; i < staticFields.length; i++) {
	    if (name.equals(staticFields[i].getName())) {
		return staticFields[i];
	    }
	}
	return null;
    }

    /**
     * Return the instance field, specified by its index.
     * Note:  because this is a RemoteClass method, only the name and
     *        type information is valid, not the data.
     *
     * @exception ArrayIndexOutOfBoundsException when the index is greater than the number of instance variables
     */
    public RemoteField getInstanceField(int n) throws Exception {
	loadFields();
	if (n < 0 || n >= instanceFields.length) {
	    throw new ArrayIndexOutOfBoundsException();
	}
	return instanceFields[n];
    }

    /** Return the value of a static field, specified by its index */
    public RemoteValue getFieldValue(int n) throws Exception {
	return getField(n).getValue(id);
    }

    /** Return the value of a static field, specified by name. */
    public RemoteValue getFieldValue(String name) throws Exception {
	loadFields();
	for (int i = 0; i < staticFields.length; i++) {
	    if (name.equals(staticFields[i].getName())) {
		return staticFields[i].getValue(id);
	    }
	}
	return null;
    }

    /** Return the method, specified by name. */
    public RemoteField getMethod(String name) throws Exception {
	if (methods == null) {
	    methods = agent.getMethods(id);
	}
	for (int i = 0; i < methods.length; i++) {
	    if (name.equals(methods[i].getName())) {
		return methods[i];
	    }
	}
	return null;
    }

    /** Return the class's methods. */
    public RemoteField[] getMethods() throws Exception {
	if (methods == null) {
	    methods = agent.getMethods(id);
	}
	return methods;
    }

    /** Return the names of all methods supported by this class. */
    public String[] getMethodNames() throws Exception {
	if (methods == null) {
	    methods = agent.getMethods(id);
	}
	String ret[] = new String[methods.length];
	for (int i = 0; i < methods.length; i++) {
	    ret[i] = methods[i].getName();
	}
	return ret;
    }

    /**
     * Set a breakpoint at a specified source line number in a class.
     *
     * @param lineno	the line number where the breakpoint is set
     * @return an empty string if successful, otherwise a description of the error.
     */
    public String setBreakpointLine(int lineno) throws Exception {
	return agent.setBreakpointLine(this, lineno);
    }

    /**
     * Set a breakpoint at the first line of a class method.
     *
     * @param method	the method where the breakpoint is set
     * @return an empty string if successful, otherwise a description of the error.
     */
    public String setBreakpointMethod(RemoteField method) throws Exception {
	return agent.setBreakpointMethod(this, method);
    }

    /**
     * Clear a breakpoint at a specific address in a class.
     *
     * @param pc	the address of the breakpoint to be cleared
     * @return an empty string if successful, otherwise a description of the error.
     */
    public String clearBreakpoint(int pc) throws Exception {
	return agent.clearBreakpoint(this, pc);
    }

    /**
     * Clear a breakpoint at a specified line.
     *
     * @param lineno	the line number of the breakpoint to be cleared
     * @return an empty string if successful, otherwise a description of the error.
     */
    public String clearBreakpointLine(int lineno) throws Exception {
	return agent.clearBreakpointLine(this, lineno);
    }

    /**
     * Clear a breakpoint at the start of a specified method.
     *
     * @param method	the method of the breakpoint to be cleared
     * @return an empty string if successful, otherwise a description of the error.
     */
    public String clearBreakpointMethod(RemoteField method) throws Exception {
	return agent.clearBreakpointMethod(this, method);
    }

    private boolean isExceptionClass() throws Exception {
	if (getName().equals("java.lang.Exception") ||
	    getName().equals("java.lang.Error")) {
	    return true;
	}
	RemoteClass superClass = superclass;
	do {
	    agent.message("isExceptionClass: superClass=" +
			  superClass.getName());
	    if (superClass.getName().equals("java.lang.Exception") ||
	    	superClass.getName().equals("java.lang.Error")) {
		return true;
	    }
	    superClass = superClass.getSuperclass();
	} while (superClass.getName().equals("java.lang.Object") == false);
	return false;
    }

    /**
     * Enter the debugger when an instance of this class is thrown.
     *
     * @exception ClassCastException when this class isn't an exception class
     */
    public void catchExceptions() throws Exception {
	if (isExceptionClass()) {
	    agent.catchExceptionClass(this);
	} else {
	    throw new ClassCastException();
	}
    }

    /**
     * Don't enter the debugger when an instance of this class is thrown.
     *
     * @exception ClassCastException when this class isn't an exception class
     */
    public void ignoreExceptions() throws Exception {
	if (isExceptionClass()) {
	    agent.ignoreExceptionClass(this);
	} else {
	    throw new ClassCastException();
	}
    }

    /** Return a (somewhat verbose) description. */
    public String description() {
	return toString();
    }

    /** Return a (somewhat verbose) description. */
    public String toString() {
	try {
	    getClassInfo();
	    return toHex(id) + ":" + (intf ? "interface" : "class") +
	        "(" + getName() + ")";
	} catch (Exception ex) {
	    return ("<communications errors>");
	}
    }
}