| /* |
| * 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. |
| */ |
| /* |
| * PdxLocalWriter.cpp |
| * |
| * Created on: Nov 3, 2011 |
| * Author: npatel |
| */ |
| |
| #include "PdxLocalWriter.hpp" |
| |
| #include <geode/CacheableEnum.hpp> |
| |
| #include "PdxHelper.hpp" |
| #include "PdxTypeRegistry.hpp" |
| |
| namespace apache { |
| namespace geode { |
| namespace client { |
| |
| PdxLocalWriter::PdxLocalWriter(DataOutput& output, |
| std::shared_ptr<PdxType> pdxType, |
| std::shared_ptr<PdxTypeRegistry> pdxTypeRegistry) |
| : PdxLocalWriter(output, pdxType, pdxType ? pdxType->getPdxClassName() : "", |
| pdxTypeRegistry) |
| |
| {} |
| |
| PdxLocalWriter::PdxLocalWriter(DataOutput& dataOutput, |
| std::shared_ptr<PdxType> pdxType, |
| std::string pdxClassName, |
| std::shared_ptr<PdxTypeRegistry> pdxTypeRegistry) |
| : m_dataOutput(&dataOutput), |
| m_pdxType(pdxType), |
| m_startPosition(nullptr), |
| m_startPositionOffset(0), |
| m_domainClassName(""), |
| m_currentOffsetIndex(0), |
| m_pdxTypeRegistry(pdxTypeRegistry), |
| m_pdxClassName(pdxClassName) { |
| initialize(); |
| } |
| |
| void PdxLocalWriter::initialize() { |
| if (m_pdxType != nullptr) { |
| m_currentOffsetIndex = 0; |
| } |
| |
| // start position, this should start of dataoutput buffer and then use |
| // bufferlen |
| m_startPosition = m_dataOutput->getBuffer(); |
| |
| // data has been write |
| m_startPositionOffset = static_cast<int32_t>(m_dataOutput->getBufferLength()); |
| |
| // Advance cursor to write pdx header |
| m_dataOutput->advanceCursor(PdxHelper::PdxHeader); |
| } |
| |
| void PdxLocalWriter::addOffset() { |
| // bufferLen gives lenght which has been written to DataOutput |
| // m_startPositionOffset: from where pdx header length starts |
| auto bufferLen = m_dataOutput->getBufferLength() - m_startPositionOffset; |
| |
| auto offset = static_cast<int32_t>(bufferLen - PdxHelper::PdxHeader); |
| |
| m_offsets.push_back(offset); |
| } |
| |
| void PdxLocalWriter::endObjectWriting() { |
| // Write header for pdx. |
| writePdxHeader(); |
| } |
| |
| void PdxLocalWriter::writePdxHeader() { |
| int32_t len = calculateLenWithOffsets(); |
| int32_t typeId = m_pdxType->getTypeId(); |
| |
| const uint8_t* starpos = m_dataOutput->getBuffer() + m_startPositionOffset; |
| PdxHelper::writeInt32(const_cast<uint8_t*>(starpos), len); |
| PdxHelper::writeInt32(const_cast<uint8_t*>(starpos + 4), typeId); |
| |
| writeOffsets(len); |
| } |
| |
| void PdxLocalWriter::writeOffsets(int32_t len) { |
| if (len <= 0xff) { |
| for (int i = static_cast<int>(m_offsets.size()) - 1; i > 0; i--) { |
| m_dataOutput->write(static_cast<uint8_t>(m_offsets[i])); |
| } |
| } else if (len <= 0xffff) { |
| for (int i = static_cast<int>(m_offsets.size()) - 1; i > 0; i--) { |
| m_dataOutput->writeInt(static_cast<uint16_t>(m_offsets[i])); |
| } |
| } else { |
| for (int i = static_cast<int>(m_offsets.size()) - 1; i > 0; i--) { |
| m_dataOutput->writeInt(static_cast<uint32_t>(m_offsets[i])); |
| } |
| } |
| } |
| PdxWriter& PdxLocalWriter::writeUnreadFields( |
| std::shared_ptr<PdxUnreadFields> unread) { |
| if (isFieldWritingStarted()) { |
| throw IllegalStateException( |
| "WriteUnreadFields must be called before any other fields are " |
| "written."); |
| } |
| |
| if (unread != nullptr) { |
| m_preserveData = std::dynamic_pointer_cast<PdxRemotePreservedData>(unread); |
| if (m_preserveData != nullptr) { |
| m_pdxType = |
| getPdxTypeRegistry()->getPdxType(m_preserveData->getMergedTypeId()); |
| if (m_pdxType == nullptr) { |
| // its local type |
| // this needs to fix for IPdxTypemapper |
| m_pdxType = getPdxTypeRegistry()->getLocalPdxType(m_pdxClassName); |
| } |
| } else { |
| throw IllegalStateException( |
| "PdxLocalWriter::writeUnreadFields: m_preserveData should not be " |
| "nullptr"); |
| } |
| } |
| return *this; |
| } |
| |
| std::shared_ptr<PdxSerializer> PdxLocalWriter::getPdxSerializer() const { |
| return m_dataOutput->getCache()->getTypeRegistry().getPdxSerializer(); |
| } |
| |
| int32_t PdxLocalWriter::calculateLenWithOffsets() { |
| auto bufferLen = m_dataOutput->getBufferLength() - m_startPositionOffset; |
| int32_t totalOffsets = 0; |
| if (m_pdxType->getNumberOfVarLenFields() > 0) { |
| totalOffsets = m_pdxType->getNumberOfVarLenFields() - |
| 1; // for first var len no need to append offset |
| } |
| auto totalLen = |
| static_cast<int32_t>(bufferLen - PdxHelper::PdxHeader + totalOffsets); |
| |
| if (totalLen <= 0xff) { // 1 byte |
| return totalLen; |
| } else if (totalLen + totalOffsets <= 0xffff) { // 2 byte |
| return totalLen + totalOffsets; |
| } else { // 4 byte |
| return totalLen + totalOffsets * 3; |
| } |
| } |
| |
| bool PdxLocalWriter::isFieldWritingStarted() { return true; } |
| |
| PdxWriter& PdxLocalWriter::writeChar(const std::string&, char16_t value) { |
| m_dataOutput->writeChar(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeBoolean(const std::string&, bool value) { |
| m_dataOutput->writeBoolean(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeByte(const std::string&, int8_t value) { |
| m_dataOutput->write(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeShort(const std::string&, int16_t value) { |
| m_dataOutput->writeInt(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeInt(const std::string&, int32_t value) { |
| m_dataOutput->writeInt(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeLong(const std::string&, int64_t value) { |
| m_dataOutput->writeInt(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeFloat(const std::string&, float value) { |
| m_dataOutput->writeFloat(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeDouble(const std::string&, double value) { |
| m_dataOutput->writeDouble(value); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeDate(const std::string&, |
| std::shared_ptr<CacheableDate> date) { |
| // m_dataOutput->writeObject(date.get()); |
| if (date != nullptr) { |
| date->toData(*m_dataOutput); |
| } else { |
| m_dataOutput->writeInt(static_cast<uint64_t>(-1L)); |
| } |
| return *this; |
| } |
| |
| PdxWriter& PdxLocalWriter::writeString(const std::string&, |
| const std::string& value) { |
| addOffset(); |
| m_dataOutput->writeString(value); |
| return *this; |
| } |
| |
| PdxWriter& PdxLocalWriter::writeStringArray( |
| const std::string&, const std::vector<std::string>& array) { |
| addOffset(); |
| m_dataOutput->writeArrayLen(static_cast<int32_t>(array.size())); |
| for (auto&& entry : array) { |
| m_dataOutput->writeString(entry); |
| } |
| return *this; |
| } |
| |
| PdxWriter& PdxLocalWriter::writeObject(const std::string&, |
| std::shared_ptr<Serializable> value) { |
| addOffset(); |
| |
| if (auto enumValPtr = std::dynamic_pointer_cast<CacheableEnum>(value)) { |
| enumValPtr->toData(*m_dataOutput); |
| } else if (auto objectArray = |
| std::dynamic_pointer_cast<CacheableObjectArray>(value)) { |
| m_dataOutput->write(static_cast<int8_t>(objectArray->getDsCode())); |
| m_dataOutput->writeArrayLen(static_cast<int32_t>(objectArray->size())); |
| m_dataOutput->write(static_cast<int8_t>(DSCode::Class)); |
| |
| auto iter = objectArray->begin(); |
| const auto actualObjPtr = std::dynamic_pointer_cast<PdxSerializable>(*iter); |
| |
| m_dataOutput->writeString(actualObjPtr->getClassName()); |
| |
| for (; iter != objectArray->end(); ++iter) { |
| m_dataOutput->writeObject(*iter); |
| } |
| } else { |
| m_dataOutput->writeObject(value); |
| } |
| |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeBooleanArray(const std::string&, |
| const std::vector<bool>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| |
| PdxWriter& PdxLocalWriter::writeCharArray(const std::string&, |
| const std::vector<char16_t>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| |
| PdxWriter& PdxLocalWriter::writeByteArray(const std::string&, |
| const std::vector<int8_t>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeShortArray(const std::string&, |
| const std::vector<int16_t>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeIntArray(const std::string&, |
| const std::vector<int32_t>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeLongArray(const std::string&, |
| const std::vector<int64_t>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeFloatArray(const std::string&, |
| const std::vector<float>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeDoubleArray(const std::string&, |
| const std::vector<double>& array) { |
| addOffset(); |
| writeArrayObject(array); |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeObjectArray( |
| const std::string&, std::shared_ptr<CacheableObjectArray> array) { |
| addOffset(); |
| if (array != nullptr) { |
| array->toData(*m_dataOutput); |
| } else { |
| m_dataOutput->write(static_cast<int8_t>(-1)); |
| } |
| return *this; |
| } |
| PdxWriter& PdxLocalWriter::writeArrayOfByteArrays( |
| const std::string&, int8_t* const* const byteArrays, int arrayLength, |
| const int* elementLength) { |
| addOffset(); |
| if (byteArrays != nullptr) { |
| m_dataOutput->writeArrayLen(arrayLength); |
| for (int i = 0; i < arrayLength; i++) { |
| m_dataOutput->writeBytes(byteArrays[i], elementLength[i]); |
| } |
| } else { |
| m_dataOutput->write(static_cast<int8_t>(-1)); |
| } |
| |
| return *this; |
| } |
| |
| PdxWriter& PdxLocalWriter::markIdentityField(const std::string&) { |
| return *this; |
| } |
| |
| uint8_t* PdxLocalWriter::getPdxStream(int& pdxLen) { |
| uint8_t* stPos = |
| const_cast<uint8_t*>(m_dataOutput->getBuffer()) + m_startPositionOffset; |
| int len = PdxHelper::readInt32 /*readByte*/ (stPos); |
| pdxLen = len; |
| // ignore len and typeid |
| return m_dataOutput->getBufferCopyFrom(stPos + 8, len); |
| } |
| |
| void PdxLocalWriter::writeByte(int8_t byte) { m_dataOutput->write(byte); } |
| |
| std::shared_ptr<PdxTypeRegistry> PdxLocalWriter::getPdxTypeRegistry() const { |
| return m_pdxTypeRegistry; |
| } |
| |
| } // namespace client |
| } // namespace geode |
| } // namespace apache |