| | |
| | | import java.util.Collection; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.*; |
| | | import org.opends.sdk.schema.Schema; |
| | | |
| | | import com.sun.opends.sdk.util.FutureResultTransformer; |
| | | import com.sun.opends.sdk.util.Validator; |
| | | |
| | | |
| | | |
| | |
| | | * An heart beat connection factory can be used to create connections |
| | | * that sends a periodic search request to a Directory Server. |
| | | */ |
| | | final class HeartBeatConnectionFactory extends |
| | | public class HeartBeatConnectionFactory extends |
| | | AbstractConnectionFactory<AsynchronousConnection> |
| | | { |
| | | private final SearchRequest heartBeat; |
| | | |
| | | private final long interval; |
| | | private final int interval; |
| | | |
| | | private final List<AsynchronousConnectionImpl> activeConnections; |
| | | |
| | | private final ConnectionFactory<?> parentFactory; |
| | | |
| | | private volatile boolean stopRequested; |
| | | |
| | | |
| | | |
| | | // FIXME: use a single global scheduler? |
| | | |
| | | /** |
| | | * Creates a new heart-beat connection factory which will create |
| | | * connections using the provided connection factory and periodically |
| | | * ping any created connections in order to detect that they are still |
| | | * alive. |
| | | * |
| | | * @param connectionFactory |
| | | * The connection factory to use for creating connections. |
| | | * @param timeout |
| | | * The time to wait between keepalive pings. |
| | | * @param unit |
| | | * The time unit of the timeout argument. |
| | | */ |
| | | HeartBeatConnectionFactory(ConnectionFactory<?> connectionFactory, |
| | | long timeout, TimeUnit unit) |
| | | { |
| | | this(connectionFactory, timeout, unit, DEFAULT_SEARCH); |
| | | } |
| | | |
| | | |
| | | |
| | | private static final SearchRequest DEFAULT_SEARCH = Requests |
| | | .newSearchRequest("", SearchScope.BASE_OBJECT, "(objectClass=*)", |
| | | "1.1"); |
| | | // FIXME: change timeout parameters to long+TimeUnit. |
| | | |
| | | |
| | | |
| | |
| | | * |
| | | * @param connectionFactory |
| | | * The connection factory to use for creating connections. |
| | | * @param timeout |
| | | * The time to wait between keepalive pings. |
| | | * @param unit |
| | | * The time unit of the timeout argument. |
| | | * @param heartBeat |
| | | * The search request to use when pinging connections. |
| | | * @param interval |
| | | * The period between keepalive pings. |
| | | */ |
| | | HeartBeatConnectionFactory(ConnectionFactory<?> connectionFactory, |
| | | long timeout, TimeUnit unit, SearchRequest heartBeat) |
| | | public HeartBeatConnectionFactory( |
| | | ConnectionFactory<?> connectionFactory, |
| | | int interval) |
| | | { |
| | | this.heartBeat = heartBeat; |
| | | this.interval = unit.toMillis(timeout); |
| | | Validator.ensureNotNull(connectionFactory); |
| | | this.interval = interval; |
| | | this.activeConnections = new LinkedList<AsynchronousConnectionImpl>(); |
| | | this.parentFactory = connectionFactory; |
| | | |
| | | Runtime.getRuntime().addShutdownHook(new Thread() |
| | | { |
| | | @Override |
| | | public void run() |
| | | { |
| | | stopRequested = true; |
| | | } |
| | | }); |
| | | |
| | | new HeartBeatThread().start(); |
| | | } |
| | | |
| | |
| | | * operations. |
| | | */ |
| | | private final class AsynchronousConnectionImpl implements |
| | | AsynchronousConnection, ConnectionEventListener, |
| | | ResultHandler<Result> |
| | | AsynchronousConnection, ConnectionEventListener |
| | | { |
| | | private final AsynchronousConnection connection; |
| | | |
| | | |
| | | |
| | | private AsynchronousConnectionImpl(AsynchronousConnection connection) |
| | | { |
| | | this.connection = connection; |
| | |
| | | return connection.isClosed(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isValid() |
| | | { |
| | | // Avoid extra pings... Let the next ping find out if this connection |
| | | // is still valid. |
| | | return connection.isValid(); |
| | | } |
| | | |
| | | public void connectionReceivedUnsolicitedNotification( |
| | | GenericExtendedResult notification) |
| | |
| | | activeConnections.remove(this); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public void handleErrorResult(ErrorResultException error) |
| | | { |
| | | // TODO: I18N |
| | | if (error instanceof TimeoutResultException) |
| | | { |
| | | close(Requests.newUnbindRequest(), "Heart beat timed out"); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public void handleResult(Result result) |
| | | { |
| | | // Do nothing |
| | | } |
| | | |
| | | |
| | | |
| | | private void sendHeartBeat() |
| | | { |
| | | search(heartBeat, this, null); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | private HeartBeatThread() |
| | | { |
| | | super("Heart Beat Thread"); |
| | | this.setDaemon(true); |
| | | } |
| | | |
| | | |
| | | |
| | | public void run() |
| | | { |
| | | while (!stopRequested) |
| | | while(true) |
| | | { |
| | | synchronized (activeConnections) |
| | | { |
| | | for (AsynchronousConnectionImpl connection : activeConnections) |
| | | { |
| | | connection.sendHeartBeat(); |
| | | if(!connection.isValid()) |
| | | { |
| | | connection.close(Requests.newUnbindRequest(), |
| | | "Connection no longer valid"); |
| | | } |
| | | } |
| | | } |
| | | try |