Hazelcast C++ Client
Hazelcast C++ Client Library
serialization.cpp
1 /*
2  * Copyright (c) 2008-2021, 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 /*
18  * Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved.
19  *
20  * Licensed under the Apache License, Version 2.0 (the "License");
21  * you may not use this file except in compliance with the License.
22  * You may obtain a copy of the License at
23  *
24  * http://www.apache.org/licenses/LICENSE-2.0
25  *
26  * Unless required by applicable law or agreed to in writing, software
27  * distributed under the License is distributed on an "AS IS" BASIS,
28  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29  * See the License for the specific language governing permissions and
30  * limitations under the License.
31  */
32 
33 #include <boost/concept_check.hpp>
34 #include <utility>
35 
36 #include "hazelcast/client/serialization/serialization.h"
37 #include "hazelcast/client/hazelcast_json_value.h"
38 #include "hazelcast/client/serialization/serialization.h"
39 #include "hazelcast/util/Util.h"
40 #include "hazelcast/util/IOUtil.h"
41 #include "hazelcast/util/Bits.h"
42 #include "hazelcast/util/MurmurHash3.h"
43 #include "hazelcast/client/spi/ClientContext.h"
44 #include "hazelcast/client/client_config.h"
45 
46 namespace hazelcast {
47  namespace client {
48  hazelcast_json_value::hazelcast_json_value(std::string json_string) : json_string_(std::move(json_string)) {
49  }
50 
51  hazelcast_json_value::~hazelcast_json_value() = default;
52 
53  const std::string &hazelcast_json_value::to_string() const {
54  return json_string_;
55  }
56 
57  bool hazelcast_json_value::operator==(const hazelcast_json_value &rhs) const {
58  return json_string_ == rhs.json_string_;
59  }
60 
61  bool hazelcast_json_value::operator!=(const hazelcast_json_value &rhs) const {
62  return !(rhs == *this);
63  }
64 
65  bool hazelcast_json_value::operator<(const hazelcast_json_value &rhs) const {
66  return json_string_ < rhs.json_string_;
67  }
68 
69  std::ostream &operator<<(std::ostream &os, const hazelcast_json_value &value) {
70  os << "jsonString: " << value.json_string_;
71  return os;
72  }
73 
74  typed_data::typed_data() : ss_(nullptr) {
75  }
76 
77  typed_data::typed_data(serialization::pimpl::data d,
78  serialization::pimpl::SerializationService &serialization_service) : data_(std::move(d)),
79  ss_(&serialization_service) {}
80 
81  serialization::pimpl::object_type typed_data::get_type() const {
82  return ss_->get_object_type(&data_);
83  }
84 
85  const serialization::pimpl::data &typed_data::get_data() const {
86  return data_;
87  }
88 
89  bool operator<(const typed_data &lhs, const typed_data &rhs) {
90  const auto& lhs_data = lhs.get_data();
91  const auto& rhs_data = rhs.get_data();
92 
93  return lhs_data < rhs_data;
94  }
95 
96  namespace serialization {
97  portable_writer::portable_writer(pimpl::DefaultPortableWriter *default_portable_writer)
98  : default_portable_writer_(default_portable_writer), class_definition_writer_(nullptr), is_default_writer_(true) {}
99 
100  portable_writer::portable_writer(pimpl::ClassDefinitionWriter *class_definition_writer)
101  : default_portable_writer_(nullptr), class_definition_writer_(class_definition_writer),
102  is_default_writer_(false) {}
103 
105  if (is_default_writer_)
106  return default_portable_writer_->end();
107  return class_definition_writer_->end();
108  }
109 
111  if (is_default_writer_)
112  return default_portable_writer_->get_raw_data_output();
113  return class_definition_writer_->get_raw_data_output();
114  }
115 
116  ClassDefinitionBuilder::ClassDefinitionBuilder(int factory_id, int class_id, int version)
117  : factory_id_(factory_id), class_id_(class_id), version_(version), index_(0), done_(false) {}
118 
119  ClassDefinitionBuilder &ClassDefinitionBuilder::add_portable_field(const std::string &field_name,
120  std::shared_ptr<ClassDefinition> def) {
121  check();
122  if (def->get_class_id() == 0) {
123  BOOST_THROW_EXCEPTION(
124  exception::illegal_argument("ClassDefinitionBuilder::addPortableField",
125  "Portable class id cannot be zero!"));
126  }
127  FieldDefinition fieldDefinition(index_++, field_name, field_type::TYPE_PORTABLE, def->get_factory_id(),
128  def->get_class_id(), def->get_version());
129  field_definitions_.push_back(fieldDefinition);
130  return *this;
131  }
132 
133  ClassDefinitionBuilder &ClassDefinitionBuilder::add_portable_array_field(const std::string &field_name,
134  std::shared_ptr<ClassDefinition> def) {
135  check();
136  if (def->get_class_id() == 0) {
137  BOOST_THROW_EXCEPTION(
138  exception::illegal_argument("ClassDefinitionBuilder::addPortableField",
139  "Portable class id cannot be zero!"));
140  }
141  FieldDefinition fieldDefinition(index_++, field_name, field_type::TYPE_PORTABLE_ARRAY,
142  def->get_factory_id(), def->get_class_id(), def->get_version());
143  field_definitions_.push_back(fieldDefinition);
144  return *this;
145  }
146 
147  ClassDefinitionBuilder &ClassDefinitionBuilder::add_field(FieldDefinition &field_definition) {
148  check();
149  int defIndex = field_definition.get_index();
150  if (index_ != defIndex) {
151  char buf[100];
152  util::hz_snprintf(buf, 100, "Invalid field index. Index in definition:%d, being added at index:%d",
153  defIndex, index_);
154  BOOST_THROW_EXCEPTION(exception::illegal_argument("ClassDefinitionBuilder::addField", buf));
155  }
156  index_++;
157  field_definitions_.push_back(field_definition);
158  return *this;
159  }
160 
161  std::shared_ptr<ClassDefinition> ClassDefinitionBuilder::build() {
162  done_ = true;
163  std::shared_ptr<ClassDefinition> cd(new ClassDefinition(factory_id_, class_id_, version_));
164 
165  std::vector<FieldDefinition>::iterator fdIt;
166  for (fdIt = field_definitions_.begin(); fdIt != field_definitions_.end(); fdIt++) {
167  cd->add_field_def(*fdIt);
168  }
169  return cd;
170  }
171 
172  void ClassDefinitionBuilder::check() {
173  if (done_) {
174  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization("ClassDefinitionBuilder::check",
175  "ClassDefinition is already built for " +
176  util::IOUtil::to_string(class_id_)));
177  }
178  }
179 
180  void ClassDefinitionBuilder::add_field(const std::string &field_name, field_type const &field_type) {
181  check();
182  FieldDefinition fieldDefinition(index_++, field_name, field_type, version_);
183  field_definitions_.push_back(fieldDefinition);
184  }
185 
186  int ClassDefinitionBuilder::get_factory_id() {
187  return factory_id_;
188  }
189 
190  int ClassDefinitionBuilder::get_class_id() {
191  return class_id_;
192  }
193 
194  int ClassDefinitionBuilder::get_version() {
195  return version_;
196  }
197 
199  : index_(0), class_id_(0), factory_id_(0), version_(-1) {
200  }
201 
202  FieldDefinition::FieldDefinition(int index, const std::string &field_name, field_type const &type,
203  int version)
204  : index_(index), field_name_(field_name), type_(type), class_id_(0), factory_id_(0), version_(version) {
205  }
206 
207  FieldDefinition::FieldDefinition(int index, const std::string &field_name, field_type const &type,
208  int factory_id, int class_id, int version)
209  : index_(index), field_name_(field_name), type_(type), class_id_(class_id), factory_id_(factory_id),
210  version_(version) {}
211 
212  const field_type &FieldDefinition::get_type() const {
213  return type_;
214  }
215 
216  std::string FieldDefinition::get_name() const {
217  return field_name_;
218  }
219 
221  return index_;
222  }
223 
225  return factory_id_;
226  }
227 
229  return class_id_;
230  }
231 
232  void FieldDefinition::write_data(pimpl::data_output &data_output) {
233  data_output.write<int32_t>(index_);
234  data_output.write<std::string>(field_name_);
235  data_output.write<byte>(static_cast<int32_t>(type_));
236  data_output.write<int32_t>(factory_id_);
237  data_output.write<int32_t>(class_id_);
238  }
239 
241  index_ = data_input.read<int32_t>();
242  field_name_ = data_input.read<std::string>();
243  type_ = static_cast<field_type>(data_input.read<byte>());
244  factory_id_ = data_input.read<int32_t>();
245  class_id_ = data_input.read<int32_t>();
246  }
247 
248  bool FieldDefinition::operator==(const FieldDefinition &rhs) const {
249  return field_name_ == rhs.field_name_ &&
250  type_ == rhs.type_ &&
251  class_id_ == rhs.class_id_ &&
252  factory_id_ == rhs.factory_id_ &&
253  version_ == rhs.version_;
254  }
255 
256  bool FieldDefinition::operator!=(const FieldDefinition &rhs) const {
257  return !(rhs == *this);
258  }
259 
260  std::ostream &operator<<(std::ostream &os, const FieldDefinition &definition) {
261  os << "FieldDefinition{" << "index: " << definition.index_ << " fieldName: " << definition.field_name_
262  << " type: " << static_cast<int32_t>(definition.type_) << " classId: " << definition.class_id_ << " factoryId: "
263  << definition.factory_id_ << " version: " << definition.version_;
264  return os;
265  }
266 
267  object_data_input::object_data_input(boost::endian::order byte_order, const std::vector<byte> &buffer,
268  int offset, pimpl::PortableSerializer &portable_ser,
269  pimpl::DataSerializer &data_ser,
270  std::shared_ptr<serialization::global_serializer> global_serializer)
271  : pimpl::data_input<std::vector<byte>>(byte_order, buffer, offset), portable_serializer_(portable_ser), data_serializer_(data_ser), global_serializer_(std::move(global_serializer)) {}
272 
273  object_data_output::object_data_output(boost::endian::order byte_order, bool dont_write,
274  pimpl::PortableSerializer *portable_ser,
275  std::shared_ptr<serialization::global_serializer> global_serializer)
276  : data_output(byte_order, dont_write), portable_serializer_(portable_ser),
277  global_serializer_(std::move(global_serializer)) {}
278 
279  portable_reader::portable_reader(pimpl::PortableSerializer &portable_ser, object_data_input &input,
280  const std::shared_ptr<ClassDefinition> &cd, bool is_default_reader)
281  : is_default_reader_(is_default_reader) {
282  if (is_default_reader) {
283  default_portable_reader_ = boost::make_optional(pimpl::DefaultPortableReader(portable_ser, input, cd));
284  } else {
285  morphing_portable_reader_ = boost::make_optional(pimpl::MorphingPortableReader(portable_ser, input, cd));
286  }
287  }
288 
290  if (is_default_reader_)
291  return default_portable_reader_->get_raw_data_input();
292  return morphing_portable_reader_->get_raw_data_input();
293  }
294 
295  template<>
296  void object_data_output::write_object(const char *object) {
297  if (!object) {
298  write<int32_t>(static_cast<int32_t>(pimpl::serialization_constants::CONSTANT_TYPE_NULL));
299  return;
300  }
301  write_object<std::string>(std::string(object));
302  }
303 
305  if (is_default_reader_)
306  return default_portable_reader_->end();
307  return morphing_portable_reader_->end();
308 
309  }
310 
312  : factory_id_(0), class_id_(0), version_(-1), binary_(new std::vector<byte>) {
313  }
314 
315  ClassDefinition::ClassDefinition(int factory_id, int class_id, int version)
316  : factory_id_(factory_id), class_id_(class_id), version_(version), binary_(new std::vector<byte>) {
317  }
318 
320  field_definitions_map_[fd.get_name()] = fd;
321  }
322 
323  const FieldDefinition &ClassDefinition::get_field(const std::string &name) const {
324  auto it = field_definitions_map_.find(name);
325  if (it != field_definitions_map_.end()) {
326  return it->second;
327  }
328  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization("ClassDefinition::getField",
329  (boost::format("Invalid field name: '%1%' for ClassDefinition {id: %2%, version: %3%}")
330  %name %class_id_ %version_).str()));
331  }
332 
333  bool ClassDefinition::has_field(const std::string &field_name) const {
334  return field_definitions_map_.find(field_name) != field_definitions_map_.end();
335  }
336 
337  field_type ClassDefinition::get_field_type(const std::string &field_name) const {
338  FieldDefinition const &fd = get_field(field_name);
339  return fd.get_type();
340  }
341 
343  return (int) field_definitions_map_.size();
344  }
345 
346 
348  return factory_id_;
349  }
350 
352  return class_id_;
353  }
354 
356  return version_;
357  }
358 
360  if (get_version() < 0) {
361  this->version_ = new_version;
362  }
363  }
364 
365  void ClassDefinition::write_data(pimpl::data_output &data_output) {
366  data_output.write<int32_t>(factory_id_);
367  data_output.write<int32_t>(class_id_);
368  data_output.write<int32_t>(version_);
369  data_output.write<int16_t>(field_definitions_map_.size());
370  for (auto &entry : field_definitions_map_) {
371  entry.second.write_data(data_output);
372  }
373  }
374 
376  factory_id_ = data_input.read<int32_t>();
377  class_id_ = data_input.read<int32_t>();
378  version_ = data_input.read<int32_t>();
379  int size = data_input.read<int16_t>();
380  for (int i = 0; i < size; i++) {
381  FieldDefinition fieldDefinition;
382  fieldDefinition.read_data(data_input);
383  add_field_def(fieldDefinition);
384  }
385  }
386 
387  bool ClassDefinition::operator==(const ClassDefinition &rhs) const {
388  return factory_id_ == rhs.factory_id_ &&
389  class_id_ == rhs.class_id_ &&
390  version_ == rhs.version_ &&
391  field_definitions_map_ == rhs.field_definitions_map_;
392  }
393 
394  bool ClassDefinition::operator!=(const ClassDefinition &rhs) const {
395  return !(rhs == *this);
396  }
397 
398  std::ostream &operator<<(std::ostream &os, const ClassDefinition &definition) {
399  os << "ClassDefinition{" << "factoryId: " << definition.factory_id_ << " classId: " << definition.class_id_
400  << " version: "
401  << definition.version_ << " fieldDefinitions: {";
402 
403  for (auto &entry : definition.field_definitions_map_) {
404  os << entry.second;
405  }
406  os << "} }";
407  return os;
408  }
409 
410  namespace pimpl {
411  ClassDefinitionWriter::ClassDefinitionWriter(PortableContext &portable_context,
412  ClassDefinitionBuilder &builder)
413  : builder_(builder), context_(portable_context),
414  empty_data_output_(portable_context.get_serialization_config().get_byte_order(), true) {}
415 
416  std::shared_ptr<ClassDefinition> ClassDefinitionWriter::register_and_get() {
417  std::shared_ptr<ClassDefinition> cd = builder_.build();
418  return context_.register_class_definition(cd);
419  }
420 
421  object_data_output &ClassDefinitionWriter::get_raw_data_output() {
422  return empty_data_output_;
423  }
424 
425  void ClassDefinitionWriter::end() {}
426 
427  data_output::data_output(boost::endian::order byte_order, bool dont_write) : byte_order_(byte_order),
428  is_no_write_(dont_write) {
429  if (is_no_write_) {
430  output_stream_.reserve(0);
431  } else {
432  output_stream_.reserve(DEFAULT_SIZE);
433  }
434  }
435 
436  template<>
437  void data_output::write(byte i) {
438  if (is_no_write_) { return; }
439  output_stream_.push_back(i);
440  }
441 
442  template<>
443  void data_output::write(char i) {
444  // C++ `char` is one byte only, `char16_t` is two bytes
445  write<int16_t>(i);
446  }
447 
448  template<>
449  void data_output::write(char16_t i) {
450  write<int16_t>(i);
451  }
452 
453  template<>
454  void data_output::write(int16_t value) {
455  if (is_no_write_) { return; }
456  if (byte_order_ == boost::endian::order::big) {
457  boost::endian::native_to_big_inplace(value);
458  } else {
459  boost::endian::native_to_little_inplace(value);
460  }
461  output_stream_.insert(output_stream_.end(), (byte *) &value, (byte *) &value + util::Bits::SHORT_SIZE_IN_BYTES);
462  }
463 
464  void data_output::write(int32_t value, boost::endian::order byte_order) {
465  if (is_no_write_) { return; }
466  if (byte_order == boost::endian::order::big) {
467  boost::endian::native_to_big_inplace(value);
468  } else {
469  boost::endian::native_to_little_inplace(value);
470  }
471  output_stream_.insert(output_stream_.end(), (byte *) &value, (byte *) &value + util::Bits::INT_SIZE_IN_BYTES);
472  }
473 
474  template<>
475  void data_output::write(int32_t value) {
476  write(value, byte_order_);
477  }
478 
479  template<>
480  void data_output::write(int64_t value) {
481  if (is_no_write_) { return; }
482  if (byte_order_ == boost::endian::order::big) {
483  boost::endian::native_to_big_inplace(value);
484  } else {
485  boost::endian::native_to_little_inplace(value);
486  }
487  output_stream_.insert(output_stream_.end(), (byte *) &value, (byte *) &value + util::Bits::LONG_SIZE_IN_BYTES);
488  }
489 
490  template<>
491  void data_output::write(float x) {
492  if (is_no_write_) { return; }
493  union {
494  float f;
495  int32_t i;
496  } u;
497  u.f = x;
498  write<int32_t>(u.i);
499  }
500 
501  template<>
502  void data_output::write(double v) {
503  if (is_no_write_) { return; }
504  union {
505  double d;
506  int64_t l;
507  } u;
508  u.d = v;
509  write<int64_t>(u.l);
510  }
511 
512  template<>
513  void data_output::write(boost::uuids::uuid v) {
514  if (is_no_write_) { return; }
515  if (byte_order_ == boost::endian::order::little) {
516  boost::endian::endian_reverse_inplace<int64_t>(*reinterpret_cast<int64_t *>(v.data));
517  boost::endian::endian_reverse_inplace<int64_t>(
518  *reinterpret_cast<int64_t *>(&v.data[util::Bits::LONG_SIZE_IN_BYTES]));
519  }
520  output_stream_.insert(output_stream_.end(), v.data, v.data + util::Bits::UUID_SIZE_IN_BYTES);
521  }
522 
523  template<>
524  void data_output::write(bool value) {
525  if (is_no_write_) { return; }
526  write<byte>(value);
527  }
528 
529  template<>
530  void data_output::write(const std::string &str) {
531  if (is_no_write_) { return; }
532 
533  write<int32_t>(str.size());
534  output_stream_.insert(output_stream_.end(), str.begin(), str.end());
535  }
536 
537  template<>
538  void data_output::write(const hazelcast_json_value &value) {
539  if (is_no_write_) { return; }
540  write<std::string>(value.to_string());
541  }
542 
543  object_type::object_type() : type_id(serialization_constants::CONSTANT_TYPE_NULL), factory_id(-1), class_id(-1) {}
544 
545  std::ostream &operator<<(std::ostream &os, const object_type &type) {
546  os << "typeId: " << static_cast<int32_t>(type.type_id) << " factoryId: " << type.factory_id << " classId: "
547  << type.class_id;
548  return os;
549  }
550 
551  int32_t DataSerializer::read_int(object_data_input &in) const {
552  return in.read<int32_t>();
553  }
554 
555  PortableContext::PortableContext(const serialization_config &serialization_conf) :
556  serialization_config_(serialization_conf) {}
557 
558  int PortableContext::get_class_version(int factory_id, int class_id) {
559  return get_class_definition_context(factory_id).get_class_version(class_id);
560  }
561 
562  void PortableContext::set_class_version(int factory_id, int class_id, int version) {
563  get_class_definition_context(factory_id).set_class_version(class_id, version);
564  }
565 
566  std::shared_ptr<ClassDefinition>
567  PortableContext::lookup_class_definition(int factory_id, int class_id, int version) {
568  return get_class_definition_context(factory_id).lookup(class_id, version);
569  }
570 
571  std::shared_ptr<ClassDefinition>
572  PortableContext::read_class_definition(object_data_input &in, int factory_id, int class_id, int version) {
573  bool shouldRegister = true;
574  ClassDefinitionBuilder builder(factory_id, class_id, version);
575 
576  // final position after portable is read
577  in.read<int32_t>();
578 
579  // field count
580  int fieldCount = in.read<int32_t>();
581  int offset = in.position();
582  for (int i = 0; i < fieldCount; i++) {
583  in.position(offset + i * util::Bits::INT_SIZE_IN_BYTES);
584  int pos = in.read<int32_t>();
585  in.position(pos);
586 
587  short len = in.read<int16_t>();
588  std::vector<byte> chars(len);
589  in.read_fully(chars);
590  chars.push_back('\0');
591 
592  field_type type(static_cast<field_type>(in.read<byte>()));
593  std::string name((char *) &(chars[0]));
594  int fieldFactoryId = 0;
595  int fieldClassId = 0;
596  int fieldVersion = version;
597  if (type == field_type::TYPE_PORTABLE) {
598  // is null
599  if (in.read<bool>()) {
600  shouldRegister = false;
601  }
602  fieldFactoryId = in.read<int32_t>();
603  fieldClassId = in.read<int32_t>();
604 
605  // TODO: what if there's a null inner Portable field
606  if (shouldRegister) {
607  fieldVersion = in.read<int32_t>();
608  read_class_definition(in, fieldFactoryId, fieldClassId, fieldVersion);
609  }
610  } else if (type == field_type::TYPE_PORTABLE_ARRAY) {
611  int k = in.read<int32_t>();
612  if (k > 0) {
613  fieldFactoryId = in.read<int32_t>();
614  fieldClassId = in.read<int32_t>();
615 
616  int p = in.read<int32_t>();
617  in.position(p);
618 
619  // TODO: what if there's a null inner Portable field
620  fieldVersion = in.read<int32_t>();
621  read_class_definition(in, fieldFactoryId, fieldClassId, fieldVersion);
622  } else {
623  shouldRegister = false;
624  }
625 
626  }
627  FieldDefinition fieldDef(i, name, type, fieldFactoryId, fieldClassId, fieldVersion);
628  builder.add_field(fieldDef);
629  }
630  std::shared_ptr<ClassDefinition> classDefinition = builder.build();
631  if (shouldRegister) {
632  classDefinition = register_class_definition(classDefinition);
633  }
634  return classDefinition;
635  }
636 
637  std::shared_ptr<ClassDefinition>
638  PortableContext::register_class_definition(std::shared_ptr<ClassDefinition> cd) {
639  return get_class_definition_context(cd->get_factory_id()).register_class_definition(cd);
640  }
641 
642  int PortableContext::get_version() {
643  return serialization_config_.get_portable_version();
644  }
645 
646  ClassDefinitionContext &PortableContext::get_class_definition_context(int factory_id) {
647  std::shared_ptr<ClassDefinitionContext> value = class_def_context_map_.get(factory_id);
648  if (value == NULL) {
649  value = std::shared_ptr<ClassDefinitionContext>(new ClassDefinitionContext(factory_id, this));
650  std::shared_ptr<ClassDefinitionContext> current = class_def_context_map_.put_if_absent(factory_id,
651  value);
652  if (current != NULL) {
653  value = current;
654  }
655  }
656  return *value;
657  }
658 
659  const serialization_config &PortableContext::get_serialization_config() const {
660  return serialization_config_;
661  }
662 
663  SerializationService::SerializationService(const serialization_config &config)
664  : serialization_config_(config), portable_context_(serialization_config_),
665  portable_serializer_(portable_context_) {}
666 
667  DefaultPortableWriter::DefaultPortableWriter(PortableSerializer &portable_ser,
668  std::shared_ptr<ClassDefinition> cd,
669  object_data_output &output)
670  : raw_(false), portable_serializer_(portable_ser), object_data_output_(output),
671  begin_(object_data_output_.position()), cd_(cd) {
672  // room for final offset
673  object_data_output_.write<int32_t>(0);
674 
675  object_data_output_.write<int32_t>(cd->get_field_count());
676 
677  offset_ = object_data_output_.position();
678  // one additional for raw data
679  int fieldIndexesLength = (cd->get_field_count() + 1) * util::Bits::INT_SIZE_IN_BYTES;
680  object_data_output_.write_zero_bytes(fieldIndexesLength);
681  }
682 
683  FieldDefinition const &DefaultPortableWriter::set_position(const std::string &field_name, field_type field_type) {
684  if (raw_) {
685  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization("PortableWriter::setPosition",
686  "Cannot write Portable fields after getRawDataOutput() is called!"));
687  }
688 
689  try {
690  FieldDefinition const &fd = cd_->get_field(field_name);
691 
692  if (written_fields_.find(field_name) != written_fields_.end()) {
693  BOOST_THROW_EXCEPTION(
694  exception::hazelcast_serialization("PortableWriter::setPosition",
695  "Field '" + std::string(field_name) +
696  "' has already been written!"));
697  }
698 
699  written_fields_.insert(field_name);
700  size_t pos = object_data_output_.position();
701  int32_t index = fd.get_index();
702  object_data_output_.write_at(offset_ + index * util::Bits::INT_SIZE_IN_BYTES, static_cast<int32_t>(pos));
703  object_data_output_.write(static_cast<int16_t>(field_name.size()));
704  object_data_output_.write_bytes(field_name);
705  object_data_output_.write<byte>(static_cast<byte>(field_type));
706 
707  return fd;
708 
709  } catch (exception::illegal_argument &iae) {
710  std::stringstream error;
711  error << "hazelcast_serialization_exception( Invalid field name: '" << field_name;
712  error << "' for ClassDefinition {class id: " << util::IOUtil::to_string(cd_->get_class_id());
713  error << ", factoryId:" + util::IOUtil::to_string(cd_->get_factory_id());
714  error << ", version: " << util::IOUtil::to_string(cd_->get_version()) << "}. Error:";
715  error << iae.what();
716 
717  BOOST_THROW_EXCEPTION(
718  exception::hazelcast_serialization("PortableWriter::setPosition", error.str()));
719  }
720 
721  }
722 
723  object_data_output &DefaultPortableWriter::get_raw_data_output() {
724  if (!raw_) {
725  size_t pos = object_data_output_.position();
726  int32_t index = cd_->get_field_count(); // last index
727  object_data_output_.write_at(offset_ + index * util::Bits::INT_SIZE_IN_BYTES, static_cast<int32_t>(pos));
728  }
729  raw_ = true;
730  return object_data_output_;
731  }
732 
733  void DefaultPortableWriter::end() {
734  object_data_output_.write_at(begin_, static_cast<int32_t>(object_data_output_.position()));
735  }
736 
737  bool SerializationService::is_null_data(const data &data) {
738  return data.data_size() == 0 &&
739  data.get_type() == static_cast<int32_t>(serialization_constants::CONSTANT_TYPE_NULL);
740  }
741 
742  template<>
743  data SerializationService::to_data(const char *object) {
744  if (!object) {
745  return to_data<std::string>(nullptr);
746  }
747  std::string str(object);
748  return to_data<std::string>(str);
749  }
750 
751  const byte SerializationService::get_version() const {
752  return 1;
753  }
754 
755  object_type SerializationService::get_object_type(const data *data) {
756  object_type type;
757 
758  if (NULL == data) {
759  type.type_id = serialization_constants::CONSTANT_TYPE_NULL;
760  return type;
761  }
762 
763  type.type_id = static_cast<serialization_constants>(data->get_type());
764 
765  if (serialization_constants::CONSTANT_TYPE_DATA == type.type_id ||
766  serialization_constants::CONSTANT_TYPE_PORTABLE == type.type_id) {
767  // 8 (data Header) = Hash(4-bytes) + data TypeId(4 bytes)
768  data_input<std::vector<byte>> dataInput(serialization_config_.get_byte_order(), data->to_byte_array(), 8);
769 
770  if (serialization_constants::CONSTANT_TYPE_DATA == type.type_id) {
771  bool identified = dataInput.read<bool>();
772  if (!identified) {
773  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
774  "SerializationService::getObjectType",
775  " DataSerializable is not 'identified data'"));
776  }
777  }
778 
779  type.factory_id = dataInput.read<int32_t>();
780  type.class_id = dataInput.read<int32_t>();
781  }
782 
783  return type;
784  }
785 
786  void SerializationService::dispose() {
787  }
788 
789  PortableSerializer &SerializationService::get_portable_serializer() {
790  return portable_serializer_;
791  }
792 
793  DataSerializer &SerializationService::get_data_serializer() {
794  return data_serializer_;
795  }
796 
797  object_data_output SerializationService::new_output_stream() {
798  return object_data_output(serialization_config_.get_byte_order(), false, &portable_serializer_,
799  serialization_config_.get_global_serializer());
800  }
801 
802  template<>
803  data SerializationService::to_data(const typed_data *object) {
804  if (!object) {
805  return data();
806  }
807 
808  return object->get_data();
809  }
810 
811  //first 4 byte is partition hash code and next last 4 byte is type id
812  unsigned int data::PARTITION_HASH_OFFSET = 0;
813 
814  unsigned int data::TYPE_OFFSET = data::PARTITION_HASH_OFFSET + util::Bits::INT_SIZE_IN_BYTES;
815 
816  unsigned int data::DATA_OFFSET = data::TYPE_OFFSET + util::Bits::INT_SIZE_IN_BYTES;
817 
818  unsigned int data::DATA_OVERHEAD = data::DATA_OFFSET;
819 
820  data::data() : cached_hash_value_(-1) {}
821 
822  data::data(std::vector<byte> buffer) : data_(std::move(buffer)), cached_hash_value_(-1) {
823  size_t size = data_.size();
824  if (size > 0 && size < data::DATA_OVERHEAD) {
825  throw (exception::exception_builder<exception::illegal_argument>("Data::setBuffer")
826  << "Provided buffer should be either empty or should contain more than "
827  << data::DATA_OVERHEAD << " bytes! Provided buffer size:" << size).build();
828  }
829 
830  cached_hash_value_ = calculate_hash();
831  }
832 
833  size_t data::data_size() const {
834  return (size_t) std::max<int>((int) total_size() - (int) data::DATA_OVERHEAD, 0);
835  }
836 
837  size_t data::total_size() const {
838  return data_.size();
839  }
840 
841  int data::get_partition_hash() const {
842  return cached_hash_value_;
843  }
844 
845  bool data::has_partition_hash() const {
846  return data_.size() >= data::DATA_OVERHEAD &&
847  *reinterpret_cast<const int32_t *>(&data_[PARTITION_HASH_OFFSET]) != 0;
848  }
849 
850  const std::vector<byte> &data::to_byte_array() const {
851  return data_;
852  }
853 
854  int32_t data::get_type() const {
855  if (total_size() == 0) {
856  return static_cast<int32_t>(serialization_constants::CONSTANT_TYPE_NULL);
857  }
858  return boost::endian::endian_load<boost::uint32_t, 4, boost::endian::order::big>(
859  &data_[data::TYPE_OFFSET]);
860  }
861 
862  int data::hash() const {
863  return cached_hash_value_;
864  }
865 
866  int data::calculate_hash() const {
867  size_t size = data_size();
868  if (size == 0) {
869  return 0;
870  }
871 
872  if (has_partition_hash()) {
873  return boost::endian::endian_load<boost::uint32_t, 4, boost::endian::order::big>(
874  &data_[data::PARTITION_HASH_OFFSET]);
875  }
876 
877  return util::murmur_hash3_x86_32((void *) &((data_)[data::DATA_OFFSET]), (int) size);
878  }
879 
880  bool data::operator<(const data &rhs) const {
881  return cached_hash_value_ < rhs.cached_hash_value_;
882  }
883 
884  bool operator==(const data &lhs, const data &rhs) {
885  return lhs.data_ == rhs.data_;
886  }
887 
888  ClassDefinitionContext::ClassDefinitionContext(int factory_id, PortableContext *portable_context)
889  : factory_id_(factory_id), portable_context_(portable_context) {}
890 
891  int ClassDefinitionContext::get_class_version(int class_id) {
892  std::shared_ptr<int> version = current_class_versions_.get(class_id);
893  return version != NULL ? *version : -1;
894  }
895 
896  void ClassDefinitionContext::set_class_version(int class_id, int version) {
897  std::shared_ptr<int> current = current_class_versions_.put_if_absent(class_id, std::shared_ptr<int>(
898  new int(version)));
899  if (current != NULL && *current != version) {
900  std::stringstream error;
901  error << "Class-id: " << class_id << " is already registered!";
902  BOOST_THROW_EXCEPTION(
903  exception::illegal_argument("ClassDefinitionContext::setClassVersion",
904  error.str()));
905  }
906  }
907 
908  std::shared_ptr<ClassDefinition> ClassDefinitionContext::lookup(int class_id, int version) {
909  long long key = combine_to_long(class_id, version);
910  return versioned_definitions_.get(key);
911 
912  }
913 
914  std::shared_ptr<ClassDefinition>
915  ClassDefinitionContext::register_class_definition(std::shared_ptr<ClassDefinition> cd) {
916  if (cd.get() == NULL) {
917  return std::shared_ptr<ClassDefinition>();
918  }
919  if (cd->get_factory_id() != factory_id_) {
920  throw (exception::exception_builder<exception::hazelcast_serialization>(
921  "ClassDefinitionContext::registerClassDefinition") << "Invalid factory-id! "
922  << factory_id_ << " -> "
923  << cd).build();
924  }
925 
926  cd->set_version_if_not_set(portable_context_->get_version());
927 
928  long long versionedClassId = combine_to_long(cd->get_class_id(), cd->get_version());
929  std::shared_ptr<ClassDefinition> currentCd = versioned_definitions_.put_if_absent(versionedClassId, cd);
930  if (currentCd.get() == NULL) {
931  return cd;
932  }
933 
934  if (currentCd.get() != cd.get() && *currentCd != *cd) {
935  throw (exception::exception_builder<exception::hazelcast_serialization>(
936  "ClassDefinitionContext::registerClassDefinition")
937  << "Incompatible class-definitions with same class-id: " << *cd << " VS "
938  << *currentCd).build();
939  }
940 
941  return currentCd;
942  }
943 
944  int64_t ClassDefinitionContext::combine_to_long(int x, int y) const {
945  return ((int64_t) x) << 32 | (((int64_t) y) & 0xFFFFFFFL);
946  }
947 
948  DefaultPortableReader::DefaultPortableReader(PortableSerializer &portable_ser,
949  object_data_input &input,
950  std::shared_ptr<ClassDefinition> cd)
951  : PortableReaderBase(portable_ser, input, cd) {}
952 
953  PortableReaderBase::PortableReaderBase(PortableSerializer &portable_ser, object_data_input &input,
954  std::shared_ptr<ClassDefinition> cd)
955  : cd_(cd), data_input_(&input), portable_serializer_(&portable_ser), raw_(false) {
956  int fieldCount;
957  try {
958  // final position after portable is read
959  final_position_ = input.read<int32_t>();
960  // field count
961  fieldCount = input.read<int32_t>();
962  } catch (exception::iexception &e) {
963  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
964  "[PortableReaderBase::PortableReaderBase]", e.what()));
965  }
966  if (fieldCount != cd->get_field_count()) {
967  char msg[50];
968  util::hz_snprintf(msg, 50, "Field count[%d] in stream does not match %d", fieldCount,
969  cd->get_field_count());
970  BOOST_THROW_EXCEPTION(
971  exception::illegal_state("[PortableReaderBase::PortableReaderBase]",
972  msg));
973  }
974  this->offset_ = input.position();
975  }
976 
977  void PortableReaderBase::set_position(const std::string &field_name, field_type const &field_type) {
978  if (raw_) {
979  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization("PortableReader::getPosition ",
980  "Cannot read Portable fields after getRawDataInput() is called!"));
981  }
982  if (!cd_->has_field(field_name)) {
983  // TODO: if no field def found, java client reads nested position:
984  // readNestedPosition(fieldName, type);
985  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization("PortableReader::getPosition ",
986  "Don't have a field named " +
987  std::string(field_name)));
988  }
989 
990  if (cd_->get_field_type(field_name) != field_type) {
991  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization("PortableReader::getPosition ",
992  "Field type did not matched for " +
993  std::string(field_name)));
994  }
995 
996  data_input_->position(offset_ + cd_->get_field(field_name).get_index() * util::Bits::INT_SIZE_IN_BYTES);
997  int32_t pos = data_input_->read<int32_t>();
998 
999  data_input_->position(pos);
1000  int16_t len = data_input_->read<int16_t>();
1001 
1002  // name + len + type
1003  data_input_->position(pos + util::Bits::SHORT_SIZE_IN_BYTES + len + 1);
1004  }
1005 
1006  hazelcast::client::serialization::object_data_input &PortableReaderBase::get_raw_data_input() {
1007  if (!raw_) {
1008  data_input_->position(offset_ + cd_->get_field_count() * util::Bits::INT_SIZE_IN_BYTES);
1009  int32_t pos = data_input_->read<int32_t>();
1010  data_input_->position(pos);
1011  }
1012  raw_ = true;
1013  return *data_input_;
1014  }
1015 
1016  void PortableReaderBase::end() {
1017  data_input_->position(final_position_);
1018  }
1019 
1020  void
1021  PortableReaderBase::check_factory_and_class(FieldDefinition fd, int32_t factory_id, int32_t class_id) const {
1022  if (factory_id != fd.get_factory_id()) {
1023  char msg[100];
1024  util::hz_snprintf(msg, 100, "Invalid factoryId! Expected: %d, Current: %d", fd.get_factory_id(),
1025  factory_id);
1026  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1027  "DefaultPortableReader::checkFactoryAndClass ",
1028  std::string(msg)));
1029  }
1030  if (class_id != fd.get_class_id()) {
1031  char msg[100];
1032  util::hz_snprintf(msg, 100, "Invalid classId! Expected: %d, Current: %d", fd.get_class_id(),
1033  class_id);
1034  BOOST_THROW_EXCEPTION(exception::hazelcast_serialization(
1035  "DefaultPortableReader::checkFactoryAndClass ",
1036  std::string(msg)));
1037  }
1038  }
1039 
1040  MorphingPortableReader::MorphingPortableReader(PortableSerializer &portable_ser, object_data_input &input,
1041  std::shared_ptr<ClassDefinition> cd)
1042  : PortableReaderBase(portable_ser, input, cd) {}
1043 
1044  PortableSerializer::PortableSerializer(PortableContext &portable_context) : context_(portable_context) {}
1045 
1046  portable_reader
1047  PortableSerializer::create_reader(object_data_input &input, int factory_id, int class_id, int version,
1048  int portable_version) {
1049 
1050  int effectiveVersion = version;
1051  if (version < 0) {
1052  effectiveVersion = context_.get_version();
1053  }
1054 
1055  std::shared_ptr<ClassDefinition> cd = context_.lookup_class_definition(factory_id, class_id,
1056  effectiveVersion);
1057  if (cd == nullptr) {
1058  int begin = input.position();
1059  cd = context_.read_class_definition(input, factory_id, class_id, effectiveVersion);
1060  input.position(begin);
1061  }
1062 
1063  return portable_reader(*this, input, cd, effectiveVersion == portable_version);
1064  }
1065 
1066  int32_t PortableSerializer::read_int(object_data_input &in) const {
1067  return in.read<int32_t>();
1068  }
1069  }
1070  }
1071  }
1072 }
1073 
1074 namespace std {
1075  std::size_t hash<hazelcast::client::hazelcast_json_value>::operator()(
1076  const hazelcast::client::hazelcast_json_value &object) const noexcept {
1077  return std::hash<std::string>{}(object.to_string());
1078  }
1079 
1080  std::size_t hash<hazelcast::client::serialization::pimpl::data>::operator()
1081  (const hazelcast::client::serialization::pimpl::data &val) const noexcept {
1082  return std::hash<int>{}(val.hash());
1083  }
1084 
1085  std::size_t hash<std::shared_ptr<hazelcast::client::serialization::pimpl::data>>::operator()
1086  (const std::shared_ptr<hazelcast::client::serialization::pimpl::data> &val) const noexcept {
1087  if (!val) {
1088  return std::hash<int>{}(-1);
1089  }
1090  return std::hash<int>{}(val->hash());
1091  }
1092 
1093  bool equal_to<std::shared_ptr<hazelcast::client::serialization::pimpl::data>>::operator()
1094  (std::shared_ptr<hazelcast::client::serialization::pimpl::data> const &lhs,
1095  std::shared_ptr<hazelcast::client::serialization::pimpl::data> const &rhs) const noexcept {
1096  if (lhs == rhs) {
1097  return true;
1098  }
1099 
1100  if (!lhs || !rhs) {
1101  return false;
1102  }
1103 
1104  return lhs->to_byte_array() == rhs->to_byte_array();
1105  }
1106 
1107  bool less<std::shared_ptr<hazelcast::client::serialization::pimpl::data>>::operator()(
1108  const std::shared_ptr<hazelcast::client::serialization::pimpl::data> &lhs,
1109  const std::shared_ptr<hazelcast::client::serialization::pimpl::data> &rhs) const noexcept {
1110  const hazelcast::client::serialization::pimpl::data *leftPtr = lhs.get();
1111  const hazelcast::client::serialization::pimpl::data *rightPtr = rhs.get();
1112  if (leftPtr == rightPtr) {
1113  return false;
1114  }
1115 
1116  if (leftPtr == NULL) {
1117  return true;
1118  }
1119 
1120  if (rightPtr == NULL) {
1121  return false;
1122  }
1123 
1124  return lhs->hash() < rhs->hash();
1125  }
1126 }
1127 
1128 
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.
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::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, std::shared_ptr< serialization::global_serializer > global_serializer=nullptr)
Internal API Constructor.
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