001: /*
002:
003: Derby - Class org.apache.derby.client.net.NetLogWriter
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.client.net;
023:
024: // network traffic tracer.
025: // This class traces communication buffers for both sends and receives.
026: // The value of the hex bytes are traced along with the ascii and ebcdic translations.
027:
028: public class NetLogWriter extends org.apache.derby.client.am.LogWriter {
029:
030: // The recevie constant is used to indicate that the bytes were read to a Stream.
031: // It indicates to this class that a receive header should be used.
032: public static final int TYPE_TRACE_RECEIVE = 2;
033:
034: // The send constant is used to indicate that the bytes were written to
035: // a Stream. It indicates to this class that a send header should be used.
036: public static final int TYPE_TRACE_SEND = 1;
037:
038: //------------------------------ internal constants --------------------------
039:
040: // This class was implemented using character arrays to translate bytes
041: // into ascii and ebcdic. The goal was to be able to quickly index into the
042: // arrays to find the characters. Char arrays instead of strings were used as
043: // much as possible in an attempt to help speed up performance.
044:
045: // An array of characters used to translate bytes to ascii.
046: // The position in the array corresponds to the hex value of the character.
047: private static final char asciiChar__[] = {
048: // 0 1 2 3 4 5 6 7 8 9 A B C D E F
049: '.',
050: '.',
051: '.',
052: '.',
053: '.',
054: '.',
055: '.',
056: '.',
057: '.',
058: '.',
059: '.',
060: '.',
061: '.',
062: '.',
063: '.',
064: '.', //0
065: '.',
066: '.',
067: '.',
068: '.',
069: '.',
070: '.',
071: '.',
072: '.',
073: '.',
074: '.',
075: '.',
076: '.',
077: '.',
078: '.',
079: '.',
080: '.', //1
081: ' ', '!',
082: '"',
083: '#',
084: '$',
085: '%',
086: '&',
087: '\'',
088: '(',
089: ')',
090: '*',
091: '+',
092: ',',
093: '-',
094: '.',
095: '/', //2
096: '0', '1', '2',
097: '3',
098: '4',
099: '5',
100: '6',
101: '7',
102: '8',
103: '9',
104: ':',
105: ';',
106: '<',
107: '=',
108: '>',
109: '?', //3
110: '@', 'A', 'B', 'C',
111: 'D',
112: 'E',
113: 'F',
114: 'G',
115: 'H',
116: 'I',
117: 'J',
118: 'K',
119: 'L',
120: 'M',
121: 'N',
122: 'O', //4
123: 'P', 'Q', 'R', 'S', 'T',
124: 'U',
125: 'V',
126: 'W',
127: 'X',
128: 'Y',
129: 'Z',
130: '[',
131: '\\',
132: ']',
133: '^',
134: '_', //5
135: '`', 'a', 'b', 'c', 'd', 'e',
136: 'f',
137: 'g',
138: 'h',
139: 'i',
140: 'j',
141: 'k',
142: 'l',
143: 'm',
144: 'n',
145: 'o', //6
146: 'p', 'q', 'r', 's', 't', 'u', 'v',
147: 'w',
148: 'x',
149: 'y',
150: 'z',
151: '{',
152: '|',
153: '}',
154: '~',
155: '.', //7
156: '.', '.', '.', '.', '.', '.', '.', '.',
157: '.',
158: '.',
159: '.',
160: '.',
161: '.',
162: '.',
163: '.',
164: '.', //8
165: '.', '.', '.', '.', '.', '.', '.', '.', '.',
166: '.',
167: '.',
168: '.',
169: '.',
170: '.',
171: '.',
172: '.', //9
173: '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
174: '.',
175: '.',
176: '.',
177: '.',
178: '.',
179: '.', //A
180: '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
181: '.',
182: '.',
183: '.',
184: '.',
185: '.', //B
186: '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
187: '.',
188: '.',
189: '.',
190: '.', //C
191: '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
192: '.', '.',
193: '.',
194: '.', //D
195: '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
196: '.', '.', '.',
197: '.', //E
198: '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
199: '.', '.', '.', '.' //F
200: };
201:
202: // This column position header is used to mark offsets into the trace.
203: private static final String colPosHeader__ = " 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0123456789ABCDEF";
204:
205: // An array of characters used to translate bytes to ebcdic.
206: // The position in the array corresponds to the hex value of the
207: // character.
208: private static final char ebcdicChar__[] = {
209: // 0 1 2 3 4 5 6 7 8 9 A B C D E F
210: '.',
211: '.',
212: '.',
213: '.',
214: '.',
215: '.',
216: '.',
217: '.',
218: '.',
219: '.',
220: '.',
221: '.',
222: '.',
223: '.',
224: '.',
225: '.', //0
226: '.',
227: '.',
228: '.',
229: '.',
230: '.',
231: '.',
232: '.',
233: '.',
234: '.',
235: '.',
236: '.',
237: '.',
238: '.',
239: '.',
240: '.',
241: '.', //1
242: '.', '.',
243: '.',
244: '.',
245: '.',
246: '.',
247: '.',
248: '.',
249: '.',
250: '.',
251: '.',
252: '.',
253: '.',
254: '.',
255: '.',
256: '.', //2
257: '.', '.', '.',
258: '.',
259: '.',
260: '.',
261: '.',
262: '.',
263: '.',
264: '.',
265: '.',
266: '.',
267: '.',
268: '.',
269: '.',
270: '.', //3
271: ' ', '.', '.', '.',
272: '.',
273: '.',
274: '.',
275: '.',
276: '.',
277: '.',
278: '.',
279: '.',
280: '<',
281: '(',
282: '+',
283: '|', //4
284: '&', '.', '.', '.', '.',
285: '.',
286: '.',
287: '.',
288: '.',
289: '.',
290: '!',
291: '$',
292: '*',
293: ')',
294: ';',
295: '.', //5
296: '-', '/', '.', '.', '.', '.',
297: '.',
298: '.',
299: '.',
300: '.',
301: '|',
302: ',',
303: '%',
304: '_',
305: '>',
306: '?', //6
307: '.', '.', '.', '.', '.', '.', '.',
308: '.',
309: '.',
310: '`',
311: ':',
312: '#',
313: '@',
314: '\'',
315: '=',
316: '"', //7
317: '.', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
318: 'h',
319: 'i',
320: '.',
321: '.',
322: '.',
323: '.',
324: '.',
325: '.', //8
326: '.', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
327: 'r',
328: '.',
329: '.',
330: '.',
331: '.',
332: '.',
333: '.', //9
334: '.', '~', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
335: '.',
336: '.',
337: '.',
338: '.',
339: '.',
340: '.', //A
341: '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
342: '.',
343: '.',
344: '.',
345: '.',
346: '.', //B
347: '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', '.', '.',
348: '.',
349: '.',
350: '.',
351: '.', //C
352: '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', '.', '.',
353: '.', '.',
354: '.',
355: '.', //D
356: '\\', '.', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '.',
357: '.', '.', '.', '.',
358: '.', //E
359: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '.',
360: '.', '.', '.', '.' //F
361: };
362:
363: // An array of characters representing hex numbers.
364: private static final char hexDigit__[] = { '0', '1', '2', '3', '4',
365: '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
366:
367: // The receive header comes befor bytes which would be read from a stream.
368: private static final String receiveHeader__ = " RECEIVE BUFFER: (ASCII) (EBCDIC)";
369:
370: // The send header comes before bytes which would be written to a stream.
371: private static final String sendHeader__ = " SEND BUFFER: (ASCII) (EBCDIC)";
372:
373: private static final char spaceChar__ = ' ';
374:
375: private static final char zeroChar__ = '0';
376:
377: // This mapping table associates a codepoint to a String describing the codepoint.
378: // This is needed because the trace prints the first codepoint in send and receive buffers.
379: // This is created lazily because there is no need to create the mapping if tracing isn't used.
380: // So this array will only be created when the com buffer trace is started.
381: private static CodePointNameTable codePointNameTable__ = null;
382:
383: //-----------------------------internal state---------------------------------
384:
385: //-----------------------------constructors/finalizer-------------------------
386:
387: // One NetLogWriter object is created per data source, iff tracing is enabled.
388: public NetLogWriter(java.io.PrintWriter printWriter, int traceLevel) {
389: super (printWriter, traceLevel);
390:
391: // Initialize the codepoint name table if not previously initialized.
392: // This is done lazily so that it is not created if the trace isn't used (save some init time).
393: if (codePointNameTable__ == null) {
394: codePointNameTable__ = new CodePointNameTable();
395: }
396: }
397:
398: //------------------------------entry points----------------------------------
399:
400: // Specialization of LogWriter.traceConnectsExit()
401: public void traceConnectsExit(
402: org.apache.derby.client.am.Connection connection) {
403: if (traceSuspended()) {
404: return;
405: }
406: NetConnection c = (NetConnection) connection;
407: synchronized (printWriter_) {
408: super .traceConnectsExit(c);
409: dncnetprint(" PROTOCOL manager levels: { ");
410: printWriter_.print("SQLAM=" + c.getSQLAM() + ", ");
411: printWriter_.print("AGENT=" + c.getAGENT() + ", ");
412: printWriter_.print("CMNTCPIP=" + c.getCMNTCPIP() + ", ");
413: printWriter_.print("RDB=" + c.getRDB() + ", ");
414: printWriter_.print("SECMGR=" + c.getSECMGR() + ", ");
415: printWriter_.print("XAMGR=" + c.getXAMGR() + ", ");
416: printWriter_.print("SYNCPTMGR=" + c.getSYNCPTMGR() + ", ");
417: printWriter_.print("RSYNCMGR=" + c.getRSYNCMGR());
418: printWriter_.println(" }");
419: printWriter_.flush();
420: }
421: }
422:
423: public void traceConnectsResetExit(
424: org.apache.derby.client.am.Connection connection) {
425: if (traceSuspended()) {
426: return;
427: }
428: NetConnection c = (NetConnection) connection;
429: synchronized (printWriter_) {
430: super .traceConnectsResetExit(c);
431: dncnetprint(" PROTOCOL manager levels: { ");
432: printWriter_.print("SQLAM=" + c.getSQLAM() + ", ");
433: printWriter_.print("AGENT=" + c.getAGENT() + ", ");
434: printWriter_.print("CMNTCPIP=" + c.getCMNTCPIP() + ", ");
435: printWriter_.print("RDB=" + c.getRDB() + ", ");
436: printWriter_.print("SECMGR=" + c.getSECMGR() + ", ");
437: printWriter_.print("XAMGR=" + c.getXAMGR() + ", ");
438: printWriter_.print("SYNCPTMGR=" + c.getSYNCPTMGR() + ", ");
439: printWriter_.print("RSYNCMGR=" + c.getRSYNCMGR());
440: printWriter_.println(" }");
441: printWriter_.flush();
442: }
443: }
444:
445: // Pass the connection handle and print it in the header
446: // What exactly is supposed to be passed, assume one complete DSS packet
447: // Write the communication buffer data to the trace.
448: // The data is passed in via a byte array. The start and length of the data is given.
449: // The type is needed to indicate if the data is part of the send or receive buffer.
450: // The class name, method name, and trcPt number are also written to the trace.
451: // Not much checking is performed on the parameters. This is done to help performance.
452: synchronized public void traceProtocolFlow(byte[] buff, int offset,
453: int len, int type, String className, String methodName,
454: int tracepoint) {
455: if (traceSuspended()) {
456: return;
457: }
458: if (!loggingEnabled(org.apache.derby.jdbc.ClientDataSource.TRACE_PROTOCOL_FLOWS)) {
459: return;
460: }
461: synchronized (printWriter_) {
462: super
463: .tracepoint("[net]", tracepoint, className,
464: methodName);
465:
466: int fullLen = len;
467: boolean printColPos = true;
468: while (fullLen >= 2) { // format each DssHdr seperately
469: // get the length of this DssHdr
470: len = ((buff[offset] & 0xff) << 8)
471: + ((buff[offset + 1] & 0xff) << 0);
472:
473: // check for valid dss header or not all of dss block
474: if ((len < 10) || (len > fullLen)) {
475: len = fullLen;
476: }
477:
478: // subtract that length from the full length
479: fullLen -= len;
480: // The data will only be written if there is a non-zero positive length.
481: if (len != 0) {
482: String codePointName = null;
483: // If the length <= 10, lookup the first codepoint so it's name can be printed
484: if (len >= 10) {
485: // Get the int value of the two byte unsigned codepoint.
486: int codePoint = getCodePoint(buff, offset + 8);
487: codePointName = codePointNameTable__
488: .lookup(codePoint);
489:
490: // if this is not a valid codepoint then format the entire buffer
491: // as one block.
492: if (codePointName == null) {
493: len += fullLen;
494: fullLen = 0;
495: }
496: }
497:
498: if (!printColPos) { // not 1st Dss header of this buffer, write seperator
499: dncnetprintln("");
500: }
501:
502: if (codePointName == null) {
503: // codePointName was still null so either < 10 bytes were given or
504: // the codepoint wasn't found in the table. Just print the plain send header.
505: dncnetprintln(getHeader(type));
506: } else {
507: // codePointName isn't null so the name of the codepoint will be printed.
508: printHeaderWithCodePointName(codePointName,
509: type);
510: }
511:
512: // Print the col position header in the trace.
513: if (printColPos) { // first Dss header of buffer, need column position header
514: dncnetprintln(colPosHeader__);
515: printColPos = false;
516: }
517:
518: // A char array will be used to translate the bytes to their character
519: // representations along with ascii and ebcdic representations.
520: char trcDump[] = new char[77];
521:
522: // bCounter, aCounter, eCounter are offsets used to help position the characters
523: short bCounter = 7;
524: short aCounter = 43;
525: short eCounter = 61;
526:
527: // The lines will be counted starting at zero.
528: // This is hard coded since we are at the beginning.
529: trcDump[0] = zeroChar__;
530: trcDump[1] = zeroChar__;
531: trcDump[2] = zeroChar__;
532: trcDump[3] = zeroChar__;
533:
534: // The 0's are already in the trace so bump the line counter up a row.
535: int lineCounter = 0x10;
536:
537: // Make sure the character array has all blanks in it.
538: // Some of these blanks will be replaced later with values.
539: // The 0's were not wrote over.
540: for (int j = 4; j < 77; j++) {
541: trcDump[j] = spaceChar__;
542: }
543:
544: // i will maintain the position in the byte array to be traced.
545: int i = 0;
546:
547: do {
548: // Get the unsigned value of the byte.
549: // int num = b[off++] & 0xff;
550: int num = (buff[offset] < 0) ? buff[offset] + 256
551: : buff[offset];
552: offset++;
553: i++;
554: // Place the characters representing the bytes in the array.
555: trcDump[bCounter++] = hexDigit__[((num >>> 4) & 0xf)];
556: trcDump[bCounter++] = hexDigit__[(num & 0xf)];
557:
558: // Place the ascii and ebcdc representations in the array.
559: trcDump[aCounter++] = asciiChar__[num];
560: trcDump[eCounter++] = ebcdicChar__[num];
561:
562: if (((i % 8) == 0)) {
563: if (((i % 16) == 0)) {
564: // Print the array each time 16 bytes are processed.
565: dncnetprintln(trcDump);
566: if (i != len) {
567: // Not yet at the end of the byte array.
568: if ((len - i) < 16) {
569: // This is the last line so blank it all out.
570: // This keeps the last line looking pretty in case
571: // < 16 bytes remain.
572: for (int j = 0; j < trcDump.length; j++) {
573: trcDump[j] = spaceChar__;
574: }
575: }
576: // Reset the counters.
577: bCounter = 0;
578: aCounter = 43;
579: eCounter = 61;
580: // Reset the lineCounter if it starts to get too large.
581: if (lineCounter == 0x100000) {
582: lineCounter = 0;
583: }
584: // Place the characters representing the line counter in the array.
585: trcDump[bCounter++] = hexDigit__[((lineCounter >>> 12) & 0xf)];
586: trcDump[bCounter++] = hexDigit__[((lineCounter >>> 8) & 0xf)];
587: trcDump[bCounter++] = hexDigit__[((lineCounter >>> 4) & 0xf)];
588: trcDump[bCounter++] = hexDigit__[(lineCounter & 0xf)];
589: bCounter += 3;
590: // Bump up the line counter.
591: lineCounter += 0x10;
592: }
593: } else {
594: // 8 bytes were processed so move the counter to adjust for
595: // spaces between the columns of bytes.
596: bCounter += 2;
597: }
598: }
599: // do this until we all the data has been traced.
600: } while (i < len);
601:
602: // print the last line and add some blank lines to make it easier to read.
603: if (len % 16 != 0) {
604: dncnetprintln(trcDump);
605: }
606: }
607: }
608: dncnetprintln("");
609: }
610: }
611:
612: // Gets the int value of the two byte unsigned codepoint.
613: private static int getCodePoint(byte[] buff, int offset) {
614: return ((buff[offset++] & 0xff) << 8)
615: + ((buff[offset] & 0xff) << 0);
616: }
617:
618: private static String getHeader(int type) {
619: switch (type) {
620: case TYPE_TRACE_SEND:
621: return sendHeader__;
622: case TYPE_TRACE_RECEIVE:
623: return receiveHeader__;
624: default:
625: return null;
626: }
627: }
628:
629: private static int getStartPosition(int type) {
630: switch (type) {
631: case TYPE_TRACE_SEND:
632: return 20; // This is right after 'SEND BUFFER: '.
633: case TYPE_TRACE_RECEIVE:
634: return 23; // This is right after 'RECEIVE BUFFER: '.
635: default:
636: return 0;
637: }
638: }
639:
640: private void printHeaderWithCodePointName(String codePointName,
641: int type) {
642: // Create a char array so some of the characters
643: // can be replaced with the name of the codepoint.
644: char headerArray[] = getHeader(type).toCharArray();
645:
646: // At most, 16 character name will be used. This is so
647: // the headers on top of the ascii and ebcdic rows aren't shifted.
648: int replaceLen = (codePointName.length() < 17) ? codePointName
649: .length() : 16;
650:
651: int offset = getStartPosition(type);
652: for (int i = 0; i < replaceLen; i++) {
653: headerArray[offset++] = codePointName.charAt(i);
654: }
655: dncnetprintln(headerArray);
656: }
657:
658: private void dncnetprint(String s) {
659: synchronized (printWriter_) {
660: printWriter_.print("[derby] " + s);
661: printWriter_.flush();
662: }
663: }
664:
665: private void dncnetprintln(String s) {
666: synchronized (printWriter_) {
667: printWriter_.println("[derby] " + s);
668: printWriter_.flush();
669: }
670: }
671:
672: private void dncnetprintln(char[] s) {
673: synchronized (printWriter_) {
674: printWriter_.print("[derby] ");
675: printWriter_.println(s);
676: printWriter_.flush();
677: }
678: }
679: }
|