KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > drda > DDMWriter


1 /*
2
3    Derby - Class org.apache.derby.impl.drda.DDMWriter
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to You under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.drda;
23
24 import java.io.OutputStream JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.BufferedInputStream JavaDoc;
27 import java.io.BufferedOutputStream JavaDoc;
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29 import java.sql.SQLException JavaDoc;
30 import java.sql.DataTruncation JavaDoc;
31 import java.math.BigDecimal JavaDoc;
32 import org.apache.derby.iapi.error.ExceptionSeverity;
33 import java.util.Arrays JavaDoc;
34 import org.apache.derby.iapi.reference.Property;
35 import org.apache.derby.iapi.services.property.PropertyUtil;
36
37 import java.io.IOException JavaDoc;
38
39 /**
40     The DDMWriter is used to write DRDA protocol. The DRDA Protocol is
41     described in the DDMReader class.
42     For more details, see DRDA Volume 3 (Distributed Data Management(DDM)
43         Architecture (DDS definition)
44 */

45 class DDMWriter
46 {
47
48     // number of nesting levels for collections. We need to mark the length
49
// location of the collection so that we can update it as we add more stuff
50
// to the collection
51
private final static int MAX_MARKS_NESTING = 10;
52
53     // Default buffer size
54
private final static int DEFAULT_BUFFER_SIZE = 32767;
55
56
57     static final BigDecimal JavaDoc ZERO = BigDecimal.valueOf(0L);
58
59     // output buffer
60
private byte[] bytes;
61
62     // offset into output buffer
63
private int offset;
64
65     // A saved mark in the stream is saved temporarily to revisit the location.
66
private int[] markStack = new int[MAX_MARKS_NESTING];
67
68     // top of the stack
69
private int top;
70
71     // CCSID manager for translation of strings in the protocol to EBCDIC
72
private CcsidManager ccsidManager;
73
74     // DRDA connection thread for this writer
75
private DRDAConnThread agent;
76
77     // This Object tracks the location of the current
78
// Dss header length bytes. This is done so
79
// the length bytes can be automatically
80
// updated as information is added to this stream.
81
private int dssLengthLocation;
82
83     // Current correlation ID
84
private int correlationID;
85
86     // Next correlation ID
87
private int nextCorrelationID;
88
89     // is this DRDA protocol or CMD protocol
90
private boolean isDRDAProtocol;
91     // trace object of the associated session
92
private DssTrace dssTrace;
93
94     // Location within the "bytes" array of the start of the header
95
// of the DSS most recently written to the buffer.
96
private int prevHdrLocation;
97
98     // Correlation id of the last DSS that was written to buffer.
99
private int previousCorrId;
100
101     // Chaining bit of the last DSS that was written to buffer.
102
private byte previousChainByte;
103
104     // Whether or not the current DSS is a continuation DSS.
105
private boolean isContinuationDss;
106
107     // In situations where we want to "mark" a buffer location so that
108
// we can "back-out" of a write to handle errors, this holds the
109
// location within the "bytes" array of the start of the header
110
// that immediately precedes the mark.
111
private int lastDSSBeforeMark;
112
113     // Constructors
114
DDMWriter (int minSize, CcsidManager ccsidManager, DRDAConnThread agent, DssTrace dssTrace)
115     {
116         this.bytes = new byte[minSize];
117         this.ccsidManager = ccsidManager;
118         this.agent = agent;
119         this.prevHdrLocation = -1;
120         this.previousCorrId = DssConstants.CORRELATION_ID_UNKNOWN;
121         this.previousChainByte = DssConstants.DSS_NOCHAIN;
122         this.isContinuationDss = false;
123         this.lastDSSBeforeMark = -1;
124         reset(dssTrace);
125     }
126
127     DDMWriter (CcsidManager ccsidManager, DRDAConnThread agent, DssTrace dssTrace)
128     {
129         this.bytes = new byte[DEFAULT_BUFFER_SIZE];
130         this.ccsidManager = ccsidManager;
131         this.agent = agent;
132         this.prevHdrLocation = -1;
133         this.previousCorrId = DssConstants.CORRELATION_ID_UNKNOWN;
134         this.previousChainByte = DssConstants.DSS_NOCHAIN;
135         this.isContinuationDss = false;
136         this.lastDSSBeforeMark = -1;
137         reset(dssTrace);
138     }
139
140     /**
141      * reset values for sending next message
142      *
143      */

144     protected void reset(DssTrace dssTrace)
145     {
146         offset = 0;
147         top = 0;
148         dssLengthLocation = 0;
149         nextCorrelationID = 1;
150         correlationID = DssConstants.CORRELATION_ID_UNKNOWN;
151         isDRDAProtocol = true;
152         this.dssTrace = dssTrace;
153     }
154
155     /**
156      * set protocol to CMD protocol
157      */

158     protected void setCMDProtocol()
159     {
160         isDRDAProtocol = false;
161     }
162
163     /**
164      * Create DSS reply object
165      */

166     protected void createDssReply()
167     {
168         beginDss(DssConstants.DSSFMT_RPYDSS, true);
169     }
170
171     /**
172      * Create DSS request object
173      * NOTE: This is _ONLY_ used for testing the protocol
174      * (via the TestProto.java file in this package)!
175      * We should never create a DSS request in normal
176      * DRDA processing (we should only create DSS replies
177      * and DSS objects).
178      */

179     protected void createDssRequest()
180     {
181         beginDss(DssConstants.DSSFMT_RQSDSS, true);
182     }
183
184     /**
185      * Create DSS data object
186      */

187     protected void createDssObject()
188     {
189         beginDss(DssConstants.DSSFMT_OBJDSS, true);
190     }
191
192     /**
193      * Mark the DSS that we're currently writing as
194      * a continued DSS, which is done by setting
195      * the high-order bit to "1", per DDM spec.
196      * This means:
197      *
198      * 1. One or more continuation DSSes will immediately
199      * follow the current (continued) DSS.
200      * 2. All continuation DSSes will have a 2-byte
201      * continuation header, followed by data; in
202      * other words, chaining state, correlation
203      * id, dss format info, and code point will
204      * NOT be included. All of that info is
205      * present ONLY in the FIRST DSS in the
206      * list of continued DSSes.
207      *
208      * NOTE: A DSS can be a "continuation" DSS _and_
209      * a "continued" DSS at the same time. However,
210      * the FIRST DSS to be continued canNOT be
211      * a continuation DSS.
212      */

213     private void markDssAsContinued(boolean forLob)
214     {
215
216         if (!forLob) {
217         // continuation bit defaults to '1' for lobs, so
218
// we only have to switch it if we're not writing
219
// lobs.
220
bytes[dssLengthLocation] |= 0x80;
221         }
222
223         // We need to set the chaining state, but ONLY
224
// IF this is the FIRST DSS in the continuation
225
// list (only the first one has chaining state
226
// in it's header; the others do not).
227
if (!isContinuationDss)
228             endDss(!forLob);
229
230     }
231
232     /**
233      * End DSS header by writing the length in the length location
234      * and setting the chain bit. Unlike the other two endDss
235      * methods, this one overrides the default chaining byte
236      * (which is set in beginDss) with the chaining byte that
237      * is passed in. NOTE: This method is only used in
238      * association with createDssRequest, and thus is for
239      * TESTING purposes only (via TestProto.java). No calls
240      * should be made to this method in normal DRDA processing
241      * (because for normal processing, chaining must be
242      * determined automatically based on DSS requests).
243      */

244     protected void endDss(byte chainByte)
245     {
246
247         // Do regular endDss processing.
248
endDss(true);
249
250         // Now override default chain state.
251
bytes[dssLengthLocation + 3] &= 0x0F; // Zero out default
252
bytes[dssLengthLocation + 3] |= chainByte;
253         previousChainByte = chainByte;
254
255     }
256
257     /**
258      * End DSS header by writing the length in the length location
259      * and setting the chain bit.
260      */

261     protected void endDss() {
262         endDss(true);
263     }
264
265     /**
266      * End DSS header by writing the length in the length location
267      * and setting the chain bit.
268      */

269     private void endDss (boolean finalizeLength)
270     {
271
272         if (finalizeLength)
273             finalizeDssLength();
274
275         if (isContinuationDss) {
276         // no chaining information for this DSS; so we're done.
277
isContinuationDss = false;
278             return;
279         }
280
281         previousCorrId = correlationID;
282         prevHdrLocation = dssLengthLocation;
283         previousChainByte = DssConstants.DSSCHAIN_SAME_ID;
284
285     }
286
287     /**
288      * End final DDM and DSS header by writing the length in the length location
289      *
290      */

291     protected void endDdmAndDss ()
292     {
293         endDdm(); // updates last DDM object
294
endDss();
295     }
296     /**
297      * Copy Data to End
298      * Create a buffer and copy from the position given to the end of data
299      *
300      * Note that the position given is treated as relative to the
301      * current DSS, for there may be other DSS blocks (chained, presumably)
302      * which are sitting unwritten in the buffer. The caller doesn't
303      * know this, though, and works only with the current DSS.
304      *
305      * getDSSLength, copyDSSDataToEnd, and truncateDSS work together to
306      * provide a sub-protocol for DRDAConnThread to use in its
307      * implementation of the LMTBLKPRC protocol. They enable the caller
308      * to determine when it has written too much data into the current
309      * DSS, to reclaim the extra data that won't fit, and to truncate
310      * that extra data once it has been reclaimed and stored elsewhere.
311      * Note that this support only works for the current DSS. Earlier,
312      * chained DSS blocks cannot be accessed using these methods. For
313      * additional background information, the interested reader should
314      * investigate bugs DERBY-491 and 492 at:
315      * http://issues.apache.org/jira/browse/DERBY-491 and
316      * http://issues.apache.org/jira/browse/DERBY-492
317      *
318      * @param start
319      */

320     protected byte [] copyDSSDataToEnd(int start)
321     {
322         start = start + dssLengthLocation;
323         int length = offset - start;
324         byte [] temp = new byte[length];
325         System.arraycopy(bytes,start,temp,0,length);
326         return temp;
327     }
328
329     // Collection methods
330

331     /**
332      * Mark the location of the length bytes for the collection so they
333      * can be updated later
334      *
335      */

336     protected void startDdm (int codePoint)
337     {
338         // save the location of the beginning of the collection so
339
// that we can come back and fill in the length bytes
340
markStack[top++] = offset;
341         ensureLength (4); // verify space for length bytes and code point
342
offset += 2; // move past the length bytes before writing the code point
343
bytes[offset] = (byte) ((codePoint >>> 8) & 0xff);
344         bytes[offset + 1] = (byte) (codePoint & 0xff);
345         offset += 2;
346     }
347
348     /**
349      * Erase all writes for the current ddm and reset the
350      * top
351      */

352     protected void clearDdm ()
353     {
354         offset = markStack[top--];
355     }
356
357     /**
358      * Clear the entire send buffer
359      *
360      */

361     protected void clearBuffer()
362     {
363         offset = 0;
364         top = 0;
365         dssLengthLocation = 0;
366         correlationID = DssConstants.CORRELATION_ID_UNKNOWN;
367         nextCorrelationID = 1;
368         isDRDAProtocol = true;
369     }
370
371     /**
372      * End the current DDM
373      *
374      */

375     protected void endDdm ()
376     {
377         // remove the top length location offset from the mark stack
378
// calculate the length based on the marked location and end of data.
379
int lengthLocation = markStack[--top];
380         int length = offset - lengthLocation;
381
382         // determine if any extended length bytes are needed. the value returned
383
// from calculateExtendedLengthByteCount is the number of extended length
384
// bytes required. 0 indicates no exteneded length.
385
int extendedLengthByteCount = calculateExtendedLengthByteCount (length);
386         if (extendedLengthByteCount != 0)
387         {
388             // ensure there is enough room in the buffer for the extended length bytes.
389
ensureLength (extendedLengthByteCount);
390
391             // calculate the length to be placed in the extended length bytes.
392
// this length does not include the 4 byte llcp.
393
int extendedLength = length - 4;
394
395             // shift the data to the right by the number of extended
396
// length bytes needed.
397
int extendedLengthLocation = lengthLocation + 4;
398             System.arraycopy (bytes,
399                                   extendedLengthLocation,
400                                   bytes,
401                                   extendedLengthLocation + extendedLengthByteCount,
402                                   extendedLength);
403
404             // write the extended length
405
int shiftSize = (extendedLengthByteCount -1) * 8;
406             for (int i = 0; i < extendedLengthByteCount; i++)
407             {
408                 bytes[extendedLengthLocation++] =
409                     (byte) ((extendedLength >>> shiftSize ) & 0xff);
410                 shiftSize -= 8;
411             }
412
413             // adjust the offset to account for the shift and insert
414
offset += extendedLengthByteCount;
415
416             // the two byte length field before the codepoint contains the length
417
// of itself, the length of the codepoint, and the number of bytes used
418
// to hold the extended length. the 2 byte length field also has the first
419
// bit on to indicate extended length bytes were used.
420
length = extendedLengthByteCount + 4;
421             length |= DssConstants.CONTINUATION_BIT;
422         }
423
424         // write the 2 byte length field (2 bytes before codepoint).
425
bytes[lengthLocation] = (byte) ((length >>> 8) & 0xff);
426         bytes[lengthLocation+1] = (byte) (length & 0xff);
427
428     }
429
430     /**
431      * Get the length of the current DSS block we're working on. This is
432      * used by the LMTBLKPRC protocol, which does its own conversational
433      * blocking protocol above the layer of the DRDA blocking. The LMTBLKPRC
434      * implementation (in DRDAConnThread) needs to be able to truncate a
435      * DSS block when splitting a QRYDTA response.
436      *
437      * @return current DSS block length
438     */

439     protected int getDSSLength()
440     {
441         return offset - dssLengthLocation;
442     }
443  
444     /**
445      * Truncate the current DSS. Before making this call, you should ensure
446      * that you have copied the data to be truncated somewhere else, by
447      * calling copyDSSDataToEnd
448      *
449      * @param value DSS length
450     */

451     protected void truncateDSS(int value)
452     {
453         offset = dssLengthLocation + value;
454     }
455
456
457     // Write routines
458

459     /**
460      * Write byte
461      *
462      * @param value byte to be written
463      */

464     protected void writeByte (int value)
465     {
466         if (SanityManager.DEBUG)
467         {
468             if (value > 255)
469                 SanityManager.THROWASSERT(
470                                        "writeByte value: " + value +
471                                        " may not be > 255");
472         }
473
474         ensureLength (1);
475         bytes[offset++] = (byte) (value & 0xff);
476     }
477
478
479     /**
480      * Write network short
481      *
482      * @param value value to be written
483      */

484     protected void writeNetworkShort (int value)
485     {
486         ensureLength (2);
487         bytes[offset] = (byte) ((value >>> 8) & 0xff);
488         bytes[offset + 1] = (byte) (value & 0xff);
489         offset += 2;
490     }
491
492     /**
493      * Write network int
494      *
495      * @param value value to be written
496      */

497     protected void writeNetworkInt (int value)
498     {
499         ensureLength (4);
500         bytes[offset] = (byte) ((value >>> 24) & 0xff);
501         bytes[offset + 1] = (byte) ((value >>> 16) & 0xff);
502         bytes[offset + 2] = (byte) ((value >>> 8) & 0xff);
503         bytes[offset + 3] = (byte) (value & 0xff);
504         offset += 4;
505     }
506
507
508     /**
509      * Write byte array
510      *
511      * @param buf byte array to be written
512      * @param length - length to write
513      */

514     protected void writeBytes (byte[] buf, int length)
515     {
516         writeBytes(buf, 0,length);
517     }
518
519
520
521     /**
522      * Write byte array
523      *
524      * @param buf byte array to be written
525      * @param start - starting position
526      * @param length - length to write
527      */

528     protected void writeBytes (byte[] buf, int start, int length)
529     {
530
531         if (SanityManager.DEBUG)
532         {
533             if (buf == null && length > 0)
534                 SanityManager.THROWASSERT("Buf is null");
535             if (length + start - 1 > buf.length)
536                 SanityManager.THROWASSERT("Not enough bytes in buffer");
537
538         }
539         ensureLength (length);
540         System.arraycopy(buf,start,bytes,offset,length);
541         offset += length;
542     }
543     /**
544      * Write byte array
545      *
546      * @param buf byte array to be written
547      **/

548     protected void writeBytes (byte[] buf)
549     {
550         writeBytes(buf,buf.length);
551     }
552
553
554
555     protected void writeLDBytes(byte[] buf)
556     {
557         writeLDBytes(buf, 0);
558     }
559
560     protected void writeLDBytes(byte[] buf, int index)
561     {
562
563         int length = buf.length;
564         int writeLen = buf.length;
565
566         writeShort(writeLen);
567
568         writeBytes(buf,0,writeLen);
569     }
570
571
572     /**
573      * Write code point and 4 bytes
574      *
575      * @param codePoint - code point to write
576      * @param value - value to write after code point
577      */

578     void writeCodePoint4Bytes (int codePoint, int value)
579     {
580         ensureLength (4);
581         bytes[offset] = (byte) ((codePoint >>> 8) & 0xff);
582         bytes[offset + 1] = (byte) (codePoint & 0xff);
583         bytes[offset + 2] = (byte) ((value >>> 8) & 0xff);
584         bytes[offset + 3] = (byte) (value & 0xff);
585         offset += 4;
586     }
587
588     /**
589      * Write scalar 1 byte object includes length, codepoint and value
590      *
591      * @param codePoint - code point to write
592      * @param value - value to write after code point
593      */

594     void writeScalar1Byte (int codePoint, int value)
595     {
596         ensureLength (5);
597         bytes[offset] = 0x00;
598         bytes[offset + 1] = 0x05;
599         bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
600         bytes[offset + 3] = (byte) (codePoint & 0xff);
601         bytes[offset + 4] = (byte) (value & 0xff);
602         offset += 5;
603     }
604
605     /**
606      * Write scalar 2 byte object includes length, codepoint and value
607      *
608      * @param codePoint - code point to write
609      * @param value - value to write after code point
610      */

611     protected void writeScalar2Bytes (int codePoint, int value)
612     {
613         ensureLength (6);
614         bytes[offset] = 0x00;
615         bytes[offset + 1] = 0x06;
616         bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
617         bytes[offset + 3] = (byte) (codePoint & 0xff);
618         bytes[offset + 4] = (byte) ((value >>> 8) & 0xff);
619         bytes[offset + 5] = (byte) (value & 0xff);
620         offset += 6;
621     }
622
623     protected void writeScalar2Bytes ( int value)
624     {
625         ensureLength (2);
626         bytes[offset] = (byte) ((value >>> 8) & 0xff);
627         bytes[offset + 1] = (byte) (value & 0xff);
628         offset += 2;
629     }
630
631     /**
632      * Write length and codepoint
633      *
634      * @param length - length of object
635      * @param codePoint - code point to write
636      */

637     protected void startDdm (int length, int codePoint)
638     {
639         ensureLength (4);
640         bytes[offset] = (byte) ((length >>> 8) & 0xff);
641         bytes[offset + 1] = (byte) (length & 0xff);
642         bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
643         bytes[offset + 3] = (byte) (codePoint & 0xff);
644         offset += 4;
645     }
646
647     /**
648      * Write scalar byte array object includes length, codepoint and value
649      *
650      * @param codePoint - code point to write
651      * @param buf - value to write after code point
652      * @param length - number of bytes to write
653      */

654     protected void writeScalarBytes (int codePoint, byte[] buf, int length)
655     {
656         if (SanityManager.DEBUG)
657         {
658             if (buf == null && length > 0)
659                 SanityManager.THROWASSERT("Buf is null");
660             if (length > buf.length)
661                 SanityManager.THROWASSERT("Not enough bytes in buffer");
662         }
663         ensureLength (length + 4);
664         bytes[offset] = (byte) (((length+4) >>> 8) & 0xff);
665         bytes[offset + 1] = (byte) ((length+4) & 0xff);
666         bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
667         bytes[offset + 3] = (byte) (codePoint & 0xff);
668         System.arraycopy(buf,0,bytes,offset + 4, length);
669         offset += length + 4;
670     }
671
672
673     
674     protected void writeScalarStream (boolean chainedWithSameCorrelator,
675                                       int codePoint,
676                       EXTDTAInputStream in,
677                                       boolean writeNullByte)
678         throws DRDAProtocolException
679     {
680
681         
682
683         // Stream equivalent of "beginDss"...
684
int spareDssLength = prepScalarStream( chainedWithSameCorrelator,
685                                             codePoint,
686                                             writeNullByte);
687         
688         // write the data
689
int bytesRead = 0;
690         int totalBytesRead = 0;
691
692                 try {
693                     
694         OutputStream JavaDoc out =
695             placeLayerBStreamingBuffer( agent.getOutputStream() );
696         
697         boolean isLastSegment = false;
698         
699         while( !isLastSegment ){
700             
701             int spareBufferLength = bytes.length - offset;
702             
703             if( SanityManager.DEBUG ){
704         
705             if( PropertyUtil.getSystemProperty("derby.debug.suicideOfLayerBStreaming") != null )
706                 throw new IOException JavaDoc();
707                 }
708             
709             bytesRead = in.read(bytes,
710                     offset,
711                     Math.min(spareDssLength,
712                          spareBufferLength));
713             
714                     totalBytesRead += bytesRead;
715                     offset += bytesRead;
716             spareDssLength -= bytesRead;
717             spareBufferLength -= bytesRead;
718
719             isLastSegment = peekStream(in) < 0;
720             
721             if(isLastSegment ||
722                spareDssLength == 0){
723             
724             flushScalarStreamSegment (isLastSegment,
725                           out);
726             
727             if( ! isLastSegment )
728                 spareDssLength = DssConstants.MAX_DSS_LENGTH - 2;
729
730             }
731             
732         }
733         
734         out.flush();
735         
736         }catch(IOException JavaDoc e){
737         agent.markCommunicationsFailure ("DDMWriter.writeScalarStream()",
738                          "",
739                          e.getMessage(),
740                          "*");
741         }
742                 
743     }
744     
745     /**
746      * Begins a DSS stream (for writing LOB data).
747      */

748     private void beginDss (boolean chainedToNextStructure,
749                            int dssType)
750     {
751         beginDss(dssType, false); // false => don't ensure length.
752

753         // always turn on continuation flags... this is helpful for lobs...
754
// these bytes will get rest if dss lengths are finalized.
755
bytes[dssLengthLocation] = (byte) 0xFF;
756         bytes[dssLengthLocation + 1] = (byte) 0xFF;
757
758         // Set whether or not this DSS should be chained to
759
// the next one. If it's chained, it has to be chained
760
// with same id (that's the nature of EXTDTA chaining).
761
if (chainedToNextStructure) {
762             dssType |= DssConstants.GDSCHAIN_SAME_ID;
763         }
764
765         bytes[dssLengthLocation + 3] = (byte) (dssType & 0xff);
766     }
767
768
769     /**
770      * prepScalarStream does the following prep for writing stream data:
771      * 1. Flushes an existing DSS segment, if necessary
772      * 2. Determines if extended length bytes are needed
773      * 3. Creates a new DSS/DDM header and a null byte indicator, if applicable
774      *
775      * If value of length was less than 0, this method processes streaming as Layer B Streaming.
776      * cf. page 315 of specification of DRDA, Version 3, Volume 3
777      *
778      */

779   private int prepScalarStream( boolean chainedWithSameCorrelator,
780                                    int codePoint,
781                                    boolean writeNullByte) throws DRDAProtocolException
782   {
783
784       ensureLength( DEFAULT_BUFFER_SIZE - offset );
785       
786       final int nullIndicatorSize = writeNullByte ? 1:0;
787
788     
789       // flush the existing DSS segment ,
790
// if this stream will not fit in the send buffer or
791
// length of this stream is unknown.
792
// Here, 10 stands for sum of headers of layer A and B.
793

794       try {
795         // The existing DSS segment was finalized by endDss; all
796
// we have to do is send it across the wire.
797
sendBytes(agent.getOutputStream());
798       }
799       catch (java.io.IOException JavaDoc e) {
800          agent.markCommunicationsFailure ("DDMWriter.writeScalarStream()",
801                                               "OutputStream.flush()",
802                                               e.getMessage(),"*");
803       }
804
805     // buildStreamDss should not call ensure length.
806
beginDss(chainedWithSameCorrelator, DssConstants.GDSFMT_OBJDSS);
807
808       writeLengthCodePoint(0x8004,codePoint);
809
810
811     // write the null byte, if necessary
812
if (writeNullByte)
813       writeByte(0x0);
814
815       //Here, 6 stands for header of layer A and
816
//4 stands for header of layer B.
817
return DssConstants.MAX_DSS_LENGTH - 6 - 4 - nullIndicatorSize;
818
819
820   }
821
822
823   // method to determine if any data is in the request.
824
// this indicates there is a dss object already in the buffer.
825
protected boolean doesRequestContainData()
826     {
827         return offset != 0;
828     }
829
830
831     // Writes out a scalar stream DSS segment, along with DSS continuation
832
// headers if necessary.
833
private void flushScalarStreamSegment ( boolean lastSegment,
834                             OutputStream JavaDoc out)
835         throws DRDAProtocolException
836     {
837
838         // either at end of data, end of dss segment, or both.
839
if (! lastSegment) {
840
841         // 32k segment filled and not at end of data.
842
try {
843                 // Mark current DSS as continued, set its chaining state,
844
// then send the data across.
845
markDssAsContinued(true); // true => for lobs
846
sendBytes (out,
847                            false);
848                 
849             }catch (java.io.IOException JavaDoc ioe) {
850                     agent.markCommunicationsFailure ("DDMWriter.flushScalarStreamSegment()",
851                                                "",
852                                                ioe.getMessage(),
853                                                "*");
854                 }
855
856
857             // Prepare a DSS continuation header for next DSS.
858
dssLengthLocation = offset;
859             bytes[offset++] = (byte) (0xff);
860             bytes[offset++] = (byte) (0xff);
861             isContinuationDss = true;
862         }else{
863         // we're done writing the data, so end the DSS.
864
endDss();
865
866     }
867
868   }
869
870
871     private void writeExtendedLengthBytes (int extendedLengthByteCount, long length)
872     {
873     int shiftSize = (extendedLengthByteCount -1) * 8;
874     for (int i = 0; i < extendedLengthByteCount; i++) {
875       bytes[offset + i] = (byte) ((length >>> shiftSize) & 0xff);
876       shiftSize -= 8;
877     }
878     offset += extendedLengthByteCount;
879   }
880
881
882   // insert a 4 byte length/codepoint pair into the buffer.
883
// total of 4 bytes inserted in buffer.
884
// Note: the length value inserted in the buffer is the same as the value
885
// passed in as an argument (this value is NOT incremented by 4 before being
886
// inserted).
887
void writeLengthCodePoint (int length, int codePoint)
888   {
889     ensureLength (4);
890     bytes[offset] = (byte) ((length >>> 8) & 0xff);
891     bytes[offset + 1] = (byte) (length & 0xff);
892     bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
893     bytes[offset + 3] = (byte) (codePoint & 0xff);
894     offset +=4;
895   }
896
897     /**
898      * Write scalar object header includes length and codepoint
899      *
900      * @param codePoint - code point to write
901      * @param dataLength - length of object data
902      */

903     protected void writeScalarHeader (int codePoint, int dataLength)
904     {
905         ensureLength (dataLength + 4);
906         bytes[offset] = (byte) (((dataLength+4) >>> 8) & 0xff);
907         bytes[offset + 1] = (byte) ((dataLength+4) & 0xff);
908         bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
909         bytes[offset + 3] = (byte) (codePoint & 0xff);
910         offset += 4;
911     }
912
913     /**
914      * Write scalar string object includes length, codepoint and value
915      * the string is converted into the appropriate codeset (EBCDIC)
916      *
917      * @param codePoint - code point to write
918      * @param string - string to be written
919      */

920     void writeScalarString (int codePoint, String JavaDoc string)
921     {
922         int stringLength = string.length();
923         ensureLength ((stringLength * 2) + 4);
924         bytes[offset] = (byte) (((stringLength+4) >>> 8) & 0xff);
925         bytes[offset + 1] = (byte) ((stringLength+4) & 0xff);
926         bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
927         bytes[offset + 3] = (byte) (codePoint & 0xff);
928         offset = ccsidManager.convertFromUCS2 (string, bytes, offset + 4);
929     }
930
931     /**
932      * Write padded scalar string object includes length, codepoint and value
933      * the string is converted into the appropriate codeset (EBCDIC)
934      *
935      * @param codePoint - code point to write
936      * @param string - string to be written
937      * @param paddedLength - length to pad string to
938      */

939     void writeScalarPaddedString (int codePoint, String JavaDoc string, int paddedLength)
940     {
941         int stringLength = string.length();
942         int fillLength = paddedLength - stringLength;
943         ensureLength (paddedLength + 4);
944         bytes[offset] = (byte) (((paddedLength+4) >>> 8) & 0xff);
945         bytes[offset + 1] = (byte) ((paddedLength+4) & 0xff);
946         bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
947         bytes[offset + 3] = (byte) (codePoint & 0xff);
948         offset = ccsidManager.convertFromUCS2 (string, bytes, offset + 4);
949         Arrays.fill(bytes,offset, offset + fillLength,ccsidManager.space);
950         offset += fillLength;
951     }
952
953     /**
954      * Write padded scalar string object value
955      * the string is converted into the appropriate codeset (EBCDIC)
956      *
957      * @param string - string to be written
958      * @param paddedLength - length to pad string to
959      */

960     protected void writeScalarPaddedString (String JavaDoc string, int paddedLength)
961     {
962         int stringLength = string.length();
963
964         int fillLength = paddedLength -stringLength;
965         ensureLength (paddedLength);
966         offset = ccsidManager.convertFromUCS2 (string, bytes, offset);
967         Arrays.fill(bytes,offset, offset + fillLength,ccsidManager.space);
968         offset += fillLength;
969     }
970
971     /**
972      * Write padded scalar <code>DRDAString</code> object value. The
973      * string is converted into the appropriate codeset.
974      *
975      * @param drdaString string to be written
976      * @param paddedLength length to pad string to
977      */

978     protected void writeScalarPaddedString (DRDAString drdaString, int paddedLength)
979     {
980         int stringLength = drdaString.length();
981         int fillLength = paddedLength - stringLength;
982         ensureLength(paddedLength);
983         System.arraycopy(drdaString.getBytes(), 0, bytes, offset, stringLength);
984         offset += stringLength;
985         Arrays.fill(bytes, offset, offset + fillLength, ccsidManager.space);
986         offset += fillLength;
987     }
988
989     /**
990      * Write padded scalar byte array object includes length, codepoint and value
991      *
992      * @param codePoint - code point to write
993      * @param buf - byte array to be written
994      * @param paddedLength - length to pad string to
995      * @param padByte - byte to be used for padding
996      */

997     protected void writeScalarPaddedBytes (int codePoint, byte[] buf, int paddedLength, byte padByte)
998     {
999         int bufLength = buf.length;
1000        ensureLength (paddedLength + 4);
1001        bytes[offset] = (byte) (((paddedLength+4) >>> 8) & 0xff);
1002        bytes[offset + 1] = (byte) ((paddedLength+4) & 0xff);
1003        bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
1004        bytes[offset + 3] = (byte) (codePoint & 0xff);
1005        offset += 4;
1006        System.arraycopy(buf,0,bytes,offset,bufLength);
1007        offset += bufLength;
1008        int fillLength = paddedLength - bufLength;
1009        Arrays.fill(bytes,offset,offset + fillLength,padByte);
1010        offset += fillLength;
1011    }
1012
1013    /**
1014     * Write padded scalar byte array object value
1015     *
1016     * @param buf - byte array to be written
1017     * @param paddedLength - length to pad string to
1018     * @param padByte - byte to be used for padding
1019     */

1020    protected void writeScalarPaddedBytes (byte[] buf, int paddedLength, byte padByte)
1021    {
1022        int bufLength = buf.length;
1023        int fillLength = paddedLength - bufLength;
1024        ensureLength (paddedLength);
1025        System.arraycopy(buf,0,bytes,offset,bufLength);
1026        offset +=bufLength;
1027        Arrays.fill(bytes,offset,offset + fillLength,padByte);
1028        offset += fillLength;
1029    }
1030
1031    /**
1032     * Write scalar byte array object includes length, codepoint and value
1033     *
1034     * @param codePoint - code point to write
1035     * @param buf - byte array to be written
1036     */

1037    protected void writeScalarBytes (int codePoint, byte[] buf)
1038    {
1039        int bufLength = buf.length;
1040        ensureLength (bufLength + 4);
1041        bytes[offset] = (byte) (((bufLength+4) >>> 8) & 0xff);
1042        bytes[offset + 1] = (byte) ((bufLength+4) & 0xff);
1043        bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
1044        bytes[offset + 3] = (byte) (codePoint & 0xff);
1045        System.arraycopy(buf,0,bytes,offset + 4,bufLength);
1046        offset += bufLength + 4;
1047    }
1048
1049    /**
1050     * Write scalar byte array object includes length, codepoint and value
1051     *
1052     * @param codePoint - code point to write
1053     * @param buf - byte array to be written
1054     * @param start - starting point
1055     * @param length - length to write
1056     */

1057    protected void writeScalarBytes (int codePoint, byte[] buf, int start, int length)
1058    {
1059        if (SanityManager.DEBUG)
1060        {
1061            if (buf == null && length > start)
1062                SanityManager.THROWASSERT("Buf is null");
1063            if (length - start > buf.length)
1064                SanityManager.THROWASSERT("Not enough bytes in buffer");
1065        }
1066        int numBytes = length - start;
1067        ensureLength (numBytes + 4);
1068        bytes[offset] = (byte) (((numBytes+4) >>> 8) & 0xff);
1069        bytes[offset + 1] = (byte) ((numBytes+4) & 0xff);
1070        bytes[offset + 2] = (byte) ((codePoint >>> 8) & 0xff);
1071        bytes[offset + 3] = (byte) (codePoint & 0xff);
1072        offset += 4;
1073        System.arraycopy(buf,start,bytes,offset,numBytes);
1074        offset += numBytes;
1075    }
1076    // The following methods write data in the platform format
1077
// The platform format was indicated during connection time as ASC since
1078
// JCC doesn't read JVM platform (yet)
1079

1080    /**
1081     * Write platform short
1082     *
1083     * @param v value to be written
1084     */

1085    protected void writeShort (int v)
1086    {
1087        writeNetworkShort(v);
1088    }
1089
1090    /**
1091     * Write boolean as short
1092     * @param b boolean value true = 1 false = 0
1093     *
1094     */

1095    protected void writeShort(boolean b)
1096    {
1097        writeNetworkShort(b ? 1 : 0);
1098    }
1099
1100    /**
1101     * Write platform int
1102     *
1103     * @param v value to be written
1104     */

1105    protected void writeInt (int v)
1106    {
1107        writeNetworkInt(v);
1108    }
1109
1110    /**
1111     * Write platform long
1112     *
1113     * @param v value to be written
1114     */

1115    protected void writeLong (long v)
1116    {
1117        ensureLength (8);
1118        bytes[offset] = (byte) ((v >>> 56) & 0xff);
1119        bytes[offset + 1] = (byte) ((v >>> 48) & 0xff);
1120        bytes[offset + 2] = (byte) ((v >>> 40) & 0xff);
1121        bytes[offset + 3] = (byte) ((v >>> 32) & 0xff);
1122        bytes[offset + 4] = (byte) ((v >>> 24) & 0xff);
1123        bytes[offset + 5] = (byte) ((v >>> 16) & 0xff);
1124        bytes[offset + 6] = (byte) ((v >>> 8) & 0xff);
1125        bytes[offset + 7] = (byte) ((v >>> 0) & 0xff);
1126        offset += 8;
1127    }
1128
1129    /**
1130     * Write platform float
1131     *
1132     * @param v value to be written
1133     */

1134    protected void writeFloat (float v)
1135    {
1136        writeInt (Float.floatToIntBits (v));
1137    }
1138
1139    /**
1140     * Write platform double
1141     *
1142     * @param v value to be written
1143     */

1144    protected void writeDouble (double v)
1145    {
1146        writeLong (Double.doubleToLongBits (v));
1147    }
1148
1149    /**
1150     * Write big decimal to buffer
1151     *
1152     * @param v value to write
1153     * @param precision Precison of decimal or numeric type
1154     * @param scale declared scale
1155     * @exception SQLException thrown if number of digits > 31
1156     */

1157    protected void writeBigDecimal (java.math.BigDecimal JavaDoc v, int precision, int scale)
1158        throws SQLException JavaDoc
1159    {
1160        int length = precision / 2 + 1;
1161        ensureLength (offset + length);
1162        bigDecimalToPackedDecimalBytes (v,precision, scale);
1163        offset += length;
1164    }
1165
1166    /**
1167     * Write platform boolean
1168     *
1169     * @param v value to be written
1170     */

1171    protected void writeBoolean (boolean v)
1172    {
1173        ensureLength (1);
1174        bytes[offset++] = (byte) ((v ? 1 : 0) & 0xff);
1175    }
1176
1177    /**
1178     * Write length delimited string
1179     *
1180     * @param s value to be written with integer
1181     *
1182     * @exception DRDAProtocolException
1183     */

1184    protected void writeLDString(String JavaDoc s) throws DRDAProtocolException
1185    {
1186        writeLDString(s,0);
1187    }
1188
1189
1190    /**
1191     * Write length delimited string
1192     *
1193     * @param s value to be written with integer
1194     * @param index column index to put in warning
1195     * @exception DRDAProtocolException
1196     */

1197    protected void writeLDString(String JavaDoc s, int index) throws DRDAProtocolException
1198    {
1199        try {
1200            byte [] byteval = s.getBytes(NetworkServerControlImpl.DEFAULT_ENCODING);
1201            int origLen = byteval.length;
1202            boolean multiByteTrunc = false;
1203            int writeLen =
1204                java.lang.Math.min(FdocaConstants.LONGVARCHAR_MAX_LEN,
1205                                   origLen);
1206            /*
1207            Need to make sure we truncate on character boundaries.
1208            We are assuming
1209            http://www.sun.com/developers/gadc/technicalpublications/articles/utf8.html
1210            To find the beginning of a multibyte character:
1211            1) Does the current byte start with the bit pattern 10xxxxxx?
1212            2) If yes, move left and go to step #1.
1213            3) Finished
1214            We assume that NetworkServerControlImpl.DEFAULT_ENCODING remains UTF-8
1215            */

1216
1217            if (SanityManager.DEBUG)
1218            {
1219                if (!(NetworkServerControlImpl.DEFAULT_ENCODING.equals("UTF8")))
1220                    SanityManager.THROWASSERT("Encoding assumed to be UTF8, but is actually" + NetworkServerControlImpl.DEFAULT_ENCODING);
1221            }
1222
1223            if (writeLen != origLen)
1224                // first position on the first byte of the multibyte char
1225
while ((byteval[writeLen -1] & 0xC0) == 0x80)
1226                {
1227                    multiByteTrunc = true;
1228                    writeLen--;
1229                    // Then subtract one more to get to the end of the
1230
// previous character
1231
if (multiByteTrunc == true)
1232                    {
1233                        writeLen = writeLen -1;
1234                    }
1235                }
1236
1237            writeShort(writeLen);
1238            writeBytes(byteval,writeLen);
1239        }
1240        catch (Exception JavaDoc e) {
1241            //this should never happen
1242
agent.agentError("Encoding " + NetworkServerControlImpl.DEFAULT_ENCODING + " not supported");
1243        }
1244    }
1245
1246    /**
1247     * Write string with default encoding
1248     *
1249     * @param s value to be written
1250     *
1251     * @exception DRDAProtocolException
1252     */

1253    protected void writeString(String JavaDoc s) throws DRDAProtocolException
1254    {
1255        try {
1256            writeBytes(s.getBytes(NetworkServerControlImpl.DEFAULT_ENCODING));
1257        } catch (Exception JavaDoc e) {
1258            //this should never happen
1259
agent.agentError("Encoding " + NetworkServerControlImpl.DEFAULT_ENCODING + " not supported");
1260        }
1261    }
1262
1263    /**
1264     * Write string with default encoding and specified length
1265     *
1266     * @param s value to be written
1267     * @param length number of bytes to be written
1268     *
1269     * @exception DRDAProtocolException
1270     */

1271    protected void writeString(String JavaDoc s, int length) throws DRDAProtocolException
1272    {
1273        byte[] bs = null;
1274        try {
1275            bs = s.getBytes(NetworkServerControlImpl.DEFAULT_ENCODING);
1276        } catch (Exception JavaDoc e) {
1277            //this should never happen
1278
agent.agentError("Encoding " + NetworkServerControlImpl.DEFAULT_ENCODING + " not supported");
1279        }
1280        int len = bs.length;
1281        if (len >= length)
1282            writeBytes(bs, length);
1283        else
1284        {
1285            writeBytes(bs);
1286            padBytes(NetworkServerControlImpl.SPACE_CHAR, length-len);
1287        }
1288    }
1289
1290    /**
1291     * Write pad bytes using spaceChar
1292     *
1293     * @param val value to be written
1294     * @param length length to be written
1295     */

1296    protected void padBytes (byte val, int length)
1297    {
1298        Arrays.fill(bytes,offset, offset + length,val);
1299        offset += length;
1300    }
1301
1302    /**
1303     * Flush buffer to outputstream
1304     *
1305     *
1306     * @exception IOException
1307     */

1308    protected void flush () throws java.io.IOException JavaDoc
1309    {
1310        flush(agent.getOutputStream());
1311    }
1312
1313    /**
1314     * Flush buffer to specified stream
1315     *
1316     * @param socketOutputStream
1317     *
1318     * @exception IOException
1319     */

1320    protected void flush(OutputStream JavaDoc socketOutputStream)
1321        throws java.io.IOException JavaDoc
1322    {
1323        try {
1324            socketOutputStream.write (bytes, 0, offset);
1325            socketOutputStream.flush();
1326        }
1327        finally {
1328            if ((dssTrace != null) && dssTrace.isComBufferTraceOn()) {
1329              dssTrace.writeComBufferData (bytes,
1330                                           0,
1331                                           offset,
1332                                           DssTrace.TYPE_TRACE_SEND,
1333                                           "Reply",
1334                                           "flush",
1335                                           5);
1336            }
1337            reset(dssTrace);
1338        }
1339    }
1340
1341    // private methods
1342

1343    /**
1344     * Write DSS header
1345     * DSS Header format is
1346     * 2 bytes - length
1347     * 1 byte - 'D0' - indicates DDM data
1348     * 1 byte - DSS format
1349     * |---|---------|----------|
1350     * | 0 | flags | type |
1351     * |---|---------|----------|
1352     * | 0 | 1 2 3 | 4 5 6 7 |
1353     * |---|---------|----------|
1354     * bit 0 - '0'
1355     * bit 1 - '0' - unchained, '1' - chained
1356     * bit 2 - '0' - do not continue on error, '1' - continue on error
1357     * bit 3 - '0' - next DSS has different correlator, '1' - next DSS has
1358     * same correlator
1359     * type - 1 - Request DSS
1360     * - 2 - Reply DSS
1361     * - 3 - Object DSS
1362     * - 4 - Communications DSS
1363     * - 5 - Request DSS where no reply is expected
1364     */

1365    private void beginDss (int dssType, boolean ensureLen)
1366    {
1367
1368        // save length position, the length will be written at the end
1369
dssLengthLocation = offset;
1370
1371        // Should this really only be for non-stream DSSes?
1372
if (ensureLen)
1373            ensureLength(6);
1374
1375        // Skip past length; we'll come back and set it later.
1376
offset += 2;
1377
1378        // write gds info
1379
bytes[offset] = (byte) 0xD0;
1380
1381        // Write DSS type, and default chain bit to be
1382
// DssConstants.DSSCHAIN_SAME_ID. This default
1383
// will be overridden by calls to "finalizeChain()"
1384
// and/or calls to "beginDss(boolean, int)" for
1385
// writing LOB data.
1386
bytes[offset + 1] = (byte) dssType;
1387        bytes[offset + 1] |= DssConstants.DSSCHAIN_SAME_ID;
1388
1389        // save correlationID for use in error messages while processing
1390
// this DSS
1391
correlationID = getCorrelationID();
1392
1393        // write the reply correlation id
1394
bytes[offset + 2] = (byte) ((correlationID >>> 8) & 0xff);
1395        bytes[offset + 3] = (byte) (correlationID & 0xff);
1396        offset += 4;
1397    }
1398
1399    /**
1400     * Finish a DSS Layer A object.
1401     * The length of dss object will be calculated based on the difference between the
1402     * start of the dss, saved on the beginDss call, and the current
1403     * offset into the buffer which marks the end of the data. In the event
1404     * the length requires the use of continuation Dss headers, one for each 32k
1405     * chunk of data, the data will be shifted and the continuation headers
1406     * will be inserted with the correct values as needed.
1407     */

1408    private void finalizeDssLength ()
1409    {
1410        // calculate the total size of the dss and the number of bytes which would
1411
// require continuation dss headers. The total length already includes the
1412
// the 6 byte dss header located at the beginning of the dss. It does not
1413
// include the length of any continuation headers.
1414
int totalSize = offset - dssLengthLocation;
1415        int bytesRequiringContDssHeader = totalSize - DssConstants.MAX_DSS_LENGTH;
1416
1417        // determine if continuation headers are needed
1418
if (bytesRequiringContDssHeader > 0)
1419        {
1420            // the continuation headers are needed, so calculate how many.
1421
// after the first 32767 worth of data, a continuation header is
1422
// needed for every 32765 bytes (32765 bytes of data + 2 bytes of
1423
// continuation header = 32767 Dss Max Size).
1424
int contDssHeaderCount = bytesRequiringContDssHeader / 32765;
1425            if (bytesRequiringContDssHeader % 32765 != 0)
1426                contDssHeaderCount++;
1427
1428            // right now the code will shift to the right. In the future we may want
1429
// to try something fancier to help reduce the copying (maybe keep
1430
// space in the beginning of the buffer??).
1431
// the offset points to the next available offset in the buffer to place
1432
// a piece of data, so the last dataByte is at offset -1.
1433
// various bytes will need to be shifted by different amounts
1434
// depending on how many dss headers to insert so the amount to shift
1435
// will be calculated and adjusted as needed. ensure there is enough room
1436
// for all the conutinuation headers and adjust the offset to point to the
1437
// new end of the data.
1438
int dataByte = offset - 1;
1439            int shiftSize = contDssHeaderCount * 2;
1440            ensureLength (shiftSize);
1441            offset += shiftSize;
1442
1443            // Notes on the behavior of the Layer B segmenting loop below:
1444
//
1445
// We start with the right most chunk. For a 3-segment object we'd
1446
// shift 2 segments: shift the first (rightmost) one 4 bytes and
1447
// the second one 2. Note that by 'first' we mean 'first time
1448
// through the loop', but that is actually the last segment
1449
// of data since we are moving right-to-left. For an object
1450
// of K segments we will pass through this loop K-1 times.
1451
// The 0th (leftmost) segment is not shifted, as it is
1452
// already in the right place. When we are done, we will
1453
// have made room in each segment for an additional
1454
// 2 bytes for the continuation header. Thus, each
1455
// segment K is shifted K*2 bytes to the right.
1456
//
1457
// Each time through the loop, "dataByte" points to the
1458
// last byte in the segment; "dataToShift" is the amount of
1459
// data that we need to shift, and "shiftSize" is the
1460
// distance that we need to shift it. Since dataByte points
1461
// at the last byte, not one byte beyond it (as with the
1462
// "offset" variable used elsewhere in DDMWriter), the start
1463
// of the segement is actually at (dataByte-dataToShift+1).
1464
//
1465
// After we have shifted the segment, we move back to the
1466
// start of the segment and set the value of the 2-byte DSS
1467
// continuation header, which needs to hold the length of
1468
// this segment's data, together with the continuation flag
1469
// if this is not the rightmost (passOne) segment.
1470
//
1471
// In general, each segment except the rightmost will contain
1472
// 32765 bytes of data, plus the 2-byte header, and its
1473
// continuation flag will be set, so the header value will
1474
// be 0xFFFF. The rightmost segment will not have the
1475
// continuation flag set, so its value may be anything from
1476
// 0x0001 to 0x7FFF, depending on the amount of data in that
1477
// segment.
1478
//
1479
// Note that the 0th (leftmost) segment also has a 2-byte
1480
// DSS header, which needs to have its continuation flag set.
1481
// This is done by resetting the "totalSize" variable below,
1482
// at which point that variable no longer holds the total size
1483
// of the object, but rather just the length of segment 0. The
1484
// total size of the object was written using extended length
1485
// bytes by the endDdm() method earlier.
1486
//
1487
// Additional information about this routine is available in the
1488
// bug notes for DERBY-125:
1489
// http://issues.apache.org/jira/browse/DERBY-125
1490

1491            // mark passOne to help with calculating the length of the final (first or
1492
// rightmost) continuation header.
1493
boolean passOne = true;
1494            do {
1495                // calculate chunk of data to shift
1496
int dataToShift = bytesRequiringContDssHeader % 32765;
1497                if (dataToShift == 0)
1498                    dataToShift = 32765;
1499                int startOfCopyData = dataByte - dataToShift + 1;
1500                System.arraycopy(bytes,startOfCopyData, bytes,
1501                                 startOfCopyData + shiftSize, dataToShift);
1502                dataByte -= dataToShift;
1503
1504
1505                // calculate the value the value of the 2 byte continuation dss
1506
// header which includes the length of itself. On the first pass,
1507
// if the length is 32767
1508
// we do not want to set the continuation dss header flag.
1509
int twoByteContDssHeader = dataToShift + 2;
1510                if (passOne)
1511                    passOne = false;
1512                else
1513                {
1514                    if (twoByteContDssHeader == DssConstants.MAX_DSS_LENGTH)
1515                    twoByteContDssHeader = (twoByteContDssHeader |
1516                        DssConstants.CONTINUATION_BIT);
1517
1518                }
1519
1520                // insert the header's length bytes
1521
bytes[dataByte + shiftSize - 1] = (byte)
1522                    ((twoByteContDssHeader >>> 8) & 0xff);
1523                bytes[dataByte + shiftSize] = (byte)
1524                    (twoByteContDssHeader & 0xff);
1525
1526                // adjust the bytesRequiringContDssHeader and the amount to shift for
1527
// data in upstream headers.
1528
bytesRequiringContDssHeader -= dataToShift;
1529                shiftSize -= 2;
1530
1531                // shift and insert another header for more data.
1532
}
1533            while (bytesRequiringContDssHeader > 0);
1534
1535            // set the continuation dss header flag on for the first header
1536
totalSize = (DssConstants.MAX_DSS_LENGTH |
1537                    DssConstants.CONTINUATION_BIT);
1538
1539
1540        }
1541
1542        // insert the length bytes in the 6 byte dss header.
1543
bytes[dssLengthLocation] = (byte) ((totalSize >>> 8) & 0xff);
1544        bytes[dssLengthLocation + 1] = (byte) (totalSize & 0xff);
1545    }
1546
1547    protected void writeExtendedLength(long size)
1548    {
1549        int numbytes = calculateExtendedLengthByteCount(size);
1550        if (size > 0)
1551            writeInt(0x8000 | numbytes);
1552        else
1553            writeInt(numbytes);
1554    }
1555
1556
1557    /**
1558     * Calculate extended length byte count which follows the DSS header
1559     * for extended DDM.
1560     *
1561     * @param ddmSize - size of DDM command
1562     * @return minimum number of extended length bytes needed. 0 indicates no
1563     * extended length needed.
1564     */

1565    private int calculateExtendedLengthByteCount (long ddmSize)
1566    {
1567        if (ddmSize <= 0x7fff)
1568            return 0;
1569        // JCC does not support 2 at this time, so we always send
1570
// at least 4
1571
// else if (ddmSize <= 0xffff)
1572
// return 2;
1573
else if (ddmSize <= 0xffffffffL)
1574            return 4;
1575        else if (ddmSize <= 0xffffffffffffL)
1576            return 6;
1577        else if (ddmSize <= 0x7fffffffffffffffL)
1578            return 8;
1579        else
1580            // shouldn't happen
1581
// XXX - add sanity debug stuff here
1582
return 0;
1583    }
1584
1585    /**
1586     * Ensure that there is space in the buffer
1587     *
1588     * @param length space required
1589     */

1590    private void ensureLength (int length)
1591    {
1592        length += offset;
1593        if (length > bytes.length) {
1594            if (SanityManager.DEBUG)
1595            {
1596                agent.trace("DANGER - Expensive expansion of buffer");
1597            }
1598            byte newBytes[] = new byte[Math.max (bytes.length << 1, length)];
1599            System.arraycopy (bytes, 0, newBytes, 0, offset);
1600            bytes = newBytes;
1601        }
1602    }
1603
1604
1605    /**
1606     * Write a Java <code>java.math.BigDecimal</code> to packed decimal bytes.
1607     *
1608     * @param b BigDecimal to write
1609     * @param precision Precision of decimal or numeric type
1610     * @return length written.
1611     *
1612     * @exception SQLException Thrown if # digits > 31
1613     */

1614    private int bigDecimalToPackedDecimalBytes (java.math.BigDecimal JavaDoc b,
1615                                                int precision, int scale)
1616    throws SQLException JavaDoc
1617    {
1618        int declaredPrecision = precision;
1619        int declaredScale = scale;
1620
1621        // packed decimal may only be up to 31 digits.
1622
if (declaredPrecision > 31) // this is a bugcheck only !!!
1623
{
1624            clearDdm ();
1625            throw new java.sql.SQLException JavaDoc ("Packed decimal may only be up to 31 digits!");
1626        }
1627
1628        // get absolute unscaled value of the BigDecimal as a String.
1629
String JavaDoc unscaledStr = b.unscaledValue().abs().toString();
1630
1631        // get precision of the BigDecimal.
1632
int bigPrecision = unscaledStr.length();
1633
1634        if (bigPrecision > 31)
1635        {
1636            clearDdm ();
1637            throw new SQLException JavaDoc ("The numeric literal \"" +
1638                             b.toString() +
1639                             "\" is not valid because its value is out of range.",
1640                             "42820",
1641                             -405);
1642        }
1643        int bigScale = b.scale();
1644        int bigWholeIntegerLength = bigPrecision - bigScale;
1645        if ( (bigWholeIntegerLength > 0) && (!unscaledStr.equals ("0")) ) {
1646            // if whole integer part exists, check if overflow.
1647
int declaredWholeIntegerLength = declaredPrecision - declaredScale;
1648            if (bigWholeIntegerLength > declaredWholeIntegerLength)
1649            {
1650                clearDdm ();
1651                throw new SQLException JavaDoc ("Overflow occurred during numeric data type conversion of \"" +
1652                                       b.toString() +
1653                                       "\".",
1654                                       "22003",
1655                                       -413);
1656            }
1657        }
1658
1659        // convert the unscaled value to a packed decimal bytes.
1660

1661        // get unicode '0' value.
1662
int zeroBase = '0';
1663
1664        // start index in target packed decimal.
1665
int packedIndex = declaredPrecision-1;
1666
1667        // start index in source big decimal.
1668
int bigIndex;
1669
1670        if (bigScale >= declaredScale) {
1671          // If target scale is less than source scale,
1672
// discard excessive fraction.
1673

1674          // set start index in source big decimal to ignore excessive fraction.
1675
bigIndex = bigPrecision-1-(bigScale-declaredScale);
1676
1677          if (bigIndex < 0) {
1678            // all digits are discarded, so only process the sign nybble.
1679
bytes[offset+(packedIndex+1)/2] =
1680              (byte) ( (b.signum()>=0)?12:13 ); // sign nybble
1681
}
1682          else {
1683            // process the last nybble together with the sign nybble.
1684
bytes[offset+(packedIndex+1)/2] =
1685              (byte) ( ( (unscaledStr.charAt(bigIndex)-zeroBase) << 4 ) + // last nybble
1686
( (b.signum()>=0)?12:13 ) ); // sign nybble
1687
}
1688          packedIndex-=2;
1689          bigIndex-=2;
1690        }
1691        else {
1692          // If target scale is greater than source scale,
1693
// pad the fraction with zero.
1694

1695          // set start index in source big decimal to pad fraction with zero.
1696
bigIndex = declaredScale-bigScale-1;
1697
1698          // process the sign nybble.
1699
bytes[offset+(packedIndex+1)/2] =
1700            (byte) ( (b.signum()>=0)?12:13 ); // sign nybble
1701

1702          for (packedIndex-=2, bigIndex-=2; bigIndex>=0; packedIndex-=2, bigIndex-=2)
1703            bytes[offset+(packedIndex+1)/2] = (byte) 0;
1704
1705          if (bigIndex == -1) {
1706            bytes[offset+(packedIndex+1)/2] =
1707              (byte) ( (unscaledStr.charAt(bigPrecision-1)-zeroBase) << 4 ); // high nybble
1708

1709            packedIndex-=2;
1710            bigIndex = bigPrecision-3;
1711          }
1712          else {
1713            bigIndex = bigPrecision-2;
1714          }
1715        }
1716
1717        // process the rest.
1718
for (; bigIndex>=0; packedIndex-=2, bigIndex-=2) {
1719          bytes[offset+(packedIndex+1)/2] =
1720            (byte) ( ( (unscaledStr.charAt(bigIndex)-zeroBase) << 4 ) + // high nybble
1721
( unscaledStr.charAt(bigIndex+1)-zeroBase ) ); // low nybble
1722
}
1723
1724        // process the first nybble when there is one left.
1725
if (bigIndex == -1) {
1726          bytes[offset+(packedIndex+1)/2] =
1727            (byte) (unscaledStr.charAt(0) - zeroBase);
1728
1729          packedIndex-=2;
1730        }
1731
1732        // pad zero in front of the big decimal if necessary.
1733
for (; packedIndex>=-1; packedIndex-=2)
1734          bytes[offset+(packedIndex+1)/2] = (byte) 0;
1735
1736        return declaredPrecision/2 + 1;
1737    }
1738
1739
1740    /***
1741     * Prepend zeros to numeric string
1742     *
1743     * @param s string
1744     * @param precision - length of padded string
1745     *
1746     * @return zero padded string
1747     */

1748    public static String JavaDoc zeroPadString(String JavaDoc s, int precision)
1749    {
1750
1751        if (s == null)
1752            return s;
1753
1754        int slen = s.length();
1755        if (precision == slen)
1756            return s;
1757        else if (precision > slen)
1758        {
1759            char[] ca = new char[precision - slen];
1760            Arrays.fill(ca,0,precision - slen,'0');
1761            return new String JavaDoc(ca) + s;
1762        }
1763        else
1764        {
1765            // Shouldn't happen but just in case
1766
// truncate
1767
return s.substring(0,precision);
1768        }
1769
1770    }
1771
1772    
1773    private void sendBytes (java.io.OutputStream JavaDoc socketOutputStream)
1774    throws java.io.IOException JavaDoc{
1775    
1776    sendBytes(socketOutputStream,
1777          true);
1778    
1779    }
1780    
1781
1782  private void sendBytes (java.io.OutputStream JavaDoc socketOutputStream,
1783              boolean flashStream )
1784      throws java.io.IOException JavaDoc
1785  {
1786    resetChainState();
1787    try {
1788      socketOutputStream.write (bytes, 0, offset);
1789      if(flashStream)
1790      socketOutputStream.flush();
1791    }
1792    finally {
1793        if ((dssTrace != null) && dssTrace.isComBufferTraceOn()) {
1794            dssTrace.writeComBufferData (bytes,
1795                                           0,
1796                                           offset,
1797                                           DssTrace.TYPE_TRACE_SEND,
1798                                           "Reply",
1799                                           "flush",
1800                                           5);
1801      }
1802      clearBuffer();
1803    }
1804  }
1805
1806    protected String JavaDoc toDebugString(String JavaDoc indent)
1807    {
1808        String JavaDoc s = indent + "***** DDMWriter toDebugString ******\n";
1809        int byteslen = 0;
1810        if ( bytes != null)
1811            byteslen = bytes.length;
1812        s += indent + "byte array length = " + bytes.length + "\n";
1813        return s;
1814    }
1815
1816    /**
1817     * Reset any chaining state that needs to be reset
1818     * at time of the send
1819     */

1820    protected void resetChainState()
1821    {
1822        prevHdrLocation = -1;
1823    }
1824
1825    /**
1826     * Looks at chaining info for previous DSS written, and use
1827     * that to figure out what the correlation id for the current
1828     * DSS should be. Return that correlation id.
1829     */

1830    private int getCorrelationID() {
1831
1832        int cId;
1833        if (previousCorrId != DssConstants.CORRELATION_ID_UNKNOWN) {
1834            if (previousChainByte == DssConstants.DSSCHAIN_SAME_ID)
1835            // then we have to use the last correlation id we sent.
1836
cId = previousCorrId;
1837            else
1838            // get correlation id as normal.
1839
cId = nextCorrelationID++;
1840        }
1841        else {
1842        // must be the case that this is the first DSS we're
1843
// writing for this connection (because we haven't
1844
// called "endDss" yet). So, get the corr id as
1845
// normal.
1846
cId = nextCorrelationID++;
1847        }
1848
1849        return cId;
1850
1851    }
1852
1853    /**
1854     * Finalize the current DSS chain and send it if
1855     * needed.
1856     *
1857     * Updates the chaining state of the most recently-written-
1858     * to-buffer DSS to correspond to the most recently-read-
1859     * from-client request. If that chaining state indicates
1860     * we've reached the end of a chain, then we go ahead
1861     * and send the buffer across the wire.
1862     * @param socketOutputStream Output stream to which we're flushing.
1863     */

1864    protected void finalizeChain(byte currChainByte,
1865        OutputStream JavaDoc socketOutputStream) throws DRDAProtocolException
1866    {
1867
1868        // Go back to previous DSS and override the default
1869
// chain state (WITH_SAME_ID) with whatever the last
1870
// request dictates.
1871

1872        if (prevHdrLocation != -1) {
1873        // Note: == -1 => the previous DSS was already sent; this
1874
// should only happen in cases where the buffer filled up
1875
// and we had to send it (which means we were probably
1876
// writing EXTDTA). In such cases, proper chaining
1877
// should already have been handled @ time of send.
1878
bytes[prevHdrLocation + 3] &= 0x0F; // Zero out old chain value.
1879
bytes[prevHdrLocation + 3] |= currChainByte;
1880        }
1881
1882        // previousChainByte needs to match what we just did.
1883
previousChainByte = currChainByte;
1884
1885        if (currChainByte != DssConstants.DSS_NOCHAIN)
1886        // then we're still inside a chain, so don't send.
1887
return;
1888
1889        // Else, we just ended the chain, so send it across.
1890

1891        if ((SanityManager.DEBUG) && (agent != null))
1892            agent.trace("Sending data");
1893
1894        resetChainState();
1895        if (doesRequestContainData()) {
1896            try {
1897                flush(socketOutputStream);
1898            } catch (java.io.IOException JavaDoc e) {
1899                agent.markCommunicationsFailure(
1900                    "DDMWriter.finalizeChain()",
1901                    "OutputStream.flush()",
1902                    e.getMessage(),"*");
1903            }
1904        }
1905
1906    }
1907
1908    /**
1909     * Takes note of the location of the most recently completed
1910     * DSS in the buffer, and then returns the current offset.
1911     * This method is used in conjunction with "clearDSSesBackToMark"
1912     * to allow for DRDAConnThread to "back-out" DSSes in the
1913     * event of errors.
1914     */

1915    protected int markDSSClearPoint()
1916    {
1917
1918        lastDSSBeforeMark = prevHdrLocation;
1919        return offset;
1920
1921    }
1922
1923    /**
1924     * Does a logical "clear" of everything written to the buffer after
1925     * the received mark. It's assumed that this method will be used
1926     * in error cases when we've started writing one or more DSSes,
1927     * but then hit an error and need to back out. After backing out,
1928     * we'll always need to write _something_ back to the client to
1929     * indicate an error (typically, we just write an SQLCARD) but what
1930     * exactly gets written is handled in DRDAConnThread. Here, we
1931     * just do the necessary prep so that whatever comes next will
1932     * succeed.
1933     */

1934    protected void clearDSSesBackToMark(int mark)
1935    {
1936
1937        // Logical clear.
1938
offset = mark;
1939
1940        // Because we've just cleared out the most recently-
1941
// written DSSes, we have to make sure the next thing
1942
// we write will have the correct correlation id. We
1943
// do this by setting the value of 'nextCorrelationID'
1944
// based on the chaining byte from the last remaining
1945
// DSS (where "remaining" means that it still exists
1946
// in the buffer after the clear).
1947
if (lastDSSBeforeMark == -1)
1948        // we cleared out the entire buffer; reset corr id.
1949
nextCorrelationID = 1;
1950        else {
1951        // last remaining DSS had chaining, so we set "nextCorrelationID"
1952
// to be 1 greater than whatever the last remaining DSS had as
1953
// its correlation id.
1954
nextCorrelationID = 1 + (int)
1955                (((bytes[lastDSSBeforeMark + 4] & 0xff) << 8) +
1956                (bytes[lastDSSBeforeMark + 5] & 0xff));
1957        }
1958
1959    }
1960
1961    
1962    private static int peekStream(InputStream JavaDoc in) throws IOException JavaDoc{
1963        
1964    in.mark(1);
1965
1966    try{
1967        return in.read();
1968        
1969    }finally{
1970        in.reset();
1971        
1972    }
1973    }
1974
1975    
1976    private static int getLayerBStreamingBufferSize(){
1977    return PropertyUtil.getSystemInt( Property.DRDA_PROP_STREAMOUTBUFFERSIZE , 0 );
1978    }
1979    
1980    
1981    private static OutputStream JavaDoc placeLayerBStreamingBuffer(OutputStream JavaDoc original){
1982    
1983    int size = getLayerBStreamingBufferSize();
1984    
1985    if(size < 1)
1986        return original;
1987    else
1988        return new BufferedOutputStream JavaDoc( original, size );
1989
1990    }
1991    
1992}
1993
1994
Popular Tags