s3proxy/src/main/java/org/gaul/s3proxy/NullBlobStore.java

252 wiersze
8.8 KiB
Java

/*
* Copyright 2014-2020 Andrew Gaul <andrew@gaul.org>
*
* Licensed 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
*
* https://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.
*/
package org.gaul.s3proxy;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.hash.HashCode;
import com.google.common.io.ByteSource;
import com.google.common.io.ByteStreams;
import com.google.common.primitives.Longs;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.MultipartPart;
import org.jclouds.blobstore.domain.MultipartUpload;
import org.jclouds.blobstore.domain.MutableStorageMetadata;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.PutOptions;
import org.jclouds.blobstore.util.ForwardingBlobStore;
import org.jclouds.io.Payload;
import org.jclouds.io.payloads.ByteSourcePayload;
final class NullBlobStore extends ForwardingBlobStore {
private NullBlobStore(BlobStore blobStore) {
super(blobStore);
}
static BlobStore newNullBlobStore(BlobStore blobStore) {
return new NullBlobStore(blobStore);
}
@Override
@Nullable
public BlobMetadata blobMetadata(String container, String name) {
Blob blob = getBlob(container, name);
if (blob == null) {
return null;
}
return blob.getMetadata();
}
@Override
@Nullable
public Blob getBlob(String container, String name) {
return getBlob(container, name, GetOptions.NONE);
}
@Override
@Nullable
public Blob getBlob(String container, String name, GetOptions options) {
Blob blob = super.getBlob(container, name, options);
if (blob == null) {
return null;
}
byte[] array;
try (InputStream is = blob.getPayload().openStream()) {
array = ByteStreams.toByteArray(is);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
long length = Longs.fromByteArray(array);
ByteSourcePayload payload = new ByteSourcePayload(
new NullByteSource().slice(0, length));
payload.setContentMetadata(blob.getPayload().getContentMetadata());
payload.getContentMetadata().setContentLength(length);
payload.getContentMetadata().setContentMD5((HashCode) null);
blob.setPayload(payload);
blob.getMetadata().setSize(length);
return blob;
}
@Override
public PageSet<? extends StorageMetadata> list(String container) {
ImmutableSet.Builder<StorageMetadata> builder = ImmutableSet.builder();
PageSet<? extends StorageMetadata> pageSet = super.list(container);
for (StorageMetadata sm : pageSet) {
MutableStorageMetadata msm = new MutableStorageMetadataImpl(sm);
msm.setSize(0L);
builder.add(msm);
}
return new PageSetImpl<>(builder.build(), pageSet.getNextMarker());
}
@Override
public String putBlob(String containerName, Blob blob) {
return putBlob(containerName, blob, PutOptions.NONE);
}
@Override
public String putBlob(String containerName, Blob blob,
PutOptions options) {
long length;
try (InputStream is = blob.getPayload().openStream()) {
length = ByteStreams.copy(is, ByteStreams.nullOutputStream());
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
byte[] array = Longs.toByteArray(length);
ByteSourcePayload payload = new ByteSourcePayload(
ByteSource.wrap(array));
payload.setContentMetadata(blob.getPayload().getContentMetadata());
payload.getContentMetadata().setContentLength((long) array.length);
payload.getContentMetadata().setContentMD5((HashCode) null);
blob.setPayload(payload);
return super.putBlob(containerName, blob, options);
}
@Override
public String completeMultipartUpload(final MultipartUpload mpu,
final List<MultipartPart> parts) {
long length = 0;
for (MultipartPart part : parts) {
length += part.partSize();
super.removeBlob(mpu.containerName(), mpu.id() + "-" +
part.partNumber());
}
byte[] array = Longs.toByteArray(length);
ByteSourcePayload payload = new ByteSourcePayload(
ByteSource.wrap(array));
payload.getContentMetadata().setContentLength((long) array.length);
super.abortMultipartUpload(mpu);
MultipartUpload mpu2 = super.initiateMultipartUpload(
mpu.containerName(), mpu.blobMetadata(), mpu.putOptions());
MultipartPart part = super.uploadMultipartPart(mpu2, 1, payload);
return super.completeMultipartUpload(mpu2, ImmutableList.of(part));
}
@Override
public void abortMultipartUpload(MultipartUpload mpu) {
for (MultipartPart part : super.listMultipartUpload(mpu)) {
super.removeBlob(mpu.containerName(), mpu.id() + "-" +
part.partNumber());
}
super.abortMultipartUpload(mpu);
}
@Override
public MultipartPart uploadMultipartPart(MultipartUpload mpu,
int partNumber, Payload payload) {
long length;
try (InputStream is = payload.openStream()) {
length = ByteStreams.copy(is, ByteStreams.nullOutputStream());
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
byte[] array = Longs.toByteArray(length);
ByteSourcePayload newPayload = new ByteSourcePayload(
ByteSource.wrap(array));
newPayload.setContentMetadata(payload.getContentMetadata());
newPayload.getContentMetadata().setContentLength((long) array.length);
newPayload.getContentMetadata().setContentMD5((HashCode) null);
// create a single-part object which contains the logical length which
// list and complete will read later
Blob blob = blobBuilder(mpu.id() + "-" + partNumber)
.payload(newPayload)
.build();
super.putBlob(mpu.containerName(), blob);
MultipartPart part = super.uploadMultipartPart(mpu, partNumber,
newPayload);
return MultipartPart.create(part.partNumber(), length, part.partETag(),
part.lastModified());
}
@Override
public List<MultipartPart> listMultipartUpload(MultipartUpload mpu) {
ImmutableList.Builder<MultipartPart> builder = ImmutableList.builder();
for (MultipartPart part : super.listMultipartUpload(mpu)) {
// get real blob size from stub blob
Blob blob = getBlob(mpu.containerName(),
mpu.id() + "-" + part.partNumber());
long length = blob.getPayload().getContentMetadata()
.getContentLength();
builder.add(MultipartPart.create(part.partNumber(), length,
part.partETag(), part.lastModified()));
}
return builder.build();
}
private static final class NullByteSource extends ByteSource {
@Override
public InputStream openStream() throws IOException {
return new NullInputStream();
}
}
private static final class NullInputStream extends InputStream {
private boolean closed;
@Override
public int read() throws IOException {
if (closed) {
throw new IOException("Stream already closed");
}
return 0;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (closed) {
throw new IOException("Stream already closed");
}
Arrays.fill(b, off, off + len, (byte) 0);
return len;
}
@Override
public void close() throws IOException {
super.close();
closed = true;
}
}
}