// Copyright 2010 Google Inc.
//
// 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 com.google.enterprise.connector.persist;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.enterprise.connector.instantiator.Configuration;
import com.google.enterprise.connector.scheduler.Schedule;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Mock persistent store. This implementation doesn't actually persist
* any objects, it just uses memory.
*/
public class MockPersistentStore implements PersistentStore {
/* Property Names */
static final String CONFIGURATION = "configuration";
static final String SCHEDULE = "schedule";
static final String CHECKPOINT = "checkpoint";
private static class StoreKey {
public final StoreContext context;
public final String property;
public StoreKey(StoreContext context, String property) {
testStoreContext(context);
this.context = context;
this.property = property;
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof StoreKey))
return false;
StoreKey otherKey = (StoreKey) other;
return context.equals(otherKey.context) &&
property.equals(otherKey.property);
}
@Override
public int hashCode() {
// See Effective Java by Joshua Bloch, Item 8.
int result = 131;
result = 17 * result + context.hashCode();
result = 17 * result + property.hashCode();
return result;
}
@Override
public String toString() {
return "{ context=" + context + ", property=" + property + " }";
}
}
private static class StoreEntry {
public final Object object;
public final Stamp stamp;
public StoreEntry(Object object, Stamp stamp) {
this.object = object;
this.stamp = stamp;
}
@Override
public String toString() {
return "{ value=" + object + ", stamp=" + stamp + " }";
}
}
/** Incremented stamp value for constructing updated stamps. */
private static int stampValue = 0;
private final Map<StoreKey, StoreEntry> storeMap =
new HashMap<StoreKey, StoreEntry>();
// Sort Inventory for predictable test results.
private final boolean sortInventory;
public MockPersistentStore() {
this(false);
}
public MockPersistentStore(boolean sortInventory) {
this.sortInventory = sortInventory;
}
public void clear() {
storeMap.clear();
stampValue = 0;
}
/* @GuardedBy(getInventory) */
private Stamp getStamp(StoreContext context, String property) {
StoreEntry entry = storeMap.get(new StoreKey(context, property));
return (entry == null) ? null : entry.stamp;
}
private synchronized Object getObject(StoreContext context, String property) {
StoreEntry entry = storeMap.get(new StoreKey(context, property));
return (entry == null) ? null : entry.object;
}
private synchronized Object storeObject(StoreContext context, String property,
Object object) {
return storeMap.put(new StoreKey(context, property),
new StoreEntry(object, new MockStamp(stampValue++)));
}
private synchronized void removeObject(StoreContext context, String property) {
storeMap.remove(new StoreKey(context, property));
}
@Override
public boolean isDisabled() {
return false;
}
@Override
public ImmutableMap<StoreContext, ConnectorStamps> getInventory() {
ImmutableMap.Builder<StoreContext, ConnectorStamps> builder;
if (sortInventory) {
builder = ImmutableSortedMap.naturalOrder();
} else {
builder = ImmutableMap.builder();
}
Set<StoreContext> instances = new HashSet<StoreContext>();
synchronized(this) {
for (StoreKey key : storeMap.keySet()) {
instances.add(key.context);
}
for (StoreContext context : instances) {
builder.put(context, new ConnectorStamps(getStamp(context, CHECKPOINT),
getStamp(context, CONFIGURATION), getStamp(context, SCHEDULE)));
}
}
return builder.build();
}
@Override
public String getConnectorState(StoreContext context) {
return (String) getObject(context, CHECKPOINT);
}
@Override
public void storeConnectorState(StoreContext context,
String connectorState) {
storeObject(context, CHECKPOINT, connectorState);
}
@Override
public void removeConnectorState(StoreContext context) {
removeObject(context, CHECKPOINT);
}
@Override
public Configuration getConnectorConfiguration(StoreContext context) {
return (Configuration) getObject(context, CONFIGURATION);
}
@Override
public void storeConnectorConfiguration(StoreContext context,
Configuration config) {
storeObject(context, CONFIGURATION, config);
}
@Override
public void removeConnectorConfiguration(StoreContext context) {
removeObject(context, CONFIGURATION);
}
@Override
public Schedule getConnectorSchedule(StoreContext context) {
return (Schedule) getObject(context, SCHEDULE);
}
@Override
public void storeConnectorSchedule(StoreContext context, Schedule schedule) {
storeObject(context, SCHEDULE, schedule);
}
@Override
public void removeConnectorSchedule(StoreContext context) {
removeObject(context, SCHEDULE);
}
@Override
public synchronized String toString() {
return "MockPersistentStore = " + storeMap.toString();
}
/**
* Test the StoreContext to make sure it is sane.
*
* @param context a StoreContext
*/
private static void testStoreContext(StoreContext context) {
Preconditions.checkNotNull(context, "StoreContext may not be null.");
}
}