View Javadoc

1   /*
2    * Copyright (C) 2003-2004 Christian Siefkes <christian@siefkes.net>.
3    * Development of this software is supported by the German Research Society,
4    * Berlin-Brandenburg Graduate School in Distributed Information Systems
5    * (DFG grant no. GRK 316).
6    *
7    * This library is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU Lesser General Public
9    * License as published by the Free Software Foundation; either
10   * version 2.1 of the License, or (at your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this library; if not, visit
19   * http://www.gnu.org/licenses/lgpl.html or write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21   */
22  package de.fu_berlin.ties.util;
23  
24  import org.apache.commons.lang.builder.ToStringBuilder;
25  
26  /***
27   * An entry in a doubly linked list. Useful when you cannot use the
28   * {@link java.util.List} implementations, e.g. because you need direct
29   * references to list entries. This class only stores a reference to the
30   * previous and next entry for list management -- you must extend it so store
31   * any useful data.
32   *
33   * @author Christian Siefkes
34   * @version $Revision: 1.3 $, $Date: 2004/08/24 18:00:38 $, $Author: siefkes $
35   */
36  public class ListEntry {
37  
38      /***
39       * Reference to the previous element in this list; <code>null</code> if this
40       * is the first element of a list.
41       */
42      private ListEntry previous = null;
43  
44      /***
45       * Reference to the next element in this list; <code>null</code> if this
46       * is the final element of a list.
47       */
48      private ListEntry next = null;
49  
50      /***
51       * Creates a new instance, without setting references to surrounding
52       * entries.
53       */
54      public ListEntry() {
55          this(null, null);
56      }
57  
58      /***
59       * Creates a new instance.
60       *
61       * @param prevEntry a reference to the previous entry, must not yet have
62       * a next element; or <code>null</code> if this is the first entry in a list
63       * @param nextEntry a reference to the next entry, must not yet have
64       * a next element; or <code>null</code> if this is the final entry in a list
65       * @throws IllegalArgumentException if <code>prevEntry</code> already has
66       * a next element ({@link #hasNext()} == <code>true</code>) or if
67       * <code>nextEntry</code> already has a previous element
68       * ({@link #hasPrevious()} == <code>true</code>)
69       */
70      public ListEntry(final ListEntry prevEntry, final ListEntry nextEntry)
71              throws IllegalArgumentException {
72          super();
73  
74          if (prevEntry != null) {
75              if (prevEntry.hasNext()) {
76                  throw new IllegalArgumentException(
77                      "Previous entry already has a next element!");
78              }
79              previous = prevEntry;
80              prevEntry.next = this;
81          }
82  
83          if (nextEntry != null) {
84              if (nextEntry.hasPrevious()) {
85                  throw new IllegalArgumentException(
86                      "Next entry already has a previous element!");
87              }
88              next = nextEntry;
89              nextEntry.previous = this;
90          }
91      }
92  
93      /***
94       * Returns <code>true</code> if there is a next element. (In other words,
95       * returns <code>true</code> if {@link #next()} would return an element
96       * rather than <code>null</code>.)
97       *
98       * @return <code>true</code> iff the list has more elements
99       */
100     public boolean hasNext() {
101         return (next != null);
102     }
103 
104     /***
105      * Returns <code>true</code> if there is a previous element. (In other
106      * words, returns <code>true</code> if {@link #previous()} would return an
107      * element rather than <code>null</code>.)
108      *
109      * @return <code>true</code> iff the list has more elements
110      */
111     public boolean hasPrevious() {
112         return (previous != null);
113     }
114 
115     /***
116      * Inserts a new element after the current one, adjusting the list structure
117      * accordingly. The new entry must not yet have a previous element (i.e.,
118      * calling {@link #hasPrevious()} must return <code>false</code>).
119      * The {@link #next()} element of either this entry or the new
120      * entry must be <code>null</code>.
121      * Inserting <code>null</code> elements is not allowed.
122      *
123      * @param newEntry the new list entry to insert
124      * @throws IllegalArgumentException if <code>newEntry</code> already has a
125      * previous element ({@link #hasPrevious()} == <code>true</code>) or
126      * both this entry and <code>newEntry</code> have a {@link #next()}
127      * element
128      * @throws NullPointerException if <code>newEntry</code> is
129      * <code>null</code>
130      */
131     public void insertAfter(final ListEntry newEntry)
132             throws IllegalArgumentException, NullPointerException {
133         if (newEntry.hasPrevious()) {
134             throw new IllegalArgumentException(
135                 "Second entry already has a previous element!");
136         }
137         if (hasNext() && newEntry.hasNext()) {
138             throw new IllegalArgumentException(
139                 "Both entries have a next element!");
140         }
141 
142         // adjust list structure: insert between this element and next one
143         if (next != null) {
144             next.previous = newEntry;
145             newEntry.next = next;
146         }
147         newEntry.previous = this;
148         next = newEntry;
149     }
150 
151     /***
152      * Inserts a new element before the current one, adjusting the list
153      * structure accordingly. If this entry has a {@link #previous()} element,
154      * the {@link #next()} element of either the new entry or the
155      * {@link #previous()} element must be <code>null</code>; otherwise the
156      * {@link #next()} element of either this entry or the new entry must be
157      * <code>null</code>.
158      * Inserting <code>null</code> elements is not allowed.
159      *
160      * @param newEntry the new list entry to insert
161      * @throws IllegalArgumentException if the conditions stated above are
162      * violated
163      * @throws NullPointerException if <code>newEntry</code> is
164      * <code>null</code>
165      */
166     public void insertBefore(final ListEntry newEntry)
167             throws IllegalArgumentException, NullPointerException {
168         if (previous != null) {
169             previous.insertAfter(newEntry);
170         } else {
171             newEntry.insertAfter(this);
172         }
173     }
174 
175     /***
176      * Returns the next element in the list, if any.
177      *
178      * @return the next element in the list, or <code>null</code> if there is
179      * no next element
180      */
181     public ListEntry next() {
182         return next;
183     }
184 
185     /***
186      * Returns the previous element in the list, if any.
187      *
188      * @return the previous element in the list, or <code>null</code> if there
189      * is no previous element
190      */
191     public ListEntry previous() {
192         return previous;
193     }
194 
195     /***
196      * Removes this entry from this list. The list structure
197      * is adjusted accordingly. Afterwards this entry won't be part of a
198      * list, i.e. both {@link #hasPrevious()} and {@link #hasNext()} will
199      * return <code>false</code>.
200      */
201     public void remove() {
202         // adjusting list structure
203         if (next != null) {
204             next.previous = previous;
205         }
206         if (previous != null) {
207             previous.next = next;
208         }
209         next = null;
210         previous = null;
211     }
212 
213     /***
214      * Returns a string representation of this object.
215      *
216      * @return a textual representation
217      */
218     public String toString() {
219         return new ToStringBuilder(this).
220             append("has previous", hasPrevious()).
221             append("has next", hasNext()).
222             toString();
223     }
224 
225 }