001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.activemq.openwire.v7;
018
019 import java.io.DataInput;
020 import java.io.DataOutput;
021 import java.io.IOException;
022 import java.lang.reflect.Constructor;
023 import org.apache.activemq.command.DataStructure;
024 import org.apache.activemq.openwire.BooleanStream;
025 import org.apache.activemq.openwire.DataStreamMarshaller;
026 import org.apache.activemq.openwire.OpenWireFormat;
027 import org.apache.activemq.util.ByteSequence;
028
029 public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
030
031 public static final Constructor STACK_TRACE_ELEMENT_CONSTRUCTOR;
032
033 static {
034 Constructor constructor = null;
035 try {
036 constructor = StackTraceElement.class.getConstructor(new Class[] {String.class, String.class,
037 String.class, int.class});
038 } catch (Throwable e) {
039 }
040 STACK_TRACE_ELEMENT_CONSTRUCTOR = constructor;
041 }
042
043 public abstract byte getDataStructureType();
044
045 public abstract DataStructure createObject();
046
047 public int tightMarshal1(OpenWireFormat wireFormat, Object o, BooleanStream bs) throws IOException {
048 return 0;
049 }
050
051 public void tightMarshal2(OpenWireFormat wireFormat, Object o, DataOutput dataOut, BooleanStream bs)
052 throws IOException {
053 }
054
055 public void tightUnmarshal(OpenWireFormat wireFormat, Object o, DataInput dataIn, BooleanStream bs)
056 throws IOException {
057 }
058
059 public int tightMarshalLong1(OpenWireFormat wireFormat, long o, BooleanStream bs) throws IOException {
060 if (o == 0) {
061 bs.writeBoolean(false);
062 bs.writeBoolean(false);
063 return 0;
064 } else if ((o & 0xFFFFFFFFFFFF0000L) == 0) {
065 bs.writeBoolean(false);
066 bs.writeBoolean(true);
067 return 2;
068 } else if ((o & 0xFFFFFFFF00000000L) == 0) {
069 bs.writeBoolean(true);
070 bs.writeBoolean(false);
071 return 4;
072 } else {
073 bs.writeBoolean(true);
074 bs.writeBoolean(true);
075 return 8;
076 }
077 }
078
079 public void tightMarshalLong2(OpenWireFormat wireFormat, long o, DataOutput dataOut, BooleanStream bs)
080 throws IOException {
081 if (bs.readBoolean()) {
082 if (bs.readBoolean()) {
083 dataOut.writeLong(o);
084 } else {
085 dataOut.writeInt((int)o);
086 }
087 } else {
088 if (bs.readBoolean()) {
089 dataOut.writeShort((int)o);
090 }
091 }
092 }
093
094 public long tightUnmarshalLong(OpenWireFormat wireFormat, DataInput dataIn, BooleanStream bs)
095 throws IOException {
096 if (bs.readBoolean()) {
097 if (bs.readBoolean()) {
098 return dataIn.readLong();
099 } else {
100 return toLong(dataIn.readInt());
101 }
102 } else {
103 if (bs.readBoolean()) {
104 return toLong(dataIn.readShort());
105 } else {
106 return 0;
107 }
108 }
109 }
110
111 protected long toLong(short value) {
112 // lets handle negative values
113 long answer = value;
114 return answer & 0xffffL;
115 }
116
117 protected long toLong(int value) {
118 // lets handle negative values
119 long answer = value;
120 return answer & 0xffffffffL;
121 }
122
123 protected DataStructure tightUnmarsalNestedObject(OpenWireFormat wireFormat, DataInput dataIn,
124 BooleanStream bs) throws IOException {
125 return wireFormat.tightUnmarshalNestedObject(dataIn, bs);
126 }
127
128 protected int tightMarshalNestedObject1(OpenWireFormat wireFormat, DataStructure o, BooleanStream bs)
129 throws IOException {
130 return wireFormat.tightMarshalNestedObject1(o, bs);
131 }
132
133 protected void tightMarshalNestedObject2(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut,
134 BooleanStream bs) throws IOException {
135 wireFormat.tightMarshalNestedObject2(o, dataOut, bs);
136 }
137
138 protected DataStructure tightUnmarsalCachedObject(OpenWireFormat wireFormat, DataInput dataIn,
139 BooleanStream bs) throws IOException {
140 if (wireFormat.isCacheEnabled()) {
141 if (bs.readBoolean()) {
142 short index = dataIn.readShort();
143 DataStructure object = wireFormat.tightUnmarshalNestedObject(dataIn, bs);
144 wireFormat.setInUnmarshallCache(index, object);
145 return object;
146 } else {
147 short index = dataIn.readShort();
148 return wireFormat.getFromUnmarshallCache(index);
149 }
150 } else {
151 return wireFormat.tightUnmarshalNestedObject(dataIn, bs);
152 }
153 }
154
155 protected int tightMarshalCachedObject1(OpenWireFormat wireFormat, DataStructure o, BooleanStream bs)
156 throws IOException {
157 if (wireFormat.isCacheEnabled()) {
158 Short index = wireFormat.getMarshallCacheIndex(o);
159 bs.writeBoolean(index == null);
160 if (index == null) {
161 int rc = wireFormat.tightMarshalNestedObject1(o, bs);
162 wireFormat.addToMarshallCache(o);
163 return 2 + rc;
164 } else {
165 return 2;
166 }
167 } else {
168 return wireFormat.tightMarshalNestedObject1(o, bs);
169 }
170 }
171
172 protected void tightMarshalCachedObject2(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut,
173 BooleanStream bs) throws IOException {
174 if (wireFormat.isCacheEnabled()) {
175 Short index = wireFormat.getMarshallCacheIndex(o);
176 if (bs.readBoolean()) {
177 dataOut.writeShort(index.shortValue());
178 wireFormat.tightMarshalNestedObject2(o, dataOut, bs);
179 } else {
180 dataOut.writeShort(index.shortValue());
181 }
182 } else {
183 wireFormat.tightMarshalNestedObject2(o, dataOut, bs);
184 }
185 }
186
187 protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn, BooleanStream bs)
188 throws IOException {
189 if (bs.readBoolean()) {
190 String clazz = tightUnmarshalString(dataIn, bs);
191 String message = tightUnmarshalString(dataIn, bs);
192 Throwable o = createThrowable(clazz, message);
193 if (wireFormat.isStackTraceEnabled()) {
194 if (STACK_TRACE_ELEMENT_CONSTRUCTOR != null) {
195 StackTraceElement ss[] = new StackTraceElement[dataIn.readShort()];
196 for (int i = 0; i < ss.length; i++) {
197 try {
198 ss[i] = (StackTraceElement)STACK_TRACE_ELEMENT_CONSTRUCTOR
199 .newInstance(new Object[] {tightUnmarshalString(dataIn, bs),
200 tightUnmarshalString(dataIn, bs),
201 tightUnmarshalString(dataIn, bs),
202 Integer.valueOf(dataIn.readInt())});
203 } catch (IOException e) {
204 throw e;
205 } catch (Throwable e) {
206 }
207 }
208 o.setStackTrace(ss);
209 } else {
210 short size = dataIn.readShort();
211 for (int i = 0; i < size; i++) {
212 tightUnmarshalString(dataIn, bs);
213 tightUnmarshalString(dataIn, bs);
214 tightUnmarshalString(dataIn, bs);
215 dataIn.readInt();
216 }
217 }
218 o.initCause(tightUnmarsalThrowable(wireFormat, dataIn, bs));
219
220 }
221 return o;
222 } else {
223 return null;
224 }
225 }
226
227 private Throwable createThrowable(String className, String message) {
228 try {
229 Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
230 Constructor constructor = clazz.getConstructor(new Class[] {String.class});
231 return (Throwable)constructor.newInstance(new Object[] {message});
232 } catch (Throwable e) {
233 return new Throwable(className + ": " + message);
234 }
235 }
236
237 protected int tightMarshalThrowable1(OpenWireFormat wireFormat, Throwable o, BooleanStream bs)
238 throws IOException {
239 if (o == null) {
240 bs.writeBoolean(false);
241 return 0;
242 } else {
243 int rc = 0;
244 bs.writeBoolean(true);
245 rc += tightMarshalString1(o.getClass().getName(), bs);
246 rc += tightMarshalString1(o.getMessage(), bs);
247 if (wireFormat.isStackTraceEnabled()) {
248 rc += 2;
249 StackTraceElement[] stackTrace = o.getStackTrace();
250 for (int i = 0; i < stackTrace.length; i++) {
251 StackTraceElement element = stackTrace[i];
252 rc += tightMarshalString1(element.getClassName(), bs);
253 rc += tightMarshalString1(element.getMethodName(), bs);
254 rc += tightMarshalString1(element.getFileName(), bs);
255 rc += 4;
256 }
257 rc += tightMarshalThrowable1(wireFormat, o.getCause(), bs);
258 }
259 return rc;
260 }
261 }
262
263 protected void tightMarshalThrowable2(OpenWireFormat wireFormat, Throwable o, DataOutput dataOut,
264 BooleanStream bs) throws IOException {
265 if (bs.readBoolean()) {
266 tightMarshalString2(o.getClass().getName(), dataOut, bs);
267 tightMarshalString2(o.getMessage(), dataOut, bs);
268 if (wireFormat.isStackTraceEnabled()) {
269 StackTraceElement[] stackTrace = o.getStackTrace();
270 dataOut.writeShort(stackTrace.length);
271 for (int i = 0; i < stackTrace.length; i++) {
272 StackTraceElement element = stackTrace[i];
273 tightMarshalString2(element.getClassName(), dataOut, bs);
274 tightMarshalString2(element.getMethodName(), dataOut, bs);
275 tightMarshalString2(element.getFileName(), dataOut, bs);
276 dataOut.writeInt(element.getLineNumber());
277 }
278 tightMarshalThrowable2(wireFormat, o.getCause(), dataOut, bs);
279 }
280 }
281 }
282
283 @SuppressWarnings("deprecation")
284 protected String tightUnmarshalString(DataInput dataIn, BooleanStream bs) throws IOException {
285 if (bs.readBoolean()) {
286 if (bs.readBoolean()) {
287 int size = dataIn.readShort();
288 byte data[] = new byte[size];
289 dataIn.readFully(data);
290 // Yes deprecated, but we know what we are doing.
291 // This allows us to create a String from a ASCII byte array. (no UTF-8 decoding)
292 return new String(data, 0);
293 } else {
294 return dataIn.readUTF();
295 }
296 } else {
297 return null;
298 }
299 }
300
301 protected int tightMarshalString1(String value, BooleanStream bs) throws IOException {
302 bs.writeBoolean(value != null);
303 if (value != null) {
304
305 int strlen = value.length();
306 int utflen = 0;
307 char[] charr = new char[strlen];
308 int c = 0;
309 boolean isOnlyAscii = true;
310
311 value.getChars(0, strlen, charr, 0);
312
313 for (int i = 0; i < strlen; i++) {
314 c = charr[i];
315 if ((c >= 0x0001) && (c <= 0x007F)) {
316 utflen++;
317 } else if (c > 0x07FF) {
318 utflen += 3;
319 isOnlyAscii = false;
320 } else {
321 isOnlyAscii = false;
322 utflen += 2;
323 }
324 }
325
326 if (utflen >= Short.MAX_VALUE) {
327 throw new IOException("Encountered a String value that is too long to encode.");
328 }
329 bs.writeBoolean(isOnlyAscii);
330 return utflen + 2;
331
332 } else {
333 return 0;
334 }
335 }
336
337 protected void tightMarshalString2(String value, DataOutput dataOut, BooleanStream bs) throws IOException {
338 if (bs.readBoolean()) {
339 // If we verified it only holds ascii values
340 if (bs.readBoolean()) {
341 dataOut.writeShort(value.length());
342 dataOut.writeBytes(value);
343 } else {
344 dataOut.writeUTF(value);
345 }
346 }
347 }
348
349 protected int tightMarshalObjectArray1(OpenWireFormat wireFormat, DataStructure[] objects,
350 BooleanStream bs) throws IOException {
351 if (objects != null) {
352 int rc = 0;
353 bs.writeBoolean(true);
354 rc += 2;
355 for (int i = 0; i < objects.length; i++) {
356 rc += tightMarshalNestedObject1(wireFormat, objects[i], bs);
357 }
358 return rc;
359 } else {
360 bs.writeBoolean(false);
361 return 0;
362 }
363 }
364
365 protected void tightMarshalObjectArray2(OpenWireFormat wireFormat, DataStructure[] objects,
366 DataOutput dataOut, BooleanStream bs) throws IOException {
367 if (bs.readBoolean()) {
368 dataOut.writeShort(objects.length);
369 for (int i = 0; i < objects.length; i++) {
370 tightMarshalNestedObject2(wireFormat, objects[i], dataOut, bs);
371 }
372 }
373 }
374
375 protected int tightMarshalConstByteArray1(byte[] data, BooleanStream bs, int i) throws IOException {
376 return i;
377 }
378
379 protected void tightMarshalConstByteArray2(byte[] data, DataOutput dataOut, BooleanStream bs, int i)
380 throws IOException {
381 dataOut.write(data, 0, i);
382 }
383
384 protected byte[] tightUnmarshalConstByteArray(DataInput dataIn, BooleanStream bs, int i)
385 throws IOException {
386 byte data[] = new byte[i];
387 dataIn.readFully(data);
388 return data;
389 }
390
391 protected int tightMarshalByteArray1(byte[] data, BooleanStream bs) throws IOException {
392 bs.writeBoolean(data != null);
393 if (data != null) {
394 return data.length + 4;
395 } else {
396 return 0;
397 }
398 }
399
400 protected void tightMarshalByteArray2(byte[] data, DataOutput dataOut, BooleanStream bs)
401 throws IOException {
402 if (bs.readBoolean()) {
403 dataOut.writeInt(data.length);
404 dataOut.write(data);
405 }
406 }
407
408 protected byte[] tightUnmarshalByteArray(DataInput dataIn, BooleanStream bs) throws IOException {
409 byte rc[] = null;
410 if (bs.readBoolean()) {
411 int size = dataIn.readInt();
412 rc = new byte[size];
413 dataIn.readFully(rc);
414 }
415 return rc;
416 }
417
418 protected int tightMarshalByteSequence1(ByteSequence data, BooleanStream bs) throws IOException {
419 bs.writeBoolean(data != null);
420 if (data != null) {
421 return data.getLength() + 4;
422 } else {
423 return 0;
424 }
425 }
426
427 protected void tightMarshalByteSequence2(ByteSequence data, DataOutput dataOut, BooleanStream bs)
428 throws IOException {
429 if (bs.readBoolean()) {
430 dataOut.writeInt(data.getLength());
431 dataOut.write(data.getData(), data.getOffset(), data.getLength());
432 }
433 }
434
435 protected ByteSequence tightUnmarshalByteSequence(DataInput dataIn, BooleanStream bs) throws IOException {
436 ByteSequence rc = null;
437 if (bs.readBoolean()) {
438 int size = dataIn.readInt();
439 byte[] t = new byte[size];
440 dataIn.readFully(t);
441 return new ByteSequence(t, 0, size);
442 }
443 return rc;
444 }
445
446 //
447 // The loose marshaling logic
448 //
449
450 public void looseMarshal(OpenWireFormat wireFormat, Object o, DataOutput dataOut) throws IOException {
451 }
452
453 public void looseUnmarshal(OpenWireFormat wireFormat, Object o, DataInput dataIn) throws IOException {
454 }
455
456 public void looseMarshalLong(OpenWireFormat wireFormat, long o, DataOutput dataOut) throws IOException {
457 dataOut.writeLong(o);
458 }
459
460 public long looseUnmarshalLong(OpenWireFormat wireFormat, DataInput dataIn) throws IOException {
461 return dataIn.readLong();
462 }
463
464 protected DataStructure looseUnmarsalNestedObject(OpenWireFormat wireFormat, DataInput dataIn)
465 throws IOException {
466 return wireFormat.looseUnmarshalNestedObject(dataIn);
467 }
468
469 protected void looseMarshalNestedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut)
470 throws IOException {
471 wireFormat.looseMarshalNestedObject(o, dataOut);
472 }
473
474 protected DataStructure looseUnmarsalCachedObject(OpenWireFormat wireFormat, DataInput dataIn)
475 throws IOException {
476 if (wireFormat.isCacheEnabled()) {
477 if (dataIn.readBoolean()) {
478 short index = dataIn.readShort();
479 DataStructure object = wireFormat.looseUnmarshalNestedObject(dataIn);
480 wireFormat.setInUnmarshallCache(index, object);
481 return object;
482 } else {
483 short index = dataIn.readShort();
484 return wireFormat.getFromUnmarshallCache(index);
485 }
486 } else {
487 return wireFormat.looseUnmarshalNestedObject(dataIn);
488 }
489 }
490
491 protected void looseMarshalCachedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut)
492 throws IOException {
493 if (wireFormat.isCacheEnabled()) {
494 Short index = wireFormat.getMarshallCacheIndex(o);
495 dataOut.writeBoolean(index == null);
496 if (index == null) {
497 index = wireFormat.addToMarshallCache(o);
498 dataOut.writeShort(index.shortValue());
499 wireFormat.looseMarshalNestedObject(o, dataOut);
500 } else {
501 dataOut.writeShort(index.shortValue());
502 }
503 } else {
504 wireFormat.looseMarshalNestedObject(o, dataOut);
505 }
506 }
507
508 protected Throwable looseUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn)
509 throws IOException {
510 if (dataIn.readBoolean()) {
511 String clazz = looseUnmarshalString(dataIn);
512 String message = looseUnmarshalString(dataIn);
513 Throwable o = createThrowable(clazz, message);
514 if (wireFormat.isStackTraceEnabled()) {
515 if (STACK_TRACE_ELEMENT_CONSTRUCTOR != null) {
516 StackTraceElement ss[] = new StackTraceElement[dataIn.readShort()];
517 for (int i = 0; i < ss.length; i++) {
518 try {
519 ss[i] = (StackTraceElement)STACK_TRACE_ELEMENT_CONSTRUCTOR
520 .newInstance(new Object[] {looseUnmarshalString(dataIn),
521 looseUnmarshalString(dataIn),
522 looseUnmarshalString(dataIn),
523 Integer.valueOf(dataIn.readInt())});
524 } catch (IOException e) {
525 throw e;
526 } catch (Throwable e) {
527 }
528 }
529 o.setStackTrace(ss);
530 } else {
531 short size = dataIn.readShort();
532 for (int i = 0; i < size; i++) {
533 looseUnmarshalString(dataIn);
534 looseUnmarshalString(dataIn);
535 looseUnmarshalString(dataIn);
536 dataIn.readInt();
537 }
538 }
539 o.initCause(looseUnmarsalThrowable(wireFormat, dataIn));
540
541 }
542 return o;
543 } else {
544 return null;
545 }
546 }
547
548 protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o, DataOutput dataOut)
549 throws IOException {
550 dataOut.writeBoolean(o != null);
551 if (o != null) {
552 looseMarshalString(o.getClass().getName(), dataOut);
553 looseMarshalString(o.getMessage(), dataOut);
554 if (wireFormat.isStackTraceEnabled()) {
555 StackTraceElement[] stackTrace = o.getStackTrace();
556 dataOut.writeShort(stackTrace.length);
557 for (int i = 0; i < stackTrace.length; i++) {
558 StackTraceElement element = stackTrace[i];
559 looseMarshalString(element.getClassName(), dataOut);
560 looseMarshalString(element.getMethodName(), dataOut);
561 looseMarshalString(element.getFileName(), dataOut);
562 dataOut.writeInt(element.getLineNumber());
563 }
564 looseMarshalThrowable(wireFormat, o.getCause(), dataOut);
565 }
566 }
567 }
568
569 protected String looseUnmarshalString(DataInput dataIn) throws IOException {
570 if (dataIn.readBoolean()) {
571 return dataIn.readUTF();
572 } else {
573 return null;
574 }
575 }
576
577 protected void looseMarshalString(String value, DataOutput dataOut) throws IOException {
578 dataOut.writeBoolean(value != null);
579 if (value != null) {
580 dataOut.writeUTF(value);
581 }
582 }
583
584 protected void looseMarshalObjectArray(OpenWireFormat wireFormat, DataStructure[] objects,
585 DataOutput dataOut) throws IOException {
586 dataOut.writeBoolean(objects != null);
587 if (objects != null) {
588 dataOut.writeShort(objects.length);
589 for (int i = 0; i < objects.length; i++) {
590 looseMarshalNestedObject(wireFormat, objects[i], dataOut);
591 }
592 }
593 }
594
595 protected void looseMarshalConstByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut,
596 int i) throws IOException {
597 dataOut.write(data, 0, i);
598 }
599
600 protected byte[] looseUnmarshalConstByteArray(DataInput dataIn, int i) throws IOException {
601 byte data[] = new byte[i];
602 dataIn.readFully(data);
603 return data;
604 }
605
606 protected void looseMarshalByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut)
607 throws IOException {
608 dataOut.writeBoolean(data != null);
609 if (data != null) {
610 dataOut.writeInt(data.length);
611 dataOut.write(data);
612 }
613 }
614
615 protected byte[] looseUnmarshalByteArray(DataInput dataIn) throws IOException {
616 byte rc[] = null;
617 if (dataIn.readBoolean()) {
618 int size = dataIn.readInt();
619 rc = new byte[size];
620 dataIn.readFully(rc);
621 }
622 return rc;
623 }
624
625 protected void looseMarshalByteSequence(OpenWireFormat wireFormat, ByteSequence data, DataOutput dataOut)
626 throws IOException {
627 dataOut.writeBoolean(data != null);
628 if (data != null) {
629 dataOut.writeInt(data.getLength());
630 dataOut.write(data.getData(), data.getOffset(), data.getLength());
631 }
632 }
633
634 protected ByteSequence looseUnmarshalByteSequence(DataInput dataIn) throws IOException {
635 ByteSequence rc = null;
636 if (dataIn.readBoolean()) {
637 int size = dataIn.readInt();
638 byte[] t = new byte[size];
639 dataIn.readFully(t);
640 rc = new ByteSequence(t, 0, size);
641 }
642 return rc;
643 }
644 }