/* * Copyright 2010 Outerthought bvba * * 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 * * 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.lilyproject.repository.impl; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import org.apache.hadoop.hbase.util.Bytes; import org.lilyproject.repository.api.Blob; import org.lilyproject.repository.api.BlobAccess; import org.lilyproject.repository.api.BlobException; import org.lilyproject.repository.api.BlobManager; import org.lilyproject.repository.api.BlobNotFoundException; import org.lilyproject.repository.api.BlobStoreAccess; import org.lilyproject.repository.api.BlobStoreAccessFactory; import org.lilyproject.util.Pair; public class BlobStoreAccessRegistry { Map<String, BlobStoreAccess> registry = new HashMap<String, BlobStoreAccess>(); private BlobStoreAccessFactory blobStoreAccessFactory; private final BlobManager blobManager; public BlobStoreAccessRegistry(BlobManager blobManager) { this.blobManager = blobManager; } public void register(BlobStoreAccess blobStoreAccess) { registry.put(blobStoreAccess.getId(), blobStoreAccess); } public void setBlobStoreAccessFactory(BlobStoreAccessFactory blobStoreAccessFactory) { this.blobStoreAccessFactory = blobStoreAccessFactory; for (BlobStoreAccess blobStoreAccess : blobStoreAccessFactory.getAll()) { register(blobStoreAccess); } } public OutputStream getOutputStream(Blob blob) throws BlobException { BlobStoreAccess blobStoreAccess = blobStoreAccessFactory.get(blob); return new BlobOutputStream(blobStoreAccess.getOutputStream(blob), blobStoreAccess.getId(), blob, blobManager, blobStoreAccess.incubate()); } public BlobAccess getBlobAccess(Blob blob) throws BlobNotFoundException, BlobException { Pair<String, byte[]> decodedKey = decodeKey(blob); BlobStoreAccess blobStoreAccess = registry.get(decodedKey.getV1()); return new BlobAccessImpl(blob, blobStoreAccess, decodedKey.getV2()); } public BlobStoreAccess getBlobStoreAccess(Blob blob) throws BlobNotFoundException, BlobException { Pair<String, byte[]> decodedKey = decodeKey(blob); return registry.get(decodedKey.getV1()); } private Pair<String, byte[]> decodeKey(Blob blob) throws BlobNotFoundException, BlobException { if (blob.getValue() == null) { throw new BlobNotFoundException(blob, "Blob has no reference to a blob in the blobstore", null); } Pair<String, byte[]> decodedKey; try { decodedKey = decode(blob.getValue()); } catch (Exception e) { throw new BlobException("Failed to decode the blobkey of the blob '" + blob + "'", e); } return decodedKey; } public void delete(Blob blob) throws BlobNotFoundException, BlobException { Pair<String, byte[]> decodedKey = decodeKey(blob); BlobStoreAccess blobStoreAccess = registry.get(decodedKey.getV1()); blobStoreAccess.delete(decodedKey.getV2()); } public void delete(byte[] blobKey) throws BlobException { Pair<String,byte[]> decodedKey = decode(blobKey); BlobStoreAccess blobStoreAccess = registry.get(decodedKey.getV1()); blobStoreAccess.delete(decodedKey.getV2()); } static private byte[] encode(String id, byte[] blobKey) { byte[] bytes = new byte[0]; bytes = Bytes.add(bytes, blobKey); byte[] idBytes = Bytes.toBytes(id); bytes = Bytes.add(bytes, idBytes); bytes = Bytes.add(bytes, Bytes.toBytes(idBytes.length)); return bytes; } static private Pair<String, byte[]> decode(byte[] key) { int sizeofInt = Bytes.SIZEOF_INT; int idLength = Bytes.toInt(key, key.length - sizeofInt, sizeofInt); String id = Bytes.toString(key, key.length - sizeofInt - idLength, idLength); byte[] blobKey = Bytes.head(key, key.length - sizeofInt - idLength); return new Pair<String, byte[]>(id, blobKey); } private class BlobOutputStream extends FilterOutputStream { private final Blob blob; private final String blobStoreAccessId; private final BlobManager blobManager; private final boolean incubate; private long size = 0; BlobOutputStream(OutputStream outputStream, String blobStoreAccessId, Blob blob, BlobManager blobManager, boolean incubate) { super(outputStream); this.blobStoreAccessId = blobStoreAccessId; this.blob = blob; this.blobManager = blobManager; this.incubate = incubate; } @Override public void close() throws IOException { super.close(); byte[] encodedBlobKey = encode(blobStoreAccessId, blob.getValue()); if (incubate) { blobManager.incubateBlob(encodedBlobKey); } blob.setValue(encodedBlobKey); blob.setSize(size); } @Override public void write(byte[] b) throws IOException { super.out.write(b); size = size + b.length; } @Override public void write(int b) throws IOException { super.out.write(b); size = size + 1; } @Override public void write(byte[] b, int off, int len) throws IOException { super.out.write(b, off, len); size = size + len; } } }