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