001: package org.jacorb.orb.giop;
002:
003: /*
004: * JacORB - a free Java ORB
005: *
006: * Copyright (C) 1997-2004 Gerald Brose.
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Library General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Library General Public License for more details.
017: *
018: * You should have received a copy of the GNU Library General Public
019: * License along with this library; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: */
022:
023: import java.io.IOException;
024: import java.util.Vector;
025: import org.jacorb.orb.CDROutputStream;
026: import org.jacorb.orb.ORB;
027: import org.jacorb.orb.ORBConstants;
028: import org.omg.CORBA.MARSHAL;
029: import org.omg.IOP.ServiceContext;
030: import org.omg.IOP.ServiceContextHelper;
031:
032: /**
033: * ServiceContextTransportingOutputStream.java
034: *
035: *
036: * Created: Sat Aug 18 12:12:22 2002
037: *
038: * @author Nicolas Noffke
039: * @version $Id: ServiceContextTransportingOutputStream.java,v 1.21 2006/05/12 14:39:53 alphonse.bendt Exp $
040: */
041:
042: public class ServiceContextTransportingOutputStream extends
043: MessageOutputStream {
044: /**
045: * <code>header_end</code> represents the end of the GIOP message header.
046: * Only valid if header_padding != 0
047: */
048: private int header_end = -1;
049:
050: /**
051: * <code>header_padding</code> represents the number of bytes used for padding
052: * between header and body
053: */
054: private int header_padding = 0;
055:
056: /**
057: * <code>padding_ctx</code> is used if ServiceContexts are actually added.
058: * This will be the last context, and the context_data is used to fill up
059: * to the next 8 byte boundary
060: */
061: private static ServiceContext padding_ctx = new ServiceContext(
062: ORBConstants.SERVICE_PADDING_CONTEXT, new byte[0]);
063:
064: private Vector contexts;
065:
066: public ServiceContextTransportingOutputStream() {
067: super ();
068: }
069:
070: public ServiceContextTransportingOutputStream(ORB orb) {
071: super (orb);
072: }
073:
074: /**
075: * GIOP 1.2 requires the message body to start on an 8 byte
076: * border, while 1.0/1.1 does not. Additionally, this padding shall
077: * only be performed, if the body is not empty (which we don't
078: * know at this stage.
079: */
080: protected void markHeaderEnd() {
081: header_end = size();
082:
083: header_padding = 8 - (size() % 8); //difference to next 8 byte border
084: header_padding = (header_padding == 8) ? 0 : header_padding;
085:
086: skip(header_padding);
087: }
088:
089: private int getHeaderEnd() {
090: return header_end;
091: }
092:
093: private int getBodyBegin() {
094: return header_end + header_padding;
095: }
096:
097: private int getHeaderPadding() {
098: return header_padding;
099: }
100:
101: private boolean hasBody() {
102: return size() > getBodyBegin();
103: }
104:
105: public void insertMsgSize() {
106: if (header_padding == 0) {
107: insertMsgSize(size() - Messages.MSG_HEADER_SIZE);
108: } else {
109: if (size() > header_end + header_padding) {
110: //has a body, so include padding by not removing it :-)
111: insertMsgSize(size() - Messages.MSG_HEADER_SIZE);
112: } else {
113: //no body written, so remove padding
114: insertMsgSize(size() - header_padding
115: - Messages.MSG_HEADER_SIZE);
116:
117: reduceSize(header_padding);
118: }
119: }
120: }
121:
122: public void write_to(GIOPConnection conn) throws IOException {
123: CDROutputStream ctx_out = null;
124:
125: if (contexts == null || contexts.size() == 0) {
126: //no additional service contexts present, so buffer can be
127: //sent as a whole
128: insertMsgSize();
129: write(conn, 0, size());
130: } else {
131: switch (giop_minor) {
132: case 0: {
133: // GIOP 1.0 (== GIOP 1.1, fall through)
134: }
135: case 1: {
136: //GIOP 1.1
137:
138: //First of all, we need to know the the length of
139: //the service context array
140:
141: //For GIOP 1.1, we have to add a padding context
142: contexts.addElement(padding_ctx);
143:
144: ctx_out = createContextStream();
145:
146: //difference to next 8 byte border
147:
148: // Need to calculate whether the service context needs any
149: // padding. This is the difference. To calculate this need
150: // to add the new CDRStream and the header size - this
151: // should end on an 8 byte boundary.
152: int difference = (8 - ((Messages.MSG_HEADER_SIZE + ctx_out
153: .size()) % 8));
154: difference = (difference == 8) ? 0 : difference;
155:
156: if (difference > 0) {
157: //the last padding context has a 0 length data
158: //part. Therefore, the last data is a ulong
159: //with value 0 (the length of the array). To
160: //increase the data part, we have to increase
161: //the size and add the actual data.
162:
163: //"unwrite" the last ulong
164: ctx_out.reduceSize(4);
165:
166: //write new length
167: ctx_out.write_ulong(difference);
168:
169: //add "new" data (by just increasing the size
170: //of the stream and not actually writing
171: //anything).
172: ctx_out.increaseSize(difference);
173: }
174:
175: //Then, we have to update the message size in the GIOP
176: //message header. The new size is the size of the
177: //"original" message minus the length ulong (4 bytes) of
178: //the original empty ServiceContext array plus the length
179: //of the new service context array
180: insertMsgSize(size() - Messages.MSG_HEADER_SIZE - 4
181: + ctx_out.size());
182:
183: //The ServiceContexts are the first attribute in
184: //the RequestHeader struct. Therefore firstly, we
185: //have to write the GIOP message header...
186: write(conn, 0, Messages.MSG_HEADER_SIZE);
187:
188: //... then add the contexts ...
189: ctx_out.write(conn, 0, ctx_out.size());
190:
191: //... and finally the rest of the message
192: //(omitting the empty original context array).
193:
194: write(conn, Messages.MSG_HEADER_SIZE + 4, size()
195: - (Messages.MSG_HEADER_SIZE + 4));
196: break;
197: }
198: case 2: {
199: //GIOP 1.2
200:
201: //First of all, we need to know the the length of
202: //the service context array
203:
204: //For GIOP 1.2, the header is padded per spec, so
205: //no additional context is needed
206:
207: ctx_out = createContextStream();
208:
209: //the new header end is the old header end minus
210: //the length ulong of the context array plus the
211: //length of the context array (wich contains its
212: //own length ulong)
213: int new_header_end = getHeaderEnd() - 4
214: + ctx_out.size();
215:
216: //difference to next 8 byte border
217: int difference = 8 - (new_header_end % 8);
218: difference = (difference == 8) ? 0 : difference;
219:
220: if (difference > 0 && hasBody()) {
221: //add padding bytes (by just increasing the
222: //size of the stream and not actually writing
223: //anything). If no body is present, no padding
224: //has to be inserted
225: ctx_out.increaseSize(difference);
226: }
227:
228: //Then, we have to update the message size in the
229: //GIOP message header. The new size is the size of
230: //the "original" message minus the length ulong (4
231: //bytes) of the original empty ServiceContext
232: //array minus the "original" header padding plus
233: //the length of the new service context array
234: //(containing the new padding)
235: insertMsgSize(size() - Messages.MSG_HEADER_SIZE - 4
236: - getHeaderPadding() + ctx_out.size());
237:
238: //The GIOP message and request header (up until
239: //the ServiceContexts) stay unmanipulated. We also
240: //have to remove the length ulong of the
241: //"original" empty service context array, because
242: //the new one has its own length attribute
243: write(conn, 0, getHeaderEnd() - 4);
244:
245: //... then add the contexts ...
246:
247: ctx_out.write(conn, 0, ctx_out.size());
248:
249: //... and finally the rest of the message
250: //(omitting the empty original context array).
251:
252: write(conn, getBodyBegin(), size() - getBodyBegin());
253:
254: break;
255: }
256: default: {
257: throw new MARSHAL("Unknown GIOP minor: " + giop_minor);
258: }
259: }
260: }
261: close();
262: if (ctx_out != null) {
263: ctx_out.close();
264: ctx_out = null;
265: }
266: }
267:
268: public void addServiceContext(ServiceContext ctx) {
269: if (contexts == null) {
270: contexts = new Vector();
271: }
272:
273: contexts.add(ctx);
274: }
275:
276: /**
277: * private hack...
278: */
279:
280: public byte[] getBody() {
281: byte[] result = org.jacorb.orb.BufferManager.getInstance()
282: .getBuffer(size() - getBodyBegin());
283:
284: System.arraycopy(getBufferCopy(), getBodyBegin(), result, 0,
285: result.length);
286:
287: return result;
288: }
289:
290: private CDROutputStream createContextStream() {
291: CDROutputStream out = new CDROutputStream(
292: (org.omg.CORBA.ORB) null);
293:
294: //write the length of the service context array.
295: out.write_ulong(contexts.size());
296:
297: for (int i = 0; i < contexts.size(); i++) {
298: ServiceContextHelper.write(out, (ServiceContext) contexts
299: .elementAt(i));
300: }
301:
302: return out;
303: }
304:
305: }// ServiceContextTransportingOutputStream
|