/* * Copyright 2013 BiasedBit * * 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.biasedbit.http.client.connection; import com.biasedbit.http.client.util.RequestContext; import org.jboss.netty.channel.ChannelHandler; /** * An HTTP connection to a server. * <p/> * HTTP requests are dispatched from the {@link com.biasedbit.http.client.HttpClient} to the {@code Connection}s * under the form of a {@link com.biasedbit.http.client.util.RequestContext}. * <p/> * To execute requests in a {@code Connection}, the caller must always ensure the connection can process its request * by calling {@link #isAvailable()} prior to {@link #execute(com.biasedbit.http.client.util.RequestContext) execute()}. * <p/> * Example: * <pre class="code"> * if (connection.isAvailable) { * // This is not guaranteed to work.. Connection may go down or be termianted by other thread meanwhile! * connection.execute(request); * }</pre> * Implementations of this interface are thread-safe. However, it is ill-advised to used them from multiple threads in * order to avoid entropic behavior. If you really want to use a single connection from multiple threads, you should * manually synchronise externally. The reason for this is that if both threads call {@link #isAvailable()} at the same * time, both will be able to {@linkplain #execute(com.biasedbit.http.client.util.RequestContext) submit requests}, even * though the implementation may not accept both (and consequently fail the last one with * {@link com.biasedbit.http.client.future.RequestFuture#EXECUTION_REJECTED}). * <p/> * Example: * <pre class="code"> * synchronized (connection) { * if (connection.isAvailable) { * // This is not guaranteed to work.. Connection may close meanwhile! * connection.execute(request); * } * }</pre> * The reason for this implementation decision is making the common case fast: a vast majority of the times that * {@link #isAvailable()} is called, {@link #execute(com.biasedbit.http.client.util.RequestContext) execute()} will * accept the request. So rather than having only execute returning {@code true} or {@code false} based on the * connection availibility, this quicker call is a very reliable heuristic to determine if requests can be submitted * or not. * * <div class="note"> * <div class="header">Note:</div> * There is no guarantee that a request will be approved if {@link #isAvailable()} returned true. Even though the * odds are extremely slim, the connection may go down between the call to {@link #isAvailable()} and {@link * #execute(com.biasedbit.http.client.util.RequestContext) execute()}. * <p/>For such cases (and only for such cases) * {@link #execute(com.biasedbit.http.client.util.RequestContext) execute()} will return {@code false} * rather than fail, the request in order for the caller to be given the chance to retry the same request in another * connection. * <p/> * In every other scenario where {@link #isAvailable()} returns false, calling * {@link #execute(com.biasedbit.http.client.util.RequestContext) execute()} <strong>will fail</strong> the request * (with cause {@link com.biasedbit.http.client.future.RequestFuture#EXECUTION_REJECTED}). * </div> * * @author <a href="http://biasedbit.com/">Bruno de Carvalho</a> */ public interface Connection extends ChannelHandler { /** * Shut down the connection, cancelling all requests executing meanwhile. * <p/> * After a connection is shut down, no more requests will be accepted. * * @param reason The motive for connection termination. */ void terminate(Throwable reason); /** * Returns the unique identifier of this connection. * * @return An identifier of the connection. */ String getId(); /** * Returns the host address to which this connection is connected to. * * @return The host address to which this connection is currently connected to. */ String getHost(); /** * Returns the port to which this connection is connected to. * * @return The port of to which this connection is connected to. */ int getPort(); /** * Returns whether this connection is available to process a request. Connections that execute HTTP 1.0 requests * will <strong>never</strong> return true after the request has been approved for processing as the socket will * be closed by the server. * * @return true if this connection is connected and ready to execute a request */ boolean isAvailable(); /** * Execute a given request context in this connection. * <p/> * All calls to this method should first test whether this connection is available or not by calling * {@link #isAvailable()} first. Calling this methods while {@link #isAvailable()} would return {@code false} will * cause the implementation to reject the request with the reason * {@link com.biasedbit.http.client.future.RequestFuture#EXECUTION_REJECTED} and return {@code true}, * meaning the request was consumed (and failed). * <p/> * The exception to the above rule is when the request is submitted and the connection goes down meanwhile. In this * case, the request <strong>will not</strong> be marked as failed and this method will return {@code false} so that * the caller may retry the same request in another connection. * <p/> * Implementations of this method that return {@code true} <strong>MUST</strong> call the connection listener's * {@link ConnectionListener#requestFinished(Connection, com.biasedbit.http.client.util.RequestContext)} when the * request completes (or fails) unless the connection terminates due to other reasons. * <p/> * You should always, <strong>always</strong> test first with {@link #isAvailable()}. * <p/> * This is a non-blocking call. * * @param context Request execution context. * * @return {@code true} if the request was accepted, {@code false} otherwise. If a request is accepted, the * {@code Connection} becomes responsible for calling * {@link com.biasedbit.http.client.future.DefaultRequestFuture#failedWithCause(Throwable) failedWithCause()} or * {@link com.biasedbit.http.client.future.DefaultRequestFuture#finishedSuccessfully(Object, * org.jboss.netty.handler.codec.http.HttpResponse) finishedSuccessfully()} on it. */ boolean execute(RequestContext context); }