001    /**
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.activemq.tool;
019    
020    import java.util.ArrayList;
021    import java.util.List;
022    
023    import javax.jms.JMSException;
024    import javax.jms.Message;
025    import javax.jms.MessageListener;
026    
027    
028    import org.apache.commons.logging.Log;
029    import org.apache.commons.logging.LogFactory;
030    
031    /**
032     * A simple container of messages for performing testing and rendezvous style
033     * code. You can use this class a {@link MessageListener} and then make
034     * assertions about how many messages it has received allowing a certain maximum
035     * amount of time to ensure that the test does not hang forever.
036     * <p/>
037     * Also you can chain these instances together with the
038     * {@link #setParent(MessageListener)} method so that you can aggregate the
039     * total number of messages consumed across a number of consumers.
040     *
041     * @version $Revision: 1.6 $
042     */
043    public class MemMessageIdList implements MessageListener {
044    
045        protected static final Log log = LogFactory.getLog(MemMessageIdList.class);
046    
047        private List messageIds = new ArrayList();
048        private Object semaphore;
049        private boolean verbose;
050        private MessageListener parent;
051        private long maximumDuration = 15000L;
052    
053        public MemMessageIdList() {
054            this(new Object());
055        }
056    
057        public MemMessageIdList(Object semaphore) {
058            this.semaphore = semaphore;
059        }
060    
061        public boolean equals(Object that) {
062            if (that instanceof MemMessageIdList) {
063                MemMessageIdList thatListMem = (MemMessageIdList) that;
064                return getMessageIds().equals(thatListMem.getMessageIds());
065            }
066            return false;
067        }
068    
069        public int hashCode() {
070            synchronized (semaphore) {
071                return messageIds.hashCode() + 1;
072            }
073        }
074    
075        public String toString() {
076            synchronized (semaphore) {
077                return messageIds.toString();
078            }
079        }
080    
081        /**
082         * @return all the messages on the list so far, clearing the buffer
083         */
084        public List flushMessages() {
085            synchronized (semaphore) {
086                List answer = new ArrayList(messageIds);
087                messageIds.clear();
088                return answer;
089            }
090        }
091    
092        public synchronized List getMessageIds() {
093            synchronized (semaphore) {
094                return new ArrayList(messageIds);
095            }
096        }
097    
098        public void onMessage(Message message) {
099            String id = null;
100            try {
101                id = message.getJMSMessageID();
102                synchronized (semaphore) {
103                    messageIds.add(id);
104                    semaphore.notifyAll();
105                }
106                if (verbose) {
107                    log.info("Received message: " + message);
108                }
109            } catch (JMSException e) {
110                e.printStackTrace();
111            }
112            if (parent != null) {
113                parent.onMessage(message);
114            }
115        }
116    
117        public int getMessageCount() {
118            synchronized (semaphore) {
119                return messageIds.size();
120            }
121        }
122    
123        public void waitForMessagesToArrive(int messageCount) {
124            log.info("Waiting for " + messageCount + " message(s) to arrive");
125    
126            long start = System.currentTimeMillis();
127    
128            for (int i = 0; i < messageCount; i++) {
129                try {
130                    if (hasReceivedMessages(messageCount)) {
131                        break;
132                    }
133                    long duration = System.currentTimeMillis() - start;
134                    if (duration >= maximumDuration) {
135                        break;
136                    }
137                    synchronized (semaphore) {
138                        semaphore.wait(maximumDuration - duration);
139                    }
140                } catch (InterruptedException e) {
141                    log.info("Caught: " + e);
142                }
143            }
144            long end = System.currentTimeMillis() - start;
145    
146            log.info("End of wait for " + end + " millis and received: " + getMessageCount() + " messages");
147        }
148    
149    
150        public boolean hasReceivedMessage() {
151            return getMessageCount() == 0;
152        }
153    
154        public boolean hasReceivedMessages(int messageCount) {
155            return getMessageCount() >= messageCount;
156        }
157    
158        public boolean isVerbose() {
159            return verbose;
160        }
161    
162        public void setVerbose(boolean verbose) {
163            this.verbose = verbose;
164        }
165    
166        public MessageListener getParent() {
167            return parent;
168        }
169    
170        /**
171         * Allows a parent listener to be specified such as to aggregate messages
172         * consumed across consumers
173         */
174        public void setParent(MessageListener parent) {
175            this.parent = parent;
176        }
177    
178    }