All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.named_data.jndn.ThreadPoolFace 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;

import java.io.IOException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.named_data.jndn.encoding.WireFormat;
import net.named_data.jndn.transport.Transport;

/**
 * ThreadPoolFace extends Face to provide the main methods for NDN communication
 * by submitting to a given ScheduledExecutorService thread pool. This also
 * uses the thread pool to schedule the interest timeouts.
 */
public class ThreadPoolFace extends Face {
  /**
   * Create a new ThreadPoolFace for communication with an NDN hub with the given
   * Transport object and connectionInfo.
   * @param threadPool The thread pool used to submit method calls such as
   * expressInterest and the related callbacks such as onData. The thread pool
   * is also used to schedule the interest timeouts.
   * @param transport A Transport object used for communication. If you do not
   * want to call processEvents, then the transport should be an async transport
   * like AsyncTcpTransport.
   * @param connectionInfo A Transport.ConnectionInfo to be used to connect to
   * the transport.
   */
  public ThreadPoolFace
    (ScheduledExecutorService threadPool, Transport transport,
     Transport.ConnectionInfo connectionInfo)
  {
    super(transport, connectionInfo);
    threadPool_ = threadPool;
  }

  /**
   * Override to submit a task to use the thread pool given to the constructor.
   * Also wrap the supplied onData, onTimeout and onNetworkNack callbacks in an
   * outer callback which submits a task to the thread pool to call the supplied
   * callback. See Face.expressInterest for calling details.
   */
  public long
  expressInterest
    (final Interest interest, OnData onData, OnTimeout onTimeout,
     final OnNetworkNack onNetworkNack, final WireFormat wireFormat)
     throws IOException
  {
    final long pendingInterestId = node_.getNextEntryId();

    // Wrap callbacks to submit to the thread pool.
    final OnData finalOnData = onData;
    final OnData onDataSubmit = new OnData() {
      public void onData(final Interest localInterest, final Data data) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onData.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnData.onData(localInterest, data);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onData", ex);
            }
          }
        });
      }
    };

    final OnTimeout finalOnTimeout = onTimeout;
    final OnTimeout onTimeoutSubmit = onTimeout == null ? null : new OnTimeout() {
      public void onTimeout(final Interest localInterest) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onTimeout.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnTimeout.onTimeout(localInterest);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onTimeout", ex);
            }
          }
        });
      }
    };

    final OnNetworkNack finalOnNetworkNack = onNetworkNack;
    final OnNetworkNack onNetworkNackSubmit =
        onNetworkNack == null ? null : new OnNetworkNack() {
      public void onNetworkNack
          (final Interest localInterest, final NetworkNack networkNack) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onData.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnNetworkNack.onNetworkNack(localInterest, networkNack);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onNetworkNack", ex);
            }
          }
        });
      }
    };

    // Make an interest copy as required by Node.expressInterest.
    final Interest interestCopy = new Interest(interest);
    threadPool_.submit(new Runnable() {
      public void run() {
        // Need to catch and log exceptions at this async entry point.
        try {
          node_.expressInterest
            (pendingInterestId, interestCopy, onDataSubmit, onTimeoutSubmit,
             onNetworkNackSubmit, wireFormat, ThreadPoolFace.this);
        } catch (Throwable ex) {
          logger_.log(Level.SEVERE, null, ex);
        }
      }
    });

    return pendingInterestId;
  }

  /**
   * Override to submit a task to use the thread pool given to the constructor.
   * Also wrap the supplied onData, onTimeout and onNetworkNack callbacks in an
   * outer callback which submits a task to the thread pool to call the supplied
   * callback. See Face.expressInterest for calling details. We make a separate
   * expressInterest overload for supplying a Name vs. Interest to avoid making
   * multiple copies of the Interest.
   */
  public long
  expressInterest
    (Name name, Interest interestTemplate, OnData onData, OnTimeout onTimeout,
     final OnNetworkNack onNetworkNack, final WireFormat wireFormat)
     throws IOException
  {
    final long pendingInterestId = node_.getNextEntryId();

    // Wrap callbacks to submit to the thread pool.
    final OnData finalOnData = onData;
    final OnData onDataSubmit = new OnData() {
      public void onData(final Interest localInterest, final Data data) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onData.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnData.onData(localInterest, data);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onData", ex);
            }
          }
        });
      }
    };

    final OnTimeout finalOnTimeout = onTimeout;
    final OnTimeout onTimeoutSubmit = onTimeout == null ? null : new OnTimeout() {
      public void onTimeout(final Interest localInterest) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onTimeout.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnTimeout.onTimeout(localInterest);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onTimeout", ex);
            }
          }
        });
      }
    };

    final OnNetworkNack finalOnNetworkNack = onNetworkNack;
    final OnNetworkNack onNetworkNackSubmit =
        onNetworkNack == null ? null : new OnNetworkNack() {
      public void onNetworkNack
          (final Interest localInterest, final NetworkNack networkNack) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onData.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnNetworkNack.onNetworkNack(localInterest, networkNack);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onNetworkNack", ex);
            }
          }
        });
      }
    };

    // Make an interest copy as required by Node.expressInterest.
    final Interest interestCopy = getInterestCopy(name, interestTemplate);
    threadPool_.submit(new Runnable() {
      public void run() {
        // Need to catch and log exceptions at this async entry point.
        try {
          node_.expressInterest
            (pendingInterestId, interestCopy, onDataSubmit, onTimeoutSubmit,
             onNetworkNackSubmit, wireFormat, ThreadPoolFace.this);
        } catch (Throwable ex) {
          logger_.log(Level.SEVERE, null, ex);
        }
      }
    });

    return pendingInterestId;
  }

  /**
   * Submit a task to the thread pool to register prefix with the connected
   * forwarder and call onInterest when a matching interest is received. To
   * register a prefix with NFD, you must first call setCommandSigningInfo.
   * @param prefix A Name for the prefix to register. This copies the Name.
   * @param onInterest If not null, this creates an interest filter from prefix
   * so that when an Interest is received which matches the filter, this calls
   * onInterest.onInterest(prefix, interest, face, interestFilterId, filter).
   * The onInterest callback should supply the Data with face.putData().
   * NOTE: You must not change the prefix or filter objects - if you need to
   * change them then make a copy.
   * If onInterest is null, it is ignored and you must call setInterestFilter.
   * NOTE: The library will log any exceptions thrown by this callback, but for
   * better error handling the callback should catch and properly handle any
   * exceptions.
   * @param onRegisterFailed If register prefix fails for any reason, this
   * calls onRegisterFailed.onRegisterFailed(prefix).
   * NOTE: The library will log any exceptions thrown by this callback, but for
   * better error handling the callback should catch and properly handle any
   * exceptions.
   * @param onRegisterSuccess This calls
   * onRegisterSuccess.onRegisterSuccess(prefix, registeredPrefixId) when this
   * receives a success message from the forwarder. If onRegisterSuccess is null,
   * this does not use it. (The onRegisterSuccess parameter comes after
   * onRegisterFailed because it can be null or omitted, unlike onRegisterFailed.)
   * NOTE: The library will log any exceptions thrown by this callback, but for
   * better error handling the callback should catch and properly handle any
   * exceptions.
   * @param flags The flags for finer control of which interests are forwarded
   * to the application.
   * @param wireFormat A WireFormat object used to encode the message.
   * @return The registered prefix ID which can be used with
   * removeRegisteredPrefix.
   */
  public long
  registerPrefix
    (final Name prefix, OnInterestCallback onInterest,
     OnRegisterFailed onRegisterFailed, OnRegisterSuccess onRegisterSuccess,
     final ForwardingFlags flags, final WireFormat wireFormat)
    throws IOException, SecurityException
  {
    final long registeredPrefixId = node_.getNextEntryId();

    // Wrap callbacks to submit to the thread pool.
    final OnInterestCallback finalOnInterest = onInterest;
    final OnInterestCallback onInterestSubmit =
        onInterest == null ? null : new OnInterestCallback() {
      public void onInterest(final Name localPrefix, final Interest interest,
          final Face face, final long interestFilterId, final InterestFilter filter) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onInterest.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnInterest.onInterest
                (localPrefix, interest, face, interestFilterId, filter);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onInterest", ex);
            }
          }
        });
      }
    };

    final OnRegisterFailed finalOnRegisterFailed = onRegisterFailed;
    final OnRegisterFailed onRegisterFailedSubmit =
        new OnRegisterFailed() {
      public void onRegisterFailed(final Name localPrefix) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onRegisterFailed.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnRegisterFailed.onRegisterFailed(localPrefix);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onRegisterFailed", ex);
            }
          }
        });
      }
    };

    // Wrap callbacks to submit to the thread pool.
    final OnRegisterSuccess finalOnRegisterSuccess = onRegisterSuccess;
    final OnRegisterSuccess onRegisterSuccessSubmit =
        onRegisterSuccess == null ? null : new OnRegisterSuccess() {
      public void onRegisterSuccess(final Name localPrefix,
                                    final long localRegisteredPrefixId) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onRegisterSuccess.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnRegisterSuccess.onRegisterSuccess
                (localPrefix, localRegisteredPrefixId);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onRegisterSuccess", ex);
            }
          }
        });
      }
    };

    threadPool_.submit(new Runnable() {
      public void run() {
        // Need to catch and log exceptions at this async entry point.
        try {
          node_.registerPrefix
            (registeredPrefixId, prefix, onInterestSubmit, onRegisterFailedSubmit,
             onRegisterSuccessSubmit, flags, wireFormat,
             commandKeyChain_, commandCertificateName_, ThreadPoolFace.this);
        } catch (Throwable ex) {
          logger_.log(Level.SEVERE, null, ex);
        }
      }
    });

    return registeredPrefixId;
  }

  /**
   * Submit a task to the thread pool to add an entry to the local interest
   * filter table to call the onInterest callback for a matching incoming
   * Interest. This method only modifies the library's local callback table and
   * does not register the prefix with the forwarder. It will always succeed.
   * To register a prefix with the forwarder, use registerPrefix.
   * @param filter The InterestFilter with a prefix and optional regex filter
   * used to match the name of an incoming Interest. This makes a copy of filter.
   * @param onInterest When an Interest is received which matches the filter,
   * this calls
   * onInterest.onInterest(prefix, interest, face, interestFilterId, filter).
   * NOTE: The library will log any exceptions thrown by this callback, but for
   * better error handling the callback should catch and properly handle any
   * exceptions.
   * @return The interest filter ID which can be used with unsetInterestFilter.
   */
  public long
  setInterestFilter
    (final InterestFilter filter, final OnInterestCallback onInterest)
  {
    final long interestFilterId = node_.getNextEntryId();

        // Wrap callbacks to submit to the thread pool.
    final OnInterestCallback finalOnInterest = onInterest;
    final OnInterestCallback onInterestSubmit = new OnInterestCallback() {
      public void onInterest(final Name prefix, final Interest interest,
          final Face face, final long interestFilterId, final InterestFilter filter) {
        threadPool_.submit(new Runnable() {
          // Call the passed-in onInterest.
          public void run() {
            // Need to catch and log exceptions at this async entry point.
            try {
              finalOnInterest.onInterest
                (prefix, interest, face, interestFilterId, filter);
            } catch (Throwable ex) {
              logger_.log(Level.SEVERE, "Error in onInterest", ex);
            }
          }
        });
      }
    };

    threadPool_.submit(new Runnable() {
      public void run() {
        // Need to catch and log exceptions at this async entry point.
        try {
          node_.setInterestFilter
            (interestFilterId, filter, onInterestSubmit, ThreadPoolFace.this);
        } catch (Throwable ex) {
          logger_.log(Level.SEVERE, null, ex);
        }
      }
    });


    return interestFilterId;
  }

  /**
   * Override to schedule in the thread pool to call callback.run() after the
   * given delay. Even though this is public, it is not part of the public API
   * of Face.
   * @param delayMilliseconds The delay in milliseconds.
   * @param callback This calls callback.run() after the delay.
   */
  public void
  callLater(double delayMilliseconds, final Runnable callback)
  {
    threadPool_.schedule
      (new Runnable() {
        public void run() {
          // Need to catch and log exceptions at this async entry point.
          try {
            callback.run();
          } catch (Throwable ex) {
            logger_.log(Level.SEVERE, null, ex);
          }
        }
       },
       (long)delayMilliseconds, TimeUnit.MILLISECONDS);
  }

  private final ScheduledExecutorService threadPool_;
  private static final Logger logger_ = Logger.getLogger
    (ThreadPoolFace.class.getName());
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy