/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.jackrabbit.core.data;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* An in-memory backend implementation used to speed up testing.
*/
public class InMemoryBackend implements Backend {
private HashMap<DataIdentifier, byte[]> data = new HashMap<DataIdentifier, byte[]>();
private HashMap<DataIdentifier, Long> timeMap = new HashMap<DataIdentifier, Long>();
private CachingDataStore store;
private Properties properties;
@Override
public void init(CachingDataStore store, String homeDir, String config)
throws DataStoreException {
// ignore
log("init");
this.store = store;
}
@Override
public void close() {
// ignore
log("close");
}
@Override
public boolean exists(final DataIdentifier identifier) {
log("exists " + identifier);
return data.containsKey(identifier);
}
@Override
public Iterator<DataIdentifier> getAllIdentifiers()
throws DataStoreException {
log("getAllIdentifiers");
return data.keySet().iterator();
}
@Override
public InputStream read(final DataIdentifier identifier)
throws DataStoreException {
log("read " + identifier);
return new ByteArrayInputStream(data.get(identifier));
}
@Override
public void writeAsync(final DataIdentifier identifier, final File file,
final AsyncUploadCallback callback) throws DataStoreException {
this.write(identifier, file, true, callback);
}
@Override
public void write(final DataIdentifier identifier, final File file)
throws DataStoreException {
this.write(identifier, file, false, null);
}
@Override
public long getLastModified(final DataIdentifier identifier)
throws DataStoreException {
log("getLastModified " + identifier);
return timeMap.get(identifier);
}
@Override
public void deleteRecord(final DataIdentifier identifier)
throws DataStoreException {
timeMap.remove(identifier);
data.remove(identifier);
}
@Override
public Set<DataIdentifier> deleteAllOlderThan(final long min) throws DataStoreException {
log("deleteAllOlderThan " + min);
Set<DataIdentifier> tobeDeleted = new HashSet<DataIdentifier>();
for (Map.Entry<DataIdentifier, Long> entry : timeMap.entrySet()) {
DataIdentifier identifier = entry.getKey();
long timestamp = entry.getValue();
if (timestamp < min && !store.isInUse(identifier)
&& store.confirmDelete(identifier)) {
store.deleteFromCache(identifier);
tobeDeleted.add(identifier);
}
}
for (DataIdentifier identifier : tobeDeleted) {
timeMap.remove(identifier);
data.remove(identifier);
}
return tobeDeleted;
}
@Override
public long getLength(final DataIdentifier identifier)
throws DataStoreException {
try {
return data.get(identifier).length;
} catch (Exception e) {
throw new DataStoreException(e);
}
}
@Override
public boolean exists(final DataIdentifier identifier, final boolean touch)
throws DataStoreException {
boolean retVal = data.containsKey(identifier);
if (retVal && touch) {
timeMap.put(identifier, System.currentTimeMillis());
}
return retVal;
}
@Override
public void touch(DataIdentifier identifier, long minModifiedDate) {
timeMap.put(identifier, System.currentTimeMillis());
}
@Override
public void touchAsync(DataIdentifier identifier, long minModifiedDate,
AsyncTouchCallback callback) {
timeMap.put(identifier, System.currentTimeMillis());
callback.onSuccess(new AsyncTouchResult(identifier));
}
private void write(final DataIdentifier identifier, final File file,
final boolean async, final AsyncUploadCallback callback)
throws DataStoreException {
log("write " + identifier + " " + file.length());
byte[] buffer = new byte[(int) file.length()];
try {
if (async && callback == null) {
throw new IllegalArgumentException(
"callback parameter cannot be null");
}
DataInputStream din = new DataInputStream(new FileInputStream(file));
din.readFully(buffer);
din.close();
data.put(identifier, buffer);
timeMap.put(identifier, System.currentTimeMillis());
} catch (IOException e) {
if (async) {
callback.onAbort(new AsyncUploadResult(identifier, file));
}
throw new DataStoreException(e);
}
if (async) {
callback.onSuccess(new AsyncUploadResult(identifier, file));
}
}
/**
* Properties used to configure the backend. If provided explicitly before
* init is invoked then these take precedence
*
* @param properties to configure S3Backend
*/
public void setProperties(Properties properties) {
this.properties = properties;
}
/**
* Log a message if logging is enabled.
*
* @param message
* the message
*/
private void log(final String message) {
// System.out.println(message);
}
}