org.akubraproject.mux.AbstractMuxConnection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of akubra-mux Show documentation
Show all versions of akubra-mux Show documentation
Abstract base classes to build BlobStores that present a single store view
/* $HeadURL:: $
* $Id$
*
* Copyright (c) 2009-2010 DuraSpace
* http://duraspace.org
*
* In collaboration with Topaz Inc.
* http://www.topazproject.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
*
* 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.akubraproject.mux;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.transaction.Transaction;
import com.google.common.collect.Iterators;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.akubraproject.Blob;
import org.akubraproject.BlobStore;
import org.akubraproject.BlobStoreConnection;
import org.akubraproject.UnsupportedIdException;
import org.akubraproject.impl.AbstractBlobStoreConnection;
/**
* An abstract base class for connections returned by multiplexing BlobStores. Sub-class
* implementations must provide a {@link #getStore} implementation. Additionally for multiplexing
* content addressable stores, sub-classes must override the default implementation of {@link
* org.akubraproject.impl.AbstractBlobStoreConnection#getBlob(java.io.InputStream, long,
* Map)} and direct the call to the appropriate backing store. Note that the returned Blob from
* the backing store must be wrapped so that the {@link
* org.akubraproject.Blob#getConnection()} of the returned Blob will return this connection
* object.
*
* @author Pradeep Krishnan
*
* @see #getStore(URI, Map)
* @see #getStores(String)
* @see #getConnection(BlobStore, Map)
* @see MuxBlob
*/
public abstract class AbstractMuxConnection extends AbstractBlobStoreConnection {
private static final Logger log = LoggerFactory.getLogger(AbstractBlobStoreConnection.class);
/**
* The transaction to pass to while opening connections to the backing stores. Note that
* this transaction is only passed to transaction capable stores. A null is passed for
* non-transactional stores.
*
* @see #getConnection(BlobStore, Map)
*/
protected final Transaction txn;
/**
* A map of store-ids to connections.
*
* @see #getConnection(BlobStore, Map)
* @see #close()
*/
protected Map cons = new HashMap();
/**
* Creates a new AbstractMuxConnection object.
*
* @param store the mux store
* @param txn the txn passed in by the user
*/
public AbstractMuxConnection(BlobStore store, Transaction txn) {
super(store);
this.txn = txn;
}
/**
* Gets the backing store where the given blob is persisted.
*
* @param blobId the blob id (can be null)
* @param hints A set of hints to allow the implementation to optimize the operation (can be
* null)
*
* @return the store. Cannot be null and must be one of the backing stores.
*
* @throws IOException for IO errors
* @throws UnsupportedIdException if blobId is not in a recognized/usable pattern by any of the
* backing stores
*/
public abstract BlobStore getStore(URI blobId, Map hints)
throws IOException, UnsupportedIdException;
/**
* Gets the set of a backing stores matching the given blobId prefix. By default the
* returned set is the set of all backing stores. Override in sub-classes to narrow down the
* set.
*
* @param prefix the blobId prefix or null
*
* @return the set of stores matching the blobId prefix
*/
public Set getStores(String prefix) {
return new HashSet(((AbstractMuxStore) getBlobStore()).getBackingStores());
}
/**
* Closes this connection and all underlying connections created using {@link
* #getConnection(BlobStore, Map)}.
*/
@Override
public void close() {
super.close();
if (cons != null) {
for (BlobStoreConnection con : cons.values())
con.close();
cons.clear();
cons = null;
}
}
/**
* Lookup/Create a connection to the given backing store.
*
* @param store the backing store
* @param hints A set of hints to allow the implementation to optimize the operation (can be
* null)
*
* @return the backing store connection or null
*
* @throws IOException on an error in opening a connection to the backing store
* @throws UnsupportedOperationException on an error in opening a connection to the backing store
*/
protected BlobStoreConnection getConnection(BlobStore store, Map hints)
throws IOException {
if (store == null)
return null;
if (cons == null)
throw new IllegalStateException("Connection closed.");
BlobStoreConnection con = cons.get(store.getId());
if (con == null) {
con = store.openConnection(txn, hints);
cons.put(store.getId(), con);
}
return con;
}
@Override
public Blob getBlob(URI blobId, Map hints)
throws IOException {
return new MuxBlob(getConnection(getStore(blobId, hints), hints).getBlob(blobId, hints), this);
}
@Override
public Iterator listBlobIds(String filterPrefix) throws IOException {
List> iterators = new ArrayList>();
for (BlobStore store : getStores(filterPrefix))
iterators.add(getConnection(store, null).listBlobIds(filterPrefix));
return Iterators.concat(iterators.iterator());
}
@Override
public void sync() throws IOException {
if (cons == null)
throw new IllegalStateException("Connection closed.");
Exception exc = null;
for (BlobStoreConnection con : cons.values()) {
try {
con.sync();
} catch (Exception e) {
if (exc == null)
exc = e;
else
log.warn("Error sync'ing connection " + con, e);
}
}
if (exc instanceof IOException)
throw (IOException) exc;
if (exc instanceof RuntimeException)
throw (RuntimeException) exc;
}
}