/*
* Copyright 2010 Sun Microsystems, Inc. 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.
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.jdi;
import org.visage.jdi.event.VisageEventQueue;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import java.util.List;
import java.util.ArrayList;
/**
*
* @author sundar
*/
public class VisageClassType extends VisageReferenceType implements ClassType {
private boolean isIsVisageTypeSet = false;
private boolean isVisageType = false;
public VisageClassType(VisageVirtualMachine visagevm, ClassType underlying) {
super(visagevm, underlying);
}
public List<InterfaceType> allInterfaces() {
return VisageWrapper.wrapInterfaceTypes(virtualMachine(), underlying().allInterfaces());
}
public VisageMethod concreteMethodByName(String name, String signature) {
return VisageWrapper.wrap(virtualMachine(), underlying().concreteMethodByName(name, signature));
}
public List<InterfaceType> interfaces() {
return VisageWrapper.wrapInterfaceTypes(virtualMachine(), underlying().interfaces());
}
public VisageValue invokeMethod(ThreadReference thread, Method method, List<? extends Value> values, int options)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException {
Value value =
underlying().invokeMethod(
VisageWrapper.unwrap(thread), VisageWrapper.unwrap(method),
VisageWrapper.unwrapValues(values), options);
return VisageWrapper.wrap(virtualMachine(), value);
}
public boolean isEnum() {
return underlying().isEnum();
}
public VisageObjectReference newInstance(ThreadReference thread, Method method, List<? extends Value> values, int options)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException {
ObjectReference result =
underlying().newInstance(
VisageWrapper.unwrap(thread), VisageWrapper.unwrap(method),
VisageWrapper.unwrapValues(values), options);
return VisageWrapper.wrap(virtualMachine(), result);
}
/**
* JDI extension: This will call the set function if one exists via invokeMethod.
* The call to invokeMethod is preceded by a call to {@link VisageEventQueue#setEventControl(boolean)} passing true
* and is followed by a call to {@link VisageEventQueue#setEventControl(boolean)} passing false.
*
* If an invokeMethod Exception occurs, it is saved and can be accessed by calling
* {@link VisageVirtualMachine#lastFieldAccessException()}.
*/
public void setValue(Field field, Value value) throws
InvalidTypeException, ClassNotLoadedException {
virtualMachine().setLastFieldAccessException(null);
Field jdiField = VisageWrapper.unwrap(field);
Value jdiValue = VisageWrapper.unwrap(value);
if (!isVisageType()) {
underlying().setValue(jdiField, jdiValue);
return;
}
if (isReadOnly(field)) {
throw new IllegalArgumentException("Error: Cannot set value of a read-only field: " + field);
}
if (isBound(field)) {
throw new IllegalArgumentException("Error: Cannot set value of a bound field: " + field);
}
//get$xxxx methods exist for fields except private fields which have no binders
List<Method> mth = underlying().methodsByName("set" + jdiField.name());
if (mth.size() == 0) {
// there is no setter
underlying().setValue(jdiField, jdiValue);
return;
}
// there is a setter
ArrayList<Value> args = new ArrayList<Value>(1);
args.add(jdiValue);
Exception theExc = null;
VisageEventQueue eq = virtualMachine().eventQueue();
try {
eq.setEventControl(true);
invokeMethod(virtualMachine().uiThread(), mth.get(0), args, ClassType.INVOKE_SINGLE_THREADED);
} catch(InvalidTypeException ee) {
theExc = ee;
} catch(ClassNotLoadedException ee) {
theExc = ee;
} catch(IncompatibleThreadStateException ee) {
theExc = ee;
} catch(InvocationException ee) {
theExc = ee;
} finally {
eq.setEventControl(false);
}
// We don't have to catch IllegalArgumentException. It is an unchecked exception for invokeMethod
// and for getValue
virtualMachine().setLastFieldAccessException(theExc);
}
public List<ClassType> subclasses() {
return VisageWrapper.wrapClassTypes(virtualMachine(), underlying().subclasses());
}
public VisageClassType superclass() {
return VisageWrapper.wrap(virtualMachine(), underlying().superclass());
}
@Override
protected ClassType underlying() {
return (ClassType) super.underlying();
}
/**
* JDI addition: Determines if this is a Visage class.
*
* @return <code>true</code> if this is a Visage class; false otherwise.
*/
@Override
public boolean isVisageType() {
if (!isIsVisageTypeSet) {
isIsVisageTypeSet = true;
VisageVirtualMachine visagevm = virtualMachine();
InterfaceType visageObjType = (InterfaceType) VisageWrapper.unwrap(visagevm.visageObjectType());
if (visageObjType != null) {
ClassType thisType = underlying();
List<InterfaceType> allIfaces = thisType.allInterfaces();
for (InterfaceType iface : allIfaces) {
if (iface.equals(visageObjType)) {
isVisageType = true;
break;
}
}
}
}
return isVisageType;
}
}