| /* |
| * 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_ |