001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdi.internal.spy;
011:
012: import java.io.ByteArrayInputStream;
013: import java.io.DataInputStream;
014: import java.io.DataOutputStream;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.io.OutputStream;
018: import java.lang.reflect.Field;
019: import java.lang.reflect.Modifier;
020:
021: /**
022: * This class implements the corresponding Java Debug Wire Protocol (JDWP) packet
023: * declared by the JDWP specification.
024: *
025: */
026: public abstract class JdwpPacket {
027: /** General JDWP constants. */
028: public static final byte FLAG_REPLY_PACKET = (byte) 0x80;
029: protected static final int MIN_PACKET_LENGTH = 11;
030:
031: /** Map with Strings for flag bits. */
032: private static String[] fgFlagStrings = null;
033:
034: /** Header fields. */
035: protected int fId = 0;
036: protected byte fFlags = 0;
037: protected byte[] fDataBuf = null;
038:
039: /**
040: * Set Id.
041: */
042: /*package*/void setId(int id) {
043: fId = id;
044: }
045:
046: /**
047: * @return Returns Id.
048: */
049: public int getId() {
050: return fId;
051: }
052:
053: /**
054: * Set Flags.
055: */
056: /*package*/void setFlags(byte flags) {
057: fFlags = flags;
058: }
059:
060: /**
061: * @return Returns Flags.
062: */
063: public byte getFlags() {
064: return fFlags;
065: }
066:
067: /**
068: * @return Returns total length of packet.
069: */
070: public int getLength() {
071: return MIN_PACKET_LENGTH + getDataLength();
072: }
073:
074: /**
075: * @return Returns length of data in packet.
076: */
077: public int getDataLength() {
078: return fDataBuf == null ? 0 : fDataBuf.length;
079: }
080:
081: /**
082: * @return Returns data of packet.
083: */
084: public byte[] data() {
085: return fDataBuf;
086: }
087:
088: /**
089: * @return Returns DataInputStream with reply data, or an empty stream if there is none.
090: */
091: public DataInputStream dataInStream() {
092: if (fDataBuf != null) {
093: return new DataInputStream(new ByteArrayInputStream(
094: fDataBuf));
095: }
096:
097: return new DataInputStream(
098: new ByteArrayInputStream(new byte[0]));
099: }
100:
101: /**
102: * Assigns data to packet.
103: */
104: public void setData(byte[] data) {
105: fDataBuf = data;
106: }
107:
108: /**
109: * Reads header fields that are specific for a type of packet.
110: */
111: protected abstract void readSpecificHeaderFields(
112: DataInputStream dataInStream) throws IOException;
113:
114: /**
115: * Writes header fields that are specific for a type of packet.
116: */
117: protected abstract void writeSpecificHeaderFields(
118: DataOutputStream dataOutStream) throws IOException;
119:
120: /**
121: * Reads complete packet.
122: */
123: public static JdwpPacket read(InputStream inStream)
124: throws IOException {
125: DataInputStream dataInStream = new DataInputStream(inStream);
126:
127: // Read header.
128: int packetLength = dataInStream.readInt();
129: int id = dataInStream.readInt();
130: byte flags = dataInStream.readByte();
131:
132: // Determine type: command or reply.
133: JdwpPacket packet;
134: if ((flags & FLAG_REPLY_PACKET) != 0)
135: packet = new JdwpReplyPacket();
136: else
137: packet = new JdwpCommandPacket();
138:
139: // Assign generic header fields.
140: packet.setId(id);
141: packet.setFlags(flags);
142:
143: // Read specific header fields and data.
144: packet.readSpecificHeaderFields(dataInStream);
145: if (packetLength - MIN_PACKET_LENGTH > 0) {
146: packet.fDataBuf = new byte[packetLength - MIN_PACKET_LENGTH];
147: dataInStream.readFully(packet.fDataBuf);
148: }
149:
150: return packet;
151: }
152:
153: /**
154: * Writes complete packet.
155: */
156: public void write(OutputStream outStream) throws IOException {
157: DataOutputStream dataOutStream = new DataOutputStream(outStream);
158:
159: writeHeader(dataOutStream);
160: writeData(dataOutStream);
161: }
162:
163: /**
164: * Writes header of packet.
165: */
166: protected void writeHeader(DataOutputStream dataOutStream)
167: throws IOException {
168: dataOutStream.writeInt(getLength());
169: dataOutStream.writeInt(getId());
170: dataOutStream.writeByte(getFlags());
171: writeSpecificHeaderFields(dataOutStream);
172: }
173:
174: /**
175: * Writes data of packet.
176: */
177: protected void writeData(DataOutputStream dataOutStream)
178: throws IOException {
179: if (fDataBuf != null) {
180: dataOutStream.write(fDataBuf);
181: }
182: }
183:
184: /**
185: * Retrieves constant mappings.
186: */
187: public static void getConstantMaps() {
188: if (fgFlagStrings != null) {
189: return;
190: }
191:
192: Field[] fields = JdwpPacket.class.getDeclaredFields();
193: fgFlagStrings = new String[8];
194:
195: for (int i = 0; i < fields.length; i++) {
196: Field field = fields[i];
197: if ((field.getModifiers() & Modifier.PUBLIC) == 0
198: || (field.getModifiers() & Modifier.STATIC) == 0
199: || (field.getModifiers() & Modifier.FINAL) == 0) {
200: continue;
201: }
202:
203: String name = field.getName();
204: if (!name.startsWith("FLAG_")) {//$NON-NLS-1$
205: continue;
206: }
207:
208: name = name.substring(5);
209:
210: try {
211: byte value = field.getByte(null);
212:
213: for (int j = 0; j < fgFlagStrings.length; j++) {
214: if ((1 << j & value) != 0) {
215: fgFlagStrings[j] = name;
216: break;
217: }
218: }
219: } catch (IllegalAccessException e) {
220: // Will not occur for own class.
221: } catch (IllegalArgumentException e) {
222: // Should not occur.
223: // We should take care that all public static final constants
224: // in this class are bytes.
225: }
226: }
227: }
228:
229: /**
230: * @return Returns a mapping with string representations of flags.
231: */
232: public static String[] getFlagMap() {
233: getConstantMaps();
234: return fgFlagStrings;
235: }
236: }
|