blob: 08d2e2105752376eaccac9331afc82801e2d12e0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifndef GEODE_SERIALIZATIONREGISTRY_H_
#define GEODE_SERIALIZATIONREGISTRY_H_
#include <string>
#include <functional>
#include <ace/Hash_Map_Manager.h>
#include <ace/Thread_Mutex.h>
#include <ace/Null_Mutex.h>
#include <geode/internal/geode_globals.hpp>
#include <geode/internal/DataSerializableInternal.hpp>
#include <geode/Serializable.hpp>
#include <geode/PdxSerializer.hpp>
#include <geode/DataOutput.hpp>
#include <geode/ExceptionTypes.hpp>
#include <geode/Delta.hpp>
#include <geode/PdxSerializable.hpp>
#include <geode/DataSerializable.hpp>
#include "util/concurrent/spinlock_mutex.hpp"
#include "NonCopyable.hpp"
#include "MemberListForVersionStamp.hpp"
#include "config.h"
#if defined(_MACOSX)
namespace ACE_VERSIONED_NAMESPACE_NAME {
// TODO CMake check type int64_t
template <>
class ACE_Export ACE_Hash<int64_t> {
public:
inline unsigned long operator()(int64_t t) const {
return static_cast<long>(t);
}
};
} // namespace ACE_VERSIONED_NAMESPACE_NAME
#endif
namespace apache {
namespace geode {
namespace client {
using internal::DataSerializableInternal;
typedef ACE_Hash_Map_Manager<int64_t, TypeFactoryMethod, ACE_Null_Mutex>
IdToFactoryMap;
typedef ACE_Hash_Map_Manager<std::string, TypeFactoryMethodPdx, ACE_Null_Mutex>
StrToPdxFactoryMap;
class TheTypeMap : private NonCopyable {
private:
IdToFactoryMap* m_map;
IdToFactoryMap* m_map2; // to hold Fixed IDs since GFE 5.7.
StrToPdxFactoryMap* m_pdxTypemap;
mutable util::concurrent::spinlock_mutex m_mapLock;
mutable util::concurrent::spinlock_mutex m_map2Lock;
mutable util::concurrent::spinlock_mutex m_pdxTypemapLock;
public:
TheTypeMap() {
m_map = new IdToFactoryMap();
// second map to hold internal Data Serializable Fixed IDs - since GFE 5.7
m_map2 = new IdToFactoryMap();
// map to hold PDX types <string, funptr>.
m_pdxTypemap = new StrToPdxFactoryMap();
setup();
}
virtual ~TheTypeMap() {
if (m_map != nullptr) {
delete m_map;
}
if (m_map2 != nullptr) {
delete m_map2;
}
if (m_pdxTypemap != nullptr) {
delete m_pdxTypemap;
}
}
void setup();
void clear();
void find(int64_t id, TypeFactoryMethod& func) const;
void find2(int64_t id, TypeFactoryMethod& func) const;
void bind(TypeFactoryMethod func);
inline void rebind(int64_t compId, TypeFactoryMethod func);
inline void unbind(int64_t compId);
inline void bind2(TypeFactoryMethod func);
inline void rebind2(int64_t compId, TypeFactoryMethod func);
inline void unbind2(int64_t compId);
inline void bindPdxType(TypeFactoryMethodPdx func);
inline void findPdxType(const std::string& objFullName,
TypeFactoryMethodPdx& func) const;
inline void unbindPdxType(const std::string& objFullName);
void rebindPdxType(std::string objFullName, TypeFactoryMethodPdx func);
};
class Pool;
/**
* Used to register handlers for the PDX DsCode. .NET client extends this to
* intercept PDX (de)serialization.
*/
class PdxTypeHandler {
public:
virtual ~PdxTypeHandler() noexcept = default;
virtual void serialize(const std::shared_ptr<PdxSerializable>& pdxSerializable,
DataOutput& dataOutput) const;
virtual std::shared_ptr<PdxSerializable> deserialize(
DataInput& dataInput) const;
};
class APACHE_GEODE_EXPORT SerializationRegistry {
public:
SerializationRegistry() : theTypeMap() {}
/** write the length of the serialization, write the typeId of the object,
* then write whatever the object's toData requires. The length at the
* front is backfilled after the serialization.
*/
inline void serialize(const Serializable* obj, DataOutput& output,
bool isDelta = false) const {
if (obj == nullptr) {
output.write(static_cast<int8_t>(DSCode::NullObj));
} else if (const auto dataSerializableFixedId =
dynamic_cast<const DataSerializableFixedId*>(obj)) {
serialize(dataSerializableFixedId, output);
} else if (const auto dataSerializablePrimitive =
dynamic_cast<const DataSerializablePrimitive*>(obj)) {
serialize(dataSerializablePrimitive, output);
} else if (const auto dataSerializable =
dynamic_cast<const DataSerializable*>(obj)) {
serialize(dataSerializable, output, isDelta);
} else if (const auto dataSerializableInternal =
dynamic_cast<const DataSerializableInternal*>(obj)) {
serialize(dataSerializableInternal, output);
} else {
throw UnsupportedOperationException(
"SerializationRegistry::serialize: Serialization type not "
"implemented.");
}
}
inline void serialize(const std::shared_ptr<Serializable>& obj, DataOutput& output,
bool isDelta = false) const {
if (obj == nullptr) {
output.write(static_cast<int8_t>(DSCode::NullObj));
} else if (auto&& pdxSerializable =
std::dynamic_pointer_cast<PdxSerializable>(obj)) {
serialize(pdxSerializable, output);
} else {
serialize(obj.get(), output, isDelta);
}
}
inline void serializeWithoutHeader(const Serializable* obj,
DataOutput& output) const {
if (const auto dataSerializableFixedId =
dynamic_cast<const DataSerializableFixedId*>(obj)) {
serializeWithoutHeader(dataSerializableFixedId, output);
} else if (const auto dataSerializablePrimitive =
dynamic_cast<const DataSerializablePrimitive*>(obj)) {
serializeWithoutHeader(dataSerializablePrimitive, output);
} else if (const auto dataSerializable =
dynamic_cast<const DataSerializable*>(obj)) {
serializeWithoutHeader(dataSerializable, output);
} else if (const auto pdxSerializable =
dynamic_cast<const PdxSerializable*>(obj)) {
serializeWithoutHeader(pdxSerializable, output);
} else if (const auto dataSerializableInternal =
dynamic_cast<const DataSerializableInternal*>(obj)) {
serializeWithoutHeader(dataSerializableInternal, output);
} else {
throw UnsupportedOperationException(
"SerializationRegistry::serializeWithoutHeader: Serialization type "
"not implemented.");
}
}
inline void serializeWithoutHeader(const std::shared_ptr<Serializable>& obj, DataOutput& output
) const {
if (auto&& pdxSerializable =
std::dynamic_pointer_cast<PdxSerializable>(obj)) {
serializeWithoutHeader(pdxSerializable, output);
} else {
serializeWithoutHeader(obj.get(), output);
}
}
inline void serialize(const std::shared_ptr<Serializable>& obj,
DataOutput& output) const {
serialize(obj.get(), output);
}
/**
* Read the length, typeid, and run the objs fromData. Returns the New
* object.
*/
std::shared_ptr<Serializable> deserialize(DataInput& input,
int8_t typeId = -1) const;
void addType(TypeFactoryMethod func);
void addType(int64_t compId, TypeFactoryMethod func);
void addPdxType(TypeFactoryMethodPdx func);
void setPdxSerializer(std::shared_ptr<PdxSerializer> pdxSerializer);
std::shared_ptr<PdxSerializer> getPdxSerializer();
void removeType(int64_t compId);
// following for internal types with Data Serializable Fixed IDs - since GFE
// 5.7
void addType2(TypeFactoryMethod func);
void addType2(int64_t compId, TypeFactoryMethod func);
void removeType2(int64_t compId);
int32_t GetPDXIdForType(Pool* pool,
std::shared_ptr<Serializable> pdxType) const;
std::shared_ptr<Serializable> GetPDXTypeById(Pool* pool,
int32_t typeId) const;
int32_t GetEnumValue(std::shared_ptr<Pool> pool,
std::shared_ptr<Serializable> enumInfo) const;
std::shared_ptr<Serializable> GetEnum(std::shared_ptr<Pool> pool,
int32_t val) const;
std::shared_ptr<PdxSerializable> getPdxType(
const std::string& className) const;
void setPdxTypeHandler(PdxTypeHandler* handler) {
this->pdxTypeHandler = std::unique_ptr<PdxTypeHandler>(handler);
}
private:
std::unique_ptr<PdxTypeHandler> pdxTypeHandler;
std::shared_ptr<PdxSerializer> pdxSerializer;
TheTypeMap theTypeMap;
inline void serialize(const DataSerializableFixedId* obj,
DataOutput& output) const {
auto id = static_cast<int32_t>(obj->getDSFID());
if (id <= std::numeric_limits<int8_t>::max() &&
id >= std::numeric_limits<int8_t>::min()) {
output.write(static_cast<int8_t>(DSCode::FixedIDByte));
output.write(static_cast<int8_t>(id));
} else if (id <= std::numeric_limits<int16_t>::max() &&
id >= std::numeric_limits<int16_t>::min()) {
output.write(static_cast<int8_t>(DSCode::FixedIDShort));
output.writeInt(static_cast<int16_t>(id));
} else {
output.write(static_cast<int8_t>(DSCode::FixedIDInt));
output.writeInt(static_cast<int32_t>(id));
}
serializeWithoutHeader(obj, output);
}
inline void serializeWithoutHeader(const DataSerializableFixedId* obj,
DataOutput& output) const {
obj->toData(output);
}
inline void serialize(const DataSerializablePrimitive* obj,
DataOutput& output) const {
auto id = obj->getDsCode();
output.write(static_cast<int8_t>(id));
serializeWithoutHeader(obj, output);
}
inline void serializeWithoutHeader(const DataSerializablePrimitive* obj,
DataOutput& output) const {
obj->toData(output);
}
inline void serialize(const DataSerializable* obj, DataOutput& output,
bool isDelta) const {
auto id = obj->getClassId();
auto dsCode = getSerializableDataDsCode(id);
output.write(static_cast<int8_t>(dsCode));
switch (dsCode) {
case DSCode::CacheableUserData:
output.write(static_cast<int8_t>(id));
break;
case DSCode::CacheableUserData2:
output.writeInt(static_cast<int16_t>(id));
break;
case DSCode::CacheableUserData4:
output.writeInt(static_cast<int32_t>(id));
break;
default:
IllegalStateException("Invalid DS Code.");
}
if (isDelta) {
const Delta* ptr = dynamic_cast<const Delta*>(obj);
ptr->toDelta(output);
} else {
serializeWithoutHeader(obj, output);
}
}
inline void serializeWithoutHeader(const DataSerializable* obj,
DataOutput& output) const {
obj->toData(output);
}
inline void serialize(const std::shared_ptr<PdxSerializable>& obj, DataOutput& output) const {
output.write(static_cast<int8_t>(DSCode::PDX));
serializeWithoutHeader(obj, output);
}
void serializeWithoutHeader(const std::shared_ptr<PdxSerializable>& obj,
DataOutput& output) const;
inline void serialize(const DataSerializableInternal* obj,
DataOutput& output) const {
serializeWithoutHeader(obj, output);
}
inline void serializeWithoutHeader(const DataSerializableInternal* obj,
DataOutput& output) const {
obj->toData(output);
}
public:
static inline DSCode getSerializableDataDsCode(int32_t classId) {
if (classId <= std::numeric_limits<int8_t>::max() &&
classId >= std::numeric_limits<int8_t>::min()) {
return DSCode::CacheableUserData;
} else if (classId <= std::numeric_limits<int16_t>::max() &&
classId >= std::numeric_limits<int16_t>::min()) {
return DSCode::CacheableUserData2;
} else {
return DSCode::CacheableUserData4;
}
}
private:
void deserialize(DataInput& input, std::shared_ptr<Serializable> obj) const;
void deserialize(DataInput& input,
std::shared_ptr<DataSerializableInternal> obj) const;
void deserialize(DataInput& input,
std::shared_ptr<DataSerializableFixedId> obj) const;
void deserialize(DataInput& input,
std::shared_ptr<DataSerializablePrimitive> obj) const;
void deserialize(DataInput& input,
std::shared_ptr<DataSerializable> obj) const;
[[noreturn]] void deserialize(DataInput& input,
std::shared_ptr<PdxSerializable> obj) const;
};
} // namespace client
} // namespace geode
} // namespace apache
#endif // GEODE_SERIALIZATIONREGISTRY_H_