blob: 7ddeabe242ef607229b1d2de77518d30c7e44cc0 [file] [log] [blame]
/**
* 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.
*/
package org.apache.hadoop.fs.azure;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static java.util.Objects.requireNonNull;
/**
* A simple memory key-value store to help mock the Windows Azure Storage
* implementation for unit testing.
*/
public class InMemoryBlockBlobStore {
private final HashMap<String, Entry> blobs = new HashMap<String, Entry>();
private HashMap<String, String> containerMetadata;
public synchronized Iterable<String> getKeys() {
return new ArrayList<String>(blobs.keySet());
}
public static class ListBlobEntry {
private final String key;
private final HashMap<String, String> metadata;
private final int contentLength;
private final boolean isPageBlob;
ListBlobEntry(String key, HashMap<String, String> metadata,
int contentLength, boolean isPageBlob) {
this.key = key;
this.metadata = metadata;
this.contentLength = contentLength;
this.isPageBlob = isPageBlob;
}
public String getKey() {
return key;
}
public HashMap<String, String> getMetadata() {
return metadata;
}
public int getContentLength() {
return contentLength;
}
public boolean isPageBlob() {
return isPageBlob;
}
}
/**
* List all the blobs whose key starts with the given prefix.
*
* @param prefix
* The prefix to check.
* @param includeMetadata
* If set, the metadata in the returned listing will be populated;
* otherwise it'll be null.
* @return The listing.
*/
public synchronized Iterable<ListBlobEntry> listBlobs(String prefix,
boolean includeMetadata) {
ArrayList<ListBlobEntry> list = new ArrayList<ListBlobEntry>();
for (Map.Entry<String, Entry> entry : blobs.entrySet()) {
if (entry.getKey().startsWith(prefix)) {
list.add(new ListBlobEntry(
entry.getKey(),
includeMetadata ?
new HashMap<String, String>(entry.getValue().metadata) :
null,
entry.getValue().content.length,
entry.getValue().isPageBlob));
}
}
return list;
}
public synchronized byte[] getContent(String key) {
return blobs.get(key).content;
}
@SuppressWarnings("unchecked")
public synchronized void setContent(String key, byte[] value,
HashMap<String, String> metadata, boolean isPageBlob,
long length) {
blobs.put(key, new Entry(value, (HashMap<String, String>)metadata.clone(),
isPageBlob, length));
}
@SuppressWarnings("unchecked")
public synchronized void setMetadata(String key,
HashMap<String, String> metadata) {
blobs.get(key).metadata = (HashMap<String, String>) metadata.clone();
}
public OutputStream uploadBlockBlob(final String key,
final HashMap<String, String> metadata) {
setContent(key, new byte[0], metadata, false, 0);
return new ByteArrayOutputStream() {
@Override
public void flush()
throws IOException {
super.flush();
byte[] tempBytes = toByteArray();
setContent(key, tempBytes, metadata, false, tempBytes.length);
}
@Override
public void close()
throws IOException {
super.close();
byte[] tempBytes = toByteArray();
setContent(key, tempBytes, metadata, false, tempBytes.length);
}
};
}
public OutputStream uploadPageBlob(final String key,
final HashMap<String, String> metadata,
final long length) {
setContent(key, new byte[0], metadata, true, length);
return new ByteArrayOutputStream() {
@Override
public void flush()
throws IOException {
super.flush();
setContent(key, toByteArray(), metadata, true, length);
}
};
}
public synchronized void copy(String sourceKey, String destKey) {
blobs.put(destKey, blobs.get(sourceKey));
}
public synchronized void delete(String key) {
blobs.remove(key);
}
public synchronized boolean exists(String key) {
return blobs.containsKey(key);
}
@SuppressWarnings("unchecked")
public synchronized HashMap<String, String> getMetadata(String key) {
Entry entry = requireNonNull(blobs.get(key), "entry for " + key);
return (HashMap<String, String>) requireNonNull(entry.metadata,
"metadata for " + key)
.clone();
}
public synchronized HashMap<String, String> getContainerMetadata() {
return containerMetadata;
}
public synchronized void setContainerMetadata(HashMap<String, String> metadata) {
containerMetadata = metadata;
}
private static class Entry {
private byte[] content;
private HashMap<String, String> metadata;
private boolean isPageBlob;
@SuppressWarnings("unused") // TODO: use it
private long length;
public Entry(byte[] content, HashMap<String, String> metadata,
boolean isPageBlob, long length) {
this.content = content;
this.metadata = metadata;
this.isPageBlob = isPageBlob;
this.length = length;
}
}
}