diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 96cc43efa6a0885098044e976cd780bb42c68a70..46d39593e4a655b252b434ad8dc8e686d5976726 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,22 +1,41 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="CompilerConfiguration">
-    <resourceExtensions />
-    <wildcardResourcePatterns>
-      <entry name="!?*.java" />
-      <entry name="!?*.form" />
-      <entry name="!?*.class" />
-      <entry name="!?*.groovy" />
-      <entry name="!?*.scala" />
-      <entry name="!?*.flex" />
-      <entry name="!?*.kt" />
-      <entry name="!?*.clj" />
-      <entry name="!?*.aj" />
-    </wildcardResourcePatterns>
-    <annotationProcessing>
-      <profile default="true" name="Default" enabled="false">
-        <processorPath useClasspath="true" />
-      </profile>
-    </annotationProcessing>
+    <bytecodeTargetLevel>
+      <module name="addressbook_main" target="1.7" />
+      <module name="addressbook_test" target="1.7" />
+      <module name="BOB_main" target="1.7" />
+      <module name="BOB_test" target="1.7" />
+      <module name="core_main" target="1.7" />
+      <module name="core_test" target="1.7" />
+      <module name="desktopgui_main" target="1.7" />
+      <module name="desktopgui_test" target="1.7" />
+      <module name="i2psnark_main" target="1.7" />
+      <module name="i2psnark_test" target="1.7" />
+      <module name="i2ptunnel_main" target="1.7" />
+      <module name="i2ptunnel_test" target="1.7" />
+      <module name="installer_main" target="1.7" />
+      <module name="installer_test" target="1.7" />
+      <module name="jetty_main" target="1.7" />
+      <module name="jetty_test" target="1.7" />
+      <module name="jrobin_main" target="1.7" />
+      <module name="jrobin_test" target="1.7" />
+      <module name="ministreaming_main" target="1.7" />
+      <module name="ministreaming_test" target="1.7" />
+      <module name="router_main" target="1.7" />
+      <module name="router_test" target="1.7" />
+      <module name="routerconsole_main" target="1.7" />
+      <module name="routerconsole_test" target="1.7" />
+      <module name="sam_main" target="1.7" />
+      <module name="sam_test" target="1.7" />
+      <module name="streaming_main" target="1.7" />
+      <module name="streaming_test" target="1.7" />
+      <module name="susidns_main" target="1.7" />
+      <module name="susidns_test" target="1.7" />
+      <module name="susimail_main" target="1.7" />
+      <module name="susimail_test" target="1.7" />
+      <module name="systray_main" target="1.7" />
+      <module name="systray_test" target="1.7" />
+    </bytecodeTargetLevel>
   </component>
 </project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index c82c6b64b8fe56e50009e003de9f3da6ea9216a6..f3527619c8b3a3205902de8c314d2e89b3459216 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -38,20 +38,7 @@
       <property name="caretWidth" class="java.lang.Integer" />
     </properties>
   </component>
-  <component name="EntryPointsManager">
-    <entry_points version="2.0" />
-  </component>
-  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
-    <OptionsSetting value="true" id="Add" />
-    <OptionsSetting value="true" id="Remove" />
-    <OptionsSetting value="true" id="Checkout" />
-    <OptionsSetting value="true" id="Update" />
-    <OptionsSetting value="true" id="Status" />
-    <OptionsSetting value="true" id="Edit" />
-    <ConfirmationsSetting value="0" id="Add" />
-    <ConfirmationsSetting value="0" id="Remove" />
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/build" />
   </component>
 </project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 3e5d2de7ad7d49098abc24bcada096b4b8ca7dd6..12768205c7c4100b1b7be33dcfc9f18fccdde23f 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,25 +2,78 @@
 <project version="4">
   <component name="ProjectModuleManager">
     <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB.iml" group="apps/BOB" />
       <module fileurl="file://$PROJECT_DIR$/apps/BOB/BOB.iml" filepath="$PROJECT_DIR$/apps/BOB/BOB.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_main.iml" group="apps/BOB" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_test.iml" group="apps/BOB" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook.iml" group="apps/addressbook" />
       <module fileurl="file://$PROJECT_DIR$/apps/addressbook/addressbook.iml" filepath="$PROJECT_DIR$/apps/addressbook/addressbook.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_main.iml" group="apps/addressbook" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_test.iml" group="apps/addressbook" />
       <module fileurl="file://$PROJECT_DIR$/apps/admin/admin.iml" filepath="$PROJECT_DIR$/apps/admin/admin.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/apps.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/apps.iml" group="apps" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core.iml" group="core" />
       <module fileurl="file://$PROJECT_DIR$/core/core.iml" filepath="$PROJECT_DIR$/core/core.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core_main.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core_main.iml" group="core" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core_test.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core_test.iml" group="core" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui.iml" group="apps/desktopgui" />
       <module fileurl="file://$PROJECT_DIR$/apps/desktopgui/desktopgui.iml" filepath="$PROJECT_DIR$/apps/desktopgui/desktopgui.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_main.iml" group="apps/desktopgui" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_test.iml" group="apps/desktopgui" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/i2p.i2p.sl.iml" filepath="$PROJECT_DIR$/.idea/modules/i2p.i2p.sl.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark.iml" group="apps/i2psnark" />
       <module fileurl="file://$PROJECT_DIR$/apps/i2psnark/i2psnark.iml" filepath="$PROJECT_DIR$/apps/i2psnark/i2psnark.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_main.iml" group="apps/i2psnark" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_test.iml" group="apps/i2psnark" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel.iml" group="apps/i2ptunnel" />
       <module fileurl="file://$PROJECT_DIR$/apps/i2ptunnel/i2ptunnel.iml" filepath="$PROJECT_DIR$/apps/i2ptunnel/i2ptunnel.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_main.iml" group="apps/i2ptunnel" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_test.iml" group="apps/i2ptunnel" />
       <module fileurl="file://$PROJECT_DIR$/apps/imagegen/identicon/identicon.iml" filepath="$PROJECT_DIR$/apps/imagegen/identicon/identicon.iml" />
       <module fileurl="file://$PROJECT_DIR$/apps/imagegen/imagegen/imagegen.iml" filepath="$PROJECT_DIR$/apps/imagegen/imagegen/imagegen.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer.iml" group="installer" />
       <module fileurl="file://$PROJECT_DIR$/installer/installer.iml" filepath="$PROJECT_DIR$/installer/installer.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer_main.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer_main.iml" group="installer" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer_test.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer_test.iml" group="installer" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty.iml" group="apps/jetty" />
       <module fileurl="file://$PROJECT_DIR$/apps/jetty/jetty.iml" filepath="$PROJECT_DIR$/apps/jetty/jetty.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_main.iml" group="apps/jetty" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_test.iml" group="apps/jetty" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin.iml" group="apps/jrobin" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_main.iml" group="apps/jrobin" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_test.iml" group="apps/jrobin" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming.iml" group="apps/ministreaming" />
       <module fileurl="file://$PROJECT_DIR$/apps/ministreaming/ministreaming.iml" filepath="$PROJECT_DIR$/apps/ministreaming/ministreaming.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_main.iml" group="apps/ministreaming" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_test.iml" group="apps/ministreaming" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router.iml" group="router" />
       <module fileurl="file://$PROJECT_DIR$/router/router.iml" filepath="$PROJECT_DIR$/router/router.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router_main.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router_main.iml" group="router" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router_test.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router_test.iml" group="router" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole.iml" group="apps/routerconsole" />
       <module fileurl="file://$PROJECT_DIR$/apps/routerconsole/routerconsole.iml" filepath="$PROJECT_DIR$/apps/routerconsole/routerconsole.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_main.iml" group="apps/routerconsole" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_test.iml" group="apps/routerconsole" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam.iml" group="apps/sam" />
       <module fileurl="file://$PROJECT_DIR$/apps/sam/sam.iml" filepath="$PROJECT_DIR$/apps/sam/sam.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam_main.iml" group="apps/sam" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam_test.iml" group="apps/sam" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming.iml" group="apps/streaming" />
       <module fileurl="file://$PROJECT_DIR$/apps/streaming/streaming.iml" filepath="$PROJECT_DIR$/apps/streaming/streaming.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_main.iml" group="apps/streaming" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_test.iml" group="apps/streaming" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns.iml" group="apps/susidns" />
       <module fileurl="file://$PROJECT_DIR$/apps/susidns/susidns.iml" filepath="$PROJECT_DIR$/apps/susidns/susidns.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_main.iml" group="apps/susidns" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_test.iml" group="apps/susidns" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail.iml" group="apps/susimail" />
       <module fileurl="file://$PROJECT_DIR$/apps/susimail/susimail.iml" filepath="$PROJECT_DIR$/apps/susimail/susimail.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_main.iml" group="apps/susimail" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_test.iml" group="apps/susimail" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray.iml" group="apps/systray" />
       <module fileurl="file://$PROJECT_DIR$/apps/systray/systray.iml" filepath="$PROJECT_DIR$/apps/systray/systray.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray_main.iml" group="apps/systray" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray_test.iml" group="apps/systray" />
       <module fileurl="file://$PROJECT_DIR$/apps/imagegen/zxing/zxing.iml" filepath="$PROJECT_DIR$/apps/imagegen/zxing/zxing.iml" />
     </modules>
   </component>
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java
index 9d8e136a1f95d19f1d70907e3951d6a8444bfd5f..d4ecee1048219c89e39961ac312289f3b08bab43 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerState.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java
@@ -11,14 +11,12 @@ import java.util.Map;
 import java.util.Set;
 import java.util.Queue;
 import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import net.i2p.data.Hash;
 import net.i2p.data.SessionKey;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.RouterContext;
-import net.i2p.router.util.CachedIteratorArrayList;
-import net.i2p.router.util.CoDelPriorityBlockingQueue;
+import net.i2p.router.util.CachedIteratorAbstractCollection;
 import net.i2p.router.util.PriBlockingQueue;
 import net.i2p.util.Log;
 import net.i2p.util.ConcurrentHashSet;
@@ -210,7 +208,7 @@ public class PeerState {
      *  Mostly messages that have been transmitted and are awaiting acknowledgement,
      *  although there could be some that have not been sent yet.
      */
-    private final List<OutboundMessageState> _outboundMessages;
+    private final CachedIteratorAbstractCollection<OutboundMessageState> _outboundMessages;
 
     /**
      *  Priority queue of messages that have not yet been sent.
@@ -370,7 +368,7 @@ public class PeerState {
         _rtt = INIT_RTT;
         _rttDeviation = _rtt;
         _inboundMessages = new HashMap<Long, InboundMessageState>(8);
-        _outboundMessages = new CachedIteratorArrayList<OutboundMessageState>(32);
+        _outboundMessages = new CachedIteratorAbstractCollection<OutboundMessageState>();
         //_outboundQueue = new CoDelPriorityBlockingQueue(ctx, "UDP-PeerState", 32);
         _outboundQueue = new PriBlockingQueue<OutboundMessageState>(ctx, "UDP-PeerState", 32);
         // all createRateStat() moved to EstablishmentManager
@@ -1568,7 +1566,7 @@ public class PeerState {
         if (_dead) {
             dropOutbound();
             return 0;
-	}
+        }
 
         int rv = 0;
         List<OutboundMessageState> succeeded = null;
@@ -1586,6 +1584,7 @@ public class PeerState {
                     iter.remove();
                     if (_retransmitter == state)
                         _retransmitter = null;
+                    _log.debug("CachedIteratorAbstractCollection: sendFailed update" + state);
                     _context.statManager().addRateData("udp.sendFailed", state.getPushCount());
                     if (failed == null) failed = new ArrayList<OutboundMessageState>(4);
                     failed.add(state);
@@ -1593,6 +1592,7 @@ public class PeerState {
                     iter.remove();
                     if (state == _retransmitter)
                         _retransmitter = null;
+                    _log.debug("CachedIteratorAbstractCollection: sendAggressiveFailed update" + state);
                     _context.statManager().addRateData("udp.sendAggressiveFailed", state.getPushCount());
                     if (failed == null) failed = new ArrayList<OutboundMessageState>(4);
                     failed.add(state);
diff --git a/router/java/src/net/i2p/router/util/CachedIteratorAbstractCollection.java b/router/java/src/net/i2p/router/util/CachedIteratorAbstractCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..304ce8379b689fcff78eeb0e4aa52479256cf821
--- /dev/null
+++ b/router/java/src/net/i2p/router/util/CachedIteratorAbstractCollection.java
@@ -0,0 +1,209 @@
+// Extend `java.util.AbstractCollection` to create a collection that can be iterated over without creation of a new
+// object
+
+// https://docs.oracle.com/javase/7/docs/api/java/util/AbstractCollection.html
+
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// The Node class below is from Java's LinkedList.java
+
+package net.i2p.router.util;
+
+import java.util.AbstractCollection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import net.i2p.I2PAppContext;
+import net.i2p.util.Log;
+
+public class CachedIteratorAbstractCollection<E> extends AbstractCollection<E> {
+
+    // FOR DEBUGGING & LOGGING PURPOSES
+    Log log = I2PAppContext.getGlobalContext().logManager().getLog(CachedIteratorAbstractCollection.class);
+
+    // Cached Iterator object
+    private final CachedIterator iterator = new CachedIterator();
+
+    // Size of the AbstractCollectionTest object
+    private transient int size = 0;
+
+    /**
+     * Node object that contains:
+     * (1) Data object
+     * (2) Link to previous Node object
+     * (3) Link to next Node object
+     */
+    private static class Node<E> {
+        E item;
+        Node<E> next;
+        Node<E> prev;
+
+        Node(Node<E> prev, E element, Node<E> next) {
+            this.item = element;
+            this.prev = prev;
+            this.next = next;
+        }
+    }
+
+    // First Node in the AbstractCollectionTest object
+    private transient Node<E> first;
+
+    // Last Node in the AbstractCollectionTest object
+    private transient Node<E> last;
+
+    /**
+     * Default constructor
+     */
+    public CachedIteratorAbstractCollection() {
+    }
+
+    /**
+     * Adds a data object (element) as a Node and sets previous/next pointers accordingly
+     *
+     */
+    @Override
+    public boolean add(E element) {
+        if (this.size == 0) {
+            final Node<E> newNode = new Node<>(null, element, null);
+            this.first = newNode;
+            this.last = newNode;
+        } else {
+            final Node<E> newLast = new Node<>(this.last, element, null);
+            this.last.next = newLast;
+            this.last = newLast;
+        }
+        this.size++;
+        log.debug("CachedIteratorAbstractCollection: Element added");
+        return true;
+    }
+
+    /**
+     *  Clears the AbstractCollectionTest object, all pointers reset to 'null'
+     *
+     */
+    @Override
+    public void clear() {
+        this.first = null;
+        this.last = null;
+        this.size = 0;
+        iterator.reset();
+        log.debug("CachedIteratorAbstractCollection: Cleared");
+    }
+
+    /**
+     *  Iterator: Resets and returns CachedIterator
+     *
+     */
+    public Iterator<E> iterator() {
+        iterator.reset();
+        return iterator;
+    }
+
+    /**
+     *  Inner CachedIterator class - implements hasNext(), next() & remove()
+     *
+     */
+    private class CachedIterator implements Iterator<E> {
+
+        private transient boolean nextCalled;
+
+        // Iteration Index
+        private transient Node<E> itrIndexNode = first;
+
+        // Methods to support iteration
+
+        /**
+         * Reset iteration
+         */
+        private void reset() {
+            itrIndexNode = first;
+            nextCalled = false;
+        }
+
+        /**
+         *  If nextCalled is true (i.e. next() has been called at least once),
+         *  remove() will remove the last returned Node
+         *
+         */
+        @Override
+        public void remove() {
+            if (nextCalled) {
+                if (itrIndexNode != null) {
+                    if (itrIndexNode.prev.prev != null) {
+                        itrIndexNode.prev = itrIndexNode.prev.prev;
+                        itrIndexNode.prev.next = itrIndexNode;
+                    } else {
+                        itrIndexNode.prev = null;
+                        first = itrIndexNode;
+                    }
+                } else {
+                    if (last.prev != null) {
+                        last.prev.next = null;
+                        last = last.prev;
+                    } else {
+                        nextCalled = false;
+                        clear();
+                        log.debug("CachedIteratorAbstractCollection: Element Removed");
+                        return;
+                    }
+                }
+                size--;
+                nextCalled = false;
+                log.debug("CachedIteratorAbstractCollection: Element Removed");
+            } else {
+                throw new IllegalStateException();
+            }
+        }
+
+        /**
+         *  Returns true as long as current Iteration Index Node (itrIndexNode)
+         *  is non-null
+         *
+         */
+        public boolean hasNext() {
+            return itrIndexNode != null;
+        }
+
+        /**
+         * Returns the next node in the iteration
+         *
+         */
+        public E next() {
+            if (this.hasNext()) {
+                Node<E> node = itrIndexNode;
+                itrIndexNode = itrIndexNode.next;
+                nextCalled = true;
+                return node.item;
+            } else {
+                throw new NoSuchElementException();
+            }
+        }
+    }
+
+    /**
+     * Return size of current LinkedListTest object
+     */
+    public int size() { return this.size; }
+}