Hazelcast C++ Client
Hazelcast C++ Client Library
Loading...
Searching...
No Matches
serialization.cpp
1/*
2 * Copyright (c) 2008-2025, Hazelcast, Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <boost/concept_check.hpp>
18#include <utility>
19
20#include "hazelcast/client/serialization/serialization.h"
21#include "hazelcast/client/hazelcast_json_value.h"
22#include "hazelcast/client/serialization/serialization.h"
23#include "hazelcast/util/Util.h"
24#include "hazelcast/util/IOUtil.h"
25#include "hazelcast/util/Bits.h"
26#include "hazelcast/util/MurmurHash3.h"
27#include "hazelcast/client/spi/ClientContext.h"
28#include "hazelcast/client/client_config.h"
29
30namespace hazelcast {
31namespace client {
33 : json_string_(std::move(json_string))
34{}
35
36hazelcast_json_value::~hazelcast_json_value() = default;
37
38const std::string&
40{
41 return json_string_;
42}
43
44bool
45hazelcast_json_value::operator==(const hazelcast_json_value& rhs) const
46{
47 return json_string_ == rhs.json_string_;
48}
49
50bool
51hazelcast_json_value::operator!=(const hazelcast_json_value& rhs) const
52{
53 return !(rhs == *this);
54}
55
56bool
57hazelcast_json_value::operator<(const hazelcast_json_value& rhs) const
58{
59 return json_string_ < rhs.json_string_;
60}
61
62std::ostream&
63operator<<(std::ostream& os, const hazelcast_json_value& value)
64{
65 os << "jsonString: " << value.json_string_;
66 return os;
67}
68
69typed_data::typed_data()
70 : ss_(nullptr)
71{}
72
73typed_data::typed_data(
74 serialization::pimpl::data d,
75 serialization::pimpl::SerializationService& serialization_service)
76 : data_(std::move(d))
77 , ss_(&serialization_service)
78{}
79
80serialization::pimpl::object_type
82{
83 return ss_->get_object_type(&data_);
84}
85
86const serialization::pimpl::data&
88{
89 return data_;
90}
91
92bool
93operator<(const typed_data& lhs, const typed_data& rhs)
94{
95 const auto& lhs_data = lhs.get_data();
96 const auto& rhs_data = rhs.get_data();
97
98 return lhs_data < rhs_data;
99}
100
101namespace serialization {
103 pimpl::DefaultPortableWriter* default_portable_writer)
104 : default_portable_writer_(default_portable_writer)
105 , class_definition_writer_(nullptr)
106 , is_default_writer_(true)
107{}
108
110 pimpl::ClassDefinitionWriter* class_definition_writer)
111 : default_portable_writer_(nullptr)
112 , class_definition_writer_(class_definition_writer)
113 , is_default_writer_(false)
114{}
115
116void
118{
119 if (is_default_writer_)
120 return default_portable_writer_->end();
121 return class_definition_writer_->end();
122}
123
126{
127 if (is_default_writer_)
128 return default_portable_writer_->get_raw_data_output();
129 return class_definition_writer_->get_raw_data_output();
130}
131
132ClassDefinitionBuilder::ClassDefinitionBuilder(int factory_id,
133 int class_id,
134 int version)
135 : factory_id_(factory_id)
136 , class_id_(class_id)
137 , version_(version)
138 , index_(0)
139 , done_(false)
140{}
141
142ClassDefinitionBuilder&
143ClassDefinitionBuilder::add_portable_field(const std::string& field_name,
144 std::shared_ptr<ClassDefinition> def)
145{
146 check();
147 if (def->get_class_id() == 0) {
148 BOOST_THROW_EXCEPTION(exception::illegal_argument(
149 "ClassDefinitionBuilder::addPortableField",
150 "Portable class id cannot be zero!"));
151 }
152 FieldDefinition fieldDefinition(index_++,
153 field_name,
154 field_type::TYPE_PORTABLE,
155 def->get_factory_id(),
156 def->get_class_id(),
157 def->get_version());
158 field_definitions_.push_back(fieldDefinition);
159 return *this;
160}
161
162ClassDefinitionBuilder&
163ClassDefinitionBuilder::add_portable_array_field(
164 const std::string& field_name,
165 std::shared_ptr<ClassDefinition> def)
166{
167 check();
168 if (def->get_class_id() == 0) {
169 BOOST_THROW_EXCEPTION(exception::illegal_argument(
170 "ClassDefinitionBuilder::addPortableField",
171 "Portable class id cannot be zero!"));
172 }
173 FieldDefinition fieldDefinition(index_++,
174 field_name,
175 field_type::TYPE_PORTABLE_ARRAY,
176 def->get_factory_id(),
177 def->get_class_id(),
178 def->get_version());
179 field_definitions_.push_back(fieldDefinition);
180 return *this;
181}
182
184ClassDefinitionBuilder::add_field(FieldDefinition& field_definition)
185{
186 check();
187 int defIndex = field_definition.get_index();
188 if (index_ != defIndex) {
189 char buf[100];
190 util::hz_snprintf(buf,
191 100,
192 "Invalid field index. Index in definition:%d, being "
193 "added at index:%d",
194 defIndex,
195 index_);
196 BOOST_THROW_EXCEPTION(
197 exception::illegal_argument("ClassDefinitionBuilder::addField", buf));
198 }
199 index_++;
200 field_definitions_.push_back(field_definition);
201 return *this;
202}
203
204std::shared_ptr<ClassDefinition>
205ClassDefinitionBuilder::build()
206{
207 done_ = true;
208 std::shared_ptr<ClassDefinition> cd(
209 new ClassDefinition(factory_id_, class_id_, version_));
210
211 std::vector<FieldDefinition>::iterator fdIt;
212 for (fdIt = field_definitions_.begin(); fdIt != field_definitions_.end();
213 fdIt++) {
214 cd->add_field_def(*fdIt);
215 }
216 return cd;
217}
218
219void
220ClassDefinitionBuilder::check()
221{
222 if (done_) {
223 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
224 "ClassDefinitionBuilder::check",
225 "ClassDefinition is already built for " +
226 util::IOUtil::to_string(class_id_)));
227 }
228}
229
230void
231ClassDefinitionBuilder::add_field(const std::string& field_name,
232 field_type const& field_type)
233{
234 check();
235 FieldDefinition fieldDefinition(index_++, field_name, field_type, version_);
236 field_definitions_.push_back(fieldDefinition);
237}
238
239int
240ClassDefinitionBuilder::get_factory_id()
241{
242 return factory_id_;
243}
244
245int
246ClassDefinitionBuilder::get_class_id()
247{
248 return class_id_;
249}
250
251int
252ClassDefinitionBuilder::get_version()
253{
254 return version_;
255}
256
258 : index_(0)
259 , class_id_(0)
260 , factory_id_(0)
261 , version_(-1)
262{}
263
265 const std::string& field_name,
266 field_type const& type,
267 int version)
268 : index_(index)
269 , field_name_(field_name)
270 , type_(type)
271 , class_id_(0)
272 , factory_id_(0)
273 , version_(version)
274{}
275
277 const std::string& field_name,
278 field_type const& type,
279 int factory_id,
280 int class_id,
281 int version)
282 : index_(index)
283 , field_name_(field_name)
284 , type_(type)
285 , class_id_(class_id)
286 , factory_id_(factory_id)
287 , version_(version)
288{}
289
290const field_type&
292{
293 return type_;
294}
295
296std::string
298{
299 return field_name_;
300}
301
302int
304{
305 return index_;
306}
307
308int
310{
311 return factory_id_;
312}
313
314int
316{
317 return class_id_;
318}
319
320void
321FieldDefinition::write_data(pimpl::data_output& data_output)
322{
323 data_output.write<int32_t>(index_);
324 data_output.write<std::string>(field_name_);
325 data_output.write<byte>(static_cast<int32_t>(type_));
326 data_output.write<int32_t>(factory_id_);
327 data_output.write<int32_t>(class_id_);
328}
329
330void
332{
333 index_ = data_input.read<int32_t>();
334 field_name_ = data_input.read<std::string>();
335 type_ = static_cast<field_type>(data_input.read<byte>());
336 factory_id_ = data_input.read<int32_t>();
337 class_id_ = data_input.read<int32_t>();
338}
339
340bool
341FieldDefinition::operator==(const FieldDefinition& rhs) const
342{
343 return field_name_ == rhs.field_name_ && type_ == rhs.type_ &&
344 class_id_ == rhs.class_id_ && factory_id_ == rhs.factory_id_ &&
345 version_ == rhs.version_;
346}
347
348bool
349FieldDefinition::operator!=(const FieldDefinition& rhs) const
350{
351 return !(rhs == *this);
352}
353
354std::ostream&
355operator<<(std::ostream& os, const FieldDefinition& definition)
356{
357 os << "FieldDefinition{"
358 << "index: " << definition.index_
359 << " fieldName: " << definition.field_name_
360 << " type: " << static_cast<int32_t>(definition.type_)
361 << " classId: " << definition.class_id_
362 << " factoryId: " << definition.factory_id_
363 << " version: " << definition.version_;
364 return os;
365}
366
368 boost::endian::order byte_order,
369 const std::vector<byte>& buffer,
370 int offset,
371 pimpl::PortableSerializer& portable_ser,
372 pimpl::compact_stream_serializer& compact_ser,
373 pimpl::DataSerializer& data_ser,
374 std::shared_ptr<serialization::global_serializer> global_serializer)
375 : pimpl::data_input<std::vector<byte>>(byte_order, buffer, offset)
376 , portable_serializer_(portable_ser)
377 , compact_serializer_(compact_ser)
378 , data_serializer_(data_ser)
379 , global_serializer_(std::move(global_serializer))
380{}
381
383 boost::endian::order byte_order,
384 bool dont_write,
385 pimpl::PortableSerializer* portable_ser,
386 pimpl::compact_stream_serializer* compact_ser,
387 std::shared_ptr<serialization::global_serializer> global_serializer)
388 : data_output(byte_order, dont_write)
389 , portable_serializer_(portable_ser)
390 , compact_serializer_(compact_ser)
391 , global_serializer_(std::move(global_serializer))
392{}
393
394portable_reader::portable_reader(pimpl::PortableSerializer& portable_ser,
395 object_data_input& input,
396 const std::shared_ptr<ClassDefinition>& cd,
397 bool is_default_reader)
398 : is_default_reader_(is_default_reader)
399{
400 if (is_default_reader) {
401 default_portable_reader_ = boost::make_optional(
402 pimpl::DefaultPortableReader(portable_ser, input, cd));
403 } else {
404 morphing_portable_reader_ = boost::make_optional(
405 pimpl::MorphingPortableReader(portable_ser, input, cd));
406 }
407}
408
409object_data_input&
411{
412 if (is_default_reader_)
413 return default_portable_reader_->get_raw_data_input();
414 return morphing_portable_reader_->get_raw_data_input();
415}
416
417template<>
418void
419object_data_output::write_object(const char* object)
420{
421 if (!object) {
422 write<int32_t>(static_cast<int32_t>(
423 pimpl::serialization_constants::CONSTANT_TYPE_NULL));
424 return;
425 }
426 write_object<std::string>(std::string(object));
427}
428
429void
431{
432 if (is_default_reader_)
433 return default_portable_reader_->end();
434 return morphing_portable_reader_->end();
435}
436
438 : factory_id_(0)
439 , class_id_(0)
440 , version_(-1)
441 , binary_(new std::vector<byte>)
442{}
443
444ClassDefinition::ClassDefinition(int factory_id, int class_id, int version)
445 : factory_id_(factory_id)
446 , class_id_(class_id)
447 , version_(version)
448 , binary_(new std::vector<byte>)
449{}
450
451void
453{
454 field_definitions_map_[fd.get_name()] = fd;
455}
456
457const FieldDefinition&
458ClassDefinition::get_field(const std::string& name) const
459{
460 auto it = field_definitions_map_.find(name);
461 if (it != field_definitions_map_.end()) {
462 return it->second;
463 }
464 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
465 "ClassDefinition::getField",
466 (boost::format("Invalid field name: '%1%' for ClassDefinition {id: %2%, "
467 "version: %3%}") %
468 name % class_id_ % version_)
469 .str()));
470}
471
472bool
473ClassDefinition::has_field(const std::string& field_name) const
474{
475 return field_definitions_map_.find(field_name) !=
476 field_definitions_map_.end();
477}
478
479field_type
480ClassDefinition::get_field_type(const std::string& field_name) const
481{
482 FieldDefinition const& fd = get_field(field_name);
483 return fd.get_type();
484}
485
486int
488{
489 return (int)field_definitions_map_.size();
490}
491
492int
494{
495 return factory_id_;
496}
497
498int
500{
501 return class_id_;
502}
503
504int
506{
507 return version_;
508}
509
510void
512{
513 if (get_version() < 0) {
514 this->version_ = new_version;
515 }
516}
517
518void
519ClassDefinition::write_data(pimpl::data_output& data_output)
520{
521 data_output.write<int32_t>(factory_id_);
522 data_output.write<int32_t>(class_id_);
523 data_output.write<int32_t>(version_);
524 data_output.write<int16_t>(field_definitions_map_.size());
525 for (auto& entry : field_definitions_map_) {
526 entry.second.write_data(data_output);
527 }
528}
529
530void
532{
533 factory_id_ = data_input.read<int32_t>();
534 class_id_ = data_input.read<int32_t>();
535 version_ = data_input.read<int32_t>();
536 int size = data_input.read<int16_t>();
537 for (int i = 0; i < size; i++) {
538 FieldDefinition fieldDefinition;
539 fieldDefinition.read_data(data_input);
540 add_field_def(fieldDefinition);
541 }
542}
543
544bool
545ClassDefinition::operator==(const ClassDefinition& rhs) const
546{
547 return factory_id_ == rhs.factory_id_ && class_id_ == rhs.class_id_ &&
548 version_ == rhs.version_ &&
549 field_definitions_map_ == rhs.field_definitions_map_;
550}
551
552bool
553ClassDefinition::operator!=(const ClassDefinition& rhs) const
554{
555 return !(rhs == *this);
556}
557
558std::ostream&
559operator<<(std::ostream& os, const ClassDefinition& definition)
560{
561 os << "ClassDefinition{"
562 << "factoryId: " << definition.factory_id_
563 << " classId: " << definition.class_id_
564 << " version: " << definition.version_ << " fieldDefinitions: {";
565
566 for (auto& entry : definition.field_definitions_map_) {
567 os << entry.second;
568 }
569 os << "} }";
570 return os;
571}
572
573namespace pimpl {
574ClassDefinitionWriter::ClassDefinitionWriter(PortableContext& portable_context,
575 ClassDefinitionBuilder& builder)
576 : builder_(builder)
577 , context_(portable_context)
578 , empty_data_output_(
579 portable_context.get_serialization_config().get_byte_order(),
580 true)
581{}
582
583std::shared_ptr<ClassDefinition>
584ClassDefinitionWriter::register_and_get()
585{
586 std::shared_ptr<ClassDefinition> cd = builder_.build();
587 return context_.register_class_definition(cd);
588}
589
591ClassDefinitionWriter::get_raw_data_output()
592{
593 return empty_data_output_;
594}
595
596void
597ClassDefinitionWriter::end()
598{}
599
600data_output::data_output(boost::endian::order byte_order, bool dont_write)
601 : byte_order_(byte_order)
602 , is_no_write_(dont_write)
603{
604 if (is_no_write_) {
605 output_stream_.reserve(0);
606 } else {
607 output_stream_.reserve(DEFAULT_SIZE);
608 }
609}
610
611template<>
612void
613data_output::write(byte i)
614{
615 if (is_no_write_) {
616 return;
617 }
618 output_stream_.push_back(i);
619}
620
621template<>
622void
623data_output::write(char i)
624{
625 // C++ `char` is one byte only, `char16_t` is two bytes
626 write<int16_t>(i);
627}
628
629template<>
630void
631data_output::write(char16_t i)
632{
633 write<int16_t>(i);
634}
635
636template<>
637void
638data_output::write(int16_t value)
639{
640 if (is_no_write_) {
641 return;
642 }
643 if (byte_order_ == boost::endian::order::big) {
644 boost::endian::native_to_big_inplace(value);
645 } else {
646 boost::endian::native_to_little_inplace(value);
647 }
648 output_stream_.insert(output_stream_.end(),
649 (byte*)&value,
650 (byte*)&value + util::Bits::SHORT_SIZE_IN_BYTES);
651}
652
653void
654data_output::write(int32_t value, boost::endian::order byte_order)
655{
656 if (is_no_write_) {
657 return;
658 }
659 if (byte_order == boost::endian::order::big) {
660 boost::endian::native_to_big_inplace(value);
661 } else {
662 boost::endian::native_to_little_inplace(value);
663 }
664 output_stream_.insert(output_stream_.end(),
665 (byte*)&value,
666 (byte*)&value + util::Bits::INT_SIZE_IN_BYTES);
667}
668
669template<>
670void
671data_output::write(int32_t value)
672{
673 write(value, byte_order_);
674}
675
676template<>
677void
678data_output::write(int64_t value)
679{
680 if (is_no_write_) {
681 return;
682 }
683 if (byte_order_ == boost::endian::order::big) {
684 boost::endian::native_to_big_inplace(value);
685 } else {
686 boost::endian::native_to_little_inplace(value);
687 }
688 output_stream_.insert(output_stream_.end(),
689 (byte*)&value,
690 (byte*)&value + util::Bits::LONG_SIZE_IN_BYTES);
691}
692
693template<>
694void
695data_output::write(float x)
696{
697 if (is_no_write_) {
698 return;
699 }
700 union
701 {
702 float f;
703 int32_t i;
704 } u;
705 u.f = x;
706 write<int32_t>(u.i);
707}
708
709template<>
710void
711data_output::write(double v)
712{
713 if (is_no_write_) {
714 return;
715 }
716 union
717 {
718 double d;
719 int64_t l;
720 } u;
721 u.d = v;
722 write<int64_t>(u.l);
723}
724
725template<>
726void
727data_output::write(boost::uuids::uuid v)
728{
729 if (is_no_write_) {
730 return;
731 }
732 if (byte_order_ == boost::endian::order::little) {
733 boost::endian::endian_reverse_inplace<int64_t>(
734 *reinterpret_cast<int64_t*>(v.data));
735 boost::endian::endian_reverse_inplace<int64_t>(
736 *reinterpret_cast<int64_t*>(&v.data[util::Bits::LONG_SIZE_IN_BYTES]));
737 }
738 output_stream_.insert(
739 output_stream_.end(), v.data, v.data + util::Bits::UUID_SIZE_IN_BYTES);
740}
741
742template<>
743void
744data_output::write(bool value)
745{
746 if (is_no_write_) {
747 return;
748 }
749 write<byte>(value);
750}
751
752template<>
753void
754data_output::write(int8_t value)
755{
756 if (is_no_write_) {
757 return;
758 }
759 write<byte>(value);
760}
761
762template<>
763void
764data_output::write(const std::string& str)
765{
766 if (is_no_write_) {
767 return;
768 }
769
770 write<int32_t>(str.size());
771 output_stream_.insert(output_stream_.end(), str.begin(), str.end());
772}
773
774template<>
775void
776data_output::write(const hazelcast_json_value& value)
777{
778 if (is_no_write_) {
779 return;
780 }
781 write<std::string>(value.to_string());
782}
783
784void
785data_output::check_available(size_t index, int requested_length)
786{
787 if (index < 0) {
788 BOOST_THROW_EXCEPTION(exception::illegal_argument(
789 "DataOutput::checkAvailable",
790 (boost::format("Negative pos! -> %1%") % index).str()));
791 }
792
793 size_t available = output_stream_.size() - index;
794
795 if (requested_length > (int)available) {
796 BOOST_THROW_EXCEPTION(exception::illegal_argument(
797 "DataOutput::checkAvailable",
798 (boost::format("Cannot write %1% bytes!") % requested_length).str()));
799 }
800}
801
802void
803data_output::write_boolean_bit_at(size_t index,
804 size_t offset_in_bits,
805 bool value)
806{
807 if (is_no_write_) {
808 return;
809 }
810 check_available(index, 1);
811 byte b = output_stream_[index];
812 if (value) {
813 b = (byte)(b | (1 << offset_in_bits));
814 } else {
815 b = (byte)(b & ~(1 << offset_in_bits));
816 }
817 output_stream_[index] = b;
818}
819
820object_type::object_type()
821 : type_id(serialization_constants::CONSTANT_TYPE_NULL)
822 , factory_id(-1)
823 , class_id(-1)
824{}
825
826std::ostream&
827operator<<(std::ostream& os, const object_type& type)
828{
829 os << "typeId: " << static_cast<int32_t>(type.type_id)
830 << " factoryId: " << type.factory_id << " classId: " << type.class_id;
831 return os;
832}
833
834int32_t
835DataSerializer::read_int(object_data_input& in) const
836{
837 return in.read<int32_t>();
838}
839
840PortableContext::PortableContext(const serialization_config& serialization_conf)
841 : serialization_config_(serialization_conf)
842{}
843
844int
845PortableContext::get_class_version(int factory_id, int class_id)
846{
847 return get_class_definition_context(factory_id).get_class_version(class_id);
848}
849
850void
851PortableContext::set_class_version(int factory_id, int class_id, int version)
852{
853 get_class_definition_context(factory_id)
854 .set_class_version(class_id, version);
855}
856
857std::shared_ptr<ClassDefinition>
858PortableContext::lookup_class_definition(int factory_id,
859 int class_id,
860 int version)
861{
862 return get_class_definition_context(factory_id).lookup(class_id, version);
863}
864
865std::shared_ptr<ClassDefinition>
866PortableContext::read_class_definition(object_data_input& in,
867 int factory_id,
868 int class_id,
869 int version)
870{
871 bool shouldRegister = true;
872 ClassDefinitionBuilder builder(factory_id, class_id, version);
873
874 // final position after portable is read
875 in.read<int32_t>();
876
877 // field count
878 int fieldCount = in.read<int32_t>();
879 int offset = in.position();
880 for (int i = 0; i < fieldCount; i++) {
881 in.position(offset + i * util::Bits::INT_SIZE_IN_BYTES);
882 int pos = in.read<int32_t>();
883 in.position(pos);
884
885 short len = in.read<int16_t>();
886 std::vector<byte> chars(len);
887 in.read_fully(chars);
888 chars.push_back('\0');
889
890 field_type type(static_cast<field_type>(in.read<byte>()));
891 std::string name((char*)&(chars[0]));
892 int fieldFactoryId = 0;
893 int fieldClassId = 0;
894 int fieldVersion = version;
895 if (type == field_type::TYPE_PORTABLE) {
896 // is null
897 if (in.read<bool>()) {
898 shouldRegister = false;
899 }
900 fieldFactoryId = in.read<int32_t>();
901 fieldClassId = in.read<int32_t>();
902
903 // TODO: what if there's a null inner Portable field
904 if (shouldRegister) {
905 fieldVersion = in.read<int32_t>();
906 read_class_definition(
907 in, fieldFactoryId, fieldClassId, fieldVersion);
908 }
909 } else if (type == field_type::TYPE_PORTABLE_ARRAY) {
910 int k = in.read<int32_t>();
911 if (k > 0) {
912 fieldFactoryId = in.read<int32_t>();
913 fieldClassId = in.read<int32_t>();
914
915 int p = in.read<int32_t>();
916 in.position(p);
917
918 // TODO: what if there's a null inner Portable field
919 fieldVersion = in.read<int32_t>();
920 read_class_definition(
921 in, fieldFactoryId, fieldClassId, fieldVersion);
922 } else {
923 shouldRegister = false;
924 }
925 }
926 FieldDefinition fieldDef(
927 i, name, type, fieldFactoryId, fieldClassId, fieldVersion);
928 builder.add_field(fieldDef);
929 }
930 std::shared_ptr<ClassDefinition> classDefinition = builder.build();
931 if (shouldRegister) {
932 classDefinition = register_class_definition(classDefinition);
933 }
934 return classDefinition;
935}
936
937std::shared_ptr<ClassDefinition>
938PortableContext::register_class_definition(std::shared_ptr<ClassDefinition> cd)
939{
940 return get_class_definition_context(cd->get_factory_id())
941 .register_class_definition(cd);
942}
943
944int
945PortableContext::get_version()
946{
947 return serialization_config_.get_portable_version();
948}
949
950ClassDefinitionContext&
951PortableContext::get_class_definition_context(int factory_id)
952{
953 std::shared_ptr<ClassDefinitionContext> value =
954 class_def_context_map_.get(factory_id);
955 if (value == NULL) {
956 value = std::shared_ptr<ClassDefinitionContext>(
957 new ClassDefinitionContext(factory_id, this));
958 std::shared_ptr<ClassDefinitionContext> current =
959 class_def_context_map_.put_if_absent(factory_id, value);
960 if (current != NULL) {
961 value = current;
962 }
963 }
964 return *value;
965}
966
967const serialization_config&
968PortableContext::get_serialization_config() const
969{
970 return serialization_config_;
971}
972
973SerializationService::SerializationService(
974 const serialization_config& config,
975 default_schema_service& schema_service)
976 : serialization_config_(config)
977 , portable_context_(serialization_config_)
978 , portable_serializer_(portable_context_)
979 , compact_serializer_(schema_service)
980{}
981
982DefaultPortableWriter::DefaultPortableWriter(
983 PortableSerializer& portable_ser,
984 std::shared_ptr<ClassDefinition> cd,
985 object_data_output& output)
986 : raw_(false)
987 , portable_serializer_(portable_ser)
988 , object_data_output_(output)
989 , begin_(object_data_output_.position())
990 , cd_(cd)
991{
992 // room for final offset
993 object_data_output_.write<int32_t>(0);
994
995 object_data_output_.write<int32_t>(cd->get_field_count());
996
997 offset_ = object_data_output_.position();
998 // one additional for raw data
999 int fieldIndexesLength =
1000 (cd->get_field_count() + 1) * util::Bits::INT_SIZE_IN_BYTES;
1001 object_data_output_.write_zero_bytes(fieldIndexesLength);
1002}
1003
1004FieldDefinition const&
1005DefaultPortableWriter::set_position(const std::string& field_name,
1006 field_type field_type)
1007{
1008 if (raw_) {
1009 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1010 "PortableWriter::setPosition",
1011 "Cannot write Portable fields after getRawDataOutput() is called!"));
1012 }
1013
1014 try {
1015 FieldDefinition const& fd = cd_->get_field(field_name);
1016
1017 if (written_fields_.find(field_name) != written_fields_.end()) {
1018 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1019 "PortableWriter::setPosition",
1020 "Field '" + std::string(field_name) +
1021 "' has already been written!"));
1022 }
1023
1024 written_fields_.insert(field_name);
1025 size_t pos = object_data_output_.position();
1026 int32_t index = fd.get_index();
1027 object_data_output_.write_at(offset_ +
1028 index * util::Bits::INT_SIZE_IN_BYTES,
1029 static_cast<int32_t>(pos));
1030 object_data_output_.write(static_cast<int16_t>(field_name.size()));
1031 object_data_output_.write_bytes(field_name);
1032 object_data_output_.write<byte>(static_cast<byte>(field_type));
1033
1034 return fd;
1035
1036 } catch (exception::illegal_argument& iae) {
1037 std::stringstream error;
1038 error << "hazelcast_serialization_exception( Invalid field name: '"
1039 << field_name;
1040 error << "' for ClassDefinition {class id: "
1041 << util::IOUtil::to_string(cd_->get_class_id());
1042 error << ", factoryId:" +
1043 util::IOUtil::to_string(cd_->get_factory_id());
1044 error << ", version: " << util::IOUtil::to_string(cd_->get_version())
1045 << "}. Error:";
1046 error << iae.what();
1047
1048 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1049 "PortableWriter::setPosition", error.str()));
1050 }
1051}
1052
1054DefaultPortableWriter::get_raw_data_output()
1055{
1056 if (!raw_) {
1057 size_t pos = object_data_output_.position();
1058 int32_t index = cd_->get_field_count(); // last index
1059 object_data_output_.write_at(offset_ +
1060 index * util::Bits::INT_SIZE_IN_BYTES,
1061 static_cast<int32_t>(pos));
1062 }
1063 raw_ = true;
1064 return object_data_output_;
1065}
1066
1067void
1068DefaultPortableWriter::end()
1069{
1070 object_data_output_.write_at(
1071 begin_, static_cast<int32_t>(object_data_output_.position()));
1072}
1073
1074bool
1075SerializationService::is_null_data(const data& data)
1076{
1077 return data.data_size() == 0 &&
1078 data.get_type() ==
1079 static_cast<int32_t>(serialization_constants::CONSTANT_TYPE_NULL);
1080}
1081
1082template<>
1083data
1084SerializationService::to_data(const char* object)
1085{
1086 if (!object) {
1087 return to_data<std::string>(nullptr);
1088 }
1089 std::string str(object);
1090 return to_data<std::string>(str);
1091}
1092
1093byte
1094SerializationService::get_version() const
1095{
1096 return 1;
1097}
1098
1099object_type
1100SerializationService::get_object_type(const data* data)
1101{
1102 object_type type;
1103
1104 if (NULL == data) {
1105 type.type_id = serialization_constants::CONSTANT_TYPE_NULL;
1106 return type;
1107 }
1108
1109 type.type_id = static_cast<serialization_constants>(data->get_type());
1110
1111 if (serialization_constants::CONSTANT_TYPE_DATA == type.type_id ||
1112 serialization_constants::CONSTANT_TYPE_PORTABLE == type.type_id) {
1113 // 8 (data Header) = Hash(4-bytes) + data TypeId(4 bytes)
1114 data_input<std::vector<byte>> dataInput(
1115 serialization_config_.get_byte_order(), data->to_byte_array(), 8);
1116
1117 if (serialization_constants::CONSTANT_TYPE_DATA == type.type_id) {
1118 bool identified = dataInput.read<bool>();
1119 if (!identified) {
1120 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1121 "SerializationService::getObjectType",
1122 " DataSerializable is not 'identified data'"));
1123 }
1124 }
1125
1126 type.factory_id = dataInput.read<int32_t>();
1127 type.class_id = dataInput.read<int32_t>();
1128 }
1129
1130 return type;
1131}
1132
1133void
1134SerializationService::dispose()
1135{}
1136
1137PortableSerializer&
1138SerializationService::get_portable_serializer()
1139{
1140 return portable_serializer_;
1141}
1142
1143compact_stream_serializer&
1144SerializationService::get_compact_serializer()
1145{
1146 return compact_serializer_;
1147}
1148
1149DataSerializer&
1150SerializationService::get_data_serializer()
1151{
1152 return data_serializer_;
1153}
1154
1156SerializationService::new_output_stream()
1157{
1158 return object_data_output(serialization_config_.get_byte_order(),
1159 false,
1160 &portable_serializer_,
1161 &compact_serializer_,
1162 serialization_config_.get_global_serializer());
1163}
1164
1165template<>
1166data
1167SerializationService::to_data(const typed_data* object)
1168{
1169 if (!object) {
1170 return data();
1171 }
1172
1173 return object->get_data();
1174}
1175
1176// first 4 byte is partition hash code and next last 4 byte is type id
1177unsigned int data::PARTITION_HASH_OFFSET = 0;
1178
1179unsigned int data::TYPE_OFFSET =
1180 data::PARTITION_HASH_OFFSET + util::Bits::INT_SIZE_IN_BYTES;
1181
1182unsigned int data::DATA_OFFSET =
1183 data::TYPE_OFFSET + util::Bits::INT_SIZE_IN_BYTES;
1184
1185unsigned int data::DATA_OVERHEAD = data::DATA_OFFSET;
1186
1187data::data()
1188 : cached_hash_value_(-1)
1189{}
1190
1191data::data(std::vector<byte> buffer, schemas_t s)
1192 : data_(std::move(buffer))
1193 , cached_hash_value_(-1)
1194 , schemas_will_be_replicated_{ std::move(s) }
1195{
1196 size_t size = data_.size();
1197 if (size > 0 && size < data::DATA_OVERHEAD) {
1198 throw(exception::exception_builder<exception::illegal_argument>(
1199 "Data::setBuffer")
1200 << "Provided buffer should be either empty or should contain "
1201 "more than "
1202 << data::DATA_OVERHEAD << " bytes! Provided buffer size:" << size)
1203 .build();
1204 }
1205
1206 cached_hash_value_ = calculate_hash();
1207}
1208
1209size_t
1210data::data_size() const
1211{
1212 return (size_t)std::max<int>((int)total_size() - (int)data::DATA_OVERHEAD,
1213 0);
1214}
1215
1216size_t
1217data::total_size() const
1218{
1219 return data_.size();
1220}
1221
1222int
1223data::get_partition_hash() const
1224{
1225 return cached_hash_value_;
1226}
1227
1228bool
1229data::has_partition_hash() const
1230{
1231 return data_.size() >= data::DATA_OVERHEAD &&
1232 *reinterpret_cast<const int32_t*>(&data_[PARTITION_HASH_OFFSET]) !=
1233 0;
1234}
1235
1236const std::vector<byte>&
1237data::to_byte_array() const
1238{
1239 return data_;
1240}
1241
1242int32_t
1243data::get_type() const
1244{
1245 if (total_size() == 0) {
1246 return static_cast<int32_t>(
1247 serialization_constants::CONSTANT_TYPE_NULL);
1248 }
1249 return boost::endian::
1250 endian_load<boost::uint32_t, 4, boost::endian::order::big>(
1251 &data_[data::TYPE_OFFSET]);
1252}
1253
1254const data::schemas_t&
1255data::schemas_will_be_replicated() const
1256{
1257 return schemas_will_be_replicated_;
1258}
1259
1260int
1261data::hash() const
1262{
1263 return cached_hash_value_;
1264}
1265
1266int
1267data::calculate_hash() const
1268{
1269 size_t size = data_size();
1270 if (size == 0) {
1271 return 0;
1272 }
1273
1274 if (has_partition_hash()) {
1275 return boost::endian::
1276 endian_load<boost::uint32_t, 4, boost::endian::order::big>(
1277 &data_[data::PARTITION_HASH_OFFSET]);
1278 }
1279
1280 return util::murmur_hash3_x86_32((void*)&((data_)[data::DATA_OFFSET]),
1281 (int)size);
1282}
1283
1284bool
1285data::operator<(const data& rhs) const
1286{
1287 return cached_hash_value_ < rhs.cached_hash_value_;
1288}
1289
1290bool
1291operator==(const data& lhs, const data& rhs)
1292{
1293 return lhs.data_ == rhs.data_;
1294}
1295
1296ClassDefinitionContext::ClassDefinitionContext(
1297 int factory_id,
1298 PortableContext* portable_context)
1299 : factory_id_(factory_id)
1300 , portable_context_(portable_context)
1301{}
1302
1303int
1304ClassDefinitionContext::get_class_version(int class_id)
1305{
1306 std::shared_ptr<int> version = current_class_versions_.get(class_id);
1307 return version != NULL ? *version : -1;
1308}
1309
1310void
1311ClassDefinitionContext::set_class_version(int class_id, int version)
1312{
1313 std::shared_ptr<int> current = current_class_versions_.put_if_absent(
1314 class_id, std::shared_ptr<int>(new int(version)));
1315 if (current != NULL && *current != version) {
1316 std::stringstream error;
1317 error << "Class-id: " << class_id << " is already registered!";
1318 BOOST_THROW_EXCEPTION(exception::illegal_argument(
1319 "ClassDefinitionContext::setClassVersion", error.str()));
1320 }
1321}
1322
1323std::shared_ptr<ClassDefinition>
1324ClassDefinitionContext::lookup(int class_id, int version)
1325{
1326 long long key = combine_to_long(class_id, version);
1327 return versioned_definitions_.get(key);
1328}
1329
1330std::shared_ptr<ClassDefinition>
1331ClassDefinitionContext::register_class_definition(
1332 std::shared_ptr<ClassDefinition> cd)
1333{
1334 if (cd.get() == NULL) {
1335 return std::shared_ptr<ClassDefinition>();
1336 }
1337 if (cd->get_factory_id() != factory_id_) {
1338 throw(exception::exception_builder<exception::hazelcast_serialization>(
1339 "ClassDefinitionContext::registerClassDefinition")
1340 << "Invalid factory-id! " << factory_id_ << " -> " << cd)
1341 .build();
1342 }
1343
1344 cd->set_version_if_not_set(portable_context_->get_version());
1345
1346 long long versionedClassId =
1347 combine_to_long(cd->get_class_id(), cd->get_version());
1348 std::shared_ptr<ClassDefinition> currentCd =
1349 versioned_definitions_.put_if_absent(versionedClassId, cd);
1350 if (currentCd.get() == NULL) {
1351 return cd;
1352 }
1353
1354 if (currentCd.get() != cd.get() && *currentCd != *cd) {
1355 throw(exception::exception_builder<exception::hazelcast_serialization>(
1356 "ClassDefinitionContext::registerClassDefinition")
1357 << "Incompatible class-definitions with same class-id: " << *cd
1358 << " VS " << *currentCd)
1359 .build();
1360 }
1361
1362 return currentCd;
1363}
1364
1365int64_t
1366ClassDefinitionContext::combine_to_long(int x, int y) const
1367{
1368 return ((int64_t)x) << 32 | (((int64_t)y) & 0xFFFFFFFL);
1369}
1370
1371DefaultPortableReader::DefaultPortableReader(
1372 PortableSerializer& portable_ser,
1373 object_data_input& input,
1374 std::shared_ptr<ClassDefinition> cd)
1375 : PortableReaderBase(portable_ser, input, cd)
1376{}
1377
1378PortableReaderBase::PortableReaderBase(PortableSerializer& portable_ser,
1379 object_data_input& input,
1380 std::shared_ptr<ClassDefinition> cd)
1381 : cd_(cd)
1382 , data_input_(&input)
1383 , portable_serializer_(&portable_ser)
1384 , raw_(false)
1385{
1386 int fieldCount;
1387 try {
1388 // final position after portable is read
1389 final_position_ = input.read<int32_t>();
1390 // field count
1391 fieldCount = input.read<int32_t>();
1392 } catch (exception::iexception& e) {
1393 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1394 "[PortableReaderBase::PortableReaderBase]", e.what()));
1395 }
1396 if (fieldCount != cd->get_field_count()) {
1397 char msg[50];
1398 util::hz_snprintf(msg,
1399 50,
1400 "Field count[%d] in stream does not match %d",
1401 fieldCount,
1402 cd->get_field_count());
1403 BOOST_THROW_EXCEPTION(exception::illegal_state(
1404 "[PortableReaderBase::PortableReaderBase]", msg));
1405 }
1406 this->offset_ = input.position();
1407}
1408
1409void
1410PortableReaderBase::set_position(const std::string& field_name,
1411 field_type const& field_type)
1412{
1413 if (raw_) {
1414 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1415 "PortableReader::getPosition ",
1416 "Cannot read Portable fields after getRawDataInput() is called!"));
1417 }
1418 if (!cd_->has_field(field_name)) {
1419 // TODO: if no field def found, java client reads nested position:
1420 // readNestedPosition(fieldName, type);
1421 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1422 "PortableReader::getPosition ",
1423 "Don't have a field named " + std::string(field_name)));
1424 }
1425
1426 if (cd_->get_field_type(field_name) != field_type) {
1427 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1428 "PortableReader::getPosition ",
1429 "Field type did not matched for " + std::string(field_name)));
1430 }
1431
1432 data_input_->position(offset_ + cd_->get_field(field_name).get_index() *
1433 util::Bits::INT_SIZE_IN_BYTES);
1434 int32_t pos = data_input_->read<int32_t>();
1435
1436 data_input_->position(pos);
1437 int16_t len = data_input_->read<int16_t>();
1438
1439 // name + len + type
1440 data_input_->position(pos + util::Bits::SHORT_SIZE_IN_BYTES + len + 1);
1441}
1442
1443hazelcast::client::serialization::object_data_input&
1444PortableReaderBase::get_raw_data_input()
1445{
1446 if (!raw_) {
1447 data_input_->position(offset_ + cd_->get_field_count() *
1448 util::Bits::INT_SIZE_IN_BYTES);
1449 int32_t pos = data_input_->read<int32_t>();
1450 data_input_->position(pos);
1451 }
1452 raw_ = true;
1453 return *data_input_;
1454}
1455
1456void
1457PortableReaderBase::end()
1458{
1459 data_input_->position(final_position_);
1460}
1461
1462void
1463PortableReaderBase::check_factory_and_class(FieldDefinition fd,
1464 int32_t factory_id,
1465 int32_t class_id) const
1466{
1467 if (factory_id != fd.get_factory_id()) {
1468 char msg[100];
1469 util::hz_snprintf(msg,
1470 100,
1471 "Invalid factoryId! Expected: %d, Current: %d",
1472 fd.get_factory_id(),
1473 factory_id);
1474 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1475 "DefaultPortableReader::checkFactoryAndClass ", std::string(msg)));
1476 }
1477 if (class_id != fd.get_class_id()) {
1478 char msg[100];
1479 util::hz_snprintf(msg,
1480 100,
1481 "Invalid classId! Expected: %d, Current: %d",
1482 fd.get_class_id(),
1483 class_id);
1484 BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1485 "DefaultPortableReader::checkFactoryAndClass ", std::string(msg)));
1486 }
1487}
1488
1489MorphingPortableReader::MorphingPortableReader(
1490 PortableSerializer& portable_ser,
1491 object_data_input& input,
1492 std::shared_ptr<ClassDefinition> cd)
1493 : PortableReaderBase(portable_ser, input, cd)
1494{}
1495
1496PortableSerializer::PortableSerializer(PortableContext& portable_context)
1497 : context_(portable_context)
1498{}
1499
1501PortableSerializer::create_reader(object_data_input& input,
1502 int factory_id,
1503 int class_id,
1504 int version,
1505 int portable_version)
1506{
1507
1508 int effectiveVersion = version;
1509 if (version < 0) {
1510 effectiveVersion = context_.get_version();
1511 }
1512
1513 std::shared_ptr<ClassDefinition> cd =
1514 context_.lookup_class_definition(factory_id, class_id, effectiveVersion);
1515 if (cd == nullptr) {
1516 int begin = input.position();
1517 cd = context_.read_class_definition(
1518 input, factory_id, class_id, effectiveVersion);
1519 input.position(begin);
1520 }
1521
1522 return portable_reader(
1523 *this, input, cd, effectiveVersion == portable_version);
1524}
1525
1526int32_t
1527PortableSerializer::read_int(object_data_input& in) const
1528{
1529 return in.read<int32_t>();
1530}
1531
1532} // namespace pimpl
1533} // namespace serialization
1534} // namespace client
1535} // namespace hazelcast
1536
1537namespace std {
1538std::size_t
1539hash<hazelcast::client::hazelcast_json_value>::operator()(
1540 const hazelcast::client::hazelcast_json_value& object) const noexcept
1541{
1542 return std::hash<std::string>{}(object.to_string());
1543}
1544
1545std::size_t
1546hash<hazelcast::client::serialization::pimpl::data>::operator()(
1547 const hazelcast::client::serialization::pimpl::data& val) const noexcept
1548{
1549 return std::hash<int>{}(val.hash());
1550}
1551
1552std::size_t
1553hash<std::shared_ptr<hazelcast::client::serialization::pimpl::data>>::
1554operator()(const std::shared_ptr<hazelcast::client::serialization::pimpl::data>&
1555 val) const noexcept
1556{
1557 if (!val) {
1558 return std::hash<int>{}(-1);
1559 }
1560 return std::hash<int>{}(val->hash());
1561}
1562
1563bool
1564equal_to<std::shared_ptr<hazelcast::client::serialization::pimpl::data>>::
1565operator()(
1566 std::shared_ptr<hazelcast::client::serialization::pimpl::data> const& lhs,
1567 std::shared_ptr<hazelcast::client::serialization::pimpl::data> const& rhs)
1568 const noexcept
1569{
1570 if (lhs == rhs) {
1571 return true;
1572 }
1573
1574 if (!lhs || !rhs) {
1575 return false;
1576 }
1577
1578 return lhs->to_byte_array() == rhs->to_byte_array();
1579}
1580
1581bool
1582less<std::shared_ptr<hazelcast::client::serialization::pimpl::data>>::
1583operator()(
1584 const std::shared_ptr<hazelcast::client::serialization::pimpl::data>& lhs,
1585 const std::shared_ptr<hazelcast::client::serialization::pimpl::data>& rhs)
1586 const noexcept
1587{
1588 const hazelcast::client::serialization::pimpl::data* leftPtr = lhs.get();
1589 const hazelcast::client::serialization::pimpl::data* rightPtr = rhs.get();
1590 if (leftPtr == rightPtr) {
1591 return false;
1592 }
1593
1594 if (leftPtr == NULL) {
1595 return true;
1596 }
1597
1598 if (rightPtr == NULL) {
1599 return false;
1600 }
1601
1602 return lhs->hash() < rhs->hash();
1603}
1604} // namespace std
hazelcast_json_value is a wrapper for Json formatted strings.
hazelcast_json_value(std::string json_string)
Create a hazelcast_json_value from a string.
const std::string & to_string() const
This method returns a Json representation of the object.
ClassDefinitionBuilder is used to build and register ClassDefinitions manually.
void add_field_def(FieldDefinition &field_definition)
Internal API.
field_type get_field_type(const std::string &field_name) const
void write_data(pimpl::data_output &data_output)
Internal API.
const FieldDefinition & get_field(const std::string &field_name) const
void read_data(object_data_input &data_input)
Internal API.
void set_version_if_not_set(int new_version)
Internal API.
bool has_field(const std::string &field_name) const
ClassDefinition defines a class schema for portable classes.
void write_data(pimpl::data_output &data_output)
void read_data(object_data_input &data_input)
object_data_input(boost::endian::order byte_order, const std::vector< byte > &buffer, int offset, pimpl::PortableSerializer &portable_ser, pimpl::compact_stream_serializer &compact_ser, pimpl::DataSerializer &data_ser, std::shared_ptr< serialization::global_serializer > global_serializer)
Internal API.
object_data_output(boost::endian::order byte_order, bool dont_write=false, pimpl::PortableSerializer *portable_ser=nullptr, pimpl::compact_stream_serializer *compact_ser=nullptr, std::shared_ptr< serialization::global_serializer > global_serializer=nullptr)
Internal API Constructor.
Provides a mean of reading portable fields from a binary in form of java primitives arrays of java pr...
object_data_output & get_raw_data_output()
After writing portable fields, one can write remaining fields in old fashioned way consecutively at t...
void end()
Internal api , should not be called by end user.
portable_writer(pimpl::DefaultPortableWriter *default_portable_writer)
Internal api constructor.
typed_data class is a wrapper class for the serialized binary data.
const serialization::pimpl::data & get_data() const
Internal API.
boost::optional< T > get() const
Deserializes the underlying binary data and produces the object of type T.
serialization::pimpl::object_type get_type() const
STL namespace.