KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jacorb > orb > giop > ServiceContextTransportingOutputStream


1 package org.jacorb.orb.giop;
2
3 /*
4  * JacORB - a free Java ORB
5  *
6  * Copyright (C) 1997-2004 Gerald Brose.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */

22
23 import java.io.IOException JavaDoc;
24 import java.util.Vector JavaDoc;
25 import org.jacorb.orb.CDROutputStream;
26 import org.jacorb.orb.ORBConstants;
27 import org.omg.CORBA.MARSHAL JavaDoc;
28 import org.omg.IOP.ServiceContext JavaDoc;
29 import org.omg.IOP.ServiceContextHelper JavaDoc;
30
31 /**
32  * ServiceContextTransportingOutputStream.java
33  *
34  *
35  * Created: Sat Aug 18 12:12:22 2002
36  *
37  * @author Nicolas Noffke
38  * @version $Id: ServiceContextTransportingOutputStream.java,v 1.20 2004/05/06 12:40:00 nicolas Exp $
39  */

40
41 public class ServiceContextTransportingOutputStream
42     extends MessageOutputStream
43 {
44     /**
45      * <code>header_end</code> represents the end of the GIOP message header.
46      * Only valid if header_padding != 0
47      */

48     private int header_end = -1;
49
50     /**
51      * <code>header_padding</code> represents the number of bytes used for padding
52      * between header and body
53      */

54     private int header_padding = 0;
55
56     /**
57      * <code>padding_ctx</code> is used if ServiceContexts are actually added.
58      * This will be the last context, and the context_data is used to fill up
59      * to the next 8 byte boundary
60      */

61     private static ServiceContext JavaDoc padding_ctx =
62         new ServiceContext JavaDoc (ORBConstants.SERVICE_PADDING_CONTEXT, new byte[0]);
63
64     private Vector JavaDoc contexts;
65
66
67     public ServiceContextTransportingOutputStream()
68     {
69         super();
70     }
71
72     /**
73      * GIOP 1.2 requires the message body to start on an 8 byte
74      * border, while 1.0/1.1 does not. Additionally, this padding shall
75      * only be performed, if the body is not empty (which we don't
76      * know at this stage.
77      */

78     protected void markHeaderEnd()
79     {
80         header_end = size();
81
82         header_padding = 8 - (size() % 8); //difference to next 8 byte border
83
header_padding = (header_padding == 8)? 0 : header_padding;
84
85         skip( header_padding );
86     }
87
88     private int getHeaderEnd()
89     {
90         return header_end;
91     }
92
93     private int getBodyBegin()
94     {
95         return header_end + header_padding;
96     }
97
98
99     private int getHeaderPadding()
100     {
101         return header_padding;
102     }
103
104     private boolean hasBody()
105     {
106         return size() > getBodyBegin();
107     }
108
109
110     public void insertMsgSize()
111     {
112         if( header_padding == 0 )
113         {
114             insertMsgSize( size() - Messages.MSG_HEADER_SIZE );
115         }
116         else
117         {
118             if( size() > header_end + header_padding)
119             {
120                 //has a body, so include padding by not removing it :-)
121
insertMsgSize( size() - Messages.MSG_HEADER_SIZE );
122             }
123             else
124             {
125                 //no body written, so remove padding
126
insertMsgSize( size() - header_padding - Messages.MSG_HEADER_SIZE );
127
128                 reduceSize( header_padding );
129             }
130         }
131     }
132
133     public void write_to( GIOPConnection conn )
134         throws IOException JavaDoc
135     {
136         CDROutputStream ctx_out = null;
137
138         if( contexts == null || contexts.size() == 0 )
139         {
140             //no additional service contexts present, so buffer can be
141
//sent as a whole
142
insertMsgSize();
143             write( conn, 0, size() );
144         }
145         else
146         {
147             switch( giop_minor )
148             {
149                 case 0 :
150                 {
151                     // GIOP 1.0 (== GIOP 1.1, fall through)
152
}
153                 case 1 :
154                 {
155                     //GIOP 1.1
156

157                     //First of all, we need to know the the length of
158
//the service context array
159

160                     //For GIOP 1.1, we have to add a padding context
161
contexts.addElement( padding_ctx );
162
163                     ctx_out = createContextStream();
164
165                     //difference to next 8 byte border
166

167                     // Need to calculate whether the service context needs any
168
// padding. This is the difference. To calculate this need
169
// to add the new CDRStream and the header size - this
170
// should end on an 8 byte boundary.
171
int difference =
172                         (8 - ((Messages.MSG_HEADER_SIZE + ctx_out.size ()) % 8));
173                     difference = (difference == 8)? 0 : difference;
174
175                     if( difference > 0 )
176                     {
177                         //the last padding context has a 0 length data
178
//part. Therefore, the last data is a ulong
179
//with value 0 (the length of the array). To
180
//increase the data part, we have to increase
181
//the size and add the actual data.
182

183                         //"unwrite" the last ulong
184
ctx_out.reduceSize( 4 );
185
186                         //write new length
187
ctx_out.write_ulong( difference );
188
189                         //add "new" data (by just increasing the size
190
//of the stream and not actually writing
191
//anything).
192
ctx_out.increaseSize( difference );
193                     }
194
195                     //Then, we have to update the message size in the GIOP
196
//message header. The new size is the size of the
197
//"original" message minus the length ulong (4 bytes) of
198
//the original empty ServiceContext array plus the length
199
//of the new service context array
200
insertMsgSize( size()
201                                    - Messages.MSG_HEADER_SIZE
202                                    - 4
203                                    + ctx_out.size() );
204
205
206                     //The ServiceContexts are the first attribute in
207
//the RequestHeader struct. Therefore firstly, we
208
//have to write the GIOP message header...
209
write( conn, 0, Messages.MSG_HEADER_SIZE );
210
211                     //... then add the contexts ...
212
ctx_out.write( conn, 0, ctx_out.size() );
213
214                     //... and finally the rest of the message
215
//(omitting the empty original context array).
216

217                     write( conn,
218                            Messages.MSG_HEADER_SIZE + 4,
219                            size() -
220                            (Messages.MSG_HEADER_SIZE + 4) );
221                     break;
222                 }
223                 case 2 :
224                 {
225                     //GIOP 1.2
226

227                     //First of all, we need to know the the length of
228
//the service context array
229

230                     //For GIOP 1.2, the header is padded per spec, so
231
//no additional context is needed
232

233                     ctx_out = createContextStream();
234
235                     //the new header end is the old header end minus
236
//the length ulong of the context array plus the
237
//length of the context array (wich contains its
238
//own length ulong)
239
int new_header_end = getHeaderEnd() - 4 + ctx_out.size();
240
241                     //difference to next 8 byte border
242
int difference = 8 - (new_header_end % 8);
243                     difference = (difference == 8)? 0 : difference;
244
245                     if( difference > 0 && hasBody() )
246                     {
247                         //add padding bytes (by just increasing the
248
//size of the stream and not actually writing
249
//anything). If no body is present, no padding
250
//has to be inserted
251
ctx_out.increaseSize( difference );
252                     }
253
254                     //Then, we have to update the message size in the
255
//GIOP message header. The new size is the size of
256
//the "original" message minus the length ulong (4
257
//bytes) of the original empty ServiceContext
258
//array minus the "original" header padding plus
259
//the length of the new service context array
260
//(containing the new padding)
261
insertMsgSize( size()
262                                    - Messages.MSG_HEADER_SIZE
263                                    - 4
264                                    - getHeaderPadding()
265                                    + ctx_out.size() );
266
267                     //The GIOP message and request header (up until
268
//the ServiceContexts) stay unmanipulated. We also
269
//have to remove the length ulong of the
270
//"original" empty service context array, because
271
//the new one has its own length attribute
272
write( conn,
273                            0,
274                            getHeaderEnd() - 4 );
275
276                     //... then add the contexts ...
277

278                     ctx_out.write( conn, 0, ctx_out.size());
279
280                     //... and finally the rest of the message
281
//(omitting the empty original context array).
282

283                     write( conn,
284                            getBodyBegin(),
285                            size() - getBodyBegin() );
286
287                     break;
288                 }
289                 default :
290                 {
291                     throw new MARSHAL JavaDoc( "Unknown GIOP minor: " + giop_minor );
292                 }
293             }
294         }
295         close();
296         if ( ctx_out != null )
297         {
298             ctx_out.close();
299             ctx_out = null;
300         }
301     }
302
303     public void addServiceContext( ServiceContext JavaDoc ctx )
304     {
305         if( contexts == null )
306         {
307             contexts = new Vector JavaDoc();
308         }
309
310         contexts.add( ctx );
311     }
312
313
314     /**
315      * private hack...
316      */

317
318     public byte[] getBody()
319     {
320         byte [] result =
321             org.jacorb.orb.BufferManager.getInstance().getBuffer( size() - getBodyBegin());
322
323         System.arraycopy( getBufferCopy(), getBodyBegin(), result, 0, result.length );
324
325         return result;
326     }
327
328
329     private CDROutputStream createContextStream()
330     {
331         CDROutputStream out = new CDROutputStream( (org.omg.CORBA.ORB JavaDoc) null );
332
333         //write the length of the service context array.
334
out.write_ulong( contexts.size() );
335
336         for( int i = 0; i < contexts.size(); i++ )
337         {
338             ServiceContextHelper.write( out,
339                                         (ServiceContext JavaDoc) contexts.elementAt( i ));
340         }
341
342         return out;
343     }
344
345 }// ServiceContextTransportingOutputStream
346
Popular Tags