001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.activemq.util;
018
019 /**
020 * Provides a base class for you to extend when you want object to maintain a
021 * doubly linked list to other objects without using a collection class.
022 *
023 * @author chirino
024 */
025 public class LinkedNode {
026
027 protected LinkedNode next = this;
028 protected LinkedNode prev = this;
029 protected boolean tail = true;
030
031 public LinkedNode getHeadNode() {
032 if (isHeadNode()) {
033 return this;
034 }
035 if (isTailNode()) {
036 return next;
037 }
038 LinkedNode rc = prev;
039 while (!rc.isHeadNode()) {
040 rc = rc.prev;
041 }
042 return rc;
043 }
044
045 public LinkedNode getTailNode() {
046 if (isTailNode()) {
047 return this;
048 }
049 if (isHeadNode()) {
050 return prev;
051 }
052 LinkedNode rc = next;
053 while (!rc.isTailNode()) {
054 rc = rc.next;
055 }
056 return rc;
057 }
058
059 public LinkedNode getNext() {
060 return tail ? null : next;
061 }
062
063 public LinkedNode getPrevious() {
064 return prev.tail ? null : prev;
065 }
066
067 public boolean isHeadNode() {
068 return prev.isTailNode();
069 }
070
071 public boolean isTailNode() {
072 return tail;
073 }
074
075 /**
076 * @param rightHead the node to link after this node.
077 * @return this
078 */
079 public LinkedNode linkAfter(LinkedNode rightHead) {
080
081 if (rightHead == this) {
082 throw new IllegalArgumentException("You cannot link to yourself");
083 }
084 if (!rightHead.isHeadNode()) {
085 throw new IllegalArgumentException("You only insert nodes that are the first in a list");
086 }
087
088 LinkedNode rightTail = rightHead.prev;
089
090 if (tail) {
091 tail = false;
092 } else {
093 rightTail.tail = false;
094 }
095
096 rightHead.prev = this; // link the head of the right side.
097 rightTail.next = next; // link the tail of the right side
098 next.prev = rightTail; // link the head of the left side
099 next = rightHead; // link the tail of the left side.
100
101 return this;
102 }
103
104 /**
105 * @param leftHead the node to link after this node.
106 * @return
107 * @return this
108 */
109 public LinkedNode linkBefore(LinkedNode leftHead) {
110
111 if (leftHead == this) {
112 throw new IllegalArgumentException("You cannot link to yourself");
113 }
114 if (!leftHead.isHeadNode()) {
115 throw new IllegalArgumentException("You only insert nodes that are the first in a list");
116 }
117
118 // The left side is no longer going to be a tail..
119 LinkedNode leftTail = leftHead.prev;
120 leftTail.tail = false;
121
122 leftTail.next = this; // link the tail of the left side.
123 leftHead.prev = prev; // link the head of the left side.
124 prev.next = leftHead; // link the tail of the right side.
125 prev = leftTail; // link the head of the right side.
126
127 return leftHead;
128 }
129
130 /**
131 * Removes this node out of the linked list it is chained in.
132 */
133 public void unlink() {
134 // If we are allready unlinked...
135 if (prev == this) {
136 reset();
137 return;
138 }
139
140 if (tail) {
141 prev.tail = true;
142 }
143
144 // Update the peers links..
145 next.prev = prev;
146 prev.next = next;
147
148 // Update our links..
149 reset();
150 }
151
152 public void reset() {
153 next = this;
154 prev = this;
155 tail = true;
156 }
157
158 }