Package org.ardverk.dht.io

Source Code of org.ardverk.dht.io.AbstractResponseHandler$UnhandledException

/*
* Copyright 2009-2012 Roger Kapsi
*
* 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 org.ardverk.dht.io;

import java.io.IOException;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Provider;

import org.ardverk.concurrent.AsyncFuture;
import org.ardverk.concurrent.AsyncFutureListener;
import org.ardverk.concurrent.AsyncProcessFuture;
import org.ardverk.dht.KUID;
import org.ardverk.dht.entity.Entity;
import org.ardverk.dht.message.RequestMessage;
import org.ardverk.dht.message.ResponseMessage;
import org.ardverk.dht.routing.Contact;
import org.ardverk.lang.Precoditions;
import org.ardverk.lang.TimeStamp;


/**
* An abstract base class for {@link ResponseHandler}s.
*/
abstract class AbstractResponseHandler<V extends Entity>
    extends AbstractMessageHandler implements ResponseHandler<V> {
 
  protected volatile AsyncProcessFuture<V> future = null;
 
  private final AtomicBoolean done = new AtomicBoolean(false);
 
  private volatile TimeStamp lastSendTime = null;
 
  private volatile TimeStamp lastResponseTime = null;
 
  public AbstractResponseHandler(Provider<MessageDispatcher> messageDispatcher) {
    super(messageDispatcher);
  }
 
  /**
   * Returns the mount of time that has passed since the last message
   * has been sent or -1 if no messages have been sent yet.
   */
  public long getLastSendTime(TimeUnit unit) {
    TimeStamp lastSendTime = this.lastSendTime;
    return lastSendTime != null ? lastSendTime.getAge(unit) : -1L;
  }
 
  /**
   * Returns the amount of time that has passed in milliseconds
   * since the last message has been sent or -1 if no messages
   * have been sent yet.
   */
  public long getLastSendTimeInMillis() {
    return getLastSendTime(TimeUnit.MILLISECONDS);
  }
 
  /**
   * Returns the mount of time that has passed since the last message
   * has been received or -1 if no messages have been received yet.
   */
  public long getLastResponseTime(TimeUnit unit) {
    TimeStamp lastResponseTime = this.lastResponseTime;
    return lastResponseTime != null ? lastResponseTime.getAge(unit) : -1L;
  }
 
  /**
   * Returns the amount of time that has passed in milliseconds
   * since the last message has been received or -1 if no messages
   * have been received yet.
   */
  public long getLastResponseTimeInMillis() {
    return getLastResponseTime(TimeUnit.MILLISECONDS);
  }
 
  @Override
  public boolean isOpen() {
    AsyncFuture<V> future = this.future;
    return future != null && !future.isDone();
  }

  /**
   * Returns {@code true} if the underlying {@link AsyncFuture} is
   * done.
   *
   * NOTE: This method is throwing an {@link IllegalStateException}
   * if the {@link AbstractRequestHandler} isn't initialized yet.
   */
  protected boolean isDone() {
    AsyncFuture<V> future = this.future;
    if (future != null) {
      return future.isDone();
    }
    throw new IllegalStateException();
  }

  /**
   * Sets the value of the underlying {@link AsyncFuture}.
   *
   * NOTE: This method is throwing an {@link IllegalStateException}
   * if the {@link AbstractRequestHandler} isn't initialized yet.
   */
  protected void setValue(V value) {
    AsyncFuture<V> future = this.future;
    if (future != null) {
      future.setValue(value);
      if (!done.getAndSet(true)) {
        done();
      }
      return;
    }
    throw new IllegalStateException();
  }
 
  /**
   * Sets the exception of the underlying {@link AsyncFuture}.
   *
   * NOTE: This method is throwing an {@link IllegalStateException}
   * if the {@link AbstractRequestHandler} isn't initialized yet.
   */
  protected void setException(Throwable t) {
    AsyncFuture<V> future = this.future;
    if (future != null) {
      future.setException(t);
      if (!done.getAndSet(true)) {
        done();
      }
      return;
    }
    throw new IllegalStateException();
  }
 
  /**
   * Sends a {@link RequestMessage} to the given {@link Contact}.
   */
  public void send(Contact dst, RequestMessage message,
      long timeout, TimeUnit unit) throws IOException {
   
    KUID contactId = dst.getId();
    send(contactId, message, timeout, unit);
  }
 
  /**
   * Sends a {@link RequestMessage} to the given {@link KUID}.
   *
   * NOTE: The receiver's {@link SocketAddress} is encoded in
   * the {@link RequestMessage}.
   */
  public void send(KUID contactId, RequestMessage message,
      long timeout, TimeUnit unit) throws IOException {
   
    if (isOpen()) {
      getMessageDispatcher().send(this, contactId,
          message, timeout, unit);
      lastSendTime = TimeStamp.now();
    }
  }
 
  @Override
  public final void start(AsyncProcessFuture<V> future) throws Exception {
    this.future = Precoditions.notNull(future, "future");
   
    future.addAsyncFutureListener(new AsyncFutureListener<V>() {
      @Override
      public void operationComplete(AsyncFuture<V> future) {
        if (!done.getAndSet(true)) {
          done();
        }
      }
    });
   
    synchronized (future) {
      if (!future.isDone()) {
        go(future);
      }
    }
  }
 
  /**
   * Called by {@link #start(AsyncProcessFuture)}.
   *
   * NOTE: A lock on the given {@link AsyncFuture} is being held.
   */
  protected abstract void go(AsyncFuture<V> future) throws Exception;
 
  /**
   * Called when the underlying {@link AsyncFuture} is done.
   */
  protected void done() {
  }
 
  @Override
  public boolean handleResponse(RequestEntity entity,
      ResponseMessage response, long time, TimeUnit unit)
      throws IOException {
   
    boolean success = false;
    synchronized (future) {
      if (isOpen()) {
        synchronized (this) {
          lastResponseTime = TimeStamp.now();
          processResponse(entity, response, time, unit);
          success = true;
        }
      }
    }
    return success;
  }
 
  /**
   * @see #handleResponse(RequestEntity, ResponseMessage, long, TimeUnit).
   */
  protected abstract void processResponse(RequestEntity entity,
      ResponseMessage response, long time, TimeUnit unit)
      throws IOException;

  @Override
  public void handleTimeout(RequestEntity entity,
      long time, TimeUnit unit) throws IOException {
   
    synchronized (future) {
      if (!isOpen()) {
        return;
      }
     
      synchronized (this) {
        processTimeout(entity, time, unit);       
      }
    }
  }
 
  /**
   * @see #handleTimeout(RequestEntity, long, TimeUnit)
   */
  protected abstract void processTimeout(RequestEntity entity,
      long time, TimeUnit unit) throws IOException;

 
  @Override
  public void handleIllegalResponse(RequestEntity entity,
      ResponseMessage response, long time, TimeUnit unit) throws IOException {
    synchronized (future) {
      if (!isOpen()) {
        return;
      }
     
      synchronized (this) {
        processIllegalResponse(entity, response, time, unit);
      }
    }
  }
 
  /**
   * @see #handleIllegalResponse(RequestEntity, ResponseMessage, long, TimeUnit)
   */
  protected void processIllegalResponse(RequestEntity entity,
      ResponseMessage response, long time, TimeUnit unit) throws IOException {
    setException(new IllegalResponseException(entity, response, time, unit));
  }
 
  @Override
  public void handleException(RequestEntity entity, Throwable exception) {
    synchronized (future) {
      if (!isOpen()) {
        return;
      }
     
      synchronized (this) {
        processException(entity, exception);       
      }
    }
  }
 
  /**
   * @see #handleException(RequestEntity, Throwable)
   */
  protected void processException(RequestEntity entity, Throwable exception) {
    setException(new UnhandledException(entity, exception));
  }
 
  public static class IllegalResponseException extends IOException {
   
    private static final long serialVersionUID = -966684138962375899L;
   
    private final RequestEntity entity;
   
    private final ResponseMessage response;
   
    private final long time;
   
    private final TimeUnit unit;
   
    protected IllegalResponseException(RequestEntity entity,
        ResponseMessage response, long time, TimeUnit unit) {
     
      this.entity = entity;
      this.response = response;
      this.time = time;
      this.unit = unit;
    }
   
    public RequestEntity getRequestEntity() {
      return entity;
    }
   
    public ResponseMessage getResponseMessage() {
      return response;
    }
   
    public long getTime(TimeUnit unit) {
      return unit.convert(time, this.unit);
    }
   
    public long getTimeInMillis() {
      return getTime(TimeUnit.MILLISECONDS);
    }
  }

  public static class UnhandledException extends IOException {
   
    private static final long serialVersionUID = -966684138962375899L;
   
    private final RequestEntity entity;
   
    protected UnhandledException(RequestEntity entity, Throwable cause) {
      super(cause);
      this.entity = entity;
    }
   
    public RequestEntity getRequestEntity() {
      return entity;
    }
  }
}
TOP

Related Classes of org.ardverk.dht.io.AbstractResponseHandler$UnhandledException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.