/*
* Copyright (c) 2011,2013 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
*
* 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.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Originally created by David Erickson, Stanford University
*
* 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.sdnplatform.core.internal;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFType;
import org.sdnplatform.core.IOFSwitch;
import org.sdnplatform.threadpool.IThreadPoolService;
/**
* A Future object used to retrieve asynchronous OFMessage replies. Unregisters
* and cancels itself by default after 60 seconds. This class is meant to be
* sub-classed and proper behavior added to the handleReply method, and
* termination of the Future to be handled in the isFinished method.
*
* @author David Erickson (daviderickson@cs.stanford.edu)
*/
public abstract class OFMessageFuture<V> implements Future<V> {
protected IThreadPoolService threadPool;
protected volatile boolean canceled;
protected CountDownLatch latch;
protected OFType responseType;
protected volatile V result;
protected IOFSwitch sw;
protected Runnable timeoutTimer;
protected int transactionId;
protected static final long DEFAULT_TIMEOUT = 60;
protected static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;
public OFMessageFuture(IThreadPoolService tp,
IOFSwitch sw, OFType responseType, int transactionId) {
this(tp, sw, responseType, transactionId,
DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT);
}
public OFMessageFuture(IThreadPoolService tp,
IOFSwitch sw, OFType responseType, int transactionId, long timeout, TimeUnit unit) {
this.threadPool = tp;
this.canceled = false;
this.latch = new CountDownLatch(1);
this.responseType = responseType;
this.sw = sw;
this.transactionId = transactionId;
final OFMessageFuture<V> future = this;
timeoutTimer = new Runnable() {
@Override
public void run() {
if (timeoutTimer == this)
future.cancel(true);
}
};
threadPool.getScheduledExecutor().schedule(timeoutTimer, timeout, unit);
}
protected void unRegister() {
this.timeoutTimer = null;
}
public void deliverFuture(IOFSwitch sw, OFMessage msg) {
if (transactionId == msg.getXid()) {
handleReply(sw, msg);
if (isFinished()) {
unRegister();
this.latch.countDown();
}
}
}
/**
* Used to handle the specific expected message this Future was reigstered
* for, the specified msg parameter is guaranteed to match the type and
* transaction id specified.
* @param sw
* @param msg
* @return
*/
protected abstract void handleReply(IOFSwitch sw, OFMessage msg);
/**
* Called directly after handleReply, subclasses implement this method to
* indicate when the future can deregister itself from receiving future
* messages, and when it is safe to return the results to any waiting
* threads.
* @return when this Future has completed its work
*/
protected abstract boolean isFinished();
/* (non-Javadoc)
* @see java.util.concurrent.Future#cancel(boolean)
*/
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (isDone()) {
return false;
} else {
unRegister();
canceled = true;
this.latch.countDown();
return !isDone();
}
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#isCancelled()
*/
@Override
public boolean isCancelled() {
return canceled;
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#isDone()
*/
@Override
public boolean isDone() {
return this.latch.getCount() == 0;
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#get()
*/
@Override
public V get() throws InterruptedException, ExecutionException {
this.latch.await();
return result;
}
/* (non-Javadoc)
* @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit)
*/
@Override
public V get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
this.latch.await(timeout, unit);
return result;
}
public int getTransactionId() {
return transactionId;
}
public void setTransactionId(int transactionId) {
this.transactionId = transactionId;
}
}