@Override
    public void run() {
      String operationResult = null;
      Exception exception = null;
      try {
        String blobId = new BlobId(blobIdVersion, BlobId.BlobIdType.NATIVE, ClusterMap.UNKNOWN_DATACENTER_ID,
            postData.getBlobProperties().getAccountId(), postData.getBlobProperties().getContainerId(),
            getPartitionForPut(), false, BlobId.BlobDataType.DATACHUNK).getID();
        if (blobs.containsKey(blobId)) {
          exception = new RouterException("Blob ID duplicate created.", RouterErrorCode.UnexpectedInternalError);
        }
        ByteBuffer blobData;
        if (postData.getChunksToStitch() != null) {
          ByteArrayOutputStream stitchedContentStream = new ByteArrayOutputStream();
          for (ChunkInfo chunkInfo : postData.getChunksToStitch()) {
            stitchedContentStream.write(blobs.get(chunkInfo.getBlobId()).getBlob().array());
          }
          blobData = ByteBuffer.wrap(stitchedContentStream.toByteArray());
        } else {
          blobData = readBlob(postData.getReadableStreamChannel(), postData.getOptions().getMaxUploadSize());
        }
        InMemoryBlob blob = new InMemoryBlob(postData.getBlobProperties(), postData.getUsermetadata(), blobData,
            postData.getChunksToStitch());
        blobs.put(blobId, blob);
        if (notificationSystem != null) {
          notificationSystem.onBlobCreated(blobId, postData.getBlobProperties(), null, null,
              postData.getOptions().isChunkUpload() ? NotificationBlobType.DataChunk : NotificationBlobType.Simple);
        }
        if (postData.getOptions().skipCompositeChunk()) {
          // now generate the PutBlobMetaInfo which includes the data chunk list
          List<Pair<String, Long>> orderedChunkList = new ArrayList<>();
          orderedChunkList.add(new Pair<>(blobId, blob.getBlobProperties().getBlobSize()));
          String reservedMetadataBlobId = blob.getBlobProperties().getReservedMetadataBlobId();
          PutBlobMetaInfo putBlobMetaInfoObj = new PutBlobMetaInfo(orderedChunkList, reservedMetadataBlobId);
          operationResult = PutBlobMetaInfo.serialize(putBlobMetaInfoObj);
        } else {
          operationResult = blobId;
        }
      } catch (RouterException e) {
        exception = e;
      } catch (Exception e) {
        exception = new RouterException(e, RouterErrorCode.UnexpectedInternalError);
      } finally {
        completeOperation(postData.getFuture(), postData.getCallback(), operationResult, exception);
      }
    }
Create a new instance.
@param postData the data that came with the POST request as {@link PostData}.
@param blobs the list of blobs in memory.
@param notificationSystem the notification system to use to notify creation/deletion of blobs.
@param clusterMap the cluster map for the cluster.
@param blobIdVersion the blob ID version to use.
ambry-test-utils/src/main/java/com/github/ambry/router/InMemoryRouter.java