blob: 1b2a93aa3f7f47dd0f35f78e1b46dff261d232ba [file] [log] [blame]
/*
* Copyright 2011 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.ipc.invalidation.ticl;
import com.google.ipc.invalidation.external.client.SystemResources;
import com.google.ipc.invalidation.external.client.SystemResources.Scheduler;
import com.google.ipc.invalidation.external.client.SystemResources.Storage;
import com.google.ipc.invalidation.external.client.types.Callback;
import com.google.ipc.invalidation.external.client.types.SimplePair;
import com.google.ipc.invalidation.external.client.types.Status;
import com.google.ipc.invalidation.util.Bytes;
import com.google.ipc.invalidation.util.InternalBase;
import com.google.ipc.invalidation.util.NamedRunnable;
import com.google.ipc.invalidation.util.TextBuilder;
import com.google.ipc.invalidation.util.TypedUtil;
import java.util.HashMap;
import java.util.Map;
/**
* Map-based in-memory implementation of {@link Storage}.
*
*/
public class MemoryStorageImpl extends InternalBase implements Storage {
private Scheduler scheduler;
private Map<String, byte[]> ticlPersistentState = new HashMap<String, byte[]>();
@Override
public void writeKey(final String key, final byte[] value, final Callback<Status> callback) {
// Need to schedule immediately because C++ locks aren't reentrant, and
// C++ locking code assumes that this call will not return directly.
// Schedule the write even if the resources are started since the
// scheduler will prevent it from running in case the resources have been
// stopped.
scheduler.schedule(Scheduler.NO_DELAY,
new NamedRunnable("MemoryStorage.writeKey") {
@Override
public void run() {
ticlPersistentState.put(key, value);
callback.accept(Status.newInstance(Status.Code.SUCCESS, ""));
}
});
}
int numKeysForTest() {
return ticlPersistentState.size();
}
@Override
public void setSystemResources(SystemResources resources) {
this.scheduler = resources.getInternalScheduler();
}
@Override
public void readKey(final String key, final Callback<SimplePair<Status, byte[]>> done) {
scheduler.schedule(Scheduler.NO_DELAY,
new NamedRunnable("MemoryStorage.readKey") {
@Override
public void run() {
byte[] value = TypedUtil.mapGet(ticlPersistentState, key);
final SimplePair<Status, byte[]> result;
if (value != null) {
result = SimplePair.of(Status.newInstance(Status.Code.SUCCESS, ""), value);
} else {
String error = "No value present in map for " + key;
result = SimplePair.of(Status.newInstance(Status.Code.PERMANENT_FAILURE, error), null);
}
done.accept(result);
}
});
}
@Override
public void deleteKey(final String key, final Callback<Boolean> done) {
scheduler.schedule(Scheduler.NO_DELAY,
new NamedRunnable("MemoryStorage.deleteKey") {
@Override
public void run() {
TypedUtil.remove(ticlPersistentState, key);
done.accept(true);
}
});
}
@Override
public void readAllKeys(final Callback<SimplePair<Status, String>> done) {
scheduler.schedule(Scheduler.NO_DELAY,
new NamedRunnable("MemoryStorage.readAllKeys") {
@Override
public void run() {
Status successStatus = Status.newInstance(Status.Code.SUCCESS, "");
for (String key : ticlPersistentState.keySet()) {
done.accept(SimplePair.of(successStatus, key));
}
done.accept(null);
}
});
}
/**
* Same as write except without any callbacks and is NOT done on the internal thread.
* Test code should typically call this before starting the client.
*/
void writeForTest(final String key, final byte[] value) {
ticlPersistentState.put(key, value);
}
/**
* Sets the scheduler, for tests. The Android tests use this to supply a scheduler that executes
* no-delay items in-line.
*/
public void setSchedulerForTest(Scheduler newScheduler) {
scheduler = newScheduler;
}
/**
* Same as read except without any callbacks and is NOT done on the internal thread.
*/
public byte[] readForTest(final String key) {
return ticlPersistentState.get(key);
}
@Override
public void toCompactString(TextBuilder builder) {
builder.append("Storage state: ");
for (Map.Entry<String, byte[]> entry : ticlPersistentState.entrySet()) {
builder.appendFormat("<%s, %s>, ", entry.getKey(), Bytes.toString(entry.getValue()));
}
}
}