1 /* 2 * hunt-proton: AMQP Protocol library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.proton.codec.MapType; 13 14 import hunt.proton.codec.PrimitiveTypeEncoding; 15 import hunt.proton.codec.AMQPType; 16 import hunt.proton.codec.EncoderImpl; 17 import hunt.proton.codec.DecoderImpl; 18 import hunt.proton.codec.AbstractPrimitiveType; 19 import hunt.collection.Collection; 20 import hunt.collection.Map; 21 import hunt.collection.ArrayList; 22 import hunt.proton.codec.LargeFloatingSizePrimitiveTypeEncoding; 23 import hunt.Exceptions; 24 import hunt.Object; 25 import hunt.collection.Map; 26 import hunt.String; 27 import hunt.proton.codec.TypeEncoding; 28 import hunt.proton.codec.EncodingCodes; 29 import hunt.proton.codec.StringType; 30 import hunt.collection.LinkedHashMap; 31 import hunt.proton.codec.TypeConstructor; 32 import hunt.proton.codec.ReadableBuffer; 33 import hunt.proton.codec.SmallFloatingSizePrimitiveTypeEncoding; 34 import hunt.logging; 35 import std.conv : to; 36 37 interface MapEncoding : PrimitiveTypeEncoding!(Map!(String,Object)) 38 { 39 void setValue(Map!(String,Object) value, int length); 40 } 41 42 class MapType : AbstractPrimitiveType!(Map!(String,Object)) 43 { 44 private MapEncoding _mapEncoding; 45 private MapEncoding _shortMapEncoding; 46 private EncoderImpl _encoder; 47 48 //private AMQPType<?> fixedKeyType; 49 50 private IAMQPType fixedKeyType; 51 52 53 this(EncoderImpl encoder, DecoderImpl decoder) 54 { 55 _encoder = encoder; 56 _mapEncoding = new AllMapEncoding(encoder, decoder); 57 _shortMapEncoding = new ShortMapEncoding(encoder, decoder); 58 encoder.register(typeid(LinkedHashMap!(String,Object)), this); 59 decoder.register(this); 60 } 61 62 public TypeInfo getTypeClass() 63 { 64 return typeid(LinkedHashMap!(String,Object)); 65 } 66 67 public void setKeyEncoding(IAMQPType keyType) 68 { 69 this.fixedKeyType = keyType; 70 } 71 72 public ITypeEncoding getEncoding(Object val) 73 { 74 int calculatedSize = calculateSize(cast(Map!(String,Object))val); 75 MapEncoding encoding = ((cast(Map!(String,Object))val).size() > 127 || calculatedSize >= 254) 76 ? _mapEncoding 77 : _shortMapEncoding; 78 79 encoding.setValue(cast(Map!(String,Object))val, calculatedSize); 80 return encoding; 81 } 82 83 private int calculateSize(Map!(String,Object) map) 84 { 85 86 //implementationMissing(false); 87 int len = 0; 88 89 //Iterator<Map.Entry<?, ?>> iter = map.entrySet().iterator(); 90 IAMQPType IfixedKeyType = this.fixedKeyType; 91 92 // Clear existing fixed key type encoding to prevent application to nested Maps 93 setKeyEncoding(null); 94 95 try 96 { 97 98 foreach (MapEntry!(String, Object) element ; map) 99 { 100 ITypeEncoding elementEncoding; 101 if (IfixedKeyType is null) 102 { 103 IAMQPType tmp = _encoder.getType( element.getKey()); 104 if (tmp is null) 105 { 106 logError( "getType Error"); 107 } 108 109 elementEncoding = tmp.getEncoding( element.getKey()); 110 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 111 } 112 else 113 { 114 elementEncoding = IfixedKeyType.getEncoding( element.getKey()); 115 } 116 117 len += elementEncoding.getConstructorSize() + elementEncoding.getValueSize( element.getKey()); 118 119 120 121 122 IAMQPType tmp = (_encoder.getType( element.getValue())); 123 if (tmp is null) 124 { 125 logError( "getType Error"); 126 } 127 ITypeEncoding elementEncodingVal = tmp.getEncoding( element.getValue()); 128 len += elementEncodingVal.getConstructorSize() + elementEncodingVal.getValueSize( element.getValue()); 129 130 131 //if (cast(String)element.getValue() !is null) 132 //{ 133 // StringType tmp = cast(StringType)(_encoder.getType(element.getValue())); 134 // if (tmp is null) 135 // { 136 // logError("getType Error"); 137 // } 138 // 139 // StringEncoding elementEncodingVal = tmp.getEncoding(cast(String)element.getValue()); 140 // len += elementEncodingVal.getConstructorSize() + elementEncodingVal.getValueSize(cast(String)element.getValue()); 141 //}else 142 //{ 143 // logError("unknown type"); 144 //} 145 } 146 } finally { 147 setKeyEncoding(IfixedKeyType); 148 } 149 150 151 152 //try { 153 // while (iter.hasNext()) 154 // { 155 // Map.Entry<?, ?> element = iter.next(); 156 // TypeEncoding elementEncoding; 157 // 158 // if (fixedKeyType is null) 159 // { 160 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 161 // } 162 // else 163 // { 164 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 165 // } 166 // 167 // len += elementEncoding.getConstructorSize() + elementEncoding.getValueSize(element.getKey()); 168 // elementEncoding = _encoder.getType(element.getValue()).getEncoding(element.getValue()); 169 // len += elementEncoding.getConstructorSize() + elementEncoding.getValueSize(element.getValue()); 170 // } 171 //} finally { 172 // // Reset Existing key type encoding for later encode step or reuse until cleared by caller 173 // setKeyEncoding(fixedKeyType); 174 //} 175 176 //scope(exit) 177 //{ 178 // setKeyEncoding(IfixedKeyType); 179 //} 180 181 return len; 182 } 183 184 185 private static ITypeConstructor findNextDecoder(DecoderImpl decoder, ReadableBuffer buffer, ITypeConstructor previousConstructor) 186 { 187 if (previousConstructor is null) 188 { 189 return decoder.readConstructor(); 190 } 191 else 192 { 193 byte encodingCode = buffer.get(buffer.position()); 194 if (encodingCode == EncodingCodes.DESCRIBED_TYPE_INDICATOR) 195 { 196 return decoder.readConstructor(); 197 } 198 else 199 { 200 IPrimitiveTypeEncoding primitiveConstructor = cast(IPrimitiveTypeEncoding) previousConstructor; 201 if (encodingCode != primitiveConstructor.getEncodingCode()) 202 { 203 return decoder.readConstructor(); 204 } 205 else 206 { 207 // consume the encoding code byte for real 208 encodingCode = buffer.get(); 209 } 210 } 211 } 212 213 return previousConstructor; 214 } 215 216 public MapEncoding getCanonicalEncoding() 217 { 218 return _mapEncoding; 219 } 220 221 222 223 //Collection!(TypeEncoding!(Map!(String,Object))) 224 public Collection!(TypeEncoding!(Map!(String,Object))) getAllEncodings() 225 { 226 ArrayList!(TypeEncoding!(Map!(String,Object))) lst = new ArrayList!(TypeEncoding!(Map!(String,Object)))(); 227 lst.add(_shortMapEncoding); 228 lst.add(_mapEncoding); 229 return lst; 230 // return Arrays.asList(_shortMapEncoding, _mapEncoding); 231 } 232 233 class AllMapEncoding 234 : LargeFloatingSizePrimitiveTypeEncoding!(Map!(String,Object)) 235 , MapEncoding 236 { 237 238 private Map!(String,Object) _value; 239 private int _length; 240 241 this(EncoderImpl encoder, DecoderImpl decoder) 242 { 243 super(encoder, decoder); 244 } 245 246 override 247 protected void writeEncodedValue(Map!(String,Object) map) 248 { 249 getEncoder().getBuffer().ensureRemaining(getSizeBytes() + getEncodedValueSize(map)); 250 getEncoder().writeRaw(2 * map.size()); 251 252 // Iterator<Map.Entry> iter = map.entrySet().iterator(); 253 IAMQPType IfixedKeyType = this.outer.fixedKeyType; 254 255 // Clear existing fixed key type encoding to prevent application to nested Maps 256 setKeyEncoding(null); 257 258 try 259 { 260 foreach (MapEntry!(String, Object) element ; map) 261 { 262 ITypeEncoding elementEncoding; 263 if (IfixedKeyType is null) 264 { 265 StringType tmp = cast(StringType)(_encoder.getType( element.getKey())); 266 if (tmp is null) 267 { 268 logError( "getType Error"); 269 } 270 271 elementEncoding = tmp.getEncoding( element.getKey()); 272 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 273 } 274 else 275 { 276 elementEncoding = IfixedKeyType.getEncoding( element.getKey()); 277 } 278 279 elementEncoding.writeConstructor(); 280 elementEncoding.writeValue( element.getKey()); 281 282 ITypeEncoding elementEncodingVal; 283 elementEncodingVal = _encoder.getType( element.getValue()).getEncoding( element.getValue()); 284 //if (tmp is null) 285 //{ 286 // logError("getType error"); 287 //} 288 // elementEncodingVal = tmp.getEncoding(cast(String)element.getValue()); 289 elementEncodingVal.writeConstructor(); 290 elementEncodingVal.writeValue( element.getValue()); 291 292 //elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 293 //elementEncoding.writeConstructor(); 294 //elementEncoding.writeValue(element.getValue()); 295 296 } 297 } finally { 298 setKeyEncoding(IfixedKeyType); 299 } 300 301 //try { 302 // while (iter.hasNext()) 303 // { 304 // // Map.Entry<?, ?> element = iter.next(); 305 // TypeEncoding elementEncoding; 306 // 307 // if (fixedKeyType is null) 308 // { 309 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 310 // } 311 // else 312 // { 313 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 314 // } 315 // 316 // elementEncoding.writeConstructor(); 317 // elementEncoding.writeValue(element.getKey()); 318 // elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 319 // elementEncoding.writeConstructor(); 320 // elementEncoding.writeValue(element.getValue()); 321 // } 322 //} finally { 323 // // Reset Existing key type encoding for later encode step or reuse until cleared by caller 324 // setKeyEncoding(fixedKeyType); 325 //} 326 } 327 328 override 329 protected int getEncodedValueSize(Map!(String,Object) val) 330 { 331 return 4 + ((val == _value) ? _length : calculateSize(val)); 332 } 333 334 override 335 public byte getEncodingCode() 336 { 337 return EncodingCodes.MAP32; 338 } 339 340 override 341 public MapType getType() 342 { 343 return this.outer; 344 } 345 346 override 347 public bool encodesSuperset(TypeEncoding!(Map!(String,Object)) encoding) 348 { 349 return (getType() == encoding.getType()); 350 } 351 352 override 353 public Object readValue() 354 { 355 DecoderImpl decoder = getDecoder(); 356 ReadableBuffer buffer = decoder.getBuffer(); 357 358 int size = decoder.readRawInt(); 359 // todo - limit the decoder with size 360 int count = decoder.readRawInt(); 361 if (count > decoder.getByteBufferRemaining()) { 362 throw new IllegalArgumentException("Map element count " ~ to!string(count) ~" is specified to be greater than the amount of data available ("~ 363 to!string(decoder.getByteBufferRemaining())~ ")"); 364 } 365 366 ITypeConstructor keyConstructor = null; 367 ITypeConstructor valueConstructor = null; 368 369 Map!(String, Object) map = new LinkedHashMap!(String,Object)(count); 370 for(int i = 0; i < count / 2; i++) 371 { 372 keyConstructor = findNextDecoder(decoder, buffer, keyConstructor); 373 if(keyConstructor is null) 374 { 375 // throw new DecodeException("Unknown constructor"); 376 logError("Unknown constructor"); 377 return null; 378 } 379 380 String key = cast(String)keyConstructor.readValue(); 381 382 bool arrayType = false; 383 byte code = buffer.get(buffer.position()); 384 switch (code) 385 { 386 case EncodingCodes.ARRAY8: 387 goto case; 388 case EncodingCodes.ARRAY32: 389 arrayType = true; 390 break; 391 default: 392 break; 393 } 394 395 valueConstructor = findNextDecoder(decoder, buffer, valueConstructor); 396 if (valueConstructor is null) 397 { 398 // throw new DecodeException("Unknown constructor"); 399 logError("Unknown constructor"); 400 return null; 401 } 402 403 Object value; 404 405 //if (arrayType) 406 //{ 407 // value = ((ArrayType.ArrayEncoding) valueConstructor).readValueArray(); 408 //} 409 //else 410 { 411 value = valueConstructor.readValue(); 412 } 413 414 map.put(key, value); 415 } 416 417 return cast(Object)map; 418 } 419 420 override 421 public void skipValue() 422 { 423 DecoderImpl decoder = getDecoder(); 424 ReadableBuffer buffer = decoder.getBuffer(); 425 int size = decoder.readRawInt(); 426 buffer.position(buffer.position() + size); 427 } 428 429 public void setValue(Map!(String,Object) value, int length) 430 { 431 _value = value; 432 _length = length; 433 } 434 435 override 436 void writeConstructor() 437 { 438 super.writeConstructor(); 439 } 440 441 override int getConstructorSize() 442 { 443 return super.getConstructorSize(); 444 } 445 446 447 } 448 449 class ShortMapEncoding 450 : SmallFloatingSizePrimitiveTypeEncoding!(Map!(String,Object)) 451 , MapEncoding 452 { 453 private Map!(String,Object) _value; 454 private int _length; 455 456 this(EncoderImpl encoder, DecoderImpl decoder) 457 { 458 super(encoder, decoder); 459 } 460 461 override 462 protected void writeEncodedValue(Map!(String,Object) map) 463 { 464 getEncoder().getBuffer().ensureRemaining(getSizeBytes() + getEncodedValueSize(map)); 465 getEncoder().writeRaw(cast(byte)(2 * map.size())); 466 467 // Iterator<Map.Entry> iter = map.entrySet().iterator(); 468 469 IAMQPType IfixedKeyType = this.outer.fixedKeyType; 470 471 // Clear existing fixed key type encoding to prevent application to nested Maps 472 setKeyEncoding(null); 473 474 try 475 { 476 foreach (MapEntry!(String, Object) element ; map) 477 { 478 ITypeEncoding elementEncoding; 479 if (IfixedKeyType is null) 480 { 481 IAMQPType tmp = _encoder.getType( element.getKey()); 482 if (tmp is null) 483 { 484 logError( "getType error"); 485 } 486 elementEncoding = tmp.getEncoding( element.getKey()); 487 } 488 else 489 { 490 elementEncoding = IfixedKeyType.getEncoding( element.getKey()); 491 } 492 493 elementEncoding.writeConstructor(); 494 elementEncoding.writeValue( element.getKey()); 495 496 elementEncoding = getEncoder().getType( element.getValue()).getEncoding( element.getValue()); 497 elementEncoding.writeConstructor(); 498 elementEncoding.writeValue( element.getValue()); 499 } 500 501 } finally 502 { 503 setKeyEncoding(IfixedKeyType); 504 } 505 //try { 506 // while (iter.hasNext()) 507 // { 508 // Map.Entry<?, ?> element = iter.next(); 509 // TypeEncoding elementEncoding; 510 // 511 // if (fixedKeyType is null) 512 // { 513 // elementEncoding = _encoder.getType(element.getKey()).getEncoding(element.getKey()); 514 // } 515 // else 516 // { 517 // elementEncoding = fixedKeyType.getEncoding(element.getKey()); 518 // } 519 // 520 // elementEncoding.writeConstructor(); 521 // elementEncoding.writeValue(element.getKey()); 522 // elementEncoding = getEncoder().getType(element.getValue()).getEncoding(element.getValue()); 523 // elementEncoding.writeConstructor(); 524 // elementEncoding.writeValue(element.getValue()); 525 // } 526 //} finally { 527 // // Reset Existing key type encoding for later encode step or reuse until cleared by caller 528 // setKeyEncoding(fixedKeyType); 529 //} 530 } 531 532 override 533 protected int getEncodedValueSize(Map!(String,Object) val) 534 { 535 return 1 + ((val == _value) ? _length : calculateSize(val)); 536 } 537 538 override 539 public byte getEncodingCode() 540 { 541 return EncodingCodes.MAP8; 542 } 543 544 override 545 public MapType getType() 546 { 547 return this.outer; 548 } 549 550 override 551 public bool encodesSuperset(TypeEncoding!(Map!(String,Object)) encoder) 552 { 553 return encoder == this; 554 } 555 556 override 557 public Object readValue() 558 { 559 DecoderImpl decoder = getDecoder(); 560 ReadableBuffer buffer = decoder.getBuffer(); 561 562 int size = (decoder.readRawByte()) & 0xff; 563 // todo - limit the decoder with size 564 int count = (decoder.readRawByte()) & 0xff; 565 566 ITypeConstructor keyConstructor = null; 567 ITypeConstructor valueConstructor = null; 568 569 Map!(String, Object) map = new LinkedHashMap!(String, Object)(count); 570 for(int i = 0; i < count / 2; i++) 571 { 572 keyConstructor = findNextDecoder(decoder, buffer, keyConstructor); 573 if(keyConstructor is null) 574 { 575 logError("Unknown constructor"); 576 return null; 577 // throw new DecodeException("Unknown constructor"); 578 } 579 580 String key = cast(String)keyConstructor.readValue(); 581 582 bool arrayType = false; 583 byte code = buffer.get(buffer.position()); 584 switch (code) 585 { 586 case EncodingCodes.ARRAY8: 587 goto case; 588 case EncodingCodes.ARRAY32: 589 arrayType = true; 590 break; 591 default: 592 break; 593 } 594 595 valueConstructor = findNextDecoder(decoder, buffer, valueConstructor); 596 if(valueConstructor is null) 597 { 598 //throw new DecodeException("Unknown constructor"); 599 logError("Unknown constructor"); 600 return null; 601 } 602 603 Object value; 604 605 //if (arrayType) 606 //{ 607 // value = ((ArrayType.ArrayEncoding) valueConstructor).readValueArray(); 608 //} 609 //else 610 { 611 value = valueConstructor.readValue(); 612 } 613 614 map.put(key, value); 615 } 616 617 return cast(Object)map; 618 } 619 620 override 621 public void skipValue() 622 { 623 DecoderImpl decoder = getDecoder(); 624 ReadableBuffer buffer = decoder.getBuffer(); 625 int size = (cast(int)decoder.readRawByte()) & 0xff; 626 buffer.position(buffer.position() + size); 627 } 628 629 public void setValue(Map!(String,Object) value, int length) 630 { 631 _value = value; 632 _length = length; 633 } 634 635 override 636 void writeConstructor() 637 { 638 super.writeConstructor(); 639 } 640 641 override int getConstructorSize() 642 { 643 return super.getConstructorSize(); 644 } 645 } 646 }