
com.spotify.mobius.QueuingConnection Maven / Gradle / Ivy
/*
* -\-\-
* Mobius
* --
* Copyright (c) 2017-2020 Spotify AB
* --
* 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 com.spotify.mobius;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReference;
/**
* Provides a connection that queues up messages until a delegate to consume them is available.
* Useful for setting up circular dependencies safely. Methods are non-blocking.
*/
class QueuingConnection implements Connection {
private final QueuingDelegate queuingDelegate = new QueuingDelegate();
/**
* Tracks the state of this connection; there are three:
*
*
* Initial, when the delegate queues all incoming events. In this state, the delegate is
* exactly the {@link #queuingDelegate} instance.
* Active, when the delegate is the 'real' connection to send events to.
* Disposed, when the delegate is the {@link #NOOP} instance, which silently discards all
* events.
*/
private final AtomicReference> delegate = new AtomicReference<>(queuingDelegate);
void setDelegate(Connection active) {
if (delegate.get() == NOOP) {
return;
}
if (!delegate.compareAndSet(queuingDelegate, active)) {
throw new IllegalStateException("Attempt at setting the active delegate twice");
}
// now that we know we have an active connection to send messages to, drain the queue of any
// messages.
queuingDelegate.drainQueueIfActive();
}
@Override
public void accept(I value) {
delegate.get().accept(value);
}
@Override
public void dispose() {
@SuppressWarnings("unchecked")
final Connection prev = delegate.getAndSet((Connection) NOOP);
prev.dispose();
}
private static final Connection> NOOP =
new Connection