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