| /* |
| * |
| * 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.client.failover; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.qpid.client.AMQConnection; |
| |
| /** |
| * FailoverRetrySupport is a continuation that wraps another continuation, delaying its execution until it is notified |
| * that a blocking condition has been met, and executing the continuation within a mutex. If the continuation fails, due |
| * to the original condition being broken, whilst the continuation is waiting for a reponse to a synchronous request, |
| * FailoverRetrySupport automatcally rechecks the condition and re-acquires the mutex and re-runs the continution. This |
| * automatic retrying is continued until the continuation succeeds, or throws an exception (different to |
| * FailoverException, which is used to signal the failure of the original condition). |
| * <p> |
| * The blocking condition used is that the connection is not currently failing over, and the mutex used is the |
| * connection failover mutex, which guards against the fail-over process being run during fail-over vulnerable methods. |
| * These are used like a lock and condition variable. |
| * <p> |
| * The wrapped operation may throw a FailoverException, this is an exception that can be raised by a |
| * {@link org.apache.qpid.client.protocol.BlockingMethodFrameListener}, in response to it being notified that a |
| * fail-over wants to start whilst it was waiting. Methods that are vulnerable to fail-over are those that are |
| * synchronous, where a failure will prevent them from getting the reply they are waiting for and asynchronous |
| * methods that should not be attempted when a fail-over is in progress. |
| * <p> |
| * Wrapping a synchronous method in a FailoverRetrySupport will have the effect that the operation will not be |
| * started during fail-over, but be delayed until any current fail-over has completed. Should a fail-over process want |
| * to start whilst waiting for the synchronous reply, the FailoverRetrySupport will detect this and retry the operation |
| * until it succeeds. Synchronous methods are usually coordinated with a |
| * {@link org.apache.qpid.client.protocol.BlockingMethodFrameListener} which is notified when a fail-over process wants |
| * to start and throws a FailoverException in response to this. |
| * <p> |
| * Wrapping an asynchronous method in a FailoverRetrySupport will have the effect that the operation will not be |
| * started during fail-over, but be delayed until any current fail-over has completed. |
| * <p> |
| * TODO InterruptedException not handled well. |
| */ |
| public class FailoverRetrySupport<T, E extends Exception> implements FailoverSupport<T, E> |
| { |
| /** Used for debugging. */ |
| private static final Logger _log = LoggerFactory.getLogger(FailoverRetrySupport.class); |
| |
| /** The protected operation that is to be retried in the event of fail-over. */ |
| private FailoverProtectedOperation<T, E> operation; |
| |
| /** The connection on which the fail-over protected operation is to be performed. */ |
| private AMQConnection connection; |
| |
| /** |
| * Creates an automatic retrying fail-over handler for the specified operation. |
| * |
| * @param operation The fail-over protected operation to wrap in this handler. |
| */ |
| public FailoverRetrySupport(FailoverProtectedOperation<T, E> operation, AMQConnection con) |
| { |
| this.operation = operation; |
| this.connection = con; |
| } |
| |
| /** |
| * Delays a continuation until the "not failing over" condition is met on the specified connection. Repeats |
| * until the operation throws AMQException or succeeds without being interrupted by fail-over. |
| * |
| * @return The result of executing the continuation. |
| * |
| * @throws E Any underlying exception is allowed to fall through. |
| */ |
| public T execute() throws E |
| { |
| return connection.executeRetrySupport(operation); |
| } |
| } |