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.broker.region.cursors;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashMap;
022import java.util.Iterator;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.activemq.broker.region.MessageReference;
027import org.apache.activemq.command.MessageId;
028
029public class OrderedPendingList implements PendingList {
030
031    private PendingNode root = null;
032    private PendingNode tail = null;
033    private final Map<MessageId, PendingNode> map = new HashMap<MessageId, PendingNode>();
034
035    public PendingNode addMessageFirst(MessageReference message) {
036        PendingNode node = new PendingNode(this, message);
037        if (root == null) {
038            root = node;
039            tail = node;
040        } else {
041            root.linkBefore(node);
042            root = node;
043        }
044        this.map.put(message.getMessageId(), node);
045        return node;
046    }
047
048    public PendingNode addMessageLast(MessageReference message) {
049        PendingNode node = new PendingNode(this, message);
050        if (root == null) {
051            root = node;
052        } else {
053            tail.linkAfter(node);
054        }
055        tail = node;
056        this.map.put(message.getMessageId(), node);
057        return node;
058    }
059
060    public void clear() {
061        this.root = null;
062        this.tail = null;
063        this.map.clear();
064    }
065
066    public boolean isEmpty() {
067        return this.map.isEmpty();
068    }
069
070    public Iterator<MessageReference> iterator() {
071        return new Iterator<MessageReference>() {
072            private PendingNode current = null;
073            private PendingNode next = root;
074
075            public boolean hasNext() {
076                return next != null;
077            }
078
079            public MessageReference next() {
080                MessageReference result = null;
081                this.current = this.next;
082                result = this.current.getMessage();
083                this.next = (PendingNode) this.next.getNext();
084                return result;
085            }
086
087            public void remove() {
088                if (this.current != null && this.current.getMessage() != null) {
089                    map.remove(this.current.getMessage().getMessageId());
090                }
091                removeNode(this.current);
092            }
093        };
094    }
095
096    public PendingNode remove(MessageReference message) {
097        PendingNode node = null;
098        if (message != null) {
099            node = this.map.remove(message.getMessageId());
100            removeNode(node);
101        }
102        return node;
103    }
104
105    public int size() {
106        return this.map.size();
107    }
108
109    void removeNode(PendingNode node) {
110        if (node != null) {
111            map.remove(node.getMessage().getMessageId());
112            if (root == node) {
113                root = (PendingNode) node.getNext();
114            }
115            if (tail == node) {
116                tail = (PendingNode) node.getPrevious();
117            }
118            node.unlink();
119        }
120    }
121
122    List<PendingNode> getAsList() {
123        List<PendingNode> result = new ArrayList<PendingNode>(size());
124        PendingNode node = root;
125        while (node != null) {
126            result.add(node);
127            node = (PendingNode) node.getNext();
128        }
129        return result;
130    }
131
132    @Override
133    public String toString() {
134        return "OrderedPendingList(" + System.identityHashCode(this) + ")";
135    }
136
137    @Override
138    public boolean contains(MessageReference message) {
139        if (message != null) {
140            for (PendingNode value : map.values()) {
141                if (value.getMessage().equals(message)) {
142                    return true;
143                }
144            }
145        }
146        return false;
147    }
148
149    @Override
150    public Collection<MessageReference> values() {
151        return getValues(this);
152    }
153
154    public static Collection<MessageReference> getValues(final PendingList pendingList) {
155        List<MessageReference> messageReferences = new ArrayList<MessageReference>();
156        Iterator<MessageReference> iterator = pendingList.iterator();
157        while (iterator.hasNext()) {
158            messageReferences.add(iterator.next());
159        }
160        return messageReferences;
161    }
162
163    @Override
164    public void addAll(PendingList pendingList) {
165        if (pendingList != null) {
166            for(MessageReference messageReference : pendingList) {
167                addMessageLast(messageReference);
168            }
169        }
170    }
171
172    @Override
173    public MessageReference get(MessageId messageId) {
174        PendingNode node = map.get(messageId);
175        if (node != null) {
176            return node.getMessage();
177        }
178        return null;
179    }
180
181    public void insertAtHead(List<MessageReference> list) {
182        if (list != null && !list.isEmpty()) {
183            PendingNode newHead = null;
184            PendingNode appendNode = null;
185            for (MessageReference ref : list) {
186                PendingNode node = new PendingNode(this, ref);
187                this.map.put(ref.getMessageId(), node);
188                if (newHead == null) {
189                    newHead = node;
190                    appendNode = node;
191                    continue;
192                }
193                appendNode.linkAfter(node);
194                appendNode = node;
195            }
196            // insert this new list at root
197            if (root == null) {
198                root = newHead;
199                tail = appendNode;
200            } else {
201                appendNode.linkAfter(root);
202                root = newHead;
203            }
204        }
205    }
206
207}