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
029
030import static org.apache.activemq.broker.region.cursors.OrderedPendingList.getValues;
031
032public class PrioritizedPendingList implements PendingList {
033
034    private static final Integer MAX_PRIORITY = 10;
035    private final OrderedPendingList[] lists = new OrderedPendingList[MAX_PRIORITY];
036    private final Map<MessageId, PendingNode> map = new HashMap<MessageId, PendingNode>();
037
038    public PrioritizedPendingList() {
039        for (int i = 0; i < MAX_PRIORITY; i++) {
040            this.lists[i] = new OrderedPendingList();
041        }
042    }
043
044    public PendingNode addMessageFirst(MessageReference message) {
045        PendingNode node = getList(message).addMessageFirst(message);
046        this.map.put(message.getMessageId(), node);
047        return node;
048    }
049
050    public PendingNode addMessageLast(MessageReference message) {
051        PendingNode node = getList(message).addMessageLast(message);
052        this.map.put(message.getMessageId(), node);
053        return node;
054    }
055
056    public void clear() {
057        for (int i = 0; i < MAX_PRIORITY; i++) {
058            this.lists[i].clear();
059        }
060        this.map.clear();
061    }
062
063    public boolean isEmpty() {
064        return this.map.isEmpty();
065    }
066
067    public Iterator<MessageReference> iterator() {
068        return new PrioritizedPendingListIterator();
069    }
070
071    public PendingNode remove(MessageReference message) {
072        PendingNode node = null;
073        if (message != null) {
074            node = this.map.remove(message.getMessageId());
075            if (node != null) {
076                node.getList().removeNode(node);
077            }
078        }
079        return node;
080    }
081
082    public int size() {
083        return this.map.size();
084    }
085
086    @Override
087    public String toString() {
088        return "PrioritizedPendingList(" + System.identityHashCode(this) + ")";
089    }
090
091    protected int getPriority(MessageReference message) {
092        int priority = javax.jms.Message.DEFAULT_PRIORITY;
093        if (message.getMessageId() != null) {
094            priority = Math.max(message.getMessage().getPriority(), 0);
095            priority = Math.min(priority, 9);
096        }
097        return priority;
098    }
099
100    protected OrderedPendingList getList(MessageReference msg) {
101        return lists[getPriority(msg)];
102    }
103
104    private class PrioritizedPendingListIterator implements Iterator<MessageReference> {
105        private int index = 0;
106        private int currentIndex = 0;
107        List<PendingNode> list = new ArrayList<PendingNode>(size());
108
109        PrioritizedPendingListIterator() {
110            for (int i = MAX_PRIORITY - 1; i >= 0; i--) {
111                OrderedPendingList orderedPendingList = lists[i];
112                if (!orderedPendingList.isEmpty()) {
113                    list.addAll(orderedPendingList.getAsList());
114                }
115            }
116        }
117        public boolean hasNext() {
118            return list.size() > index;
119        }
120
121        public MessageReference next() {
122            PendingNode node = list.get(this.index);
123            this.currentIndex = this.index;
124            this.index++;
125            return node.getMessage();
126        }
127
128        public void remove() {
129            PendingNode node = list.get(this.currentIndex);
130            if (node != null) {
131                map.remove(node.getMessage().getMessageId());
132                node.getList().removeNode(node);
133            }
134        }
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    @Override
151    public void addAll(PendingList pendingList) {
152        for(MessageReference messageReference : pendingList) {
153            addMessageLast(messageReference);
154        }
155    }
156
157    @Override
158    public MessageReference get(MessageId messageId) {
159        PendingNode node = map.get(messageId);
160        if (node != null) {
161            return node.getMessage();
162        }
163        return null;
164    }
165
166}