/*
* Copyright (C) 2015 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 interactivespaces.util.data.persist;
import interactivespaces.InteractiveSpacesException;
import interactivespaces.util.data.json.JsonMapper;
import interactivespaces.util.data.json.StandardJsonMapper;
import interactivespaces.util.io.FileSupport;
import interactivespaces.util.io.FileSupportImpl;
import com.google.common.collect.Maps;
import java.io.File;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* The standard implementation of a concurrent JSON file.
*
* @author Keith M. Hughes
*/
public class StandardConcurrentJsonFile implements ConcurrentJsonFile {
/**
* The JSON mapper.
*/
private static final JsonMapper MAPPER = StandardJsonMapper.INSTANCE;
/**
* The file which stores the JSON.
*/
private File file;
/**
* The read/write lock.
*
* <p>
* This lock will be fair between reader and writer threads.
*/
private ReadWriteLock rwlock = new ReentrantReadWriteLock(true);
/**
* The map.
*/
private Map<String, Object> map = Maps.newHashMap();
/**
* The file support for file operations.
*/
private FileSupport fileSupport = FileSupportImpl.INSTANCE;
/**
* Construct a new concurrent file.
*
* @param file
* the file system file
*/
public StandardConcurrentJsonFile(File file) {
this.file = file;
}
@Override
public boolean load() throws InteractiveSpacesException {
rwlock.readLock().lock();
try {
if (fileSupport.exists(file)) {
String value = fileSupport.readFile(file);
map = MAPPER.parseObject(value);
return true;
} else {
return false;
}
} catch (Exception e) {
throw new InteractiveSpacesException(String.format("Could not read %s", file), e);
} finally {
rwlock.readLock().unlock();
}
}
@Override
public Object get(String key) {
rwlock.readLock().lock();
try {
return map.get(key);
} finally {
rwlock.readLock().unlock();
}
}
@Override
public Map<String, Object> getAll() {
rwlock.readLock().lock();
try {
return Maps.newHashMap(map);
} finally {
rwlock.readLock().unlock();
}
}
@Override
public void save() throws InteractiveSpacesException {
rwlock.writeLock().lock();
try {
fileSupport.writeFile(file, MAPPER.toString(map));
} catch (Exception e) {
throw new InteractiveSpacesException(String.format("Could not read %s", file), e);
} finally {
rwlock.writeLock().unlock();
}
}
@Override
public void replaceAll(Map<String, Object> newData) {
rwlock.writeLock().lock();
try {
map.clear();
map.putAll(newData);
} finally {
rwlock.writeLock().unlock();
}
}
@Override
public void put(String key, Object value) {
rwlock.writeLock().lock();
try {
map.put(key, value);
} finally {
rwlock.writeLock().unlock();
}
}
@Override
public void putAll(Map<String, Object> values) {
rwlock.writeLock().lock();
try {
for (Entry<String, Object> entry : values.entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
} finally {
rwlock.writeLock().unlock();
}
}
}