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; } +}