| /******************************************************************************* |
| * Copyright (c) 2000, 2010 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.io.PrintWriter; |
| import java.util.Date; |
| import java.util.Map; |
| |
| import org.eclipse.jdi.Bootstrap; |
| import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; |
| import org.eclipse.jdi.internal.jdwp.JdwpPacket; |
| import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; |
| import org.eclipse.jdi.internal.jdwp.JdwpString; |
| import org.eclipse.jdt.internal.debug.core.JDIDebugOptions; |
| |
| import com.sun.jdi.ClassNotPreparedException; |
| import com.sun.jdi.InternalException; |
| import com.sun.jdi.InvalidStackFrameException; |
| import com.sun.jdi.Mirror; |
| import com.sun.jdi.NativeMethodException; |
| import com.sun.jdi.ObjectCollectedException; |
| import com.sun.jdi.VMDisconnectedException; |
| import com.sun.jdi.VMMismatchException; |
| import com.sun.jdi.VMOutOfMemoryException; |
| import com.sun.jdi.VirtualMachine; |
| |
| /** |
| * this class implements the corresponding interfaces declared by the JDI |
| * specification. See the com.sun.jdi package for more information. |
| * |
| */ |
| public class MirrorImpl implements Mirror { |
| |
| /** Description of Mirror object. */ |
| protected String fDescription; |
| /** Virtual Machine of Mirror object. */ |
| private VirtualMachineImpl fVirtualMachineImpl; |
| /** |
| * VerboseWriter where verbose info is written to, null if no verbose must |
| * be given. |
| */ |
| protected VerboseWriter fVerboseWriter = null; |
| /** |
| * True if a Jdwp request has been sent to the VM and the response is not |
| * yet (fully) processed. |
| */ |
| private boolean fPendingJdwpRequest = false; |
| |
| /** |
| * Constructor only to be used by Virtual Machine objects: stores |
| * description of Mirror object and Virtual Machine. |
| */ |
| public MirrorImpl(String description) { |
| fDescription = description; |
| fVirtualMachineImpl = (VirtualMachineImpl) this; |
| PrintWriter writer = ((VirtualMachineManagerImpl) org.eclipse.jdi.Bootstrap |
| .virtualMachineManager()).verbosePrintWriter(); |
| if (writer != null) |
| fVerboseWriter = new VerboseWriter(writer); |
| } |
| |
| /** |
| * Constructor stores description of Mirror object and its Virtual Machine. |
| */ |
| public MirrorImpl(String description, VirtualMachineImpl virtualMachineImpl) { |
| fVirtualMachineImpl = virtualMachineImpl; |
| fDescription = description; |
| PrintWriter writer = ((VirtualMachineManagerImpl) org.eclipse.jdi.Bootstrap |
| .virtualMachineManager()).verbosePrintWriter(); |
| if (writer != null) |
| fVerboseWriter = new VerboseWriter(writer); |
| } |
| |
| /** |
| * @return Returns description of Mirror object. |
| */ |
| @Override |
| public String toString() { |
| return fDescription; |
| } |
| |
| /** |
| * @return Returns Virtual Machine of Mirror object. |
| */ |
| public VirtualMachine virtualMachine() { |
| return fVirtualMachineImpl; |
| } |
| |
| /** |
| * @return Returns Virtual Machine implementation of Mirror object. |
| */ |
| public VirtualMachineImpl virtualMachineImpl() { |
| return fVirtualMachineImpl; |
| } |
| |
| /** |
| * Processing before each Jdwp event. |
| */ |
| public void initJdwpEventSet(JdwpCommandPacket commandPacket) { |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println("Received event set"); //$NON-NLS-1$ |
| fVerboseWriter.println("length", commandPacket.getLength()); //$NON-NLS-1$ |
| fVerboseWriter.println("id", commandPacket.getId()); //$NON-NLS-1$ |
| fVerboseWriter.println( |
| "flags", commandPacket.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ |
| fVerboseWriter.println( |
| "command set", (byte) (commandPacket.getCommand() >>> 8)); //$NON-NLS-1$ |
| fVerboseWriter |
| .println("command", (byte) commandPacket.getCommand()); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Processing after each Jdwp Event. |
| */ |
| public void handledJdwpEventSet() { |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(); |
| fVerboseWriter.flush(); |
| } |
| } |
| |
| /** |
| * Processing before each Jdwp request. Note that this includes building the |
| * request message and parsing the response. |
| */ |
| public void initJdwpRequest() { |
| if (fVerboseWriter != null) { |
| fVerboseWriter.gotoPosition(6); |
| } |
| } |
| |
| /** |
| * Writes command packet header if verbose is on. |
| */ |
| public void writeVerboseCommandPacketHeader(JdwpCommandPacket commandPacket) { |
| if (fVerboseWriter != null) { |
| int command = commandPacket.getCommand(); |
| int currentPosition = fVerboseWriter.position(); |
| fVerboseWriter.gotoPosition(0); |
| fVerboseWriter.print("Sending command ("); //$NON-NLS-1$ |
| fVerboseWriter.printValue(command, JdwpCommandPacket.commandMap()); |
| fVerboseWriter.println(")"); //$NON-NLS-1$ |
| fVerboseWriter.println("length", commandPacket.getLength()); //$NON-NLS-1$ |
| fVerboseWriter.println("id", commandPacket.getId()); //$NON-NLS-1$ |
| fVerboseWriter.println( |
| "flags", commandPacket.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ |
| fVerboseWriter.println("command set", (byte) (command >>> 8)); //$NON-NLS-1$ |
| fVerboseWriter.println("command", (byte) command); //$NON-NLS-1$ |
| fVerboseWriter.gotoPosition(currentPosition); |
| } |
| } |
| |
| /** |
| * Processing after each Jdwp Request. |
| */ |
| public void handledJdwpRequest() { |
| if (fVerboseWriter != null && fPendingJdwpRequest) { |
| fVerboseWriter.println(); |
| fVerboseWriter.flush(); |
| } |
| fPendingJdwpRequest = false; |
| } |
| |
| /** |
| * Performs a VM request. |
| * |
| * @return Returns reply data. |
| */ |
| public JdwpReplyPacket requestVM(int command, byte[] outData) { |
| JdwpCommandPacket commandPacket = new JdwpCommandPacket(command); |
| commandPacket.setData(outData); |
| long sent = System.currentTimeMillis(); |
| fVirtualMachineImpl.packetSendManager().sendPacket(commandPacket); |
| fPendingJdwpRequest = true; |
| writeVerboseCommandPacketHeader(commandPacket); |
| |
| JdwpReplyPacket reply = fVirtualMachineImpl.packetReceiveManager() |
| .getReply(commandPacket); |
| long recieved = System.currentTimeMillis(); |
| if (JDIDebugOptions.DEBUG_JDI_REQUEST_TIMES) { |
| StringBuffer buf = new StringBuffer(); |
| buf.append(JDIDebugOptions.FORMAT.format(new Date(sent))); |
| buf.append(" JDI Request: "); //$NON-NLS-1$ |
| buf.append(commandPacket.toString()); |
| buf.append("\n\tResponse Time: "); //$NON-NLS-1$ |
| buf.append(recieved - sent); |
| buf.append("ms"); //$NON-NLS-1$ |
| buf.append(" length: "); //$NON-NLS-1$ |
| buf.append(reply.getLength()); |
| System.out.println(buf.toString()); |
| } |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(); |
| fVerboseWriter.println("Received reply"); //$NON-NLS-1$ |
| fVerboseWriter.println("length", reply.getLength()); //$NON-NLS-1$ |
| fVerboseWriter.println("id", reply.getId()); //$NON-NLS-1$ |
| fVerboseWriter.println( |
| "flags", reply.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ |
| fVerboseWriter |
| .println( |
| "error code", reply.errorCode(), JdwpReplyPacket.errorMap()); //$NON-NLS-1$ |
| } |
| |
| return reply; |
| } |
| |
| /** |
| * Performs a VM request. |
| * |
| * @return Returns reply data. |
| */ |
| public JdwpReplyPacket requestVM(int command, ByteArrayOutputStream outData) { |
| return requestVM(command, outData.toByteArray()); |
| } |
| |
| /** |
| * Performs a VM request for a specified object. |
| * |
| * @return Returns reply data. |
| */ |
| public JdwpReplyPacket requestVM(int command, ObjectReferenceImpl object) { |
| ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); |
| DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); |
| try { |
| object.write(this, dataOutStream); |
| } catch (IOException e) { |
| defaultIOExceptionHandler(e); |
| } |
| return requestVM(command, byteOutStream); |
| } |
| |
| /** |
| * Performs a VM request for a specified object. |
| * |
| * @return Returns reply data. |
| */ |
| public JdwpReplyPacket requestVM(int command, ReferenceTypeImpl refType) { |
| ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); |
| DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); |
| try { |
| refType.write(this, dataOutStream); |
| } catch (IOException e) { |
| defaultIOExceptionHandler(e); |
| } |
| return requestVM(command, byteOutStream); |
| } |
| |
| /** |
| * Performs a VM request. |
| * |
| * @return Returns reply data. |
| */ |
| public JdwpReplyPacket requestVM(int command) { |
| return requestVM(command, (byte[]) null); |
| } |
| |
| /** |
| * Performs default error handling. |
| */ |
| public void defaultReplyErrorHandler(int error) { |
| switch (error) { |
| case JdwpReplyPacket.NONE: |
| break; |
| case JdwpReplyPacket.INVALID_OBJECT: |
| throw new ObjectCollectedException(); |
| case JdwpReplyPacket.INVALID_CLASS: |
| throw new ClassNotPreparedException(); |
| case JdwpReplyPacket.CLASS_NOT_PREPARED: |
| throw new ClassNotPreparedException(); |
| case JdwpReplyPacket.OUT_OF_MEMORY: |
| throw new VMOutOfMemoryException(); |
| case JdwpReplyPacket.ILLEGAL_ARGUMENT: |
| throw new IllegalArgumentException(); |
| case JdwpReplyPacket.NATIVE_METHOD: |
| throw new NativeMethodException(); |
| case JdwpReplyPacket.INVALID_FRAMEID: |
| throw new InvalidStackFrameException(); |
| case JdwpReplyPacket.NOT_IMPLEMENTED: |
| throw new UnsupportedOperationException(); |
| case JdwpReplyPacket.HCR_OPERATION_REFUSED: |
| throw new org.eclipse.jdi.hcr.OperationRefusedException(); |
| case JdwpReplyPacket.VM_DEAD: |
| throw new VMDisconnectedException(); |
| default: |
| throw new InternalException( |
| JDIMessages.MirrorImpl_Got_error_code_in_reply___1 + error, |
| error); |
| } |
| } |
| |
| /** |
| * Performs default handling of IOException in creating or interpreting a |
| * Jdwp packet. |
| */ |
| public void defaultIOExceptionHandler(Exception e) { |
| throw new InternalException(JDIMessages.MirrorImpl_Got_invalid_data___2 |
| + e); |
| } |
| |
| /** |
| * Waits for a specified command packet from the VM. |
| * |
| * @return Returns Command Packet from VM. |
| */ |
| public final JdwpCommandPacket getCommandVM(int command, long timeout) |
| throws InterruptedException { |
| return fVirtualMachineImpl.packetReceiveManager().getCommand(command, |
| timeout); |
| } |
| |
| /** |
| * @exception VMMismatchException |
| * is thrown if the Mirror argument and this mirror do not |
| * belong to the same VirtualMachine. |
| */ |
| public void checkVM(Mirror mirror) throws VMMismatchException { |
| if (((MirrorImpl) mirror).virtualMachineImpl() != this |
| .virtualMachineImpl()) |
| throw new VMMismatchException(); |
| } |
| |
| /** |
| * Disconnects VM. |
| */ |
| public void disconnectVM() { |
| fVirtualMachineImpl.setDisconnected(true); |
| fVirtualMachineImpl.packetSendManager().disconnectVM(); |
| fVirtualMachineImpl.packetReceiveManager().disconnectVM(); |
| ((VirtualMachineManagerImpl) Bootstrap.virtualMachineManager()) |
| .removeConnectedVM(fVirtualMachineImpl); |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public byte readByte(String description, DataInputStream in) |
| throws IOException { |
| byte result = in.readByte(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public short readShort(String description, DataInputStream in) |
| throws IOException { |
| short result = in.readShort(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public int readInt(String description, DataInputStream in) |
| throws IOException { |
| int result = in.readInt(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public long readLong(String description, DataInputStream in) |
| throws IOException { |
| long result = in.readLong(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public byte readByte(String description, Map<Integer, String> valueToString, |
| DataInputStream in) throws IOException { |
| byte result = in.readByte(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result, valueToString); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public short readShort(String description, Map<Integer, String> valueToString, |
| DataInputStream in) throws IOException { |
| short result = in.readShort(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result, valueToString); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public int readInt(String description, Map<Integer, String> valueToString, DataInputStream in) |
| throws IOException { |
| int result = in.readInt(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result, valueToString); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public String readString(String description, DataInputStream in) |
| throws IOException { |
| String result = JdwpString.read(in); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public boolean readBoolean(String description, DataInputStream in) |
| throws IOException { |
| boolean result = in.readBoolean(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public char readChar(String description, DataInputStream in) |
| throws IOException { |
| char result = in.readChar(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public double readDouble(String description, DataInputStream in) |
| throws IOException { |
| double result = in.readDouble(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public float readFloat(String description, DataInputStream in) |
| throws IOException { |
| float result = in.readFloat(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public byte[] readByteArray(int length, String description, |
| DataInputStream in) throws IOException { |
| byte[] result = new byte[length]; |
| in.readFully(result); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result); |
| } |
| return result; |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeByte(byte value, String description, DataOutputStream out) |
| throws IOException { |
| out.writeByte(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeShort(short value, String description, DataOutputStream out) |
| throws IOException { |
| out.writeShort(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeInt(int value, String description, DataOutputStream out) |
| throws IOException { |
| out.writeInt(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeLong(long value, String description, DataOutputStream out) |
| throws IOException { |
| out.writeLong(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeByte(byte value, String description, Map<Integer, String> valueToString, |
| DataOutputStream out) throws IOException { |
| out.writeByte(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value, valueToString); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeShort(short value, String description, Map<Integer, String> valueToString, |
| DataOutputStream out) throws IOException { |
| out.writeShort(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value, valueToString); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeInt(int value, String description, Map<Integer, String> valueToString, |
| DataOutputStream out) throws IOException { |
| out.writeInt(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value, valueToString); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeString(String value, String description, |
| DataOutputStream out) throws IOException { |
| JdwpString.write(value, out); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeBoolean(boolean value, String description, |
| DataOutputStream out) throws IOException { |
| out.writeBoolean(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeChar(char value, String description, DataOutputStream out) |
| throws IOException { |
| out.writeChar(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeDouble(double value, String description, |
| DataOutputStream out) throws IOException { |
| out.writeDouble(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeFloat(float value, String description, DataOutputStream out) |
| throws IOException { |
| out.writeFloat(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeShort(short value, String description, String[] bitNames, |
| DataOutputStream out) throws IOException { |
| out.writeShort(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value, bitNames); |
| } |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeInt(int value, String description, String[] bitNames, |
| DataOutputStream out) throws IOException { |
| out.writeInt(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value, bitNames); |
| } |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public byte readByte(String description, String[] bitNames, |
| DataInputStream in) throws IOException { |
| byte result = in.readByte(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result, bitNames); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public short readShort(String description, String[] bitNames, |
| DataInputStream in) throws IOException { |
| short result = in.readShort(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result, bitNames); |
| } |
| return result; |
| } |
| |
| /** |
| * Reads Jdwp data and, if verbose is on, outputs verbose info. |
| * |
| * @return Returns value that has been read. |
| */ |
| public int readInt(String description, String[] bitNames, DataInputStream in) |
| throws IOException { |
| int result = in.readInt(); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, result, bitNames); |
| } |
| return result; |
| } |
| |
| /** |
| * Writes Jdwp data and, if verbose is on, outputs verbose info. |
| */ |
| public void writeByte(byte value, String description, String[] bitNames, |
| DataOutputStream out) throws IOException { |
| out.writeByte(value); |
| if (fVerboseWriter != null) { |
| fVerboseWriter.println(description, value, bitNames); |
| } |
| } |
| |
| /** |
| * @return Returns VerboseWriter where verbose info is written to, null if |
| * no verbose must be given. |
| */ |
| public VerboseWriter verboseWriter() { |
| return fVerboseWriter; |
| } |
| } |