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.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 new Integer(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 Constructor constructor = clazz.getConstructor(new Class[] {String.class}); 233 return (Throwable)constructor.newInstance(new Object[] {message}); 234 } catch (Throwable e) { 235 return new Throwable(className + ": " + message); 236 } 237 } 238 239 protected int tightMarshalThrowable1(OpenWireFormat wireFormat, Throwable o, BooleanStream bs) 240 throws IOException { 241 if (o == null) { 242 bs.writeBoolean(false); 243 return 0; 244 } else { 245 int rc = 0; 246 bs.writeBoolean(true); 247 rc += tightMarshalString1(o.getClass().getName(), bs); 248 rc += tightMarshalString1(cutMessageIfNeeded(o.getMessage()), bs); 249 if (wireFormat.isStackTraceEnabled()) { 250 rc += 2; 251 StackTraceElement[] stackTrace = o.getStackTrace(); 252 for (int i = 0; i < stackTrace.length; i++) { 253 StackTraceElement element = stackTrace[i]; 254 rc += tightMarshalString1(element.getClassName(), bs); 255 rc += tightMarshalString1(element.getMethodName(), bs); 256 rc += tightMarshalString1(element.getFileName(), bs); 257 rc += 4; 258 } 259 rc += tightMarshalThrowable1(wireFormat, o.getCause(), bs); 260 } 261 return rc; 262 } 263 } 264 265 protected void tightMarshalThrowable2(OpenWireFormat wireFormat, Throwable o, DataOutput dataOut, 266 BooleanStream bs) throws IOException { 267 if (bs.readBoolean()) { 268 tightMarshalString2(o.getClass().getName(), dataOut, bs); 269 tightMarshalString2(cutMessageIfNeeded(o.getMessage()), dataOut, bs); 270 if (wireFormat.isStackTraceEnabled()) { 271 StackTraceElement[] stackTrace = o.getStackTrace(); 272 dataOut.writeShort(stackTrace.length); 273 for (int i = 0; i < stackTrace.length; i++) { 274 StackTraceElement element = stackTrace[i]; 275 tightMarshalString2(element.getClassName(), dataOut, bs); 276 tightMarshalString2(element.getMethodName(), dataOut, bs); 277 tightMarshalString2(element.getFileName(), dataOut, bs); 278 dataOut.writeInt(element.getLineNumber()); 279 } 280 tightMarshalThrowable2(wireFormat, o.getCause(), dataOut, bs); 281 } 282 } 283 } 284 285 @SuppressWarnings("deprecation") 286 protected String tightUnmarshalString(DataInput dataIn, BooleanStream bs) throws IOException { 287 if (bs.readBoolean()) { 288 if (bs.readBoolean()) { 289 int size = dataIn.readShort(); 290 byte data[] = new byte[size]; 291 dataIn.readFully(data); 292 // Yes deprecated, but we know what we are doing. 293 // This allows us to create a String from a ASCII byte array. (no UTF-8 decoding) 294 return new String(data, 0); 295 } else { 296 return dataIn.readUTF(); 297 } 298 } else { 299 return null; 300 } 301 } 302 303 protected int tightMarshalString1(String value, BooleanStream bs) throws IOException { 304 bs.writeBoolean(value != null); 305 if (value != null) { 306 307 int strlen = value.length(); 308 int utflen = 0; 309 char[] charr = new char[strlen]; 310 int c = 0; 311 boolean isOnlyAscii = true; 312 313 value.getChars(0, strlen, charr, 0); 314 315 for (int i = 0; i < strlen; i++) { 316 c = charr[i]; 317 if ((c >= 0x0001) && (c <= 0x007F)) { 318 utflen++; 319 } else if (c > 0x07FF) { 320 utflen += 3; 321 isOnlyAscii = false; 322 } else { 323 isOnlyAscii = false; 324 utflen += 2; 325 } 326 } 327 328 if (utflen >= Short.MAX_VALUE) { 329 throw new IOException("Encountered a String value that is too long to encode."); 330 } 331 bs.writeBoolean(isOnlyAscii); 332 return utflen + 2; 333 334 } else { 335 return 0; 336 } 337 } 338 339 protected void tightMarshalString2(String value, DataOutput dataOut, BooleanStream bs) throws IOException { 340 if (bs.readBoolean()) { 341 // If we verified it only holds ascii values 342 if (bs.readBoolean()) { 343 dataOut.writeShort(value.length()); 344 dataOut.writeBytes(value); 345 } else { 346 dataOut.writeUTF(value); 347 } 348 } 349 } 350 351 protected int tightMarshalObjectArray1(OpenWireFormat wireFormat, DataStructure[] objects, 352 BooleanStream bs) throws IOException { 353 if (objects != null) { 354 int rc = 0; 355 bs.writeBoolean(true); 356 rc += 2; 357 for (int i = 0; i < objects.length; i++) { 358 rc += tightMarshalNestedObject1(wireFormat, objects[i], bs); 359 } 360 return rc; 361 } else { 362 bs.writeBoolean(false); 363 return 0; 364 } 365 } 366 367 protected void tightMarshalObjectArray2(OpenWireFormat wireFormat, DataStructure[] objects, 368 DataOutput dataOut, BooleanStream bs) throws IOException { 369 if (bs.readBoolean()) { 370 dataOut.writeShort(objects.length); 371 for (int i = 0; i < objects.length; i++) { 372 tightMarshalNestedObject2(wireFormat, objects[i], dataOut, bs); 373 } 374 } 375 } 376 377 protected int tightMarshalConstByteArray1(byte[] data, BooleanStream bs, int i) throws IOException { 378 return i; 379 } 380 381 protected void tightMarshalConstByteArray2(byte[] data, DataOutput dataOut, BooleanStream bs, int i) 382 throws IOException { 383 dataOut.write(data, 0, i); 384 } 385 386 protected byte[] tightUnmarshalConstByteArray(DataInput dataIn, BooleanStream bs, int i) 387 throws IOException { 388 byte data[] = new byte[i]; 389 dataIn.readFully(data); 390 return data; 391 } 392 393 protected int tightMarshalByteArray1(byte[] data, BooleanStream bs) throws IOException { 394 bs.writeBoolean(data != null); 395 if (data != null) { 396 return data.length + 4; 397 } else { 398 return 0; 399 } 400 } 401 402 protected void tightMarshalByteArray2(byte[] data, DataOutput dataOut, BooleanStream bs) 403 throws IOException { 404 if (bs.readBoolean()) { 405 dataOut.writeInt(data.length); 406 dataOut.write(data); 407 } 408 } 409 410 protected byte[] tightUnmarshalByteArray(DataInput dataIn, BooleanStream bs) throws IOException { 411 byte rc[] = null; 412 if (bs.readBoolean()) { 413 int size = dataIn.readInt(); 414 rc = new byte[size]; 415 dataIn.readFully(rc); 416 } 417 return rc; 418 } 419 420 protected int tightMarshalByteSequence1(ByteSequence data, BooleanStream bs) throws IOException { 421 bs.writeBoolean(data != null); 422 if (data != null) { 423 return data.getLength() + 4; 424 } else { 425 return 0; 426 } 427 } 428 429 protected void tightMarshalByteSequence2(ByteSequence data, DataOutput dataOut, BooleanStream bs) 430 throws IOException { 431 if (bs.readBoolean()) { 432 dataOut.writeInt(data.getLength()); 433 dataOut.write(data.getData(), data.getOffset(), data.getLength()); 434 } 435 } 436 437 protected ByteSequence tightUnmarshalByteSequence(DataInput dataIn, BooleanStream bs) throws IOException { 438 ByteSequence rc = null; 439 if (bs.readBoolean()) { 440 int size = dataIn.readInt(); 441 byte[] t = new byte[size]; 442 dataIn.readFully(t); 443 return new ByteSequence(t, 0, size); 444 } 445 return rc; 446 } 447 448 // 449 // The loose marshaling logic 450 // 451 452 public void looseMarshal(OpenWireFormat wireFormat, Object o, DataOutput dataOut) throws IOException { 453 } 454 455 public void looseUnmarshal(OpenWireFormat wireFormat, Object o, DataInput dataIn) throws IOException { 456 } 457 458 public void looseMarshalLong(OpenWireFormat wireFormat, long o, DataOutput dataOut) throws IOException { 459 dataOut.writeLong(o); 460 } 461 462 public long looseUnmarshalLong(OpenWireFormat wireFormat, DataInput dataIn) throws IOException { 463 return dataIn.readLong(); 464 } 465 466 protected DataStructure looseUnmarsalNestedObject(OpenWireFormat wireFormat, DataInput dataIn) 467 throws IOException { 468 return wireFormat.looseUnmarshalNestedObject(dataIn); 469 } 470 471 protected void looseMarshalNestedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut) 472 throws IOException { 473 wireFormat.looseMarshalNestedObject(o, dataOut); 474 } 475 476 protected DataStructure looseUnmarsalCachedObject(OpenWireFormat wireFormat, DataInput dataIn) 477 throws IOException { 478 if (wireFormat.isCacheEnabled()) { 479 if (dataIn.readBoolean()) { 480 short index = dataIn.readShort(); 481 DataStructure object = wireFormat.looseUnmarshalNestedObject(dataIn); 482 wireFormat.setInUnmarshallCache(index, object); 483 return object; 484 } else { 485 short index = dataIn.readShort(); 486 return wireFormat.getFromUnmarshallCache(index); 487 } 488 } else { 489 return wireFormat.looseUnmarshalNestedObject(dataIn); 490 } 491 } 492 493 protected void looseMarshalCachedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut) 494 throws IOException { 495 if (wireFormat.isCacheEnabled()) { 496 Short index = wireFormat.getMarshallCacheIndex(o); 497 dataOut.writeBoolean(index == null); 498 if (index == null) { 499 index = wireFormat.addToMarshallCache(o); 500 dataOut.writeShort(index.shortValue()); 501 wireFormat.looseMarshalNestedObject(o, dataOut); 502 } else { 503 dataOut.writeShort(index.shortValue()); 504 } 505 } else { 506 wireFormat.looseMarshalNestedObject(o, dataOut); 507 } 508 } 509 510 protected Throwable looseUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn) 511 throws IOException { 512 if (dataIn.readBoolean()) { 513 String clazz = looseUnmarshalString(dataIn); 514 String message = looseUnmarshalString(dataIn); 515 Throwable o = createThrowable(clazz, message); 516 if (wireFormat.isStackTraceEnabled()) { 517 if (STACK_TRACE_ELEMENT_CONSTRUCTOR != null) { 518 StackTraceElement ss[] = new StackTraceElement[dataIn.readShort()]; 519 for (int i = 0; i < ss.length; i++) { 520 try { 521 ss[i] = (StackTraceElement)STACK_TRACE_ELEMENT_CONSTRUCTOR 522 .newInstance(new Object[] {looseUnmarshalString(dataIn), 523 looseUnmarshalString(dataIn), 524 looseUnmarshalString(dataIn), 525 new Integer(dataIn.readInt())}); 526 } catch (IOException e) { 527 throw e; 528 } catch (Throwable e) { 529 } 530 } 531 o.setStackTrace(ss); 532 } else { 533 short size = dataIn.readShort(); 534 for (int i = 0; i < size; i++) { 535 looseUnmarshalString(dataIn); 536 looseUnmarshalString(dataIn); 537 looseUnmarshalString(dataIn); 538 dataIn.readInt(); 539 } 540 } 541 o.initCause(looseUnmarsalThrowable(wireFormat, dataIn)); 542 543 } 544 return o; 545 } else { 546 return null; 547 } 548 } 549 550 protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o, DataOutput dataOut) 551 throws IOException { 552 dataOut.writeBoolean(o != null); 553 if (o != null) { 554 looseMarshalString(o.getClass().getName(), dataOut); 555 looseMarshalString(cutMessageIfNeeded(o.getMessage()), dataOut); 556 if (wireFormat.isStackTraceEnabled()) { 557 StackTraceElement[] stackTrace = o.getStackTrace(); 558 dataOut.writeShort(stackTrace.length); 559 for (int i = 0; i < stackTrace.length; i++) { 560 StackTraceElement element = stackTrace[i]; 561 looseMarshalString(element.getClassName(), dataOut); 562 looseMarshalString(element.getMethodName(), dataOut); 563 looseMarshalString(element.getFileName(), dataOut); 564 dataOut.writeInt(element.getLineNumber()); 565 } 566 looseMarshalThrowable(wireFormat, o.getCause(), dataOut); 567 } 568 } 569 } 570 571 protected String looseUnmarshalString(DataInput dataIn) throws IOException { 572 if (dataIn.readBoolean()) { 573 return dataIn.readUTF(); 574 } else { 575 return null; 576 } 577 } 578 579 protected void looseMarshalString(String value, DataOutput dataOut) throws IOException { 580 dataOut.writeBoolean(value != null); 581 if (value != null) { 582 dataOut.writeUTF(value); 583 } 584 } 585 586 protected void looseMarshalObjectArray(OpenWireFormat wireFormat, DataStructure[] objects, 587 DataOutput dataOut) throws IOException { 588 dataOut.writeBoolean(objects != null); 589 if (objects != null) { 590 dataOut.writeShort(objects.length); 591 for (int i = 0; i < objects.length; i++) { 592 looseMarshalNestedObject(wireFormat, objects[i], dataOut); 593 } 594 } 595 } 596 597 protected void looseMarshalConstByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut, 598 int i) throws IOException { 599 dataOut.write(data, 0, i); 600 } 601 602 protected byte[] looseUnmarshalConstByteArray(DataInput dataIn, int i) throws IOException { 603 byte data[] = new byte[i]; 604 dataIn.readFully(data); 605 return data; 606 } 607 608 protected void looseMarshalByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut) 609 throws IOException { 610 dataOut.writeBoolean(data != null); 611 if (data != null) { 612 dataOut.writeInt(data.length); 613 dataOut.write(data); 614 } 615 } 616 617 protected byte[] looseUnmarshalByteArray(DataInput dataIn) throws IOException { 618 byte rc[] = null; 619 if (dataIn.readBoolean()) { 620 int size = dataIn.readInt(); 621 rc = new byte[size]; 622 dataIn.readFully(rc); 623 } 624 return rc; 625 } 626 627 protected void looseMarshalByteSequence(OpenWireFormat wireFormat, ByteSequence data, DataOutput dataOut) 628 throws IOException { 629 dataOut.writeBoolean(data != null); 630 if (data != null) { 631 dataOut.writeInt(data.getLength()); 632 dataOut.write(data.getData(), data.getOffset(), data.getLength()); 633 } 634 } 635 636 protected ByteSequence looseUnmarshalByteSequence(DataInput dataIn) throws IOException { 637 ByteSequence rc = null; 638 if (dataIn.readBoolean()) { 639 int size = dataIn.readInt(); 640 byte[] t = new byte[size]; 641 dataIn.readFully(t); 642 rc = new ByteSequence(t, 0, size); 643 } 644 return rc; 645 } 646 647 protected String cutMessageIfNeeded(final String message) { 648 return (message.length() > MAX_EXCEPTION_MESSAGE_SIZE)? 649 message.substring(0, MAX_EXCEPTION_MESSAGE_SIZE - 3) + "..." : message; 650 651 } 652}