org.apache.qpid.proton.reactor.Reactor Maven / Gradle / Ivy
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.qpid.proton.reactor;
import java.io.IOException;
import java.util.Set;
import org.apache.qpid.proton.engine.BaseHandler;
import org.apache.qpid.proton.engine.Collector;
import org.apache.qpid.proton.engine.Connection;
import org.apache.qpid.proton.engine.Event.Type;
import org.apache.qpid.proton.engine.Handler;
import org.apache.qpid.proton.engine.HandlerException;
import org.apache.qpid.proton.engine.Record;
import org.apache.qpid.proton.reactor.impl.ReactorImpl;
/**
* The proton reactor provides a general purpose event processing
* library for writing reactive programs. A reactive program is defined
* by a set of event handlers. An event handler is just any class or
* object that extends the Handler interface. For convenience, a class
* can extend {@link BaseHandler} and only handle the events that it cares to
* implement methods for.
*
* This class is not thread safe (with the exception of the {@link #wakeup()}
* method) and should only be used by a single thread at any given time.
*/
public interface Reactor {
public static final class Factory
{
public static Reactor create() throws IOException {
return new ReactorImpl();
}
}
/**
* Updates the last time that the reactor's state has changed, potentially
* resulting in events being generated.
* @return the current time in milliseconds
* {@link System#currentTimeMillis()}.
*/
long mark();
/** @return the last time that {@link #mark()} was called. */
long now();
/** @return an instance of {@link Record} that can be used to associate
* other objects (attachments) with this instance of the
* Reactor class.
*/
Record attachments();
/**
* The value the reactor will use for {@link Selector#select(long)} that is called as part of {@link #process()}.
*
* @param timeout a timeout value in milliseconds, to associate with this instance of
* the reactor. This can be retrieved using the
* {@link #getTimeout()} method
*/
void setTimeout(long timeout);
/**
* @return the value previously set using {@link #setTimeout(long)} or
* 0 if no previous value has been set.
*/
long getTimeout();
/**
* @return the global handler for this reactor. Every event the reactor
* sees is dispatched to the global handler. To receive every
* event generated by the reactor, associate a child handler
* with the global handler. For example:
*
* getGlobalHandler().add(yourHandler);
*
*/
Handler getGlobalHandler();
/**
* Sets a new global handler. You probably don't want to do this and
* would be better adding a handler to the value returned by the
* {{@link #getGlobalHandler()} method.
* @param handler the new global handler.
*/
void setGlobalHandler(Handler handler);
/**
* @return the handler for this reactor. Every event the reactor sees,
* which is not handled by a child of the reactor (such as a
* timer, connection, acceptor, or selector) is passed to this
* handler. To receive these events, it is recommend that you
* associate a child handler with the handler returned by this
* method. For example:
*
* getHandler().add(yourHandler);
*
*/
Handler getHandler();
/**
* Sets a new handler, that will receive any events not handled by a child
* of the reactor. Note that setting a handler via this method replaces
* the previous handler, and will result in no further events being
* dispatched to the child handlers associated with the previous handler.
* For this reason it is recommended that you do not use this method and
* instead add child handlers to the value returned by the
* {@link #getHandler()} method.
* @param handler the new handler for this reactor.
*/
void setHandler(Handler handler);
/**
* @return a set containing the child objects associated wit this reactor.
* This will contain any active instances of: {@link Task} - created
* using the {@link #schedule(int, Handler)} method,
* {@link Connection} - created using the
* {@link #connection(Handler)} method, {@link Acceptor} -
* created using the {@link #acceptor(String, int)} method.
* {@link #acceptor(String, int, Handler)} method, or
* {@link Selectable} - created using the {@link #selectable()}
* method.
*/
Set children();
/**
* @return the Collector used to gather events generated by this reactor.
*/
Collector collector();
/**
* Creates a new Selectable
as a child of this reactor.
* @return the newly created Selectable
.
*/
Selectable selectable();
/**
* Updates the specified Selectable
either emitting a
* {@link Type#SELECTABLE_UPDATED} event if the selectable is not terminal,
* or {@link Type#SELECTABLE_FINAL} if the selectable is terminal and has
* not already emitted a {@link Type#SELECTABLE_FINAL} event.
* @param selectable
*/
void update(Selectable selectable);
/**
* Yields, causing the next call to {@link #process()} to return
* successfully - without processing any events. If multiple calls
* can be made to yield
and only the next invocation of
* {@link #process()} will be affected.
*/
void yield() ;
/**
* @return true
if the reactor is in quiesced state (e.g. has
* no events to process). false
is returned otherwise.
*/
boolean quiesced();
/**
* Process any events pending for this reactor. Events are dispatched to
* the handlers registered with the reactor, or child objects associated
* with the reactor. This method blocks until the reactor has no more work
* to do (and no more work pending, in terms of scheduled tasks or open
* selectors to process).
* @return true
if the reactor may have more events in the
* future. For example: if there are scheduled tasks, or open
* selectors. false
is returned if the reactor has
* (and will have) no more events to process.
* @throws HandlerException if an unchecked exception is thrown by one of
* the handlers - it will be re-thrown attached to an instance of
* HandlerException
.
*/
boolean process() throws HandlerException;
/**
* Wakes up the thread (if any) blocked in the {@link #process()} method.
* This is the only method of this class that is thread safe, in that it
* can be used at the same time as another thread is using the reactor.
*/
void wakeup();
/**
* Starts the reactor. This method should be invoked before the first call
* to {@link #process()}.
*/
void start();
/**
* Stops the reactor. This method should be invoked after the last call to
* {@link #process()}.
* @throws HandlerException
*/
void stop() throws HandlerException;
/**
* Simplifies the use of the reactor by wrapping the use of
* start
, run
, and stop
method
* calls.
*
* Logically the implementation of this method is:
*
* start();
* while(process()) {}
* stop();
*
* @throws HandlerException if an unchecked exception is thrown by one of
* the handlers - it will be re-thrown attached to an instance of
* HandlerException
.
*/
void run() throws HandlerException;
/**
* Schedules execution of a task to take place at some point in the future.
* @param delay the number of milliseconds, in the future, to schedule the
* task for.
* @param handler a handler to associate with the task. This is notified
* when the deadline for the task is reached.
* @return an object representing the task that has been scheduled.
*/
Task schedule(int delay, Handler handler);
/**
* Creates a new out-bound connection.
* @param handler a handler that is notified when events occur for the
* connection. Typically the host and port to connect to
* would be supplied to the connection object inside the
* logic which handles the {@link Type#CONNECTION_INIT}
* event.
* @return the newly created connection object.
*/
Connection connection(Handler handler);
/**
* Creates a new acceptor. This is equivalent to calling:
*
* acceptor(host, port, null);
*
* @param host
* @param port
* @return the newly created acceptor object.
* @throws IOException
*/
Acceptor acceptor(String host, int port) throws IOException;
/**
* Creates a new acceptor. This acceptor listens for in-bound connections.
* @param host the host name or address of the NIC to listen on.
* @param port the port number to listen on.
* @param handler if non-null
this handler is registered with
* each new connection accepted by the acceptor.
* @return the newly created acceptor object.
* @throws IOException
*/
Acceptor acceptor(String host, int port, Handler handler)
throws IOException;
/**
* Frees any resources (such as sockets and selectors) held by the reactor
* or its children.
*/
void free();
}