Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
start unit testing LowLevelStorageService
  • Loading branch information
barmintor committed Apr 2, 2013
1 parent 8c39edd commit a534c8c
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 102 deletions.
Expand Up @@ -2,28 +2,22 @@
package org.fcrepo.services;

import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.ImmutableMap.builder;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.ImmutableSet.builder;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Maps.transformEntries;
import static com.google.common.collect.Sets.difference;
import static com.yammer.metrics.MetricRegistry.name;
import static java.security.MessageDigest.getInstance;
import static org.fcrepo.services.RepositoryService.metrics;
import static org.fcrepo.utils.FixityResult.FixityState.REPAIRED;
import static org.fcrepo.utils.FixityResult.FixityState.SUCCESS;
import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;
import static org.slf4j.LoggerFactory.getLogger;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
Expand All @@ -35,24 +29,22 @@
import javax.jcr.Session;

import org.fcrepo.Datastream;
import org.fcrepo.services.functions.GetBinaryKey;
import org.fcrepo.services.functions.GetBinaryStore;
import org.fcrepo.utils.FixityResult;
import org.fcrepo.utils.LowLevelCacheEntry;
import org.infinispan.Cache;
import org.infinispan.loaders.CacheLoaderManager;
import org.infinispan.loaders.CacheStore;
import org.infinispan.loaders.decorators.ChainingCacheStore;
import org.modeshape.jcr.JcrRepository;
import org.modeshape.jcr.value.BinaryKey;
import org.modeshape.jcr.value.BinaryValue;
import org.modeshape.jcr.value.binary.BinaryStore;
import org.modeshape.jcr.value.binary.BinaryStoreException;
import org.modeshape.jcr.value.binary.infinispan.InfinispanBinaryStore;
import org.slf4j.Logger;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.yammer.metrics.Counter;
import com.yammer.metrics.Timer;

Expand All @@ -74,46 +66,31 @@ public class LowLevelStorageService {

@Inject
private Repository repo;

GetBinaryStore getBinaryStore = new GetBinaryStore();

GetBinaryKey getBinaryKey = new GetBinaryKey();

/**
* For use with non-mutating methods.
*/
private Session readOnlySession;

private JcrRepository getRepositoryInstance() {
return (JcrRepository) readOnlySession.getRepository();
}

public Collection<FixityResult> getFixity(
final Node resource, final MessageDigest digest,
final URI dsChecksum, final long dsSize) throws RepositoryException {
logger.debug("Checking resource: " + resource.getPath());

return transformBinaryBlobs(
resource,
new Maps.EntryTransformer<LowLevelCacheEntry, InputStream, FixityResult>() {

public FixityResult transformEntry(LowLevelCacheEntry entry,
InputStream is) {
logger.debug("Checking fixity for resource in cache store " + entry.toString());
FixityResult result = null;
try {
result = entry.checkFixity(dsChecksum, dsSize, digest);
} catch (BinaryStoreException e) {
logger.error("Exception checking low-level fixity: {}", e);
throw new IllegalStateException(e);
}
return result;
}

}).values();
ServiceHelpers.getCheckCacheFixityFunction(digest, dsChecksum, dsSize));
}

public <T> Map<LowLevelCacheEntry, T> transformBinaryBlobs(
public <T> Collection<T> transformBinaryBlobs(
final Node resource,
final Maps.EntryTransformer<LowLevelCacheEntry, InputStream, T> transform)
final Function<LowLevelCacheEntry, T> transform)
throws RepositoryException {
return transformEntries(getBinaryBlobs(resource), transform);
return transform(getBinaryBlobs(resource), transform);
}

/**
Expand All @@ -122,67 +99,28 @@ public <T> Map<LowLevelCacheEntry, T> transformBinaryBlobs(
* @return a map of binary stores and input streams
* @throws RepositoryException
*/
public Map<LowLevelCacheEntry, InputStream> getBinaryBlobs(
public Set<LowLevelCacheEntry> getBinaryBlobs(
final Node resource) throws RepositoryException {

final BinaryValue v =
(BinaryValue) resource.getNode(JCR_CONTENT).getProperty(
JCR_DATA).getBinary();

return getBinaryBlobs(v.getKey());
return getBinaryBlobs(getBinaryKey.apply(resource));

}

/**
*
* @param key a Modeshape BinaryValue's key.
* @return a map of binary stores and input streams
*/
public Map<LowLevelCacheEntry, InputStream> getBinaryBlobs(BinaryKey key) {

ImmutableMap.Builder<LowLevelCacheEntry, InputStream> blobs = builder();

for (LowLevelCacheEntry c : getLowLevelCacheStores(key)) {
try {
final InputStream is = c.getInputStream();
blobs.put(c, is);
} catch (BinaryStoreException e) {
//we didn't find anything.
}
}
return blobs.build();
}

/**
* Extract the BinaryStore out of Modeshape (infinspan, jdbc, file, transient, etc)
* @return
* @return a set of binary stores
*/
BinaryStore getBinaryStore() {
try {
return getRepositoryInstance().getConfiguration()
.getBinaryStorage().getBinaryStore();
} catch (Exception e) { // boo, catching all exceptions. unfortunately, that's all getBinaryStore promises..
throw new IllegalStateException(e);
}
public Set<LowLevelCacheEntry> getBinaryBlobs(BinaryKey key) {

}
ImmutableSet.Builder<LowLevelCacheEntry> blobs = builder();

/**
* Get the list of low-level cache stores at play. If it's an infinispan node, for instance, figure out exactly
* which cachestores are being used.
*
* @return a list of "BinaryCacheStore", an abstraction over a plain BinaryStore or a specific Infinispan Cache
*/
private List<LowLevelCacheEntry> getLowLevelCacheStores(BinaryKey key) {

List<LowLevelCacheEntry> stores = new ArrayList<LowLevelCacheEntry>();

BinaryStore store = getBinaryStore();
BinaryStore store = getBinaryStore.apply(repo);

if (store == null) {
return stores;
return blobs.build();
}

// if we have an Infinispan store, it may have multiple stores (or cluster nodes)
if (store instanceof InfinispanBinaryStore) {
InfinispanBinaryStore ispnStore = (InfinispanBinaryStore) store;
Expand All @@ -203,18 +141,18 @@ private List<LowLevelCacheEntry> getLowLevelCacheStores(BinaryKey key) {
(ChainingCacheStore) cacheStore;
// the stores are a map of the cache store and the configuration; i'm just throwing the configuration away..
for (CacheStore s : chainingCacheStore.getStores().keySet()) {
stores.add(new LowLevelCacheEntry(store, s, key));
blobs.add(new LowLevelCacheEntry(store, s, key));
}
} else {
// just a nice, simple infinispan cache.
stores.add(new LowLevelCacheEntry(store, cacheStore, key));
blobs.add(new LowLevelCacheEntry(store, cacheStore, key));
}
}
} else {
stores.add(new LowLevelCacheEntry(store, key));
blobs.add(new LowLevelCacheEntry(store, key));
}

return stores;
return blobs.build();
}

@PostConstruct
Expand Down
Expand Up @@ -4,6 +4,9 @@
import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;

import java.net.URI;
import java.security.MessageDigest;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
Expand All @@ -13,6 +16,12 @@
import javax.jcr.Value;
import javax.jcr.ValueFormatException;

import org.fcrepo.services.functions.CheckCacheEntryFixity;
import org.fcrepo.utils.FixityResult;
import org.fcrepo.utils.LowLevelCacheEntry;

import com.google.common.base.Function;

public class ServiceHelpers {

public static Long getNodePropertySize(Node node)
Expand Down Expand Up @@ -63,5 +72,11 @@ public static Long getContentSize(Node ds) throws ValueFormatException,
return ds.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary()
.getSize();
}

public static Function<LowLevelCacheEntry, FixityResult> getCheckCacheFixityFunction(
final MessageDigest digest,
final URI dsChecksum, final long dsSize) {
return new CheckCacheEntryFixity(digest, dsChecksum, dsSize);
}

}
@@ -0,0 +1,42 @@
package org.fcrepo.services.functions;

import static org.slf4j.LoggerFactory.getLogger;

import java.net.URI;
import java.security.MessageDigest;

import org.fcrepo.services.LowLevelStorageService;
import org.fcrepo.utils.FixityResult;
import org.fcrepo.utils.LowLevelCacheEntry;
import org.modeshape.jcr.value.binary.BinaryStoreException;
import org.slf4j.Logger;

import com.google.common.base.Function;

public class CheckCacheEntryFixity implements Function<LowLevelCacheEntry, FixityResult> {

private static final Logger logger = getLogger(LowLevelStorageService.class);

private MessageDigest digest;
private URI dsChecksum;
private long dsSize;
public CheckCacheEntryFixity(final MessageDigest digest,
final URI dsChecksum, final long dsSize) {
this.digest = digest;
this.dsChecksum = dsChecksum;
this.dsSize = dsSize;
}
@Override
public FixityResult apply(LowLevelCacheEntry input) {
logger.debug("Checking fixity for resource in cache store " + input.toString());
FixityResult result = null;
try {
result = input.checkFixity(dsChecksum, dsSize, digest);
} catch (BinaryStoreException e) {
logger.error("Exception checking low-level fixity: {}", e);
throw new IllegalStateException(e);
}
return result;
}

}
@@ -0,0 +1,28 @@
package org.fcrepo.services.functions;

import static org.modeshape.jcr.api.JcrConstants.JCR_CONTENT;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;

import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.ValueFormatException;

import org.modeshape.jcr.value.BinaryKey;
import org.modeshape.jcr.value.BinaryValue;

import com.google.common.base.Function;

public class GetBinaryKey implements Function<Node, BinaryKey>{

@Override
public BinaryKey apply(Node input) {
try {
return ((BinaryValue) input.getNode(JCR_CONTENT).getProperty(
JCR_DATA).getBinary()).getKey();
} catch (RepositoryException e) {
throw new IllegalArgumentException(e);
}
}

}
@@ -0,0 +1,25 @@
package org.fcrepo.services.functions;

import javax.jcr.Repository;

import org.modeshape.jcr.JcrRepository;
import org.modeshape.jcr.value.binary.BinaryStore;

import com.google.common.base.Function;

public class GetBinaryStore implements Function<Repository, BinaryStore>{
/**
* Extract the BinaryStore out of Modeshape (infinspan, jdbc, file, transient, etc)
* @return
*/
@Override
public BinaryStore apply(Repository input) {
try {
return ((JcrRepository)input).getConfiguration()
.getBinaryStorage().getBinaryStore();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

}
Expand Up @@ -19,6 +19,7 @@
import org.fcrepo.services.LowLevelStorageService;
import org.fcrepo.services.ObjectService;
import org.fcrepo.utils.FixityResult;
import org.fcrepo.utils.LowLevelCacheEntry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
Expand Down Expand Up @@ -80,11 +81,11 @@ public void testGetBinaryBlobs() throws Exception {

final Datastream ds = datastreamService.getDatastream("testLLObject", "testRepositoryContent");

Iterator<InputStream> inputStreamList = lowLevelService.getBinaryBlobs(ds.getNode()).values().iterator();
Iterator<LowLevelCacheEntry> inputStreamList = lowLevelService.getBinaryBlobs(ds.getNode()).iterator();

int i = 0;
while(inputStreamList.hasNext()) {
InputStream is = inputStreamList.next();
InputStream is = inputStreamList.next().getInputStream();

String myString = IOUtils.toString(is, "UTF-8");

Expand Down
Expand Up @@ -12,6 +12,7 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.jcr.Node;
import javax.jcr.Repository;
Expand Down Expand Up @@ -83,9 +84,9 @@ private void tamperWithNode(final Node node) throws Exception {


logger.info("Tampering with node " + node.toString());
final Map<LowLevelCacheEntry,InputStream> binaryBlobs = lowLevelService.getBinaryBlobs(node);
final Set<LowLevelCacheEntry> binaryBlobs = lowLevelService.getBinaryBlobs(node);

Iterator<LowLevelCacheEntry> it = binaryBlobs.keySet().iterator();
Iterator<LowLevelCacheEntry> it = binaryBlobs.iterator();


LowLevelCacheEntry entryToTamper = it.next();
Expand Down

0 comments on commit a534c8c

Please sign in to comment.