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            return this.map.containsKey(message.getMessageId());
141        }
142        return false;
143    }
144
145    @Override
146    public Collection<MessageReference> values() {
147        return getValues(this);
148    }
149
150    public static Collection<MessageReference> getValues(final PendingList pendingList) {
151        List<MessageReference> messageReferences = new ArrayList<MessageReference>();
152        Iterator<MessageReference> iterator = pendingList.iterator();
153        while (iterator.hasNext()) {
154            messageReferences.add(iterator.next());
155        }
156        return messageReferences;
157    }
158
159    @Override
160    public void addAll(PendingList pendingList) {
161        if (pendingList != null) {
162            for(MessageReference messageReference : pendingList) {
163                addMessageLast(messageReference);
164            }
165        }
166    }
167
168    @Override
169    public MessageReference get(MessageId messageId) {
170        PendingNode node = map.get(messageId);
171        if (node != null) {
172            return node.getMessage();
173        }
174        return null;
175    }
176
177    public void insertAtHead(List<MessageReference> list) {
178        if (list != null && !list.isEmpty()) {
179            PendingNode newHead = null;
180            PendingNode appendNode = null;
181            for (MessageReference ref : list) {
182                PendingNode node = new PendingNode(this, ref);
183                this.map.put(ref.getMessageId(), node);
184                if (newHead == null) {
185                    newHead = node;
186                    appendNode = node;
187                    continue;
188                }
189                appendNode.linkAfter(node);
190                appendNode = node;
191            }
192            // insert this new list at root
193            if (root == null) {
194                root = newHead;
195                tail = appendNode;
196            } else {
197                appendNode.linkAfter(root);
198                root = newHead;
199            }
200        }
201    }
202
203}