Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
nl.renarj.jasdb.service.metadata.JasDBMetadataStore Maven / Gradle / Ivy
package nl.renarj.jasdb.service.metadata;
import nl.renarj.jasdb.api.SimpleEntity;
import nl.renarj.jasdb.api.metadata.Bag;
import nl.renarj.jasdb.api.metadata.IndexDefinition;
import nl.renarj.jasdb.api.metadata.Instance;
import nl.renarj.jasdb.api.metadata.MetadataProvider;
import nl.renarj.jasdb.api.metadata.MetadataStore;
import nl.renarj.jasdb.core.exceptions.JasDBStorageException;
import nl.renarj.jasdb.core.platform.HomeLocatorUtil;
import nl.renarj.jasdb.core.platform.PlatformManagerFactory;
import nl.renarj.jasdb.core.utils.FileUtils;
import nl.renarj.jasdb.storage.transactional.FSWriter;
import nl.renarj.jasdb.storage.transactional.RecordIteratorImpl;
import nl.renarj.jasdb.storage.transactional.RecordResultImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import javax.inject.Singleton;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.Optional.of;
/**
* @author Renze de Vries
*/
@Component
@Singleton
public class JasDBMetadataStore implements MetadataStore {
private static final Logger LOG = LoggerFactory.getLogger(JasDBMetadataStore.class);
private static final String METADATA_FILE = "metadata.pjs";
private static final String PID_FILE = "metadata.pid";
public static final String DEFAULT_INSTANCE = "default";
private FSWriter writer;
private File datastoreLocation;
private boolean lastShutdownClean = true;
private Map> instanceMetaMap = new ConcurrentHashMap<>();
private Map> bagMetaMap = new ConcurrentHashMap<>();
private Map metadataProviders = new ConcurrentHashMap<>();
public JasDBMetadataStore() throws JasDBStorageException {
openStore();
}
private void openStore() throws JasDBStorageException {
datastoreLocation = HomeLocatorUtil.determineDatastoreLocation();
handleCreateNewPidFile();
writer = new FSWriter(new File(datastoreLocation, METADATA_FILE));
writer.openWriter();
ServiceLoader providers = ServiceLoader.load(MetadataProvider.class);
for(MetadataProvider provider : providers) {
metadataProviders.put(provider.getMetadataType(), provider);
provider.setMetadataStore(this);
}
loadRecords();
ensureDefaultInstance();
}
private void handleCreateNewPidFile() throws JasDBStorageException {
File pidFile = new File(datastoreLocation, PID_FILE);
lastShutdownClean = !pidFile.exists();
LOG.info("Last shutdown clean: {}", lastShutdownClean);
try {
if(datastoreLocation.exists() || datastoreLocation.mkdirs()) {
FileUtils.writeToFile(pidFile, "JasDB Instance Started, " + PlatformManagerFactory.getPlatformManager().getProcessId());
LOG.info("Created JasDB pid file: {}", pidFile);
} else {
throw new JasDBStorageException("Unable to create database path, directories could not be created: " + datastoreLocation) ;
}
} catch(IOException e) {
throw new JasDBStorageException("Unable to open JasDB metadata store, pid file: " + pidFile.toString() + " could not be created");
}
}
private void loadRecords() throws JasDBStorageException {
for(RecordIteratorImpl recordIterator = writer.readAllRecords(); recordIterator.hasNext(); ) {
RecordResultImpl recordResult = recordIterator.next();
SimpleEntity entity = SimpleEntity.fromStream(recordResult.getStream());
String type = entity.getValue(Constants.META_TYPE).toString();
if(type.equals(Constants.INSTANCE_TYPE)) {
InstanceMeta instance = InstanceMeta.fromEntity(entity);
instanceMetaMap.put(instance.getInstanceId(), new MetaWrapper(instance, recordResult.getRecordPointer()));
} else if(type.equals(Constants.BAG_TYPE)) {
BagMeta bagMeta = BagMeta.fromEntity(entity);
String bagId = getBagKey(bagMeta.getInstanceId(), bagMeta.getName());
bagMetaMap.put(bagId, new MetaWrapper(bagMeta, recordResult.getRecordPointer()));
} else if(metadataProviders.containsKey(type)) {
metadataProviders.get(type).registerMetadataEntity(entity, recordResult.getRecordPointer());
} else {
throw new JasDBStorageException("Unable to load metadata record: " + entity.toString() + " unknown type: " + type);
}
}
}
@Override
public boolean isLastShutdownClean() throws JasDBStorageException {
return lastShutdownClean;
}
private void ensureDefaultInstance() throws JasDBStorageException {
if(!instanceMetaMap.containsKey(DEFAULT_INSTANCE)) {
addInstance(new InstanceMeta(DEFAULT_INSTANCE, datastoreLocation.toString()));
}
}
@Override
@PreDestroy
public void closeStore() throws JasDBStorageException {
if(writer != null) {
writer.closeWriter();
writer = null;
File pidFile = new File(datastoreLocation, PID_FILE);
if(!pidFile.delete()) {
LOG.warn("PID file: {} could not be removed", pidFile);
}
}
}
@Override
public long addMetadataEntity(SimpleEntity entity) throws JasDBStorageException {
return writer.writeRecord(SimpleEntity.toJson(entity), null);
}
@Override
public long updateMetadataEntity(SimpleEntity entity, long previousRecord) throws JasDBStorageException {
return writer.updateRecord(SimpleEntity.toJson(entity), () -> of(previousRecord), null);
}
@Override
public void deleteMetadataEntity(long recordPointer) throws JasDBStorageException {
writer.removeRecord(() -> of(recordPointer), null);
}
@Override
public List getBags(String instanceId) throws JasDBStorageException {
List bags = new ArrayList<>();
for(Map.Entry> bagEntry : bagMetaMap.entrySet()) {
if(bagEntry.getKey().startsWith(instanceId)) {
bags.add(bagEntry.getValue().getMetadataObject());
}
}
return bags;
}
@Override
public Bag getBag(String instanceId, String name) throws JasDBStorageException {
MetaWrapper bagWrapper = bagMetaMap.get(getBagKey(instanceId, name));
if(bagWrapper != null) {
return bagWrapper.getMetadataObject();
} else {
return null;
}
}
@Override
public boolean containsBag(String instanceId, String bag) throws JasDBStorageException {
return bagMetaMap.containsKey(getBagKey(instanceId, bag));
}
private String getBagKey(String instanceId, String bag) {
return instanceId + "_" + bag;
}
@Override
public void addBag(Bag bag) throws JasDBStorageException {
if(instanceMetaMap.containsKey(bag.getInstanceId())) {
String bagId = getBagKey(bag.getInstanceId(), bag.getName());
if(!bagMetaMap.containsKey(bagId)) {
SimpleEntity entity = BagMeta.toEntity(bag);
String bagData = SimpleEntity.toJson(entity);
long recordPointer = writer.writeRecord(bagData, null);
bagMetaMap.put(bagId, new MetaWrapper<>(bag, recordPointer));
} else {
throw new JasDBStorageException("Unable to add bag: " + bag.getName() + ", already exists");
}
} else {
throw new JasDBStorageException("Unable to create bag, instance: " + bag.getInstanceId() + " does not exist");
}
}
@Override
public void removeBag(String instanceId, String name) throws JasDBStorageException {
String bagId = getBagKey(instanceId, name);
if(bagMetaMap.containsKey(bagId)) {
MetaWrapper bagMetaWrapper = bagMetaMap.get(bagId);
writer.removeRecord(() -> of(bagMetaWrapper.getRecordPointer()), null);
bagMetaMap.remove(bagId);
} else {
throw new JasDBStorageException("Unable to delete bag: " + name + " does not exist");
}
}
@Override
public void addBagIndex(String instanceId, String bagName, IndexDefinition indexDefinition) throws JasDBStorageException {
Bag bag = getBag(instanceId, bagName);
if(bag != null) {
List indexDefinitions = new ArrayList<>(bag.getIndexDefinitions());
if(!indexDefinitions.contains(indexDefinition)) {
indexDefinitions.add(indexDefinition);
updateBag(instanceId, bagName, new BagMeta(instanceId, bagName, indexDefinitions));
}
} else {
throw new JasDBStorageException("Unable to add index to bag: " + bagName + ",could not be found");
}
}
@Override
public void removeBagIndex(String instanceId, String bagName, IndexDefinition indexDefinition) throws JasDBStorageException {
Bag bag = getBag(instanceId, bagName);
if(bag != null) {
List indexDefinitions = new ArrayList<>(bag.getIndexDefinitions());
if(indexDefinitions.contains(indexDefinition)) {
indexDefinitions.remove(indexDefinition);
updateBag(instanceId, bagName, new BagMeta(instanceId, bagName, indexDefinitions));
}
} else {
throw new JasDBStorageException("Unable to remove index for bag: " + bagName + ",could not be found");
}
}
/**
* Small helper method to update the bag definition
* @param instanceId The instanceId
* @param bagName The name of the bag
* @param newBagData The new updated bag data
* @throws JasDBStorageException If unable to update the bag
*/
private void updateBag(String instanceId, String bagName, Bag newBagData) throws JasDBStorageException {
String bagId = getBagKey(instanceId, bagName);
MetaWrapper bagMetaWrapper = bagMetaMap.get(bagId);
long recordPointer = writer.updateRecord(SimpleEntity.toJson(BagMeta.toEntity(newBagData)), () -> of(bagMetaWrapper.getRecordPointer()), null);
bagMetaWrapper.setRecordPointer(recordPointer);
bagMetaWrapper.setMetadataObject(newBagData);
}
@Override
public boolean containsIndex(String instanceId, String bagName, IndexDefinition indexDefinition) throws JasDBStorageException {
Bag bag = getBag(instanceId, bagName);
return bag.getIndexDefinitions().contains(indexDefinition);
}
@Override
public List getInstances() throws JasDBStorageException {
List instances = new ArrayList<>();
for(MetaWrapper instanceMeta : instanceMetaMap.values()) {
instances.add(instanceMeta.getMetadataObject());
}
return instances;
}
@Override
public Instance getInstance(String instanceId) throws JasDBStorageException {
MetaWrapper metaWrapper = instanceMetaMap.get(instanceId);
if(metaWrapper != null) {
return metaWrapper.getMetadataObject();
} else {
return null;
}
}
@Override
public boolean containsInstance(String instanceId) throws JasDBStorageException {
return instanceMetaMap.containsKey(instanceId);
}
@Override
public void addInstance(Instance instance) throws JasDBStorageException {
if(!instanceMetaMap.containsKey(instance.getInstanceId())) {
SimpleEntity entity = InstanceMeta.toEntity(instance);
String jsonData = SimpleEntity.toJson(entity);
long recordPointer = writer.writeRecord(jsonData, null);
instanceMetaMap.put(instance.getInstanceId(), new MetaWrapper<>(instance, recordPointer));
} else {
throw new JasDBStorageException("Unable to create instance, already exists");
}
}
@Override
public void removeInstance(String instanceId) throws JasDBStorageException {
if(!DEFAULT_INSTANCE.equalsIgnoreCase(instanceId)) {
MetaWrapper instanceMetaWrapper = instanceMetaMap.get(instanceId);
if(instanceMetaWrapper != null) {
writer.removeRecord(() -> of(instanceMetaWrapper.getRecordPointer()), null);
instanceMetaMap.remove(instanceId);
} else {
throw new JasDBStorageException("Unable to delete non existing instance: " + instanceId);
}
} else {
throw new JasDBStorageException("Not allowed to remove default instance");
}
}
@Override
public T getMetadataProvider(String type) {
return (T)metadataProviders.get(type);
}
}