blob: 9218e7b4130b6be08207d854428d93c8422b3385 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdi.internal;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket;
import org.eclipse.jdi.internal.jdwp.JdwpID;
import org.eclipse.jdi.internal.jdwp.JdwpObjectID;
import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.InternalException;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.Type;
import com.sun.jdi.Value;
/**
* this class implements the corresponding interfaces
* declared by the JDI specification. See the com.sun.jdi package
* for more information.
*
*/
public class ArrayReferenceImpl extends ObjectReferenceImpl implements ArrayReference {
/** JDWP Tag. */
public static final byte tag = JdwpID.ARRAY_TAG;
private int fLength = -1;
/**
* Creates new ArrayReferenceImpl.
*/
public ArrayReferenceImpl(VirtualMachineImpl vmImpl, JdwpObjectID objectID) {
super("ArrayReference", vmImpl, objectID); //$NON-NLS-1$
}
/**
* @returns tag.
*/
public byte getTag() {
return tag;
}
/**
* @returns Returns an array component value.
*/
public Value getValue(int index) throws IndexOutOfBoundsException {
return (Value)getValues(index, 1).get(0);
}
/**
* @returns Returns all of the components in this array.
*/
public List getValues() {
return getValues(0, -1);
}
/**
* @returns Returns a range of array components.
*/
public List getValues(int firstIndex, int length) throws IndexOutOfBoundsException {
int arrayLength= length();
if (firstIndex < 0 || firstIndex >= arrayLength) {
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Invalid_index_1);
}
if (length == -1) {
// length == -1 means all elements to the end.
length = arrayLength - firstIndex;
} else if (length < -1) {
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Invalid_number_of_value_to_get_from_array_1);
} else if (firstIndex + length > arrayLength) {
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Attempted_to_get_more_values_from_array_than_length_of_array_2);
}
// Note that this information should not be cached.
initJdwpRequest();
try {
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
DataOutputStream outData = new DataOutputStream(outBytes);
write(this, outData); // arrayObject
writeInt(firstIndex, "firstIndex", outData); //$NON-NLS-1$
writeInt(length, "length", outData); //$NON-NLS-1$
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.AR_GET_VALUES, outBytes);
switch (replyPacket.errorCode()) {
case JdwpReplyPacket.INVALID_INDEX:
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Invalid_index_of_array_reference_given_1);
}
defaultReplyErrorHandler(replyPacket.errorCode());
DataInputStream replyData = replyPacket.dataInStream();
/* NOTE: The JDWP documentation is not clear on this: it turns out that the following is received from the VM:
* - type tag;
* - length of array;
* - values of elements.
*/
int type = readByte("type", JdwpID.tagMap(), replyData); //$NON-NLS-1$
int readLength = readInt("length", replyData); //$NON-NLS-1$
// See also ValueImpl.
switch(type) {
// Multidimensional array.
case ArrayReferenceImpl.tag:
// Object references.
case ClassLoaderReferenceImpl.tag:
case ClassObjectReferenceImpl.tag:
case StringReferenceImpl.tag:
case ObjectReferenceImpl.tag:
case ThreadGroupReferenceImpl.tag:
case ThreadReferenceImpl.tag:
return readObjectSequence(readLength, replyData);
// Primitive type.
case BooleanValueImpl.tag:
case ByteValueImpl.tag:
case CharValueImpl.tag:
case DoubleValueImpl.tag:
case FloatValueImpl.tag:
case IntegerValueImpl.tag:
case LongValueImpl.tag:
case ShortValueImpl.tag:
return readPrimitiveSequence(readLength, type, replyData);
case VoidValueImpl.tag:
case 0:
default:
throw new InternalException(JDIMessages.ArrayReferenceImpl_Invalid_ArrayReference_Value_tag_encountered___2 + type);
}
} catch (IOException e) {
defaultIOExceptionHandler(e);
return null;
} finally {
handledJdwpRequest();
}
}
/**
* @returns Returns sequence of object reference values.
*/
private List readObjectSequence(int length, DataInputStream in) throws IOException {
List elements = new ArrayList(length);
for (int i = 0; i < length; i++) {
ValueImpl value = ObjectReferenceImpl.readObjectRefWithTag(this, in);
elements.add(value);
}
return elements;
}
/**
* @returns Returns sequence of values of primitive type.
*/
private List readPrimitiveSequence(int length, int type, DataInputStream in) throws IOException {
List elements = new ArrayList(length);
for (int i = 0; i < length; i++) {
ValueImpl value = ValueImpl.readWithoutTag(this, type, in);
elements.add(value);
}
return elements;
}
/**
* @returns Returns the number of components in this array.
*/
public int length() {
if (fLength == -1) {
initJdwpRequest();
try {
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.AR_LENGTH, this);
defaultReplyErrorHandler(replyPacket.errorCode());
DataInputStream replyData = replyPacket.dataInStream();
fLength = readInt("length", replyData); //$NON-NLS-1$
} catch (IOException e) {
defaultIOExceptionHandler(e);
return 0;
} finally {
handledJdwpRequest();
}
}
return fLength;
}
/**
* Replaces an array component with another value.
*/
public void setValue(int index, Value value) throws InvalidTypeException, ClassNotLoadedException {
ArrayList list = new ArrayList(1);
list.add(value);
setValues(index, list, 0, 1);
}
/**
* Replaces all array components with other values.
*/
public void setValues(List values) throws InvalidTypeException, ClassNotLoadedException {
setValues(0, values, 0, -1);
}
/**
* Replaces a range of array components with other values.
*/
public void setValues(int index, List values, int srcIndex, int length) throws InvalidTypeException, ClassNotLoadedException {
int valuesSize= values.size();
int arrayLength= length();
if (index < 0 || index >= arrayLength) {
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Invalid_index_1);
}
if (srcIndex < 0 || srcIndex >= valuesSize) {
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Invalid_srcIndex_2);
}
if (length < -1) {
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Invalid_number_of_value_to_set_in_array_3);
} else if (length == -1) {
// length == -1 indicates as much values as possible.
length = arrayLength - index;
int lengthTmp= valuesSize - srcIndex;
if (lengthTmp < length) {
length= lengthTmp;
}
} else if (index + length > arrayLength) {
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_length_of_array_3);
} else if (srcIndex + length > valuesSize) {
// Check if enough values are given.
throw new IndexOutOfBoundsException(JDIMessages.ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_given_4);
}
// check and convert the values if needed.
List checkedValues= checkValues(values.subList(srcIndex, srcIndex + length), ((ArrayTypeImpl) referenceType()).componentType());
// Note that this information should not be cached.
initJdwpRequest();
try {
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
DataOutputStream outData = new DataOutputStream(outBytes);
write(this, outData);
writeInt(index, "index", outData); //$NON-NLS-1$
writeInt(length, "length", outData); //$NON-NLS-1$
Iterator iterValues= checkedValues.iterator();
while (iterValues.hasNext()) {
ValueImpl value= (ValueImpl)iterValues.next();
if (value != null) {
value.write(this, outData);
} else {
ValueImpl.writeNull(this, outData);
}
}
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.AR_SET_VALUES, outBytes);
switch (replyPacket.errorCode()) {
case JdwpReplyPacket.TYPE_MISMATCH:
throw new InvalidTypeException();
case JdwpReplyPacket.INVALID_CLASS:
throw new ClassNotLoadedException(type().name());
}
defaultReplyErrorHandler(replyPacket.errorCode());
} catch (IOException e) {
defaultIOExceptionHandler(e);
} finally {
handledJdwpRequest();
}
}
/**
* Check the type and the vm of the values. If the given type is a primitive type,
* the values may be convert for match this type.
* @see ValueImpl#checkValue(Value, Type, VirtualMachineImpl)
*/
private List checkValues(List values, Type type) throws InvalidTypeException {
List checkedValues= new ArrayList(values.size());
Iterator iterValues= values.iterator();
while (iterValues.hasNext()) {
checkedValues.add(ValueImpl.checkValue((Value) iterValues.next(), type, virtualMachineImpl()));
}
return checkedValues;
}
/**
* @return Returns description of Mirror object.
*/
public String toString() {
try {
StringBuffer buf = new StringBuffer(type().name());
// Insert length of string between (last) square braces.
buf.insert(buf.length() - 1, length());
// Append space and idString.
buf.append(' ');
buf.append(idString());
return buf.toString();
} catch (ObjectCollectedException e) {
return JDIMessages.ArrayReferenceImpl__Garbage_Collected__ArrayReference_5 + "[" + length() + "] " + idString(); //$NON-NLS-1$ //$NON-NLS-2$
} catch (Exception e) {
return fDescription;
}
}
/**
* @return Reads JDWP representation and returns new instance.
*/
public static ArrayReferenceImpl read(MirrorImpl target, DataInputStream in) throws IOException {
VirtualMachineImpl vmImpl = target.virtualMachineImpl();
JdwpObjectID ID = new JdwpObjectID(vmImpl);
ID.read(in);
if (target.fVerboseWriter != null) {
target.fVerboseWriter.println("arrayReference", ID.value()); //$NON-NLS-1$
}
if (ID.isNull()) {
return null;
}
ArrayReferenceImpl mirror = new ArrayReferenceImpl(vmImpl, ID);
return mirror;
}
}