| /* |
| * 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. |
| */ |
| |
| #include <mutex> |
| #include <functional> |
| |
| #include <ace/Singleton.h> |
| #include <ace/Thread_Mutex.h> |
| |
| #include <geode/internal/geode_globals.hpp> |
| #include <geode/CacheableBuiltins.hpp> |
| #include <geode/CacheableObjectArray.hpp> |
| #include <geode/CacheableDate.hpp> |
| #include <geode/CacheableFileName.hpp> |
| #include <geode/CacheableString.hpp> |
| #include <geode/CacheableUndefined.hpp> |
| #include <geode/CacheableEnum.hpp> |
| #include <geode/Struct.hpp> |
| #include <geode/DataInput.hpp> |
| #include <geode/DataOutput.hpp> |
| #include <geode/Region.hpp> |
| #include <geode/Properties.hpp> |
| #include <geode/ExceptionTypes.hpp> |
| #include <geode/RegionAttributes.hpp> |
| #include <geode/PoolManager.hpp> |
| #include <geode/PdxWrapper.hpp> |
| |
| #include "config.h" |
| |
| #include "SerializationRegistry.hpp" |
| #include "CacheableToken.hpp" |
| #include "EventId.hpp" |
| #include "CacheableObjectPartList.hpp" |
| #include "ClientConnectionResponse.hpp" |
| #include "QueueConnectionResponse.hpp" |
| #include "LocatorListResponse.hpp" |
| #include "ClientProxyMembershipID.hpp" |
| #include "GetAllServersResponse.hpp" |
| #include "TXCommitMessage.hpp" |
| #include "ThinClientPoolDM.hpp" |
| #include "PdxType.hpp" |
| #include "EnumInfo.hpp" |
| #include "VersionTag.hpp" |
| #include "DiskStoreId.hpp" |
| #include "DiskVersionTag.hpp" |
| #include "PdxHelper.hpp" |
| |
| namespace apache { |
| namespace geode { |
| namespace client { |
| |
| void TheTypeMap::setup() { |
| // Register Geode builtins here!! |
| // update type ids in DSCode.hpp |
| |
| bind(CacheableByte::createDeserializable); |
| bind(CacheableBoolean::createDeserializable); |
| bind(BooleanArray::createDeserializable); |
| bind(CacheableBytes::createDeserializable); |
| bind(CacheableFloat::createDeserializable); |
| bind(CacheableFloatArray::createDeserializable); |
| bind(CacheableDouble::createDeserializable); |
| bind(CacheableDoubleArray::createDeserializable); |
| bind(CacheableDate::createDeserializable); |
| bind(CacheableFileName::createDeserializable); |
| bind(CacheableHashMap::createDeserializable); |
| bind(CacheableHashSet::createDeserializable); |
| bind(CacheableHashTable::createDeserializable); |
| bind(CacheableIdentityHashMap::createDeserializable); |
| bind(CacheableLinkedHashSet::createDeserializable); |
| bind(CacheableInt16::createDeserializable); |
| bind(CacheableInt16Array::createDeserializable); |
| bind(CacheableInt32::createDeserializable); |
| bind(CacheableInt32Array::createDeserializable); |
| bind(CacheableInt64::createDeserializable); |
| bind(CacheableInt64Array::createDeserializable); |
| bind(CacheableObjectArray::createDeserializable); |
| bind(CacheableString::createDeserializable); |
| bind(CacheableString::createDeserializableHuge); |
| bind(CacheableString::createUTFDeserializable); |
| bind(CacheableString::createUTFDeserializableHuge); |
| bind(CacheableStringArray::createDeserializable); |
| bind(CacheableVector::createDeserializable); |
| bind(CacheableArrayList::createDeserializable); |
| bind(CacheableLinkedList::createDeserializable); |
| bind(CacheableStack::createDeserializable); |
| bind(CacheableCharacter::createDeserializable); |
| bind(CharArray::createDeserializable); |
| bind(CacheableToken::createDeserializable); |
| bind(RegionAttributes::createDeserializable); |
| bind(Properties::createDeserializable); |
| |
| bind2(CacheableUndefined::createDeserializable); |
| bind2(EventId::createDeserializable); |
| bind2(Struct::createDeserializable); |
| bind2(ClientConnectionResponse::create); |
| bind2(QueueConnectionResponse::create); |
| bind2(LocatorListResponse::create); |
| bind2(ClientProxyMembershipID::createDeserializable); |
| bind2(GetAllServersResponse::create); |
| bind2(EnumInfo::createDeserializable); |
| bind2(DiskStoreId::createDeserializable); |
| } |
| |
| /** This starts at reading the typeid.. assumes the length has been read. */ |
| std::shared_ptr<Serializable> SerializationRegistry::deserialize( |
| DataInput& input, int8_t typeId) const { |
| bool findinternal = false; |
| auto typedTypeId = static_cast<DSCode>(typeId); |
| int64_t compId = typeId; |
| |
| if (typeId == -1) { |
| compId = input.read(); |
| typedTypeId = static_cast<DSCode>(compId); |
| } |
| |
| LOGDEBUG("SerializationRegistry::deserialize typeid = %d currentTypeId= %" PRId8, |
| typeId, typedTypeId); |
| |
| switch (typedTypeId) { |
| case DSCode::CacheableNullString: { |
| return std::shared_ptr<Serializable>( |
| CacheableString::createDeserializable()); |
| } |
| case DSCode::PDX: { |
| return pdxTypeHandler->deserialize(input); |
| } |
| case DSCode::CacheableEnum: { |
| auto enumObject = CacheableEnum::create(" ", " ", 0); |
| enumObject->fromData(input); |
| return enumObject; |
| } |
| case DSCode::CacheableUserData: { |
| compId |= ((static_cast<int64_t>(input.read())) << 32); |
| break; |
| } |
| case DSCode::CacheableUserData2: { |
| compId |= ((static_cast<int64_t>(input.readInt16())) << 32); |
| break; |
| } |
| case DSCode::CacheableUserData4: { |
| int32_t classId = input.readInt32(); |
| compId |= ((static_cast<int64_t>(classId)) << 32); |
| break; |
| } |
| case DSCode::FixedIDByte: { |
| compId = input.read(); |
| findinternal = true; |
| break; |
| } |
| case DSCode::FixedIDShort: { |
| compId = input.readInt16(); |
| findinternal = true; |
| break; |
| } |
| case DSCode::FixedIDInt: { |
| int32_t fixedId = input.readInt32(); |
| compId = fixedId; |
| findinternal = true; |
| break; |
| } |
| case DSCode::NullObj: { |
| return nullptr; |
| } |
| default: |
| break; |
| } |
| |
| TypeFactoryMethod createType = nullptr; |
| |
| if (findinternal) { |
| theTypeMap.find2(compId, createType); |
| } else { |
| theTypeMap.find(compId, createType); |
| } |
| |
| if (createType == nullptr) { |
| if (findinternal) { |
| LOGERROR( |
| "Unregistered class ID %d during deserialization: Did the " |
| "application register serialization types?", |
| compId); |
| } else { |
| LOGERROR( |
| "Unregistered class ID %d during deserialization: Did the " |
| "application register serialization types?", |
| (compId >> 32)); |
| } |
| |
| // instead of a null key or null value... an Exception should be thrown.. |
| throw IllegalStateException("Unregistered class ID in deserialization"); |
| } |
| |
| std::shared_ptr<Serializable> obj(createType()); |
| |
| deserialize(input, obj); |
| |
| return obj; |
| } |
| |
| void SerializationRegistry::deserialize( |
| DataInput& input, std::shared_ptr<Serializable> obj) const { |
| if (!obj) { |
| // nothing to read |
| } else if (const auto dataSerializableInternal = |
| std::dynamic_pointer_cast<DataSerializableInternal>(obj)) { |
| deserialize(input, dataSerializableInternal); |
| } else if (const auto dataSerializableFixedId = |
| std::dynamic_pointer_cast<DataSerializableFixedId>(obj)) { |
| deserialize(input, dataSerializableFixedId); |
| } else if (const auto dataSerializablePrimitive = |
| std::dynamic_pointer_cast<DataSerializablePrimitive>(obj)) { |
| deserialize(input, dataSerializablePrimitive); |
| } else if (const auto dataSerializable = |
| std::dynamic_pointer_cast<DataSerializable>(obj)) { |
| deserialize(input, dataSerializable); |
| } else if (const auto pdxSerializable = |
| std::dynamic_pointer_cast<PdxSerializable>(obj)) { |
| deserialize(input, pdxSerializable); |
| } else { |
| throw UnsupportedOperationException("Serialization type not implemented."); |
| } |
| } |
| |
| void SerializationRegistry::deserialize( |
| DataInput& input, |
| std::shared_ptr<DataSerializableInternal> dataSerializableInternal) const { |
| dataSerializableInternal->fromData(input); |
| } |
| |
| void SerializationRegistry::deserialize( |
| DataInput& input, |
| std::shared_ptr<DataSerializableFixedId> dataSerializableFixedId) const { |
| dataSerializableFixedId->fromData(input); |
| } |
| |
| void SerializationRegistry::deserialize( |
| DataInput& input, |
| std::shared_ptr<DataSerializablePrimitive> dataSerializablePrimitive) |
| const { |
| dataSerializablePrimitive->fromData(input); |
| } |
| |
| void SerializationRegistry::deserialize( |
| DataInput& input, |
| std::shared_ptr<DataSerializable> dataSerializable) const { |
| dataSerializable->fromData(input); |
| } |
| |
| void SerializationRegistry::deserialize( |
| DataInput& /*input*/, |
| std::shared_ptr<PdxSerializable> /*pdxSerializable*/) const { |
| throw UnsupportedOperationException( |
| "SerializationRegistry::deserialize<PdxSerializable> not implemented"); |
| } |
| |
| void SerializationRegistry::serializeWithoutHeader(const std::shared_ptr<PdxSerializable>& obj, |
| DataOutput& output) const { |
| pdxTypeHandler->serialize(obj, output); |
| } |
| |
| void SerializationRegistry::addType(TypeFactoryMethod func) { |
| theTypeMap.bind(func); |
| } |
| |
| void SerializationRegistry::addPdxType(TypeFactoryMethodPdx func) { |
| theTypeMap.bindPdxType(func); |
| } |
| |
| void SerializationRegistry::addType(int64_t compId, TypeFactoryMethod func) { |
| theTypeMap.rebind(compId, func); |
| } |
| |
| void SerializationRegistry::removeType(int64_t compId) { |
| theTypeMap.unbind(compId); |
| } |
| |
| void SerializationRegistry::addType2(TypeFactoryMethod func) { |
| theTypeMap.bind2(func); |
| } |
| |
| void SerializationRegistry::addType2(int64_t compId, TypeFactoryMethod func) { |
| theTypeMap.rebind2(compId, func); |
| } |
| |
| void SerializationRegistry::removeType2(int64_t compId) { |
| theTypeMap.unbind2(compId); |
| } |
| |
| std::shared_ptr<PdxSerializable> SerializationRegistry::getPdxType( |
| const std::string& className) const { |
| TypeFactoryMethodPdx objectType = nullptr; |
| theTypeMap.findPdxType(className, objectType); |
| std::shared_ptr<PdxSerializable> pdxSerializable; |
| |
| if (nullptr == objectType) { |
| try { |
| pdxSerializable = std::make_shared<PdxWrapper>(nullptr, className); |
| } catch (const Exception&) { |
| LOGERROR("Unregistered class " + className + |
| " during PDX deserialization: Did the application register the " |
| "PDX type or serializer?"); |
| throw IllegalStateException( |
| "Unregistered class or serializer in PDX deserialization"); |
| } |
| } else { |
| pdxSerializable = objectType(); |
| } |
| return pdxSerializable; |
| } |
| |
| void SerializationRegistry::setPdxSerializer( |
| std::shared_ptr<PdxSerializer> serializer) { |
| this->pdxSerializer = serializer; |
| } |
| |
| std::shared_ptr<PdxSerializer> SerializationRegistry::getPdxSerializer() { |
| return pdxSerializer; |
| } |
| |
| int32_t SerializationRegistry::GetPDXIdForType( |
| Pool* pool, std::shared_ptr<Serializable> pdxType) const { |
| if (auto poolDM = dynamic_cast<ThinClientPoolDM*>(pool)) { |
| return poolDM->GetPDXIdForType(pdxType); |
| } |
| |
| throw IllegalStateException("Pool not found, Pdx operation failed"); |
| } |
| |
| std::shared_ptr<Serializable> SerializationRegistry::GetPDXTypeById( |
| Pool* pool, int32_t typeId) const { |
| if (auto poolDM = dynamic_cast<ThinClientPoolDM*>(pool)) { |
| return poolDM->GetPDXTypeById(typeId); |
| } |
| |
| throw IllegalStateException("Pool not found, Pdx operation failed"); |
| } |
| |
| int32_t SerializationRegistry::GetEnumValue( |
| std::shared_ptr<Pool> pool, std::shared_ptr<Serializable> enumInfo) const { |
| if (pool == nullptr) { |
| throw IllegalStateException("Pool not found, Pdx operation failed"); |
| } |
| |
| return static_cast<ThinClientPoolDM*>(pool.get())->GetEnumValue(enumInfo); |
| } |
| std::shared_ptr<Serializable> SerializationRegistry::GetEnum( |
| std::shared_ptr<Pool> pool, int32_t val) const { |
| if (pool == nullptr) { |
| throw IllegalStateException("Pool not found, Pdx operation failed"); |
| } |
| |
| return static_cast<ThinClientPoolDM*>(pool.get())->GetEnum(val); |
| } |
| |
| void TheTypeMap::clear() { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_mapLock); |
| m_map->unbind_all(); |
| |
| std::lock_guard<util::concurrent::spinlock_mutex> guard2(m_map2Lock); |
| m_map2->unbind_all(); |
| |
| std::lock_guard<util::concurrent::spinlock_mutex> guard3(m_pdxTypemapLock); |
| m_pdxTypemap->unbind_all(); |
| } |
| |
| void TheTypeMap::find(int64_t id, TypeFactoryMethod& func) const { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_mapLock); |
| m_map->find(id, func); |
| } |
| |
| void TheTypeMap::find2(int64_t id, TypeFactoryMethod& func) const { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_map2Lock); |
| m_map2->find(id, func); |
| } |
| |
| void TheTypeMap::bind(TypeFactoryMethod func) { |
| auto obj = func(); |
| int64_t compId; |
| |
| if (const auto dataSerializablePrimitive = |
| std::dynamic_pointer_cast<DataSerializablePrimitive>(obj)) { |
| compId = static_cast<int64_t>(dataSerializablePrimitive->getDsCode()); |
| } else if (const auto dataSerializableInternal = |
| std::dynamic_pointer_cast<DataSerializableInternal>(obj)) { |
| compId = static_cast<int64_t>(dataSerializableInternal->getInternalId()); |
| } else if (const auto dataSerializable = |
| std::dynamic_pointer_cast<DataSerializable>(obj)) { |
| auto id = dataSerializable->getClassId(); |
| compId = static_cast<int64_t>( |
| SerializationRegistry::getSerializableDataDsCode(id)) | |
| static_cast<int64_t>(id) << 32; |
| } else { |
| throw UnsupportedOperationException( |
| "TheTypeMap::bind: Serialization type not implemented."); |
| } |
| |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_mapLock); |
| int bindRes = m_map->bind(compId, func); |
| if (bindRes == 1) { |
| LOGERROR("A class with ID %d is already registered.", compId); |
| throw IllegalStateException("A class with given ID is already registered."); |
| } else if (bindRes == -1) { |
| LOGERROR("Unknown error while adding class ID %d to map.", compId); |
| throw IllegalStateException("Unknown error while adding type to map."); |
| } |
| } |
| |
| void TheTypeMap::rebind(int64_t compId, TypeFactoryMethod func) { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_mapLock); |
| int bindRes = m_map->rebind(compId, func); |
| if (bindRes == -1) { |
| LOGERROR( |
| "Unknown error " |
| "while adding class ID %d to map.", |
| compId); |
| throw IllegalStateException( |
| "Unknown error " |
| "while adding type to map."); |
| } |
| } |
| |
| void TheTypeMap::unbind(int64_t compId) { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_mapLock); |
| m_map->unbind(compId); |
| } |
| |
| void TheTypeMap::bind2(TypeFactoryMethod func) { |
| auto obj = func(); |
| |
| int64_t compId = 0; |
| if (const auto dataSerializableFixedId = |
| std::dynamic_pointer_cast<DataSerializableFixedId>(obj)) { |
| compId = static_cast<int64_t>(dataSerializableFixedId->getDSFID()); |
| } else { |
| throw UnsupportedOperationException( |
| "TheTypeMap::bind2: Unknown serialization type."); |
| } |
| |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_map2Lock); |
| int bindRes = m_map2->bind(compId, func); |
| if (bindRes == 1) { |
| LOGERROR( |
| "A fixed class with " |
| "ID %d is already registered.", |
| compId); |
| throw IllegalStateException( |
| "A fixed class with " |
| "given ID is already registered."); |
| } else if (bindRes == -1) { |
| LOGERROR( |
| "Unknown error " |
| "while adding class ID %d to map2.", |
| compId); |
| throw IllegalStateException( |
| "Unknown error " |
| "while adding to map2."); |
| } |
| } |
| |
| void TheTypeMap::rebind2(int64_t compId, TypeFactoryMethod func) { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_map2Lock); |
| m_map2->rebind(compId, func); |
| } |
| |
| void TheTypeMap::unbind2(int64_t compId) { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_map2Lock); |
| m_map2->unbind(compId); |
| } |
| |
| void TheTypeMap::bindPdxType(TypeFactoryMethodPdx func) { |
| auto obj = func(); |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_pdxTypemapLock); |
| auto&& objFullName = obj->getClassName(); |
| |
| int bindRes = m_pdxTypemap->bind(objFullName, func); |
| |
| if (bindRes == 1) { |
| LOGERROR("A object with FullName " + objFullName + |
| " is already registered."); |
| throw IllegalStateException( |
| "A Object with given FullName is already registered."); |
| } else if (bindRes == -1) { |
| LOGERROR("Unknown error while adding Pdx Object named " + objFullName + |
| " to map."); |
| throw IllegalStateException("Unknown error while adding type to map."); |
| } |
| } |
| |
| void TheTypeMap::findPdxType(const std::string& objFullName, |
| TypeFactoryMethodPdx& func) const { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_pdxTypemapLock); |
| m_pdxTypemap->find(objFullName, func); |
| } |
| |
| void TheTypeMap::rebindPdxType(std::string objFullName, |
| TypeFactoryMethodPdx func) { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_pdxTypemapLock); |
| int bindRes = m_pdxTypemap->rebind(objFullName, func); |
| if (bindRes == -1) { |
| LOGERROR("Unknown error while adding Pdx Object FullName " + objFullName + |
| " to map."); |
| throw IllegalStateException( |
| "Unknown error " |
| "while adding type to map."); |
| } |
| } |
| |
| void TheTypeMap::unbindPdxType(const std::string& objFullName) { |
| std::lock_guard<util::concurrent::spinlock_mutex> guard(m_pdxTypemapLock); |
| m_pdxTypemap->unbind(objFullName); |
| } |
| |
| void PdxTypeHandler::serialize(const std::shared_ptr<PdxSerializable>& pdxSerializable, |
| DataOutput& dataOutput) const { |
| PdxHelper::serializePdx(dataOutput, pdxSerializable); |
| } |
| |
| std::shared_ptr<PdxSerializable> PdxTypeHandler::deserialize( |
| DataInput& dataInput) const { |
| return PdxHelper::deserializePdx(dataInput, false); |
| } |
| |
| } // namespace client |
| } // namespace geode |
| } // namespace apache |