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.command;
018
019import java.util.concurrent.atomic.AtomicReference;
020
021/**
022 * @openwire:marshaller code="110"
023 *
024 */
025public class MessageId implements DataStructure, Comparable<MessageId> {
026
027    public static final byte DATA_STRUCTURE_TYPE = CommandTypes.MESSAGE_ID;
028
029    protected String textView;
030    protected ProducerId producerId;
031    protected long producerSequenceId;
032    protected long brokerSequenceId;
033
034    private transient String key;
035    private transient int hashCode;
036
037    private transient AtomicReference<Object> dataLocator = new AtomicReference<Object>();
038    private transient Object entryLocator;
039    private transient Object plistLocator;
040    private transient Object futureOrSequenceLong;
041
042    public MessageId() {
043        this.producerId = new ProducerId();
044    }
045
046    public MessageId(ProducerInfo producerInfo, long producerSequenceId) {
047        this.producerId = producerInfo.getProducerId();
048        this.producerSequenceId = producerSequenceId;
049    }
050
051    public MessageId(String messageKey) {
052        setValue(messageKey);
053    }
054
055    public MessageId(String producerId, long producerSequenceId) {
056        this(new ProducerId(producerId), producerSequenceId);
057    }
058
059    public MessageId(ProducerId producerId, long producerSequenceId) {
060        this.producerId = producerId;
061        this.producerSequenceId = producerSequenceId;
062    }
063
064    /**
065     * Sets the value as a String
066     */
067    public void setValue(String messageKey) {
068        key = messageKey;
069        // Parse off the sequenceId
070        int p = messageKey.lastIndexOf(":");
071        if (p >= 0) {
072            producerSequenceId = Long.parseLong(messageKey.substring(p + 1));
073            messageKey = messageKey.substring(0, p);
074        } else {
075            throw new NumberFormatException();
076        }
077        producerId = new ProducerId(messageKey);
078    }
079
080    /**
081     * Sets the transient text view of the message which will be ignored if the message is marshaled on a transport; so
082     * is only for in-JVM changes to accommodate foreign JMS message IDs
083     */
084    public void setTextView(String key) {
085        this.textView = key;
086    }
087
088    /**
089     * @openwire:property version=10
090     * @return
091     */
092    public String getTextView() {
093        return textView;
094    }
095
096    @Override
097    public byte getDataStructureType() {
098        return DATA_STRUCTURE_TYPE;
099    }
100
101    @Override
102    public boolean equals(Object o) {
103        if (this == o) {
104            return true;
105        }
106        if (o == null || o.getClass() != getClass()) {
107            return false;
108        }
109
110        MessageId id = (MessageId) o;
111        return producerSequenceId == id.producerSequenceId && producerId.equals(id.producerId);
112    }
113
114    @Override
115    public int hashCode() {
116        if (hashCode == 0) {
117            hashCode = producerId.hashCode() ^ (int) producerSequenceId;
118        }
119        return hashCode;
120    }
121
122    public String toProducerKey() {
123        if (textView == null) {
124            return toString();
125        } else {
126            return producerId.toString() + ":" + producerSequenceId;
127        }
128    }
129
130    @Override
131    public String toString() {
132        if (key == null) {
133            if (textView != null) {
134                if (textView.startsWith("ID:")) {
135                    key = textView;
136                } else {
137                    key = "ID:" + textView;
138                }
139            } else {
140                key = producerId.toString() + ":" + producerSequenceId;
141            }
142        }
143        return key;
144    }
145
146    /**
147     * @openwire:property version=1 cache=true
148     */
149    public ProducerId getProducerId() {
150        return producerId;
151    }
152
153    public void setProducerId(ProducerId producerId) {
154        this.producerId = producerId;
155    }
156
157    /**
158     * @openwire:property version=1
159     */
160    public long getProducerSequenceId() {
161        return producerSequenceId;
162    }
163
164    public void setProducerSequenceId(long producerSequenceId) {
165        this.producerSequenceId = producerSequenceId;
166    }
167
168    /**
169     * @openwire:property version=1
170     */
171    public long getBrokerSequenceId() {
172        return brokerSequenceId;
173    }
174
175    public void setBrokerSequenceId(long brokerSequenceId) {
176        this.brokerSequenceId = brokerSequenceId;
177    }
178
179    @Override
180    public boolean isMarshallAware() {
181        return false;
182    }
183
184    public MessageId copy() {
185        MessageId copy = new MessageId(producerId, producerSequenceId);
186        copy.key = key;
187        copy.brokerSequenceId = brokerSequenceId;
188        copy.dataLocator = dataLocator;
189        copy.entryLocator = entryLocator;
190        copy.futureOrSequenceLong = futureOrSequenceLong;
191        copy.plistLocator = plistLocator;
192        copy.textView = textView;
193        return copy;
194    }
195
196    /**
197     * @param
198     * @return
199     * @see java.lang.Comparable#compareTo(java.lang.Object)
200     */
201    @Override
202    public int compareTo(MessageId other) {
203        int result = -1;
204        if (other != null) {
205            result = this.toString().compareTo(other.toString());
206        }
207        return result;
208    }
209
210    /**
211     * @return a locator which aids a message store in loading a message faster. Only used by the message stores.
212     */
213    public Object getDataLocator() {
214        return dataLocator.get();
215    }
216
217    /**
218     * Sets a locator which aids a message store in loading a message faster. Only used by the message stores.
219     */
220    public void setDataLocator(Object value) {
221        this.dataLocator.set(value);
222    }
223
224    public Object getFutureOrSequenceLong() {
225        return futureOrSequenceLong;
226    }
227
228    public void setFutureOrSequenceLong(Object futureOrSequenceLong) {
229        this.futureOrSequenceLong = futureOrSequenceLong;
230    }
231
232    public Object getEntryLocator() {
233        return entryLocator;
234    }
235
236    public void setEntryLocator(Object entryLocator) {
237        this.entryLocator = entryLocator;
238    }
239
240    public Object getPlistLocator() {
241        return plistLocator;
242    }
243
244    public void setPlistLocator(Object plistLocator) {
245        this.plistLocator = plistLocator;
246    }
247
248    private Object readResolve() {
249        dataLocator = new AtomicReference<Object>();
250        return this;
251    }
252}