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