com.kolibrifx.plovercrest.server.local.DefaultPlovercrestLocal Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plovercrest-server Show documentation
Show all versions of plovercrest-server Show documentation
Plovercrest server library.
The newest version!
/*
* Copyright (c) 2010-2017, KolibriFX AS. Licensed under the Apache License, version 2.0.
*/
package com.kolibrifx.plovercrest.server.local;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import com.kolibrifx.common.Disposable;
import com.kolibrifx.plovercrest.client.AbstractPlovercrest;
import com.kolibrifx.plovercrest.client.DefaultTableListInfo;
import com.kolibrifx.plovercrest.client.MultiTableWriter;
import com.kolibrifx.plovercrest.client.MultiTableWriterSerializerFactory;
import com.kolibrifx.plovercrest.client.PlovercrestException;
import com.kolibrifx.plovercrest.client.PlovercrestLocal;
import com.kolibrifx.plovercrest.client.Table;
import com.kolibrifx.plovercrest.client.TableListInfo;
import com.kolibrifx.plovercrest.client.TableMetadata;
import com.kolibrifx.plovercrest.client.TableNamesObserver;
import com.kolibrifx.plovercrest.client.TableSerializer;
import com.kolibrifx.plovercrest.client.TableSerializerFactory;
import com.kolibrifx.plovercrest.client.TableSubscriber;
import com.kolibrifx.plovercrest.client.internal.SafeTableNamesObserver;
import com.kolibrifx.plovercrest.client.internal.SafeTableSubscriber;
import com.kolibrifx.plovercrest.client.internal.SubscriptionQuery;
import com.kolibrifx.plovercrest.client.internal.SubscriptionQuery.QueryKind;
import com.kolibrifx.plovercrest.client.internal.shared.TableMetadataUtils;
import com.kolibrifx.plovercrest.server.PlovercrestEngine;
import com.kolibrifx.plovercrest.server.PlovercrestEngineBuilder;
import com.kolibrifx.plovercrest.server.TableInfo;
import com.kolibrifx.plovercrest.server.internal.EventDispatcher;
import com.kolibrifx.plovercrest.server.internal.StreamObservers;
import com.kolibrifx.plovercrest.server.internal.ThreadedEventDispatcher;
import com.kolibrifx.plovercrest.server.internal.local.LocalMultiTableWriter;
import com.kolibrifx.plovercrest.server.internal.local.LocalTable;
import com.kolibrifx.plovercrest.server.streams.PlovercrestStreamEngineBuilder;
import com.kolibrifx.plovercrest.server.streams.Stream;
import com.kolibrifx.plovercrest.server.streams.StreamEngine;
import com.kolibrifx.plovercrest.server.streams.StreamNamesListener;
import com.kolibrifx.plovercrest.server.streams.StreamObserver;
public class DefaultPlovercrestLocal extends AbstractPlovercrest implements PlovercrestLocal {
private final PlovercrestEngine engine;
private final StreamObservers streamObservers;
private final String dataPath;
private final TableSerializerFactory serializerFactory;
private final StreamEngine streamEngine;
public DefaultPlovercrestLocal(final TableSerializerFactory serializerFactory, final String dataPath) {
this(serializerFactory, dataPath, new ThreadedEventDispatcher());
}
public DefaultPlovercrestLocal(final TableSerializerFactory serializerFactory,
final String dataPath,
final EventDispatcher dispatcher) {
this.serializerFactory = serializerFactory;
this.dataPath = dataPath;
this.engine = new PlovercrestEngineBuilder(dataPath).dispatcher(dispatcher).build();
this.streamEngine = new PlovercrestStreamEngineBuilder(engine).serializerFactory(serializerFactory).build();
this.streamObservers = new StreamObservers(streamEngine);
}
// TODO: (#34) This should support streams
@Override
public Collection list() {
return engine.getTableNames().stream().map(name -> new DefaultTableListInfo(name, true))
.collect(Collectors.toList());
}
private LocalTable createImpl(final String name, final Class elementClass,
final TableSerializer serializer) {
final TableInfo info =
new TableInfo(name, TableMetadataUtils.createFromSerializer(serializer, serializerFactory));
streamEngine.create(info);
// We open as ByteBuffer because there is no way to pass the serializer
final Stream stream = streamEngine.openRaw(name);
return new LocalTable(stream, name, elementClass, serializer, info.getMetadata(), streamObservers,
errorListenerSubject);
}
@Override
public Table open(final String name, final Class clazz) {
try {
final Stream stream = streamEngine.openRaw(name);
if (stream == null) {
return null;
}
return openLocalTable(clazz, stream, name);
} catch (final PlovercrestException e) {
errorListenerSubject.onOpenError(e);
throw e;
}
}
@Override
public TableMetadata getMetadata(final String name) {
final com.kolibrifx.plovercrest.server.Table table = engine.open(name);
if (table == null) {
return null;
} else {
return table.getInfo().getMetadata();
}
}
private LocalTable openLocalTable(final Class clazz, final Stream stream, final String name) {
final TableSerializer serializer;
try {
serializer = serializerFactory.createSerializer(stream.getMetadata(), clazz);
} catch (final PlovercrestException e) {
// include table name in error message
throw new PlovercrestException("Failed to create serializer for table '" + name + "'. " + e.getMessage(),
e);
}
return new LocalTable(stream, name, clazz, serializer, stream.getMetadata(), streamObservers,
errorListenerSubject);
}
@Override
public void close() {
streamObservers.close();
streamEngine.close();
engine.close();
}
@Override
public boolean delete(final String name) {
return engine.delete(name);
}
@Override
public boolean rename(final String oldName, final String newName) {
return engine.rename(oldName, newName) != null;
}
@Override
public MultiTableWriter createMultiTableWriter(final MultiTableWriterSerializerFactory factory,
final MultiTableWriter.WriterMode mode) {
return new LocalMultiTableWriter(this, streamEngine, factory, mode);
}
@Override
public String getDataPath() {
return dataPath;
}
@Override
public Disposable addSubscriber(final String tableName, final Class elementClass, final long fromTimestamp,
final TableSubscriber subscriber) {
open(tableName, elementClass); // to throw exception if e.g. type definition is wrong
final SafeTableSubscriber safeSubscriber = new SafeTableSubscriber<>(subscriber);
final StreamObserver observer = new StreamObserver() {
private TableSerializer serializer;
private long lastTimestamp = -1;
T deserialize(final long timestamp, final ByteBuffer bytes) {
if (serializer == null) {
// It should normally be possible to open the table and get the serializer from it at this point.
// If not, use the TableSerializerFactory as a fallback.
final Table table = open(tableName, elementClass);
if (table == null) {
serializer = serializerFactory.createSerializer(elementClass);
} else {
serializer = table.getSerializer();
}
}
return serializer.unserialize(timestamp, bytes);
}
@Override
public void onObserve(final long timestamp, final long index, final ByteBuffer bytes) {
safeSubscriber.receive(tableName, deserialize(timestamp, bytes));
lastTimestamp = timestamp;
}
@Override
public void onObserveEnd(final long lastValidTimestamp, final long elementCount) {
if (lastValidTimestamp > lastTimestamp) {
safeSubscriber.receiveLastValidTimestamp(tableName, lastValidTimestamp);
}
}
@Override
public void onObserveFrozen() {
safeSubscriber.receiveTableFrozen(tableName);
}
};
return streamObservers.subscribe(tableName, new SubscriptionQuery(QueryKind.TIMESTAMP, fromTimestamp), observer,
ByteBuffer.class);
}
PlovercrestEngine getEngine() {
return engine;
}
@Override
public Disposable addTableNamesObserver(final TableNamesObserver listener) {
final SafeTableNamesObserver observer = new SafeTableNamesObserver(listener);
return streamEngine.addStreamNamesListener(new StreamNamesListener() {
@Override
public void onRemoved(final Set names) {
for (final String name : names) {
observer.onTableDeleted(name);
}
}
@Override
public void onInit(final Set allNames) {
observer.onTablesReset(allNames);
}
@Override
public void onAdded(final Set names) {
for (final String name : names) {
observer.onTableCreated(name);
}
}
});
}
@Override
public Table create(final String name, final Class elementClass) {
final TableSerializer serializer = serializerFactory.createSerializer(elementClass);
return createImpl(name, elementClass, serializer);
}
@Override
public Table create(final String name, final TableSerializer serializer) {
return createImpl(name, serializer.elementClass(), serializer);
}
}