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    }