java.nio.file.AtomicMoveNotSupportedException#org.sonatype.nexus.blobstore.api.Blob源码实例Demo

下面列出了java.nio.file.AtomicMoveNotSupportedException#org.sonatype.nexus.blobstore.api.Blob 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

private Blob createMockBlob(String id) {
  String createdBy = "createdBy";
  String createdByIp = "createdByIp";
  DateTime creationTime = new DateTime();
  Blob blob = mock(Blob.class);

  Map<String, String> headers = new HashMap<>();
  headers.put(CREATED_BY_HEADER, createdBy);
  headers.put(CREATED_BY_IP_HEADER, createdByIp);
  when(blob.getHeaders()).thenReturn(headers);

  BlobMetrics metrics = new BlobMetrics(creationTime, "hash", 1L);
  when(blob.getMetrics()).thenReturn(metrics);

  BlobId blobId = new BlobId(id);
  when(blob.getId()).thenReturn(blobId);
  when(blobStore.get(blobId)).thenReturn(blob);

  return blob;
}
 
源代码2 项目: nexus-public   文件: MemoryBlobSessionTest.java
@Before
public void setUp() {
  Blob restoredBlob = mockBlob(RESTORED_BLOB_ID);
  Blob copiedBlob = mockBlob(COPIED_BLOB_ID);

  when(blobStore.create(blobData, headers, null)).thenAnswer(this::newBlob);
  when(blobStore.create(blobData, headers, RESTORED_BLOB_ID)).thenReturn(restoredBlob);
  when(blobStore.create(sourceFile, headers, TEST_BLOB_SIZE, TEST_BLOB_HASH)).thenAnswer(this::newBlob);
  when(blobStore.copy(EXISTING_BLOB_ID, headers)).thenReturn(copiedBlob);

  when(blobStore.exists(any())).thenReturn(true);
  when(blobStore.get(any())).thenAnswer(this::getBlob);

  BlobStoreConfiguration storeConfiguration = mock(BlobStoreConfiguration.class);
  when(storeConfiguration.getName()).thenReturn("test-blob-store");
  when(blobStore.getBlobStoreConfiguration()).thenReturn(storeConfiguration);
}
 
/**
 * Extracts the contents for the first matching {@code composer.json} file (of which there should only be one) as a
 * map representing the parsed JSON content. If no such file is found then an empty map is returned.
 */
public Map<String, Object> extractFromZip(final Blob blob) throws IOException {
  try (InputStream is = blob.getInputStream()) {
    try (ArchiveInputStream ais = archiveStreamFactory.createArchiveInputStream(ArchiveStreamFactory.ZIP, is)) {
      ArchiveEntry entry = ais.getNextEntry();
      while (entry != null) {
        Map<String, Object> contents = processEntry(ais, entry);
        if (!contents.isEmpty()) {
          return contents;
        }
        entry = ais.getNextEntry();
      }
    }
    return Collections.emptyMap();
  }
  catch (ArchiveException e) {
    throw new IOException("Error reading from archive", e);
  }
}
 
源代码4 项目: nexus-public   文件: BlobTx.java
private PrefetchedAssetBlob createPrefetchedAssetBlob(final Blob blob,
                                                      final Map<HashAlgorithm, HashCode> hashes,
                                                      final boolean hashesVerified,
                                                      final String contentType)
{
  PrefetchedAssetBlob assetBlob = new PrefetchedAssetBlob(
      nodeAccess,
      blobStore,
      blob,
      contentType,
      hashes,
      hashesVerified);

  newlyCreatedBlobs.add(assetBlob);
  return assetBlob;
}
 
源代码5 项目: nexus-public   文件: FileBlobStoreIT.java
@Test
public void hardDeletePreventsGetDespiteOpenStreams() throws Exception {
  final byte[] content = new byte[TEST_DATA_LENGTH];
  new Random().nextBytes(content);

  final Blob blob = underTest.create(new ByteArrayInputStream(content), TEST_HEADERS);

  final InputStream inputStream = blob.getInputStream();

  // Read half the data
  inputStream.read(new byte[content.length / 2]);

  // force delete
  underTest.deleteHard(blob.getId());

  final Blob newBlob = underTest.get(blob.getId());
  assertThat(newBlob, is(nullValue()));
}
 
源代码6 项目: nexus-public   文件: FluentBlobsImpl.java
@Override
public TempBlob ingest(final InputStream in,
                       @Nullable final String contentType,
                       final Iterable<HashAlgorithm> hashing)
{
  Optional<ClientInfo> clientInfo = facet.clientInfo();

  Builder<String, String> tempHeaders = ImmutableMap.builder();
  tempHeaders.put(TEMPORARY_BLOB_HEADER, "");
  tempHeaders.put(REPO_NAME_HEADER, facet.repository().getName());
  tempHeaders.put(BLOB_NAME_HEADER, "temp");
  tempHeaders.put(CREATED_BY_HEADER, clientInfo.map(ClientInfo::getUserid).orElse("system"));
  tempHeaders.put(CREATED_BY_IP_HEADER, clientInfo.map(ClientInfo::getRemoteIP).orElse("system"));
  tempHeaders.put(CONTENT_TYPE_HEADER, ofNullable(contentType).orElse(APPLICATION_OCTET_STREAM));

  MultiHashingInputStream hashingStream = new MultiHashingInputStream(hashing, in);
  Blob blob = facet.stores().blobStore.create(hashingStream, tempHeaders.build());

  return new TempBlob(blob, hashingStream.hashes(), true, facet.stores().blobStore);
}
 
源代码7 项目: nexus-repository-helm   文件: HelmRestoreBlobIT.java
private void runBlobRestore(final boolean isDryRun) {
  Asset asset;
  Blob blob;
  try (StorageTx tx = getStorageTx(proxyRepository)) {
    tx.begin();
    asset = tx.findAssetWithProperty(AssetEntityAdapter.P_NAME, MONGO_PATH_FULL_728_TARGZ,
        tx.findBucket(proxyRepository));
    assertThat(asset, Matchers.notNullValue());
    blob = tx.getBlob(asset.blobRef());
  }
  testHelper.simulateAssetMetadataLoss();
  Properties properties = new Properties();
  properties.setProperty(HEADER_PREFIX + REPO_NAME_HEADER, proxyRepository.getName());
  properties.setProperty(HEADER_PREFIX + BLOB_NAME_HEADER, asset.name());
  properties.setProperty(HEADER_PREFIX + CONTENT_TYPE_HEADER, asset.contentType());

  helmRestoreBlobStrategy.restore(properties, blob, BlobStoreManager.DEFAULT_BLOBSTORE_NAME, isDryRun);
}
 
源代码8 项目: nexus-repository-r   文件: RRestoreBlobIT.java
private void runBlobRestore(final boolean isDryRun) {
  Asset asset;
  Blob blob;
  try (StorageTx tx = getStorageTx(proxyRepository)) {
    tx.begin();
    asset = tx.findAssetWithProperty(AssetEntityAdapter.P_NAME, AGRICOLAE_131_TARGZ.fullPath,
        tx.findBucket(proxyRepository));
    assertThat(asset, Matchers.notNullValue());
    blob = tx.getBlob(asset.blobRef());
  }
  testHelper.simulateAssetMetadataLoss();
  Properties properties = new Properties();
  properties.setProperty(HEADER_PREFIX + REPO_NAME_HEADER, proxyRepository.getName());
  properties.setProperty(HEADER_PREFIX + BLOB_NAME_HEADER, asset.name());
  properties.setProperty(HEADER_PREFIX + CONTENT_TYPE_HEADER, asset.contentType());

  rRestoreBlobStrategy.restore(properties, blob, BlobStoreManager.DEFAULT_BLOBSTORE_NAME, isDryRun);
}
 
源代码9 项目: nexus-blobstore-s3   文件: S3BlobStore.java
@Override
@Guarded(by = STARTED)
public Blob create(final InputStream blobData, final Map<String, String> headers) {
  checkNotNull(blobData);

  return create(headers, destination -> {
      try (InputStream data = blobData) {
        MetricsInputStream input = new MetricsInputStream(data);
        TransferManager transferManager = new TransferManager(s3);
        transferManager.upload(getConfiguredBucket(), destination, input, new ObjectMetadata())
            .waitForCompletion();
        return input.getMetrics();
      } catch (InterruptedException e) {
        throw new BlobStoreException("error uploading blob", e, null);
      }
    });
}
 
源代码10 项目: nexus-public   文件: BlobStoreGroup.java
@Nullable
@Override
@Guarded(by = STARTED)
public Blob get(final BlobId blobId, final boolean includeDeleted) {
  if (includeDeleted) {
    // check directly without using cache
    return members.get().stream()
        .map((BlobStore member) -> member.get(blobId, true))
        .filter(Objects::nonNull)
        .findAny()
        .orElse(null);
  }
  else {
    return locate(blobId)
      .map((BlobStore target) -> target.get(blobId, false))
      .orElse(null);
  }
}
 
@Override
public void assertAssetMatchesBlob(final Repository repository, final String... names) {
  for (String name : names) {
    try (StorageTx tx = getStorageTx(repository)) {
      tx.begin();
      Asset asset = tx.findAssetWithProperty(AssetEntityAdapter.P_NAME, name, tx.findBucket(repository));
      Blob blob = tx.requireBlob(asset.blobRef());

      assertThat(repository.getName(), equalTo(blob.getHeaders().get(Bucket.REPO_NAME_HEADER)));
      assertThat(asset.name(), equalTo(blob.getHeaders().get(BlobStore.BLOB_NAME_HEADER)));
      assertThat(asset.createdBy(), equalTo(blob.getHeaders().get(BlobStore.CREATED_BY_HEADER)));
      assertThat(asset.createdByIp(), equalTo(blob.getHeaders().get(BlobStore.CREATED_BY_IP_HEADER)));
      assertThat(asset.contentType(), equalTo(blob.getHeaders().get(BlobStore.CONTENT_TYPE_HEADER)));
      assertThat(asset.attributes().child("checksum").get("sha1"), equalTo(blob.getMetrics().getSha1Hash()));
      assertThat(asset.size(), equalTo(blob.getMetrics().getContentSize()));
    }
  }
}
 
private void updatePackageRootIfShaIncorrect(final Repository repository,
                                             final Asset asset,
                                             final Blob blob,
                                             final NestedAttributesMap newPackageRoot,
                                             final NpmPackageId packageId,
                                             final String packageVersion)
{
  NpmHostedFacet hostedFacet = repository.facet(NpmHostedFacet.class);
  try {
    NestedAttributesMap oldPackageRoot = getPackageRoot(UnitOfWork.currentTx(), repository, packageId);
    if (oldPackageRoot != null) {
      String oldSha = extractShasum(oldPackageRoot, packageVersion);
      String newSha = extractShasum(newPackageRoot, packageVersion);

      if (!Objects.equals(oldSha, newSha)) {
        maybeUpdateIntegrity(asset, blob, packageVersion, oldPackageRoot, newPackageRoot);

        hostedFacet.putPackageRoot(packageId, null, newPackageRoot);
      }
    }
  }
  catch (IOException e) {
    log.error("Failed to update asset {}", asset.name(), e);
  }
}
 
private String calculateIntegrity(final Asset asset, final Blob blob, final String algorithm) {
  try {
    HashCode hash;
    if (algorithm.equalsIgnoreCase(SHA1.name())) {
      hash = hash(SHA1, blob.getInputStream());
    }
    else {
      hash = hash(SHA512, blob.getInputStream());
    }

    return algorithm + "-" + Base64.getEncoder().encodeToString(hash.asBytes());
  }
  catch (IOException e) {
    log.error("Failed to calculate hash for asset {}", asset.name(), e);
  }
  return "";
}
 
源代码14 项目: nexus-public   文件: FileBlobStoreIT.java
@Test
public void getDirectPathBlobIdStreamSuccess() throws IOException {
  byte[] content = "hello".getBytes();
  Blob blob = underTest.create(new ByteArrayInputStream(content), ImmutableMap.of(
      CREATED_BY_HEADER, "test",
      BLOB_NAME_HEADER, "health-check/repositoryName/file.txt",
      DIRECT_PATH_BLOB_HEADER, "true"
  ));
  verifyMoveOperationsAtomic(blob);

  assertThat(underTest.getDirectPathBlobIdStream("health-check").count(), is(1L));
  // confirm same result for deeper prefix
  assertThat(underTest.getDirectPathBlobIdStream("health-check/repositoryName").count(), is(1L));
  // confirm same result for the top
  assertThat(underTest.getDirectPathBlobIdStream(".").count(), is(1L));
  assertThat(underTest.getDirectPathBlobIdStream("").count(), is(1L));

  BlobId blobId = underTest.getDirectPathBlobIdStream("health-check").findFirst().get();
  assertThat(blobId, is(blob.getId()));

  // this check is more salient when run on Windows but confirms that direct path BlobIds use unix style paths
  assertThat(blobId.asUniqueString().contains("\\"), is(false));
  assertThat(blobId.asUniqueString().contains("/"), is(true));
}
 
源代码15 项目: nexus-public   文件: DatastoreDeadBlobFinder.java
/**
 * Verify that the Blob exists and is in agreement with the stored Asset metadata.;
 */
private void verifyBlob(final Blob blob, final Asset asset) throws MismatchedSHA1Exception, BlobUnavilableException, IOException {
  BlobMetrics metrics = blob.getMetrics();

  String assetChecksum =
      asset.blob().map(AssetBlob::checksums).map(checksums -> checksums.get(HashAlgorithm.SHA1.name())).orElse(null);
  if (!metrics.getSha1Hash().equals(assetChecksum)) {
    throw new MismatchedSHA1Exception();
  }

  try (InputStream blobstream = blob.getInputStream()) {
    if (metrics.getContentSize() > 0 && blobstream.available() == 0) {
      throw new BlobUnavilableException();
    }
  }
}
 
源代码16 项目: nexus-public   文件: OrientNpmHostedFacetTest.java
private void mockPackageMetadata() {
  Asset packageAssetRoot = mock(Asset.class);
  when(packageAssetRoot.name()).thenReturn("@foo/bar");
  when(packageAssetRoot.getEntityMetadata())
      .thenReturn(new DetachedEntityMetadata(new DetachedEntityId("foo"), new DetachedEntityVersion("a")));
  when(packageAssetRoot.formatAttributes()).thenReturn(new NestedAttributesMap("metadata", new HashMap<>()));
  BlobRef blobRef = mock(BlobRef.class);
  when(packageAssetRoot.requireBlobRef()).thenReturn(blobRef);
  Blob blob = mock(Blob.class);
  when(storageTx.requireBlob(blobRef)).thenReturn(blob);

  when(blob.getInputStream())
      .thenReturn(new ByteArrayInputStream("{\"name\": \"@foo/bar\",\"versions\": {\"0.1\": {}}}".getBytes()));

  when(storageTx.findAssetWithProperty(eq(P_NAME), eq("@foo/bar"), any(Bucket.class))).thenReturn(packageAssetRoot);

}
 
源代码17 项目: nexus-public   文件: BlobTx.java
private AssetBlob createAssetBlob(final Function<BlobStore, Blob> blobFunction,
                                  final Map<HashAlgorithm, HashCode> hashes,
                                  final boolean hashesVerified,
                                  final String contentType)
{
  AssetBlob assetBlob = new AssetBlob(
      nodeAccess,
      blobStore,
      blobFunction,
      contentType,
      hashes,
      hashesVerified);

  newlyCreatedBlobs.add(assetBlob);
  return assetBlob;
}
 
源代码18 项目: nexus-public   文件: MavenFacetImpl.java
private void rebuildMetadata(final Blob metadataBlob) throws IOException {
  Metadata metadata = MavenModels.readMetadata(metadataBlob.getInputStream());

  // avoid triggering nested rebuilds as the rebuilder will already do that if necessary
  rebuilding.set(TRUE);
  try {
    metadataRebuilder.rebuildInTransaction(
        getRepository(),
        false,
        false,
        metadata.getGroupId(),
        metadata.getArtifactId(),
        metadata.getVersion()
    );
  }
  finally {
    rebuilding.remove();
  }
}
 
源代码19 项目: nexus-public   文件: MavenFacetImplTest.java
@Test
public void testGet_expiredMetadata() throws Exception {
  String path = "/org/sonatype/nexus/nexus-base/3.19.0-SNAPSHOT/maven-metadata.xml";
  Asset asset = createMetadataAsset(path, INVALIDATED);
  Blob blob = mock(Blob.class);
  when(blob.getInputStream())
      .thenReturn(getClass().getResourceAsStream("/org/sonatype/nexus/repository/maven/gavMetadata.xml"));
  when(storageTx.findAssetWithProperty(any(), any(), any(Bucket.class))).thenReturn(asset);
  when(storageTx.requireBlob(any())).thenReturn(blob);
  MavenPath mavenPath = maven2MavenPathParser.parsePath(path);
  Content content = underTest.get(mavenPath);

  assertThat(content, not(nullValue()));
  assertThat(content.getContentType(), is(TEXT_XML));
  verify(metadataRebuilder)
      .rebuildInTransaction(any(), eq(false), eq(false), eq("org.sonatype.nexus"), eq("nexus-base"),
          eq("3.19.0-SNAPSHOT"));
}
 
源代码20 项目: nexus-public   文件: MavenFacetImplTest.java
@Test
public void testGet_currentMetadata() throws Exception {
  String path = "/org/sonatype/nexus/nexus-base/3.19.0-SNAPSHOT/maven-metadata.xml";
  Asset asset = createMetadataAsset(path, "valid");
  Blob blob = mock(Blob.class);
  when(blob.getInputStream())
      .thenReturn(getClass().getResourceAsStream("/org/sonatype/nexus/repository/maven/gavMetadata.xml"));
  when(storageTx.findAssetWithProperty(any(), any(), any(Bucket.class))).thenReturn(asset);
  when(storageTx.requireBlob(any())).thenReturn(blob);
  MavenPath mavenPath = maven2MavenPathParser.parsePath(path);
  Content content = underTest.get(mavenPath);

  assertThat(content, not(nullValue()));
  assertThat(content.getContentType(), is(TEXT_XML));
  verify(storageTx, never()).deleteAsset(any());
  verify(metadataRebuilder, never())
      .rebuildInTransaction(any(), eq(false), eq(false), eq("org.sonatype.nexus"), eq("nexus-base"),
          eq("3.19.0-SNAPSHOT"));
}
 
源代码21 项目: nexus-public   文件: DatastoreDeadBlobFinderTest.java
@Test
public void anAssetBlobCanBeDeletedWhileTheSystemIsInspected() {
  AssetBlob missingAssetBlob = mockAssetBlob(mock(AssetBlob.class));
  when(asset.blob()).thenReturn(Optional.of(missingAssetBlob)); // first pass we have a missing blobRef

  FluentAsset reloadedAsset = createAsset(assetBlob);
  Blob reloadedBlob = mock(Blob.class); // second pass the blobRef is there but file does not exist
  when(reloadedBlob.getMetrics()).thenReturn(blobMetrics);
  BlobId missingBlobId = reloadedAsset.blob().get().blobRef().getBlobId();
  when(blobStore.get(missingBlobId)).thenReturn(reloadedBlob);

  mockAssetBrowse();
  mockAssetReload(reloadedAsset);

  when(reloadedBlob.getMetrics()).thenReturn(blobMetrics);
  when(reloadedBlob.getInputStream()).thenThrow(new BlobStoreException("Blob has been deleted", new BlobId("foo")));

  List<DeadBlobResult<Asset>> result = deadBlobFinder.find(repository, true);

  assertThat(result, hasSize(1));
  assertThat(result.get(0).getResultState(), is(DELETED));
}
 
源代码22 项目: nexus-public   文件: BaseRestoreBlobStrategy.java
@Override
public void restore(final Properties properties,
                    final Blob blob,
                    final String blobStoreName,
                    final boolean isDryRun)
{
  RestoreBlobData blobData = new RestoreBlobData(blob, properties, blobStoreName, repositoryManager);
  Optional<StorageFacet> storageFacet = blobData.getRepository().optionalFacet(StorageFacet.class);
  T restoreData = createRestoreData(blobData);

  if (storageFacet.isPresent() && canAttemptRestore(restoreData)) {
    doRestore(storageFacet.get(), blobData, restoreData, isDryRun);
  }
  else {
    log.debug("Skipping asset, blob store: {}, repository: {}, blob name: {}, blob id: {}",
        blobStoreName, blobData.getRepository().getName(), blobData.getBlobName(), blob.getId());
  }
}
 
@Override
protected Blob doCreate(final InputStream blobData,
                        final Map<String, String> headers,
                        @Nullable final BlobId blobId)
{
  return createInternal(headers, destination -> {
    try (InputStream data = blobData) {
      MetricsInputStream input = new MetricsInputStream(data);

      uploader.upload(storage, getConfiguredBucketName(), destination, input);
      return input.getMetrics();
    }
  }, blobId);
}
 
源代码24 项目: nexus-public   文件: BlobStoreGroup.java
@Override
@Guarded(by = STARTED)
public Blob copy(final BlobId blobId, final Map<String, String> headers) {
  BlobStore target = locate(blobId)
      .orElseThrow(() -> new BlobStoreException("Unable to find blob", blobId));
  Blob blob = target.copy(blobId, headers);
  locatedBlobs.put(blob.getId(), target.getBlobStoreConfiguration().getName());
  return blob;
}
 
@Nullable
@Override
@Guarded(by = STARTED)
@Timed
public Blob get(final BlobId blobId, final boolean includeDeleted) {
  checkNotNull(blobId);

  final GoogleCloudStorageBlob blob = liveBlobs.getUnchecked(blobId);

  if (blob.isStale()) {
    Lock lock = blob.lock();
    try {
      if (blob.isStale()) {
        GoogleCloudBlobAttributes blobAttributes = new GoogleCloudBlobAttributes(bucket, attributePath(blobId));
        boolean loaded = blobAttributes.load();
        if (!loaded) {
          log.warn("Attempt to access non-existent blob {} ({})", blobId, blobAttributes);
          return null;
        }

        if (blobAttributes.isDeleted() && !includeDeleted) {
          log.warn("Attempt to access soft-deleted blob {} ({})", blobId, blobAttributes);
          return null;
        }

        blob.refresh(blobAttributes.getHeaders(), blobAttributes.getMetrics());
      }
    }
    catch (IOException e) {
      throw new BlobStoreException(e, blobId);
    }
    finally {
      lock.unlock();
    }
  }

  log.debug("Accessing blob {}", blobId);
  return blob;
}
 
源代码26 项目: nexus-public   文件: StorageTxImpl.java
@Override
@Guarded(by = ACTIVE)
public Blob requireBlob(final BlobRef blobRef) {
  Blob blob = getBlob(blobRef);
  if (blob == null) {
    throw new MissingBlobException(blobRef);
  }
  return blob;
}
 
源代码27 项目: nexus-repository-p2   文件: P2FacetImpl.java
/**
 * Convert an asset blob to {@link Content}.
 *
 * @return content of asset blob
 */
@Override
public Content toContent(final Asset asset, final Blob blob) {
  Content content = new Content(new BlobPayload(blob, asset.requireContentType()));
  Content.extractFromAsset(asset, HASH_ALGORITHMS, content.getAttributes());
  return content;
}
 
@Test
public void executeSkipsAssetsWithANonEmptyCreatedBy() {
  Blob blob = createMockBlob("blobId");
  Asset asset = createAsset(blob);
  asset.createdBy("somebody");
  assetStore.save(asset);

  task.execute();

  Asset updatedAsset = assetStore.getById(id(asset));
  assertThat(updatedAsset.name(), is(asset.name()));
  assertThat(updatedAsset.createdBy(), is("somebody"));
  assertThat(updatedAsset.createdByIp(), is(nullValue()));
}
 
源代码29 项目: nexus-public   文件: AssetBlob.java
public AssetBlob(final NodeAccess nodeAccess,
                 final BlobStore blobStore,
                 final Function<BlobStore, Blob> blobFunction,
                 final String contentType,
                 final Map<HashAlgorithm, HashCode> hashes,
                 final boolean hashesVerified)
{
  this.nodeAccess = checkNotNull(nodeAccess);
  this.blobStore = checkNotNull(blobStore);
  this.blobFunction = checkNotNull(blobFunction);
  this.contentType = checkNotNull(contentType);
  this.hashes = checkNotNull(hashes);
  this.hashesVerified = hashesVerified;
}
 
源代码30 项目: nexus-blobstore-s3   文件: S3BlobStore.java
private Blob create(final Map<String, String> headers, final BlobIngester ingester) {
  checkNotNull(headers);

  checkArgument(headers.containsKey(BLOB_NAME_HEADER), "Missing header: %s", BLOB_NAME_HEADER);
  checkArgument(headers.containsKey(CREATED_BY_HEADER), "Missing header: %s", CREATED_BY_HEADER);

  final BlobId blobId = blobIdLocationResolver.fromHeaders(headers);

  final String blobPath = contentPath(blobId);
  final String attributePath = attributePath(blobId);
  final S3Blob blob = liveBlobs.getUnchecked(blobId);

  Lock lock = blob.lock();
  try {
    log.debug("Writing blob {} to {}", blobId, blobPath);

    final StreamMetrics streamMetrics = ingester.ingestTo(blobPath);
    final BlobMetrics metrics = new BlobMetrics(new DateTime(), streamMetrics.getSha1(), streamMetrics.getSize());
    blob.refresh(headers, metrics);

    S3BlobAttributes blobAttributes = new S3BlobAttributes(s3, getConfiguredBucket(), attributePath, headers, metrics);

    blobAttributes.store();
    storeMetrics.recordAddition(blobAttributes.getMetrics().getContentSize());

    return blob;
  }
  catch (IOException e) {
    // Something went wrong, clean up the files we created
    deleteQuietly(attributePath);
    deleteQuietly(blobPath);
    throw new BlobStoreException(e, blobId);
  }
  finally {
    lock.unlock();
  }
}