/* * 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(); }