com.kolibrifx.plovercrest.server.streams.PluggableStreamEngine 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.streams;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import com.kolibrifx.common.Disposable;
import com.kolibrifx.plovercrest.client.PlovercrestException;
import com.kolibrifx.plovercrest.server.TableInfo;
import com.kolibrifx.plovercrest.server.internal.streams.MultiProviderStreamNamesListener;
/**
* Basic pluggable {@link StreamEngine} implementation. Most production code should use
* {@link PlovercrestStreamEngineBuilder} instead constructing this class directly; it is exposed
* for unit testing purposes.
*/
public class PluggableStreamEngine implements StreamEngine {
private static final Logger log = Logger.getLogger(PluggableStreamEngine.class);
private final Collection providers = new ArrayList<>();
private final Collection disposables = new ArrayList<>();
@Override
public Stream open(final String name, final Class elementType) {
for (final StreamProvider provider : providers) {
try {
final Stream stream = provider.tryOpen(this, name, elementType);
if (stream != null) {
return stream;
}
} catch (final PlovercrestException e) {
log.error(e.getMessage(), e);
throw e;
} catch (final RuntimeException e) {
log.error(e.getMessage(), e);
throw new PlovercrestException("Error opening '" + name + "': " + e.getMessage(), e);
}
}
return null;
}
@Override
public Stream openRaw(final String name) {
return open(name, ByteBuffer.class);
}
public void addProvider(final StreamProvider provider) {
providers.add(provider);
}
@Override
public Collection list() {
return providers.stream().flatMap(x -> x.list().stream()).collect(Collectors.toList());
}
@Override
public void create(final TableInfo info) {
final Stream stream = openRaw(info.getName());
if (stream != null) {
throw new PlovercrestException("A stream named " + info.getName() + " already exists");
}
for (final StreamProvider p : providers) {
final boolean created = p.tryCreate(info);
if (created) {
return;
}
}
throw new PlovercrestException("No provider was able to create a stream named " + info.getName());
}
@Override
public boolean delete(final String name) {
final Stream stream = openRaw(name);
if (stream == null) {
return false;
} else {
return stream.delete();
}
}
@Override
public boolean rename(final String oldName, final String newName) {
if (oldName.equals(newName)) {
return false;
}
if (openRaw(newName) != null) {
return false;
}
final Stream oldTable = open(oldName, ByteBuffer.class);
if (oldTable == null) {
return false;
}
return oldTable.rename(newName);
}
@Override
public void close() {
for (final Disposable d : disposables) {
d.close();
}
disposables.clear();
}
@Override
public Disposable addStreamNamesListener(final StreamNamesListener listener) {
return new MultiProviderStreamNamesListener(providers, listener);
}
@Override
public Disposable addCreateListener(final String name, final StreamCreateListener listener) {
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicReference disposableRef = new AtomicReference<>();
disposableRef.set(addStreamNamesListener(new StreamNamesListener() {
@Override
public void onRemoved(final Set names) {
// ignored
}
@Override
public void onInit(final Set allNames) {
processNames(allNames);
}
@Override
public void onAdded(final Set names) {
processNames(names);
}
private void processNames(final Set names) {
if (names.contains(name) && done.compareAndSet(false, true)) {
listener.onCreated(name);
// disposableRef can be unset due to reentrancy
if (disposableRef.get() != null) {
disposableRef.get().close();
}
}
}
}));
if (done.get()) {
// can happen due to reentrancy
disposableRef.get().close();
}
return new Disposable() {
@Override
public void close() {
done.set(true);
disposableRef.get().close();
}
};
}
}