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