net.named_data.jndn.impl.PendingInterestTable Maven / Gradle / Ivy
/**
* Copyright (C) 2015-2018 Regents of the University of California.
* @author: Jeff Thompson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
package net.named_data.jndn.impl;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.named_data.jndn.Interest;
import net.named_data.jndn.Data;
import net.named_data.jndn.OnData;
import net.named_data.jndn.OnNetworkNack;
import net.named_data.jndn.OnTimeout;
import net.named_data.jndn.encoding.EncodingException;
import net.named_data.jndn.util.Common;
import net.named_data.jndn.util.SignedBlob;
/**
* A PendingInterestTable is an internal class to hold a list of pending
* interests with their callbacks.
*/
public class PendingInterestTable {
/**
* Entry holds the callbacks and other fields for an entry in the pending
* interest table.
*/
public static class Entry {
/**
* Create a new Entry with the given fields. Note: You should not call this
* directly but call PendingInterestTable.add.
*/
public Entry
(long pendingInterestId, Interest interest, OnData onData,
OnTimeout onTimeout, OnNetworkNack onNetworkNack)
{
pendingInterestId_ = pendingInterestId;
interest_ = interest;
onData_ = onData;
onTimeout_ = onTimeout;
onNetworkNack_ = onNetworkNack;
}
/**
* Get the pendingInterestId given to the constructor.
* @return The pendingInterestId.
*/
public final long
getPendingInterestId() { return pendingInterestId_; }
/**
* Get the interest given to the constructor (from Face.expressInterest).
* @return The interest. NOTE: You must not change the interest object - if
* you need to change it then make a copy.
*/
public final Interest
getInterest() { return interest_; }
/**
* Get the OnData callback given to the constructor.
* @return The OnData callback.
*/
public final OnData
getOnData() { return onData_; }
/**
* Get the OnNetworkNack callback given to the constructor.
* @return The OnNetworkNack callback.
*/
public final OnNetworkNack
getOnNetworkNack() { return onNetworkNack_; }
/**
* Set the isRemoved flag which is returned by getIsRemoved().
*/
public final void
setIsRemoved() { isRemoved_ = true; }
/**
* Check if setIsRemoved() was called.
* @return True if setIsRemoved() was called.
*/
public final boolean
getIsRemoved() { return isRemoved_; }
/**
* Call onTimeout_ (if defined). This ignores exceptions from the call to
* onTimeout_.
*/
public final void
callTimeout()
{
if (onTimeout_ != null) {
try {
onTimeout_.onTimeout(interest_);
} catch (Throwable ex) {
logger_.log(Level.SEVERE, "Error in onTimeout", ex);
}
}
}
private final Interest interest_;
private final long pendingInterestId_; /**< A unique identifier for this entry so it can be deleted */
private final OnData onData_;
private final OnTimeout onTimeout_;
private final OnNetworkNack onNetworkNack_;
private boolean isRemoved_ = false;
}
/**
* Add a new entry to the pending interest table. However, if
* removePendingInterest was already called with the pendingInterestId, don't
* add an entry and return null.
* @param pendingInterestId The getNextEntryId() for the pending interest ID
* which Face got so it could return it to the caller.
* @param interestCopy The Interest which was sent, which has already been
* copied by expressInterest.
* @param onData Call onData.onData when a matching data packet is
* received.
* @param onTimeout This calls onTimeout.onTimeout if the interest times out.
* If onTimeout is null, this does not use it.
* @param onNetworkNack Call onNetworkNack.onNetworkNack when a network Nack
* packet is received.
* @return The new PendingInterestTable.Entry, or null if
* removePendingInterest was already called with the pendingInterestId.
*/
public synchronized final Entry
add(long pendingInterestId, Interest interestCopy, OnData onData,
OnTimeout onTimeout, OnNetworkNack onNetworkNack)
{
int removeRequestIndex = removeRequests_.indexOf(pendingInterestId);
if (removeRequestIndex >= 0) {
// removePendingInterest was called with the pendingInterestId returned by
// expressInterest before we got here, so don't add a PIT entry.
removeRequests_.remove(removeRequestIndex);
return null;
}
Entry entry = new Entry
(pendingInterestId, interestCopy, onData, onTimeout, onNetworkNack);
table_.add(entry);
return entry;
}
/**
* Find all entries from the pending interest table where data conforms to
* the entry's interest selectors, remove the entries from the table, set each
* entry's isRemoved flag, and add to the entries list.
* @param data The incoming Data packet to find the interest for.
* @param entries Add matching PendingInterestTable.Entry from the pending
* interest table. The caller should pass in an empty ArrayList.
*/
public synchronized final void
extractEntriesForExpressedInterest(Data data, ArrayList entries)
throws EncodingException
{
// Go backwards through the list so we can remove entries.
for (int i = table_.size() - 1; i >= 0; --i) {
Entry pendingInterest = table_.get(i);
if (pendingInterest.getInterest().matchesData(data)) {
entries.add(table_.get(i));
// We let the callback from callLater call _processInterestTimeout, but
// for efficiency, mark this as removed so that it returns right away.
table_.remove(i);
pendingInterest.setIsRemoved();
}
}
}
/**
* Find all entries from the pending interest table where the OnNetworkNack
* callback is not null and the entry's interest is the same as the given
* interest, remove the entries from the table, set each entry's isRemoved
* flag, and add to the entries list. (We don't remove the entry if the
* OnNetworkNack callback is null so that OnTimeout will be called later.) The
* interests are the same if their default wire encoding is the same (which
* has everything including the name, nonce, link object and selectors).
* @param interest The Interest to search for (typically from a Nack packet).
* @param entries Add matching PendingInterestTable.Entry from the pending
* interest table. The caller should pass in an empty ArrayList.
*/
public synchronized final void
extractEntriesForNackInterest(Interest interest, ArrayList entries)
{
SignedBlob encoding = interest.wireEncode();
// Go backwards through the list so we can remove entries.
for (int i = table_.size() - 1; i >= 0; --i) {
Entry pendingInterest = table_.get(i);
if (pendingInterest.getOnNetworkNack() == null)
continue;
// wireEncode returns the encoding cached when the interest was sent (if
// it was the default wire encoding).
if (pendingInterest.getInterest().wireEncode().equals(encoding)) {
entries.add(table_.get(i));
// We let the callback from callLater call _processInterestTimeout, but
// for efficiency, mark this as removed so that it returns right away.
table_.remove(i);
pendingInterest.setIsRemoved();
}
}
}
/**
* Remove the pending interest entry with the pendingInterestId from the
* pending interest table and set its isRemoved flag. This does not affect
* another pending interest with a different pendingInterestId, even if it has
* the same interest name. If there is no entry with the pendingInterestId, do
* nothing.
* @param pendingInterestId The ID returned from expressInterest.
*/
public synchronized final void
removePendingInterest(long pendingInterestId)
{
int count = 0;
// Go backwards through the list so we can remove entries.
// Remove all entries even though pendingInterestId should be unique.
for (int i = table_.size() - 1; i >= 0; --i) {
if ((table_.get(i)).getPendingInterestId() == pendingInterestId) {
++count;
// For efficiency, mark this as removed so that
// processInterestTimeout doesn't look for it.
(table_.get(i)).setIsRemoved();
table_.remove(i);
}
}
if (count == 0)
logger_.log
(Level.WARNING, "removePendingInterest: Didn't find pendingInterestId {0}",
pendingInterestId);
if (count == 0) {
// The pendingInterestId was not found. Perhaps this has been called before
// the callback in expressInterest can add to the PIT. Add this
// removal request which will be checked before adding to the PIT.
if (removeRequests_.indexOf(pendingInterestId) < 0)
// Not already requested, so add the request.
removeRequests_.add(pendingInterestId);
}
}
/**
* Remove the specific pendingInterest entry from the table and set its
* isRemoved flag. However, if the pendingInterest isRemoved flag is already
* true or the entry is not in the pending interest table then do nothing.
* @param pendingInterest The Entry from the pending interest table.
* @return True if the entry was removed, false if not.
*/
public synchronized final boolean
removeEntry(Entry pendingInterest)
{
if (pendingInterest.getIsRemoved())
// extractEntriesForExpressedInterest or removePendingInterest has
// removed pendingInterest from the table, so we don't need to look for it.
// Do nothing.
return false;
if (table_.remove(pendingInterest)) {
pendingInterest.setIsRemoved();
return true;
}
else
return false;
}
private final ArrayList table_ = new ArrayList();
private final ArrayList removeRequests_ = new ArrayList();
private static final Logger logger_ = Logger.getLogger
(PendingInterestTable.class.getName());
// This is to force an import of net.named_data.jndn.util.
private static Common dummyCommon_ = new Common();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy