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