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