001: package org.drools.reteoo;
002:
003: import java.io.Serializable;
004: import java.util.Iterator;
005: import java.util.NoSuchElementException;
006:
007: /*
008: * Copyright 2005 JBoss Inc
009: *
010: * Licensed under the Apache License, Version 2.0 (the "License");
011: * you may not use this file except in compliance with the License.
012: * You may obtain a copy of the License at
013: *
014: * http://www.apache.org/licenses/LICENSE-2.0
015: *
016: * Unless required by applicable law or agreed to in writing, software
017: * distributed under the License is distributed on an "AS IS" BASIS,
018: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019: * See the License for the specific language governing permissions and
020: * limitations under the License.
021: */
022:
023: /**
024: * This is a simple linked linked implementation. Each node must implement </code>LinkedListNode<code> so that it references
025: * the node before and after it. This way a node can be removed without having to scan the list to find it. This class
026: * does not provide an Iterator implementation as its designed for efficiency and not genericity. There are a number of
027: * ways to iterate the list.
028: * <p>
029: * Simple iterator:
030: * <pre>
031: * for ( LinkedListNode node = list.getFirst(); node != null; node = node.getNext() ) {
032: * }
033: * </pre>
034: *
035: * Iterator that pops the first entry:
036: * <pre>
037: * for ( LinkedListNode node = list.removeFirst(); node != null; node = list.removeFirst() ) {
038: * }
039: * </pre>
040: *
041: *
042: * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a>
043: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
044: *
045: */
046: public class ObjectSinkNodeList implements Serializable {
047: private static final long serialVersionUID = 400L;
048:
049: private ObjectSinkNode firstNode;
050: private ObjectSinkNode lastNode;
051:
052: private int size;
053:
054: /**
055: * Construct an empty <code>LinkedList</code>
056: */
057: public ObjectSinkNodeList() {
058:
059: }
060:
061: /**
062: * Add a <code>ObjectSinkNode</code> to the list. If the <code>LinkedList</code> is empty then the first and
063: * last nodes are set to the added node.
064: *
065: * @param node
066: * The <code>ObjectSinkNode</code> to be added
067: */
068: public void add(final ObjectSinkNode node) {
069: if (this .firstNode == null) {
070: this .firstNode = node;
071: this .lastNode = node;
072: ;
073: } else {
074: this .lastNode.setNextObjectSinkNode(node);
075: node.setPreviousObjectSinkNode(this .lastNode);
076: this .lastNode = node;
077: }
078: this .size++;
079: }
080:
081: /**
082: * Removes a <code>ObjectSinkNode</code> from the list. This works by attach the previous reference to the child reference.
083: * When the node to be removed is the first node it calls <code>removeFirst()</code>. When the node to be removed is the last node
084: * it calls <code>removeLast()</code>.
085: *
086: * @param node
087: * The <code>ObjectSinkNode</code> to be removed.
088: */
089: public void remove(final ObjectSinkNode node) {
090: if ((this .firstNode != node) && (this .lastNode != node)) {
091: node.getPreviousObjectSinkNode().setNextObjectSinkNode(
092: node.getNextObjectSinkNode());
093: node.getNextObjectSinkNode().setPreviousObjectSinkNode(
094: node.getPreviousObjectSinkNode());
095: this .size--;
096: node.setPreviousObjectSinkNode(null);
097: node.setNextObjectSinkNode(null);
098:
099: } else {
100: if (this .firstNode == node) {
101: removeFirst();
102: } else if (this .lastNode == node) {
103: removeLast();
104: }
105: }
106: }
107:
108: /**
109: * Return the first node in the list
110: * @return
111: * The first <code>ObjectSinkNode</code>.
112: */
113: public final ObjectSinkNode getFirst() {
114: return this .firstNode;
115: }
116:
117: /**
118: * Return the last node in the list
119: * @return
120: * The last <code>ObjectSinkNode</code>.
121: */
122: public final ObjectSinkNode getLast() {
123: return this .lastNode;
124: }
125:
126: /**
127: * Remove the first node from the list. The next node then becomes the first node. If this is the last
128: * node then both first and last node references are set to null.
129: *
130: * @return
131: * The first <code>ObjectSinkNode</code>.
132: */
133: public ObjectSinkNode removeFirst() {
134: if (this .firstNode == null) {
135: return null;
136: }
137: final ObjectSinkNode node = this .firstNode;
138: this .firstNode = node.getNextObjectSinkNode();
139: node.setNextObjectSinkNode(null);
140: if (this .firstNode != null) {
141: this .firstNode.setPreviousObjectSinkNode(null);
142: } else {
143: this .lastNode = null;
144: }
145: this .size--;
146: return node;
147: }
148:
149: /**
150: * Remove the last node from the list. The previous node then becomes the last node. If this is the last
151: * node then both first and last node references are set to null.
152: *
153: * @return
154: * The first <code>ObjectSinkNode</code>.
155: */
156: public ObjectSinkNode removeLast() {
157: if (this .lastNode == null) {
158: return null;
159: }
160: final ObjectSinkNode node = this .lastNode;
161: this .lastNode = node.getPreviousObjectSinkNode();
162: node.setPreviousObjectSinkNode(null);
163: if (this .lastNode != null) {
164: this .lastNode.setNextObjectSinkNode(null);
165: } else {
166: this .firstNode = this .lastNode;
167: }
168: this .size--;
169: return node;
170: }
171:
172: /**
173: * @return
174: * boolean value indicating the empty status of the list
175: */
176: public final boolean isEmpty() {
177: return (this .firstNode == null);
178: }
179:
180: /**
181: * Iterates the list removing all the nodes until there are no more nodes to remove.
182: */
183: public void clear() {
184: while (removeFirst() != null) {
185: }
186: }
187:
188: /**
189: * @return
190: * return size of the list as an int
191: */
192: public final int size() {
193: return this .size;
194: }
195:
196: /**
197: * Returns a list iterator
198: * @return
199: */
200: public Iterator iterator() {
201: return new Iterator() {
202: private ObjectSinkNode currentNode = null;
203: private ObjectSinkNode nextNode = getFirst();
204:
205: public boolean hasNext() {
206: return (this .nextNode != null);
207: }
208:
209: public Object next() {
210: this .currentNode = this .nextNode;
211: if (this .currentNode != null) {
212: this .nextNode = this .currentNode
213: .getNextObjectSinkNode();
214: } else {
215: throw new NoSuchElementException(
216: "No more elements to return");
217: }
218: return this .currentNode;
219: }
220:
221: public void remove() {
222: if (this .currentNode != null) {
223: ObjectSinkNodeList.this .remove(this .currentNode);
224: this .currentNode = null;
225: } else {
226: throw new IllegalStateException(
227: "No item to remove. Call next() before calling remove().");
228: }
229: }
230: };
231: }
232:
233: }
|