blob: 2885d9623bbe931425a81fd4785018046346685b [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* 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.intellij.util.messages;
import com.intellij.openapi.Disposable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Core of IntelliJ IDEA messaging infrastructure. Basic functions:
* <pre>
* <ul>
* <li>allows to {@link #syncPublisher(Topic) push messages};</li>
* <li>
* allows to {@link #connect() create connections} for further {@link MessageBusConnection#subscribe(Topic, Object) subscriptions};
* </li>
* </ul>
* </pre>
* <p/>
* Use <code>'com.intellij.openapi.components.ComponentManager#getMessageBus()'</code> to obtain one.
* <p/>
* Please see <a href="Wiki">http://confluence.jetbrains.net/display/IDEADEV/IntelliJ+IDEA+Messaging+infrastructure</a>.
*/
public interface MessageBus {
/**
* Messages buses can be organised into hierarchies. That allows facilities {@link Topic#getBroadcastDirection() broadcasting}.
* <p/>
* Current method exposes parent bus (if any is defined).
*
* @return parent bus (if defined)
*/
@Nullable
MessageBus getParent();
/**
* Allows to create new connection that is not bound to any {@link Disposable}.
*
* @return newly created connection
*/
@NotNull
MessageBusConnection connect();
/**
* Allows to create new connection that is bound to the given {@link Disposable}. That means that returned connection
* will be automatically {@link MessageBusConnection#dispose() released} if given {@link Disposable disposable parent} is collected.
*
* @param parentDisposable target parent disposable to which life cycle newly created connection shall be bound
* @return newly created connection which life cycle is bound to the given disposable parent
*/
@NotNull
MessageBusConnection connect(@NotNull Disposable parentDisposable);
/**
* Allows to retrieve an interface for publishing messages to the target topic.
* <p/>
* Basically, the whole processing looks as follows:
* <pre>
* <ol>
* <li>
* Messaging clients create new {@link MessageBusConnection connections} within the target message bus and
* {@link MessageBusConnection#subscribe(Topic, Object) subscribe} to the target {@link Topic topics};
* </li>
* <li>
* Every time somebody wants to send a message for particular topic, he or she calls current method and receives object
* that conforms to the {@link Topic#getListenerClass() business interface} of the target topic. Every method call on that
* object is dispatched by the messaging infrastructure to the subscribers.
* {@link Topic#getBroadcastDirection() broadcasting} is performed if necessary as well;
* </li>
* </ol>
* </pre>
* <p/>
* It's also very important to understand message processing strategy in case of <b>nested dispatches</b>.
* Consider the following situation:
* <pre>
* <ol>
* <li>
* <code>Subscriber<sub>1</sub></code> and <code>subscriber<sub>2</sub></code> are registered for the same topic within
* the same message bus;
* </li>
* <li><code>Message<sub>1</sub></code> is sent to that topic within the same message bus;</li>
* <li>Queued messages delivery starts;</li>
* <li>Queued messages delivery ends as there are no messages queued but not dispatched;</li>
* <li><code>Message<sub>1</sub></code> is queued for delivery to both subscribers;</li>
* <li>Queued messages delivery starts;</li>
* <li><code>Message<sub>1</sub></code> is being delivered to the <code>subscriber<sub>1</sub></code>;</li>
* <li><code>Subscriber<sub>1</sub></code> sends <code>message<sub>2</sub></code> to the same topic within the same bus;</li>
* <li>Queued messages delivery starts;</li>
* <li>
* <b>Important:</b> <code>subscriber<sub>2</sub></code> is being notified about all queued but not delivered messages,
* i.e. its callback is invoked for the message<sub>1</sub>;
* </li>
* <li>Queued messages delivery ends because all subscribers have been notified on the <code>message<sub>1</sub></code>;</li>
* <li><code>Message<sub>2</sub></code> is queued for delivery to both subscribers;</li>
* <li>Queued messages delivery starts;</li>
* <li><code>Subscriber<sub>1</sub></code> is notified on <code>message<sub>2</sub></code></li>
* <li><code>Subscriber<sub>2</sub></code> is notified on <code>message<sub>2</sub></code></li>
* </ol>
* </pre>
* <p/>
* <b>Thread-safety.</b>
* All subscribers are notified sequentially from the calling thread.
* <p/>
* <b>Memory management.</b>
* Returned objects are very light-weight and stateless, so, they are cached by the message bus in <code>'per-topic'</code> manner.
* That means that caller of this method is not obliged to keep returned reference along with the reference to the message for
* further publishing. It's enough to keep reference to the message bus only and publish
* like {@code 'messageBus.syncPublisher(targetTopic).targetMethod()'}.
*
* @param topic target topic
* @param <L> {@link Topic#getListenerClass() business interface} of the target topic
* @return publisher for target topic
*/
@NotNull
<L> L syncPublisher(@NotNull Topic<L> topic);
/**
* @deprecated use {@link #syncPublisher(Topic)} instead
*/
@NotNull
@Deprecated
<L> L asyncPublisher(@NotNull Topic<L> topic);
/**
* Disposes current bus, i.e. drops all queued but not delivered messages (if any) and disallows further
* {@link #connect(Disposable) connections}.
*/
void dispose();
}