org.modeshape.jcr.value.binary.CompositeBinaryStore Maven / Gradle / Ivy
/*
* ModeShape (http://www.modeshape.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.modeshape.jcr.value.binary;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.jcr.RepositoryException;
import org.modeshape.common.collection.Collections;
import org.modeshape.common.logging.Logger;
import org.modeshape.common.util.CheckArg;
import org.modeshape.jcr.JcrI18n;
import org.modeshape.jcr.TextExtractors;
import org.modeshape.jcr.mimetype.MimeTypeDetector;
import org.modeshape.jcr.mimetype.NullMimeTypeDetector;
import org.modeshape.jcr.text.TextExtractorContext;
import org.modeshape.jcr.value.BinaryKey;
import org.modeshape.jcr.value.BinaryValue;
/**
* A {@link BinaryStore} implementation that stores files in other BinaryStores. This store is initialized with a map of number of
* BinaryStores. On retrieval, the CompositeBinaryStore will look in all the other BinaryStores for the value. When storing a
* value, the CompositeBinaryStore may receive a StorageHint that MAY be used when determining which named BinaryStore to write
* to. If a storage hint is not provided (or doesn't match a store), the value will be stored in the default store.
*/
public class CompositeBinaryStore implements BinaryStore {
private static final String DEFAULT_STRATEGY_HINT = "default";
private volatile TextExtractors extractors;
private volatile MimeTypeDetector detector = NullMimeTypeDetector.INSTANCE;
protected Logger logger = Logger.getLogger(getClass());
private Map namedStores;
private BinaryStore defaultBinaryStore;
/**
* Initialize a new CompositeBinaryStore using a Map of other BinaryKeys that are keyed by an implementer-provided key. The
* named stores must include a default BinaryStore that will be used in the absence of storage hints.
*
* @param namedStores a {@code Map} of inner stores, grouped by the hint.
*/
public CompositeBinaryStore( Map namedStores ) {
this.namedStores = namedStores;
this.defaultBinaryStore = null;
}
/**
* Initialize the store, and initialize all the named stores.
*/
@Override
public void start() {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
BinaryStore bs = it.next().getValue();
bs.start();
}
}
/**
* Shut down all the named stores
*/
@Override
public void shutdown() {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
BinaryStore bs = it.next().getValue();
bs.shutdown();
}
}
@Override
public long getMinimumBinarySizeInBytes() {
long minimumBinarySize = Long.MAX_VALUE;
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
BinaryStore bs = it.next().getValue();
if (minimumBinarySize > bs.getMinimumBinarySizeInBytes()) {
minimumBinarySize = bs.getMinimumBinarySizeInBytes();
}
}
return minimumBinarySize;
}
@Override
public void setMinimumBinarySizeInBytes( long minSizeInBytes ) {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
BinaryStore bs = it.next().getValue();
bs.setMinimumBinarySizeInBytes(minSizeInBytes);
}
}
@Override
public void setTextExtractors( TextExtractors textExtractors ) {
CheckArg.isNotNull(textExtractors, "textExtractors");
this.extractors = textExtractors;
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
BinaryStore bs = it.next().getValue();
bs.setTextExtractors(textExtractors);
}
}
@Override
public void setMimeTypeDetector( MimeTypeDetector mimeTypeDetector ) {
this.detector = mimeTypeDetector != null ? mimeTypeDetector : NullMimeTypeDetector.INSTANCE;
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
BinaryStore bs = it.next().getValue();
bs.setMimeTypeDetector(mimeTypeDetector);
}
}
@Override
public BinaryValue storeValue( InputStream stream, boolean markAsUnused ) throws BinaryStoreException {
return storeValue(stream, DEFAULT_STRATEGY_HINT, markAsUnused);
}
@Override
public BinaryValue storeValue( InputStream stream, String hint, boolean markAsUnused ) throws BinaryStoreException {
BinaryStore binaryStore = selectBinaryStore(hint);
BinaryValue bv = binaryStore.storeValue(stream, markAsUnused);
logger.debug("Stored binary " + bv.getKey() + " into binary store " + binaryStore + " used=" + markAsUnused);
return bv;
}
/**
* Move a value from one named store to another store
*
* @param key Binary key to transfer from the source store to the destination store
* @param source a hint for discovering the source repository; may be null
* @param destination a hint for discovering the destination repository
* @return the {@link BinaryKey} value of the moved binary, never {@code null}
* @throws BinaryStoreException if a source store cannot be found or the source store does not contain the binary key
*/
public BinaryKey moveValue( BinaryKey key,
String source,
String destination ) throws BinaryStoreException {
final BinaryStore sourceStore;
if (source == null) {
sourceStore = findBinaryStoreContainingKey(key);
} else {
sourceStore = selectBinaryStore(source);
}
// could not find source store, or
if (sourceStore == null || !sourceStore.hasBinary(key)) {
throw new BinaryStoreException(JcrI18n.unableToFindBinaryValue.text(key, sourceStore));
}
BinaryStore destinationStore = selectBinaryStore(destination);
// key is already in the destination store
if (sourceStore.equals(destinationStore)) {
return key;
}
final BinaryValue binaryValue = storeValue(sourceStore.getInputStream(key), destination, false);
sourceStore.markAsUnused(java.util.Collections.singleton(key));
return binaryValue.getKey();
}
/**
* Move a BinaryKey to a named store
*
* @param key Binary key to transfer from the source store to the destination store
* @param destination a hint for discovering the destination repository
* @throws BinaryStoreException if anything unexpected fails
*/
public void moveValue( BinaryKey key,
String destination ) throws BinaryStoreException {
moveValue(key, null, destination);
}
@Override
public InputStream getInputStream( BinaryKey key ) throws BinaryStoreException {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
final Map.Entry entry = it.next();
final String binaryStoreKey = entry.getKey();
BinaryStore binaryStore = entry.getValue();
logger.trace("Checking binary store " + binaryStoreKey + " for key " + key);
try {
return binaryStore.getInputStream(key);
} catch (BinaryStoreException e) {
// this exception is "normal", and is thrown
logger.trace(e, "The named store " + binaryStoreKey + " raised exception");
}
}
throw new BinaryStoreException(JcrI18n.unableToFindBinaryValue.text(key, this.toString()));
}
@Override
public boolean hasBinary( BinaryKey key ) {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
BinaryStore bs = it.next().getValue();
if (bs.hasBinary(key)) {
return true;
}
}
return false;
}
@SuppressWarnings( "unused" )
@Override
public void markAsUnused( Iterable keys ) throws BinaryStoreException {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
final String binaryStoreKey = entry.getKey();
BinaryStore bs = entry.getValue();
try {
bs.markAsUnused(keys);
} catch (BinaryStoreException e) {
logger.debug(e, "The named store " + binaryStoreKey + " raised exception");
}
}
}
@Override
public void markAsUsed( Iterable keys ) {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
final String binaryStoreKey = entry.getKey();
BinaryStore bs = entry.getValue();
try {
bs.markAsUsed(keys);
} catch (BinaryStoreException e) {
logger.debug(e, "The named store " + binaryStoreKey + " raised exception");
}
}
}
@SuppressWarnings( "unused" )
@Override
public void removeValuesUnusedLongerThan( long minimumAge,
TimeUnit unit ) throws BinaryStoreException {
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
final String binaryStoreKey = entry.getKey();
BinaryStore bs = entry.getValue();
try {
bs.removeValuesUnusedLongerThan(minimumAge, unit);
} catch (BinaryStoreException e) {
logger.debug(e, "The named store " + binaryStoreKey + " raised exception");
}
}
}
@Override
public String getText( BinaryValue binary ) throws BinaryStoreException {
if (binary instanceof InMemoryBinaryValue) {
if (extractors == null || !extractors.extractionEnabled()) {
return null;
}
// The extracted text will never be stored, so try directly using the text extractors ...
return extractors.extract((InMemoryBinaryValue)binary, new TextExtractorContext(detector));
}
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
final String binaryStoreKey = entry.getKey();
BinaryStore bs = entry.getValue();
try {
if (bs.hasBinary(binary.getKey())) {
return bs.getText(binary);
}
} catch (BinaryStoreException e) {
logger.debug(e, "The named store " + binaryStoreKey + " raised exception");
if (!it.hasNext()) {
throw e;
}
}
}
throw new BinaryStoreException(JcrI18n.unableToFindBinaryValue.text(binary.getKey(), this));
}
@Override
public String getMimeType( BinaryValue binary,
String name ) throws IOException, RepositoryException {
if (detector == null) {
return null;
}
String detectedMimeType = detector.mimeTypeOf(name, binary);
if (binary instanceof InMemoryBinaryValue) {
return detectedMimeType;
}
Iterator> it = getNamedStoreIterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
final String binaryStoreKey = entry.getKey();
BinaryStore bs = entry.getValue();
try {
if (bs.hasBinary(binary.getKey())) {
return bs.getMimeType(binary, name);
}
} catch (BinaryStoreException e) {
logger.debug(e, "The named store " + binaryStoreKey + " raised exception");
if (!it.hasNext()) {
throw e;
}
}
}
throw new BinaryStoreException(JcrI18n.unableToFindBinaryValue.text(binary.getKey(), this));
}
@Override
public Iterable getAllBinaryKeys() throws BinaryStoreException {
Iterable generatedIterable = new HashSet();
Iterator> binaryStoreIterator = getNamedStoreIterator();
while (binaryStoreIterator.hasNext()) {
BinaryStore bs = binaryStoreIterator.next().getValue();
generatedIterable = Collections.concat(generatedIterable, bs.getAllBinaryKeys());
}
return generatedIterable;
}
/**
* Get an iterator over all the named stores
*
* @return an iterator over the map of binary stores and their given names
*/
public Iterator> getNamedStoreIterator() {
return namedStores.entrySet().iterator();
}
/**
* Get the named binary store that contains the key
*
* @param key the key to the binary content; never null
* @return the BinaryStore that contains the given key
*/
public BinaryStore findBinaryStoreContainingKey( BinaryKey key ) {
Iterator> binaryStoreIterator = getNamedStoreIterator();
while (binaryStoreIterator.hasNext()) {
BinaryStore bs = binaryStoreIterator.next().getValue();
if (bs.hasBinary(key)) {
return bs;
}
}
return null;
}
/**
* Select a named binary store for the given hint
*
* @param hint a hint to a binary store; possibly null
* @return a named BinaryStore from the hint, or the default store
*/
private BinaryStore selectBinaryStore( String hint ) {
BinaryStore namedBinaryStore = null;
if (hint != null) {
logger.trace("Selecting named binary store for hint: " + hint);
namedBinaryStore = namedStores.get(hint);
}
if (namedBinaryStore == null) {
namedBinaryStore = getDefaultBinaryStore();
}
logger.trace("Selected binary store: " + namedBinaryStore.toString());
return namedBinaryStore;
}
private BinaryStore getDefaultBinaryStore() {
if (defaultBinaryStore == null) {
if (namedStores.containsKey(DEFAULT_STRATEGY_HINT)) {
defaultBinaryStore = namedStores.get(DEFAULT_STRATEGY_HINT);
} else {
logger.trace("Did not find a named binary store with the key 'default', picking the first binary store in the list");
final Iterator iterator = namedStores.values().iterator();
if (iterator.hasNext()) {
defaultBinaryStore = iterator.next();
}
}
}
return defaultBinaryStore;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy