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(DataInput dataIn, BooleanStream bs) throws IOException { 415 byte rc[] = null; 416 if (bs.readBoolean()) { 417 int size = dataIn.readInt(); 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(DataInput dataIn, BooleanStream bs) throws IOException { 442 ByteSequence rc = null; 443 if (bs.readBoolean()) { 444 int size = dataIn.readInt(); 445 byte[] t = new byte[size]; 446 dataIn.readFully(t); 447 return new ByteSequence(t, 0, size); 448 } 449 return rc; 450 } 451 452 // 453 // The loose marshaling logic 454 // 455 456 public void looseMarshal(OpenWireFormat wireFormat, Object o, DataOutput dataOut) throws IOException { 457 } 458 459 public void looseUnmarshal(OpenWireFormat wireFormat, Object o, DataInput dataIn) throws IOException { 460 } 461 462 public void looseMarshalLong(OpenWireFormat wireFormat, long o, DataOutput dataOut) throws IOException { 463 dataOut.writeLong(o); 464 } 465 466 public long looseUnmarshalLong(OpenWireFormat wireFormat, DataInput dataIn) throws IOException { 467 return dataIn.readLong(); 468 } 469 470 protected DataStructure looseUnmarsalNestedObject(OpenWireFormat wireFormat, DataInput dataIn) 471 throws IOException { 472 return wireFormat.looseUnmarshalNestedObject(dataIn); 473 } 474 475 protected void looseMarshalNestedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut) 476 throws IOException { 477 wireFormat.looseMarshalNestedObject(o, dataOut); 478 } 479 480 protected DataStructure looseUnmarsalCachedObject(OpenWireFormat wireFormat, DataInput dataIn) 481 throws IOException { 482 if (wireFormat.isCacheEnabled()) { 483 if (dataIn.readBoolean()) { 484 short index = dataIn.readShort(); 485 DataStructure object = wireFormat.looseUnmarshalNestedObject(dataIn); 486 wireFormat.setInUnmarshallCache(index, object); 487 return object; 488 } else { 489 short index = dataIn.readShort(); 490 return wireFormat.getFromUnmarshallCache(index); 491 } 492 } else { 493 return wireFormat.looseUnmarshalNestedObject(dataIn); 494 } 495 } 496 497 protected void looseMarshalCachedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut) 498 throws IOException { 499 if (wireFormat.isCacheEnabled()) { 500 Short index = wireFormat.getMarshallCacheIndex(o); 501 dataOut.writeBoolean(index == null); 502 if (index == null) { 503 index = wireFormat.addToMarshallCache(o); 504 dataOut.writeShort(index.shortValue()); 505 wireFormat.looseMarshalNestedObject(o, dataOut); 506 } else { 507 dataOut.writeShort(index.shortValue()); 508 } 509 } else { 510 wireFormat.looseMarshalNestedObject(o, dataOut); 511 } 512 } 513 514 protected Throwable looseUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn) 515 throws IOException { 516 if (dataIn.readBoolean()) { 517 String clazz = looseUnmarshalString(dataIn); 518 String message = looseUnmarshalString(dataIn); 519 Throwable o = createThrowable(clazz, message); 520 if (wireFormat.isStackTraceEnabled()) { 521 if (STACK_TRACE_ELEMENT_CONSTRUCTOR != null) { 522 StackTraceElement ss[] = new StackTraceElement[dataIn.readShort()]; 523 for (int i = 0; i < ss.length; i++) { 524 try { 525 ss[i] = (StackTraceElement)STACK_TRACE_ELEMENT_CONSTRUCTOR 526 .newInstance(new Object[] {looseUnmarshalString(dataIn), 527 looseUnmarshalString(dataIn), 528 looseUnmarshalString(dataIn), 529 new Integer(dataIn.readInt())}); 530 } catch (IOException e) { 531 throw e; 532 } catch (Throwable e) { 533 } 534 } 535 o.setStackTrace(ss); 536 } else { 537 short size = dataIn.readShort(); 538 for (int i = 0; i < size; i++) { 539 looseUnmarshalString(dataIn); 540 looseUnmarshalString(dataIn); 541 looseUnmarshalString(dataIn); 542 dataIn.readInt(); 543 } 544 } 545 o.initCause(looseUnmarsalThrowable(wireFormat, dataIn)); 546 547 } 548 return o; 549 } else { 550 return null; 551 } 552 } 553 554 protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o, DataOutput dataOut) 555 throws IOException { 556 dataOut.writeBoolean(o != null); 557 if (o != null) { 558 looseMarshalString(o.getClass().getName(), dataOut); 559 looseMarshalString(cutMessageIfNeeded(o.getMessage()), dataOut); 560 if (wireFormat.isStackTraceEnabled()) { 561 StackTraceElement[] stackTrace = o.getStackTrace(); 562 dataOut.writeShort(stackTrace.length); 563 for (int i = 0; i < stackTrace.length; i++) { 564 StackTraceElement element = stackTrace[i]; 565 looseMarshalString(element.getClassName(), dataOut); 566 looseMarshalString(element.getMethodName(), dataOut); 567 looseMarshalString(element.getFileName(), dataOut); 568 dataOut.writeInt(element.getLineNumber()); 569 } 570 looseMarshalThrowable(wireFormat, o.getCause(), dataOut); 571 } 572 } 573 } 574 575 protected String looseUnmarshalString(DataInput dataIn) throws IOException { 576 if (dataIn.readBoolean()) { 577 return dataIn.readUTF(); 578 } else { 579 return null; 580 } 581 } 582 583 protected void looseMarshalString(String value, DataOutput dataOut) throws IOException { 584 dataOut.writeBoolean(value != null); 585 if (value != null) { 586 dataOut.writeUTF(value); 587 } 588 } 589 590 protected void looseMarshalObjectArray(OpenWireFormat wireFormat, DataStructure[] objects, 591 DataOutput dataOut) throws IOException { 592 dataOut.writeBoolean(objects != null); 593 if (objects != null) { 594 dataOut.writeShort(objects.length); 595 for (int i = 0; i < objects.length; i++) { 596 looseMarshalNestedObject(wireFormat, objects[i], dataOut); 597 } 598 } 599 } 600 601 protected void looseMarshalConstByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut, 602 int i) throws IOException { 603 dataOut.write(data, 0, i); 604 } 605 606 protected byte[] looseUnmarshalConstByteArray(DataInput dataIn, int i) throws IOException { 607 byte data[] = new byte[i]; 608 dataIn.readFully(data); 609 return data; 610 } 611 612 protected void looseMarshalByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut) 613 throws IOException { 614 dataOut.writeBoolean(data != null); 615 if (data != null) { 616 dataOut.writeInt(data.length); 617 dataOut.write(data); 618 } 619 } 620 621 protected byte[] looseUnmarshalByteArray(DataInput dataIn) throws IOException { 622 byte rc[] = null; 623 if (dataIn.readBoolean()) { 624 int size = dataIn.readInt(); 625 rc = new byte[size]; 626 dataIn.readFully(rc); 627 } 628 return rc; 629 } 630 631 protected void looseMarshalByteSequence(OpenWireFormat wireFormat, ByteSequence data, DataOutput dataOut) 632 throws IOException { 633 dataOut.writeBoolean(data != null); 634 if (data != null) { 635 dataOut.writeInt(data.getLength()); 636 dataOut.write(data.getData(), data.getOffset(), data.getLength()); 637 } 638 } 639 640 protected ByteSequence looseUnmarshalByteSequence(DataInput dataIn) throws IOException { 641 ByteSequence rc = null; 642 if (dataIn.readBoolean()) { 643 int size = dataIn.readInt(); 644 byte[] t = new byte[size]; 645 dataIn.readFully(t); 646 rc = new ByteSequence(t, 0, size); 647 } 648 return rc; 649 } 650 651 protected String cutMessageIfNeeded(final String message) { 652 return (message.length() > MAX_EXCEPTION_MESSAGE_SIZE)? 653 message.substring(0, MAX_EXCEPTION_MESSAGE_SIZE - 3) + "..." : message; 654 655 } 656}