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 */
017package 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 */
025public 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 this
107     */
108    public LinkedNode linkBefore(LinkedNode leftHead) {
109
110        if (leftHead == this) {
111            throw new IllegalArgumentException("You cannot link to yourself");
112        }
113        if (!leftHead.isHeadNode()) {
114            throw new IllegalArgumentException("You only insert nodes that are the first in a list");
115        }
116
117        // The left side is no longer going to be a tail..
118        LinkedNode leftTail = leftHead.prev;
119        leftTail.tail = false;
120
121        leftTail.next = this; // link the tail of the left side.
122        leftHead.prev = prev; // link the head of the left side.
123        prev.next = leftHead; // link the tail of the right side.
124        prev = leftTail; // link the head of the right side.
125
126        return leftHead;
127    }
128
129    /**
130     * Removes this node out of the linked list it is chained in.
131     */
132    public void unlink() {
133        // If we are allready unlinked...
134        if (prev == this) {
135            reset();
136            return;
137        }
138
139        if (tail) {
140            prev.tail = true;
141        }
142
143        // Update the peers links..
144        next.prev = prev;
145        prev.next = next;
146
147        // Update our links..
148        reset();
149    }
150
151    public void reset() {
152        next = this;
153        prev = this;
154        tail = true;
155    }
156}