KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > corba > se > impl > encoding > CDROutputStream_1_2


1 /*
2  * @(#)CDROutputStream_1_2.java 1.12 04/03/01
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package com.sun.corba.se.impl.encoding;
8
9 import org.omg.CORBA.BAD_PARAM JavaDoc;
10 import org.omg.CORBA.INTERNAL JavaDoc;
11 import org.omg.CORBA.CompletionStatus JavaDoc;
12 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
13 import com.sun.corba.se.impl.encoding.CodeSetConversion;
14 import com.sun.corba.se.impl.orbutil.ORBConstants;
15
16 public class CDROutputStream_1_2 extends CDROutputStream_1_1
17 {
18     // There's a situation with chunking with fragmentation
19
// in which the alignment for a primitive value is needed
20
// to fill fragment N, but the primitive won't fit so
21
// must go into fragment N + 1. The behavior is the same
22
// as that for specialChunks.
23
//
24
// Unfortunately, given the current code, we can't reuse
25
// specialChunk. If you wrap each of the following
26
// write calls with handleSpecialChunkBegin/End, you
27
// will lose your state because the primitive calls will
28
// change the variables, etc.
29
//
30
// All of the CDR code should be rewritten moving chunking
31
// to a different level, perhaps in the buffer managers.
32
// We want to move to a compositional model rather than
33
// using inheritance.
34
//
35
// Note that in the grow case, chunks are _NOT_ closed
36
// at grow points, now.
37
//
38
// **** NOTE ****
39
// Since we will not support valuetypes with GIOP 1.1, that
40
// also means we do not support chunking there.
41
//
42
protected boolean primitiveAcrossFragmentedChunk = false;
43
44     // Used in chunking. Here's how this works:
45
//
46
// When chunking and writing an array of primitives, a string, or a
47
// wstring, _AND_ it won't fit in the buffer do the following. (As
48
// you can see, this is a very "special" chunk.)
49
//
50
// 1. Write the length of the chunk including the array length
51
// 2. Set specialChunk to true
52
// 3 applies to ALL chunking:
53
// 3. In grow, if we need to fragment and specialChunk is false
54
// a) call end_block
55
// b) fragment
56
// Now back to the array only case:
57
// [write the data]
58
// 4. if specialChunk is true
59
// a) Close the chunk
60
// b) Set specialChunk to false
61

62     protected boolean specialChunk = false;
63
64     // Indicates whether the header should be padded. In GIOP 1.2 and above, the
65
// body must be aligned on a 8-octet boundary, and so the header needs to be
66
// padded appropriately. However, if there is no body to a request or reply
67
// message, there is no need to pad the header, in the unfragmented case.
68
private boolean headerPadding;
69     
70     protected void handleSpecialChunkBegin(int requiredSize)
71     {
72         // If we're chunking and the item won't fit in the buffer
73
if (inBlock && requiredSize + bbwi.position() > bbwi.buflen) {
74
75             // Duplicating some code from end_block. Compute
76
// and write the total chunk length.
77

78             int oldSize = bbwi.position();
79             bbwi.position(blockSizeIndex - 4);
80
81             //write_long(oldSize - blockSizeIndex);
82
writeLongWithoutAlign((oldSize - blockSizeIndex) + requiredSize);
83             bbwi.position(oldSize);
84     
85             // Set the special flag so we don't end the chunk when
86
// we fragment
87
specialChunk = true;
88         }
89     }
90
91     protected void handleSpecialChunkEnd()
92     {
93         // If we're in a chunk and the item spanned fragments
94
if (inBlock && specialChunk) {
95
96             // This is unnecessary, but I just want to show that
97
// we're done with the current chunk. (the end_block
98
// call is inappropriate here)
99
inBlock = false;
100             blockSizeIndex = -1;
101             blockSizePosition = -1;
102             
103             // Start a new chunk since we fragmented during the item.
104
// Thus, no one can go back to add more to the chunk length
105
start_block();
106
107             // Now turn off the flag so we go back to the normal
108
// behavior of closing a chunk when we fragment and
109
// reopening afterwards.
110
specialChunk = false;
111         }
112     }
113     
114     // Called after writing primitives
115
private void checkPrimitiveAcrossFragmentedChunk()
116     {
117         if (primitiveAcrossFragmentedChunk) {
118             primitiveAcrossFragmentedChunk = false;
119
120             inBlock = false;
121
122             // It would be nice to have a StreamPosition
123
// abstraction if we could avoid allocation
124
// overhead.
125
blockSizeIndex = -1;
126             blockSizePosition = -1;
127
128             // Start a new chunk
129
start_block();
130         }
131     }
132
133
134     public void write_octet(byte x) {
135         super.write_octet(x);
136         checkPrimitiveAcrossFragmentedChunk();
137     }
138
139     public void write_short(short x) {
140         super.write_short(x);
141         checkPrimitiveAcrossFragmentedChunk();
142     }
143
144     public void write_long(int x) {
145         super.write_long(x);
146         checkPrimitiveAcrossFragmentedChunk();
147     }
148
149     public void write_longlong(long x) {
150         super.write_longlong(x);
151         checkPrimitiveAcrossFragmentedChunk();
152     }
153
154     // Called by RequestMessage_1_2 or ReplyMessage_1_2 classes only.
155
void setHeaderPadding(boolean headerPadding) {
156         this.headerPadding = headerPadding;
157     }
158
159     protected void alignAndReserve(int align, int n) {
160
161         // headerPadding bit is set by the write operation of RequestMessage_1_2
162
// or ReplyMessage_1_2 classes. When set, the very first body write
163
// operation (from the stub code) would trigger an alignAndReserve
164
// method call, that would in turn add the appropriate header padding,
165
// such that the body is aligned on a 8-octet boundary. The padding
166
// is required for GIOP versions 1.2 and above, only if body is present.
167
if (headerPadding == true) {
168             headerPadding = false;
169             alignOnBoundary(ORBConstants.GIOP_12_MSG_BODY_ALIGNMENT);
170         }
171         
172         // In GIOP 1.2, we always end fragments at our
173
// fragment size, which is an "evenly divisible
174
// 8 byte boundary" (aka divisible by 16). A fragment can
175
// end with appropriate alignment padding, but no padding
176
// is needed with respect to the next GIOP fragment
177
// header since it ends on an 8 byte boundary.
178

179         bbwi.position(bbwi.position() + computeAlignment(align));
180
181         if (bbwi.position() + n > bbwi.buflen)
182             grow(align, n);
183     }
184
185     protected void grow(int align, int n) {
186         
187         // Save the current size for possible post-fragmentation calculation
188
int oldSize = bbwi.position();
189
190         // See notes where specialChunk is defined, as well as the
191
// above notes for primitiveAcrossFragmentedChunk.
192
//
193
// If we're writing a primitive and chunking, we need to update
194
// the chunk length to include the length of the primitive (unless
195
// this complexity is handled by specialChunk).
196
//
197
// Note that this is wasted processing in the grow case, but that
198
// we don't actually close the chunk in that case.
199
boolean handleChunk = (inBlock && !specialChunk);
200         if (handleChunk) {
201             int oldIndex = bbwi.position();
202
203             bbwi.position(blockSizeIndex - 4);
204
205             writeLongWithoutAlign((oldIndex - blockSizeIndex) + n);
206
207             bbwi.position(oldIndex);
208         }
209
210         bbwi.needed = n;
211         bufferManagerWrite.overflow(bbwi);
212
213         // At this point, if we fragmented, we should have a ByteBufferWithInfo
214
// with the fragment header already marshalled. The buflen and position
215
// should be updated accordingly, and the fragmented flag should be set.
216

217         // Note that fragmented is only true in the streaming and collect cases.
218
if (bbwi.fragmented) {
219
220             // Clear the flag
221
bbwi.fragmented = false;
222
223             // Update fragmentOffset so indirections work properly.
224
// At this point, oldSize is the entire length of the
225
// previous buffer. bbwi.position() is the length of the
226
// fragment header of this buffer.
227
fragmentOffset += (oldSize - bbwi.position());
228
229             // We just fragmented, and need to signal that we should
230
// start a new chunk after writing the primitive.
231
if (handleChunk)
232                 primitiveAcrossFragmentedChunk = true;
233             
234         }
235     }
236
237     public GIOPVersion getGIOPVersion() {
238         return GIOPVersion.V1_2;
239     }
240
241     public void write_wchar(char x)
242     {
243         // In GIOP 1.2, a wchar is encoded as an unsigned octet length
244
// followed by the octets of the converted wchar. This is good,
245
// but it causes problems with our chunking code. We don't
246
// want that octet to get put in a different chunk at the end
247
// of the previous fragment.
248
//
249
// Ensure that this won't happen by overriding write_wchar_array
250
// and doing our own handleSpecialChunkBegin/End here.
251
CodeSetConversion.CTBConverter converter = getWCharConverter();
252
253         converter.convert(x);
254
255         handleSpecialChunkBegin(1 + converter.getNumBytes());
256
257         write_octet((byte)converter.getNumBytes());
258
259         byte[] result = converter.getBytes();
260
261         // Write the bytes without messing with chunking
262
// See CDROutputStream_1_0
263
internalWriteOctetArray(result, 0, converter.getNumBytes());
264
265         handleSpecialChunkEnd();
266     }
267
268     public void write_wchar_array(char[] value, int offset, int length)
269     {
270         if (value == null) {
271         throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
272         }
273
274         CodeSetConversion.CTBConverter converter = getWCharConverter();
275
276         // Unfortunately, because of chunking, we have to convert the
277
// entire char[] to a byte[] array first so we can know how
278
// many bytes we're writing ahead of time. You can't split
279
// an array of primitives into multiple chunks.
280
int totalNumBytes = 0;
281
282         // Remember that every wchar starts with an octet telling
283
// its length. The buffer size is an upper bound estimate.
284
int maxLength = (int)Math.ceil(converter.getMaxBytesPerChar() * length);
285         byte[] buffer = new byte[maxLength + length];
286
287         for (int i = 0; i < length; i++) {
288             // Convert one wchar
289
converter.convert(value[offset + i]);
290
291             // Make sure to add the octet length
292
buffer[totalNumBytes++] = (byte)converter.getNumBytes();
293
294             // Copy it into our buffer
295
System.arraycopy(converter.getBytes(), 0,
296                              buffer, totalNumBytes,
297                              converter.getNumBytes());
298
299             totalNumBytes += converter.getNumBytes();
300         }
301
302         // Now that we know the total length, we can deal with chunking.
303
// Note that we don't have to worry about alignment since they're
304
// just octets.
305
handleSpecialChunkBegin(totalNumBytes);
306
307         // Must use totalNumBytes rather than buffer.length since the
308
// buffer.length is only the upper bound estimate.
309
internalWriteOctetArray(buffer, 0, totalNumBytes);
310
311         handleSpecialChunkEnd();
312     }
313
314     public void write_wstring(String JavaDoc value) {
315         if (value == null) {
316         throw wrapper.nullParam(CompletionStatus.COMPLETED_MAYBE);
317         }
318
319         // In GIOP 1.2, wstrings are not terminated by a null. The
320
// length is the number of octets in the converted format.
321
// A zero length string is represented with the 4 byte length
322
// value of 0.
323
if (value.length() == 0) {
324             write_long(0);
325             return;
326         }
327
328         CodeSetConversion.CTBConverter converter = getWCharConverter();
329
330         converter.convert(value);
331
332         handleSpecialChunkBegin(computeAlignment(4) + 4 + converter.getNumBytes());
333
334         write_long(converter.getNumBytes());
335
336         // Write the octet array without tampering with chunking
337
internalWriteOctetArray(converter.getBytes(), 0, converter.getNumBytes());
338
339         handleSpecialChunkEnd();
340     }
341 }
342
Popular Tags