1 /* 2 * %CopyrightBegin% 3 * 4 * Copyright Ericsson AB 1999-2016. All Rights Reserved. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * %CopyrightEnd% 19 * 20 */ 21 /** 22 * The TypeCode class for Java IDL 23 * 24 */ 25 package com.ericsson.otp.ic; 26 27 /** 28 The TypeCode class is the implementation of the OMG-IDL TypeCode type. 29 **/ 30 31 public class TypeCode { 32 33 private TCKind _kind; 34 private java.lang.String _id,_name; 35 private int _length,_member_count,_default_index; 36 private TypeCode _member_type,_discriminator_type,_content_type; 37 private Any _member_label; 38 private boolean extracted; 39 private TypeCode _members[]; 40 private java.lang.String _member_names[]; 41 private Any _member_labels[]; 42 43 44 45 /* 46 * Constructors 47 */ TypeCode()48 public TypeCode() { 49 extracted = false; 50 _members = null; 51 _member_names = null; 52 _member_labels = null; 53 _kind = null; 54 _id = null; 55 _name = null; 56 _length = -1; 57 _member_count = -1; 58 _default_index = -1; 59 _member_type = null; 60 _content_type = null; 61 _discriminator_type = null; 62 _member_label = null; 63 } 64 TypeCode(TCKind __kind)65 public TypeCode(TCKind __kind) { 66 _kind = __kind; 67 } 68 69 70 /* 71 * Operation "TypeCode::equal" 72 */ 73 74 /** 75 Comparisson method for TypeCode. 76 @return true if the input TypeCode value equals the value of the current object, false otherwize 77 **/ equal(TypeCode tc)78 public boolean equal(TypeCode tc) { 79 80 try { 81 82 TCKind tck = tc.kind(); 83 84 switch (tck.value()) { 85 86 case TCKind._tk_short: 87 case TCKind._tk_long: 88 case TCKind._tk_longlong: 89 case TCKind._tk_ushort: 90 case TCKind._tk_ulong: 91 case TCKind._tk_ulonglong: 92 case TCKind._tk_float: 93 case TCKind._tk_double: 94 case TCKind._tk_boolean: 95 case TCKind._tk_char: 96 case TCKind._tk_wchar: 97 case TCKind._tk_octet: 98 case TCKind._tk_string: 99 case TCKind._tk_wstring: 100 case TCKind._tk_any: 101 case TCKind._tk_void: 102 case TCKind._tk_atom: 103 104 return (tck.value() == _kind.value()); 105 106 case TCKind._tk_struct: 107 108 if((tc.id().compareTo(_id) == 0) && 109 (tc.name().compareTo(_name) == 0) && 110 (tc.member_count() == _member_count)){ 111 112 for (int i = 0; i < _member_count; i++) 113 if (!tc.member_type(i).equal(_members[i])) 114 return false; 115 116 return true; 117 } 118 else 119 return false; 120 121 case TCKind._tk_union: 122 123 if((tc.id().compareTo(_id) == 0) && 124 (tc.name().compareTo(_name) == 0) && 125 (tc.member_count() == _member_count) && 126 (tc.discriminator_type().equal(_discriminator_type))){ 127 128 for (int i = 0; i < _member_count; i++) 129 if ((!tc.member_type(i).equal(_members[i])) && 130 (tc.member_name(i).compareTo(_member_names[i]) != 0)) 131 return false; 132 133 return true; 134 } 135 else 136 return false; 137 138 case TCKind._tk_sequence: 139 case TCKind._tk_array: 140 141 if((tck.value() == _kind.value()) && 142 (tc.content_type().equal(_content_type))) 143 return true; 144 else 145 return false; 146 147 case TCKind._tk_enum: 148 if((tck.value() == _kind.value()) && 149 (tc.member_count() == _member_count)) { 150 151 for (int i = 0; i < _member_count; i++) 152 if (tc.member_name(i).compareTo(_member_names[i]) != 0) 153 return false; 154 155 return true; 156 } 157 else 158 return false; 159 160 // Not used in real 161 case TCKind._tk_null: 162 case TCKind._tk_TypeCode: 163 case TCKind._tk_Principal: 164 case TCKind._tk_objref: 165 case TCKind._tk_alias: 166 case TCKind._tk_except: 167 case TCKind._tk_longdouble: 168 case TCKind._tk_fixed: 169 170 return (tck.value() == _kind.value()); 171 172 default : 173 return false; 174 175 } 176 } catch (Exception e) { 177 return false; 178 } 179 180 } 181 182 183 /* 184 * Operation "TypeCode::kind" 185 */ 186 187 /** 188 Accessor method for the TCKind value of TypeCode. 189 @return TCKind, the TCKind value of the TypeCode object. 190 **/ kind()191 public TCKind kind() { 192 return _kind; 193 } 194 195 /** 196 Insertion method for the TCKind value of TypeCode. 197 Sets the TCKind value of the object. 198 **/ kind(TCKind __kind)199 public void kind(TCKind __kind) { 200 _kind = __kind; 201 } 202 203 /** 204 Insertion method for the TCKind value of TypeCode. 205 Sets the TCKind value of the object. 206 **/ kind(java.lang.String atom)207 public static TCKind kind(java.lang.String atom) 208 throws java.lang.Exception { 209 210 if (atom.equals("tk_null")) 211 return TCKind.tk_null; 212 else 213 if (atom.equals("tk_void")) 214 return TCKind.tk_void; 215 else 216 if (atom.equals("tk_short")) 217 return TCKind.tk_short; 218 else 219 if (atom.equals("tk_long")) 220 return TCKind.tk_long; 221 else 222 if (atom.equals("tk_ushort")) 223 return TCKind.tk_ushort; 224 else 225 if (atom.equals("tk_ulong")) 226 return TCKind.tk_ulong; 227 else 228 if (atom.equals("tk_float")) 229 return TCKind.tk_float; 230 else 231 if (atom.equals("tk_double")) 232 return TCKind.tk_double; 233 else 234 if (atom.equals("tk_boolean")) 235 return TCKind.tk_boolean; 236 else 237 if (atom.equals("tk_char")) 238 return TCKind.tk_char; 239 else 240 if (atom.equals("tk_octet")) 241 return TCKind.tk_octet; 242 else 243 if (atom.equals("tk_any")) 244 return TCKind.tk_any; 245 else 246 if (atom.equals("tk_TypeCode")) 247 return TCKind.tk_TypeCode; 248 else 249 if (atom.equals("tk_Principal")) 250 return TCKind.tk_Principal; 251 else 252 if (atom.equals("tk_objref")) 253 return TCKind.tk_objref; 254 else 255 if (atom.equals("tk_struct")) 256 return TCKind.tk_struct; 257 else 258 if (atom.equals("tk_union")) 259 return TCKind.tk_union; 260 else 261 if (atom.equals("tk_enum")) 262 return TCKind.tk_enum; 263 else 264 if (atom.equals("tk_string")) 265 return TCKind.tk_string; 266 else 267 if (atom.equals("tk_sequence")) 268 return TCKind.tk_sequence; 269 else 270 if (atom.equals("tk_array")) 271 return TCKind.tk_array; 272 else 273 if (atom.equals("tk_alias")) 274 return TCKind.tk_alias; 275 else 276 if (atom.equals("tk_except")) 277 return TCKind.tk_except; 278 else 279 if (atom.equals("tk_longlong")) 280 return TCKind.tk_longlong; 281 else 282 if (atom.equals("tk_ulonglong")) 283 return TCKind.tk_ulonglong; 284 else 285 if (atom.equals("tk_longdouble")) 286 return TCKind.tk_longdouble; 287 else 288 if (atom.equals("tk_wchar")) 289 return TCKind.tk_wchar; 290 else 291 if (atom.equals("tk_wstring")) 292 return TCKind.tk_wstring; 293 else 294 if (atom.equals("tk_fixed")) 295 return TCKind.tk_fixed; 296 else 297 if (atom.equals("tk_atom")) 298 return TCKind.tk_atom; 299 else 300 throw new java.lang.Exception("BAD KIND"); 301 302 } 303 304 305 306 /* 307 * Operation "TypeCode::id" 308 */ 309 310 /** 311 Accessor method for the id value of TypeCode. 312 @return String, the id value of TypeCode object 313 **/ id()314 public java.lang.String id() 315 throws java.lang.Exception{ 316 317 if (_id == null) 318 throw new java.lang.Exception("BAD KIND"); 319 320 return _id; 321 } 322 323 324 /** 325 Insertion method for the id value of TypeCode. 326 Sets the id value of the object. 327 **/ id(java.lang.String __id)328 public void id(java.lang.String __id) { 329 330 _id = __id; 331 } 332 333 334 335 /* 336 * Operation "TypeCode::name" 337 */ 338 339 /** 340 Accessor method for the name value of TypeCode. 341 @return String, the name value of TypeCode object 342 **/ name()343 public java.lang.String name() 344 throws java.lang.Exception{ 345 346 if (_name == null) 347 throw new java.lang.Exception("BAD KIND"); 348 349 return _name; 350 } 351 352 /** 353 Insertion method for the name value of TypeCode. 354 Sets the name value of the object. 355 **/ name(java.lang.String __name)356 public void name(java.lang.String __name) { 357 _name = __name; 358 } 359 360 361 362 /* 363 * Operation "TypeCode::member_count" 364 */ 365 366 /** 367 Accessor method for the member number value of TypeCode. 368 @return int, the number of members of TypeCode object 369 **/ member_count()370 public int member_count() 371 throws java.lang.Exception{ 372 373 if (_member_count == -1) 374 throw new java.lang.Exception("BAD KIND"); 375 376 return _member_count; 377 } 378 379 /** 380 Insertion method for the member number value of TypeCode. 381 Sets the number of members value of the object. 382 **/ member_count(int __member_count)383 public void member_count(int __member_count) { 384 385 switch(_kind.value()) { 386 case TCKind._tk_struct: 387 _members = new TypeCode[__member_count]; 388 _member_names = new java.lang.String[__member_count]; 389 _member_count = __member_count; 390 break; 391 case TCKind._tk_union: 392 _members = new TypeCode[__member_count]; 393 _member_names = new java.lang.String[__member_count]; 394 _member_labels = new Any[__member_count]; 395 _member_count = __member_count; 396 break; 397 case TCKind._tk_enum: 398 _member_names = new java.lang.String[__member_count]; 399 _member_count = __member_count; 400 break; 401 default : 402 // Do nothing 403 } 404 } 405 406 407 /* 408 * Operation "TypeCode::member_name" 409 */ 410 411 /** 412 Member name accessor method for TypeCode. 413 @return String, the name value of the member of the TypeCode object 414 on the selected index 415 **/ member_name(int __index)416 public java.lang.String member_name(int __index) 417 throws java.lang.Exception{ 418 419 return _member_names[__index]; 420 } 421 422 /** 423 Insertion method for the indexed member name of TypeCode. 424 Sets the name of a member value of the object at the selected index.. 425 **/ member_name(int __index, java.lang.String __member_name)426 public void member_name(int __index, java.lang.String __member_name) { 427 _member_names[__index] = __member_name; 428 } 429 430 431 /* 432 * Operation "TypeCode::member_type" 433 */ 434 435 /** 436 Member type accessor method for TypeCode. 437 @return TypeCOde, the type of the member of the TypeCode object 438 on the selected index 439 **/ member_type(int __index)440 public TypeCode member_type(int __index) 441 throws java.lang.Exception{ 442 443 return _members[__index]; 444 } 445 446 /** 447 Insertion method for the indexed member type of TypeCode. 448 Sets the type of a member value of the object at the selected index.. 449 **/ member_type(int __index, TypeCode __member_type)450 public void member_type(int __index, TypeCode __member_type) { 451 _members[__index] = __member_type; 452 } 453 454 455 /* 456 * Operation "TypeCode::member_label" 457 */ 458 459 /** 460 Member label accessor method for TypeCode. 461 @return Any, the label of the member of the TypeCode object 462 on the selected index 463 **/ member_label(int __index)464 public Any member_label(int __index) 465 throws java.lang.Exception{ 466 467 return _member_labels[__index]; 468 } 469 470 /** 471 Insertion method for the indexed member label of TypeCode. 472 Sets the label of a member value of the object at the selected index. 473 **/ member_label(int __index, Any __member_label)474 public void member_label(int __index, Any __member_label) { 475 _member_labels[__index] = __member_label; 476 } 477 478 479 /* 480 * Operation "TypeCode::discriminator_type" 481 */ 482 483 /** 484 Discriminator type accessor method for TypeCode. 485 @return TypeCode, the type of the discriminator of the TypeCode object 486 **/ discriminator_type()487 public TypeCode discriminator_type() 488 throws java.lang.Exception{ 489 490 if (_discriminator_type == null) 491 throw new java.lang.Exception("BAD KIND"); 492 493 return _discriminator_type; 494 } 495 496 /** 497 Insertion method for the type of the discriminator value of TypeCode. 498 Sets the discriminator type value of the object. 499 **/ discriminator_type(TypeCode __discriminator_type)500 public void discriminator_type(TypeCode __discriminator_type) { 501 _discriminator_type = __discriminator_type; 502 } 503 504 505 /* 506 * Operation "TypeCode::default_index" 507 */ 508 509 /** 510 Index accessor method for TypeCode. 511 @return int, the default index value of the member of the TypeCode object 512 **/ default_index()513 public int default_index() 514 throws java.lang.Exception{ 515 516 if (_default_index == -1) 517 throw new java.lang.Exception("BAD KIND"); 518 519 return _default_index; 520 } 521 522 /** 523 Insertion method for the default index value of TypeCode. 524 Sets the default index value of the object. 525 **/ default_index(int __default_index)526 public void default_index(int __default_index) { 527 _default_index = __default_index; 528 } 529 530 531 /* 532 * Operation "TypeCode::length" 533 */ 534 535 /** 536 Length accessor method for TypeCode. 537 @return int, the length of the TypeCode object 538 **/ length()539 public int length() 540 throws java.lang.Exception{ 541 542 if (_length == -1) 543 throw new java.lang.Exception("BAD KIND"); 544 545 return _length; 546 } 547 548 /** 549 Insertion method for the length value of TypeCode. 550 Sets the length value of the object. 551 **/ length(int __length)552 public void length(int __length) { 553 _length = __length; 554 } 555 556 557 /* 558 * Operation "TypeCode::content_type" 559 */ 560 561 /** 562 Content type accessor method for TypeCode. 563 @return TypeCode, the content type of the TypeCode object 564 **/ content_type()565 public TypeCode content_type() 566 throws java.lang.Exception { 567 568 if (_content_type == null) 569 throw new java.lang.Exception("BAD KIND"); 570 571 return _content_type; 572 } 573 574 /** 575 Insertion method for the content type value of TypeCode. 576 Sets the content type value of the object. 577 **/ content_type(TypeCode __content_type)578 public void content_type(TypeCode __content_type) { 579 _content_type = __content_type; 580 } 581 582 583 /** 584 Marshal operation for TypeCode. 585 **/ marshal(com.ericsson.otp.erlang.OtpOutputStream _os, TypeCode _tc)586 public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _os, TypeCode _tc) 587 throws java.lang.Exception { 588 589 TypeCode memberTC = null; 590 int len = -1; 591 592 switch(_tc.kind().value()) { 593 594 case TCKind._tk_short : 595 _os.write_atom("tk_short"); 596 break; 597 case TCKind._tk_ushort : 598 _os.write_atom("tk_ushort"); 599 break; 600 case TCKind._tk_long : 601 _os.write_atom("tk_long"); 602 break; 603 case TCKind._tk_longlong : 604 _os.write_atom("tk_longlong"); 605 break; 606 case TCKind._tk_ulong : 607 _os.write_atom("tk_ulong"); 608 break; 609 case TCKind._tk_ulonglong : 610 _os.write_atom("tk_ulonglong"); 611 break; 612 case TCKind._tk_float : 613 _os.write_atom("tk_float"); 614 break; 615 case TCKind._tk_double : 616 _os.write_atom("tk_double"); 617 break; 618 case TCKind._tk_boolean : 619 _os.write_atom("tk_boolean"); 620 break; 621 case TCKind._tk_char : 622 _os.write_atom("tk_char"); 623 break; 624 case TCKind._tk_wchar : 625 _os.write_atom("tk_wchar"); 626 break; 627 case TCKind._tk_octet : 628 _os.write_atom("tk_octet"); 629 break; 630 case TCKind._tk_string : 631 _os.write_tuple_head(2); 632 _os.write_atom("tk_string"); 633 _os.write_ulong(_tc.length()); 634 break; 635 case TCKind._tk_wstring : 636 _os.write_tuple_head(2); 637 _os.write_atom("tk_wstring"); 638 _os.write_ulong(_tc.length()); 639 break; 640 case TCKind._tk_struct: 641 len = _tc.member_count(); 642 _os.write_tuple_head(4); 643 _os.write_atom("tk_struct"); 644 _os.write_string(_tc.id()); 645 _os.write_string(_tc.name()); 646 // Member list 647 _os.write_list_head(len); 648 for(int i=0; i<len; i++) { 649 _os.write_tuple_head(2); 650 _os.write_string(_tc.member_name(i)); 651 marshal(_os,_tc.member_type(i)); 652 } 653 _os.write_nil(); 654 break; 655 case TCKind._tk_union: 656 len = _tc.member_count(); 657 _os.write_tuple_head(6); 658 _os.write_atom("tk_union"); 659 _os.write_string(_tc.id()); 660 _os.write_string(_tc.name()); 661 marshal(_os,_tc.discriminator_type()); 662 _os.write_int(_tc.default_index()); 663 // Member list 664 _os.write_list_head(len); 665 for(int i=0; i<len; i++) { 666 _os.write_tuple_head(3); 667 _tc.member_label(i).write_value(_os); 668 _os.write_string(_tc.member_name(i)); 669 marshal(_os,_tc.member_type(i)); 670 } 671 _os.write_nil(); 672 break; 673 case TCKind._tk_sequence: 674 _os.write_tuple_head(3); 675 _os.write_atom("tk_sequence"); 676 marshal(_os,_tc.content_type()); 677 _os.write_int(_tc.length()); 678 break; 679 case TCKind._tk_array: 680 _os.write_tuple_head(3); 681 _os.write_atom("tk_array"); 682 marshal(_os,_tc.content_type()); 683 _os.write_int(_tc.length()); 684 break; 685 case TCKind._tk_enum: 686 len = _tc.member_count(); 687 _os.write_tuple_head(4); 688 _os.write_atom("tk_enum"); 689 _os.write_string(_tc.id()); 690 _os.write_string(_tc.name()); 691 _os.write_list_head(len); 692 for(int i=0; i<len; i++) 693 _os.write_string(_tc.member_name(i)); 694 _os.write_nil(); 695 break; 696 case TCKind._tk_any: 697 _os.write_atom("tk_any"); 698 break; 699 case TCKind._tk_void : 700 _os.write_atom("tk_void"); 701 break; 702 /* 703 * Not supported types 704 */ 705 default : 706 throw new java.lang.Exception("Unsupported type"); 707 708 } 709 710 } 711 712 713 /** 714 Unmarshal operation for TypeCode. 715 @return TypeCode, the TypeCode read from the input stream. 716 **/ unmarshal(com.ericsson.otp.erlang.OtpInputStream _is)717 public static TypeCode unmarshal(com.ericsson.otp.erlang.OtpInputStream _is) 718 throws java.lang.Exception { 719 720 TypeCode _tc, __member; 721 TCKind __kind; 722 int __len; 723 int __tag = _is.peek(); 724 725 switch(__tag) { 726 case (com.ericsson.otp.erlang.OtpExternal.atomTag): 727 case (com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag): 728 case (com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag): 729 __kind = TypeCode.kind(_is.read_atom()); 730 731 switch(__kind.value()) { 732 case TCKind._tk_short : 733 case TCKind._tk_ushort : 734 case TCKind._tk_long : 735 case TCKind._tk_longlong : 736 case TCKind._tk_ulong : 737 case TCKind._tk_ulonglong : 738 case TCKind._tk_float : 739 case TCKind._tk_double : 740 case TCKind._tk_boolean : 741 case TCKind._tk_char : 742 case TCKind._tk_wchar : 743 case TCKind._tk_octet : 744 case TCKind._tk_void : 745 case TCKind._tk_any : 746 _tc = new TypeCode(); 747 _tc.kind(__kind); 748 749 return _tc; 750 default : 751 throw new java.lang.Exception("Unsupported type"); 752 } 753 754 case (com.ericsson.otp.erlang.OtpExternal.smallTupleTag): 755 case (com.ericsson.otp.erlang.OtpExternal.largeTupleTag): 756 757 __len = _is.read_tuple_head(); 758 __tag = _is.peek(); 759 760 switch(__tag) { 761 762 case (com.ericsson.otp.erlang.OtpExternal.atomTag): 763 case (com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag): 764 case (com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag): 765 766 __kind = TypeCode.kind(_is.read_atom()); 767 _tc = new TypeCode(); 768 _tc.kind(__kind); 769 770 switch(__kind.value()) { 771 772 case TCKind._tk_string : 773 _tc.length((int)_is.read_ulong()); 774 return _tc; 775 776 case TCKind._tk_wstring : 777 _tc.length((int)_is.read_ulong()); 778 return _tc; 779 780 case TCKind._tk_struct: 781 782 _tc.id(_is.read_string()); 783 _tc.name(_is.read_string()); 784 __len = _is.read_list_head(); 785 _tc.member_count(__len); 786 787 for(int i=0; i<__len; i++) { 788 _is.read_tuple_head(); 789 _tc.member_name(i,_is.read_string()); 790 _tc.member_type(i,unmarshal(_is)); 791 } 792 _is.read_nil(); 793 794 return _tc; 795 796 797 case TCKind._tk_union: 798 799 _tc.id(_is.read_string()); 800 _tc.name(_is.read_string()); 801 _tc.discriminator_type(unmarshal(_is)); 802 _tc.default_index(_is.read_int()); 803 __len = _is.read_list_head(); 804 _tc.member_count(__len); 805 806 for(int i=0; i<__len; i++) { 807 _is.read_tuple_head(); 808 809 __tag = _is.peek(); 810 Any __label = new Any(); 811 TypeCode __label_type = new TypeCode(); 812 813 __label_type.kind(com.ericsson.otp.ic.TCKind.tk_long); 814 __label.type(__label_type); 815 816 switch(__tag) { 817 case (com.ericsson.otp.erlang.OtpExternal.stringTag): 818 java.lang.String __enum = _is.read_string(); 819 __label.insert_string(__enum); 820 break; 821 case (com.ericsson.otp.erlang.OtpExternal.atomTag): 822 case (com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag): 823 case (com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag): 824 825 java.lang.String __default = _is.read_atom(); 826 __label.insert_atom(__default); 827 break; 828 default: 829 __label.insert_long(_is.read_int()); 830 } 831 832 _tc.member_label(i,__label); 833 _tc.member_name(i,_is.read_string()); 834 _tc.member_type(i,unmarshal(_is)); 835 } 836 _is.read_nil(); 837 838 return _tc; 839 840 841 case TCKind._tk_sequence: 842 _tc.content_type(unmarshal(_is)); 843 _tc.length(_is.read_int()); 844 return _tc; 845 846 847 case TCKind._tk_array: 848 _tc.content_type(unmarshal(_is)); 849 _tc.length(_is.read_int()); 850 return _tc; 851 852 853 case TCKind._tk_enum: 854 855 _tc.id(_is.read_string()); 856 _tc.name(_is.read_string()); 857 __len = _is.read_list_head(); 858 _tc.member_count(__len); 859 860 for(int i=0; i<__len; i++) 861 _tc.member_name(i,_is.read_string()); 862 863 _is.read_nil(); 864 865 return _tc; 866 867 default: 868 throw new java.lang.Exception("Unsupported type"); 869 870 } 871 872 default: 873 throw new java.lang.Exception("Unsupported type"); 874 } 875 876 } 877 878 return null; 879 } 880 881 } 882 883 884