001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.framing;
022
023 import org.apache.mina.common.ByteBuffer;
024
025 import org.slf4j.Logger;
026 import org.slf4j.LoggerFactory;
027
028 public class BasicContentHeaderProperties implements CommonContentHeaderProperties
029 {
030 private static final Logger _logger = LoggerFactory.getLogger(BasicContentHeaderProperties.class);
031
032 private static final AMQShortString ZERO_STRING = null;
033
034 /**
035 * We store the encoded form when we decode the content header so that if we need to write it out without modifying
036 * it we can do so without incurring the expense of reencoding it
037 */
038 private byte[] _encodedForm;
039
040 /** Flag indicating whether the entire content header has been decoded yet */
041 private boolean _decoded = true;
042
043 /**
044 * We have some optimisations for partial decoding for maximum performance. The headers are used in the broker for
045 * routing in some cases so we can decode that separately.
046 */
047 private boolean _decodedHeaders = true;
048
049 /**
050 * We have some optimisations for partial decoding for maximum performance. The content type is used by all clients
051 * to determine the message type
052 */
053 private boolean _decodedContentType = true;
054
055 private AMQShortString _contentType;
056
057 private AMQShortString _encoding;
058
059 private FieldTable _headers;
060
061 private byte _deliveryMode;
062
063 private byte _priority;
064
065 private AMQShortString _correlationId;
066
067 private AMQShortString _replyTo;
068
069 private long _expiration;
070
071 private AMQShortString _messageId;
072
073 private long _timestamp;
074
075 private AMQShortString _type;
076
077 private AMQShortString _userId;
078
079 private AMQShortString _appId;
080
081 private AMQShortString _clusterId;
082
083 private int _propertyFlags = 0;
084 private static final int CONTENT_TYPE_MASK = 1 << 15;
085 private static final int ENCONDING_MASK = 1 << 14;
086 private static final int HEADERS_MASK = 1 << 13;
087 private static final int DELIVERY_MODE_MASK = 1 << 12;
088 private static final int PROPRITY_MASK = 1 << 11;
089 private static final int CORRELATION_ID_MASK = 1 << 10;
090 private static final int REPLY_TO_MASK = 1 << 9;
091 private static final int EXPIRATION_MASK = 1 << 8;
092 private static final int MESSAGE_ID_MASK = 1 << 7;
093 private static final int TIMESTAMP_MASK = 1 << 6;
094 private static final int TYPE_MASK = 1 << 5;
095 private static final int USER_ID_MASK = 1 << 4;
096 private static final int APPLICATION_ID_MASK = 1 << 3;
097 private static final int CLUSTER_ID_MASK = 1 << 2;
098
099
100 /**
101 * This is 0_10 specific. We use this property to check if some message properties have been changed.
102 */
103 private boolean _hasBeenUpdated = false;
104
105 public boolean reset()
106 {
107 boolean result = _hasBeenUpdated;
108 _hasBeenUpdated = false;
109 return result;
110 }
111
112 public void updated()
113 {
114 _hasBeenUpdated = true;
115 }
116
117 public BasicContentHeaderProperties()
118 { }
119
120 public int getPropertyListSize()
121 {
122 if (_encodedForm != null)
123 {
124 return _encodedForm.length;
125 }
126 else
127 {
128 int size = 0;
129
130 if ((_propertyFlags & (CONTENT_TYPE_MASK)) > 0)
131 {
132 size += EncodingUtils.encodedShortStringLength(_contentType);
133 }
134
135 if ((_propertyFlags & ENCONDING_MASK) > 0)
136 {
137 size += EncodingUtils.encodedShortStringLength(_encoding);
138 }
139
140 if ((_propertyFlags & HEADERS_MASK) > 0)
141 {
142 size += EncodingUtils.encodedFieldTableLength(_headers);
143 }
144
145 if ((_propertyFlags & DELIVERY_MODE_MASK) > 0)
146 {
147 size += 1;
148 }
149
150 if ((_propertyFlags & PROPRITY_MASK) > 0)
151 {
152 size += 1;
153 }
154
155 if ((_propertyFlags & CORRELATION_ID_MASK) > 0)
156 {
157 size += EncodingUtils.encodedShortStringLength(_correlationId);
158 }
159
160 if ((_propertyFlags & REPLY_TO_MASK) > 0)
161 {
162 size += EncodingUtils.encodedShortStringLength(_replyTo);
163 }
164
165 if ((_propertyFlags & EXPIRATION_MASK) > 0)
166 {
167 if (_expiration == 0L)
168 {
169 size += EncodingUtils.encodedShortStringLength(ZERO_STRING);
170 }
171 else
172 {
173 size += EncodingUtils.encodedShortStringLength(_expiration);
174 }
175 }
176
177 if ((_propertyFlags & MESSAGE_ID_MASK) > 0)
178 {
179 size += EncodingUtils.encodedShortStringLength(_messageId);
180 }
181
182 if ((_propertyFlags & TIMESTAMP_MASK) > 0)
183 {
184 size += 8;
185 }
186
187 if ((_propertyFlags & TYPE_MASK) > 0)
188 {
189 size += EncodingUtils.encodedShortStringLength(_type);
190 }
191
192 if ((_propertyFlags & USER_ID_MASK) > 0)
193 {
194 size += EncodingUtils.encodedShortStringLength(_userId);
195 }
196
197 if ((_propertyFlags & APPLICATION_ID_MASK) > 0)
198 {
199 size += EncodingUtils.encodedShortStringLength(_appId);
200 }
201
202 if ((_propertyFlags & CLUSTER_ID_MASK) > 0)
203 {
204 size += EncodingUtils.encodedShortStringLength(_clusterId);
205 }
206
207 return size;
208 }
209 }
210
211 private void clearEncodedForm()
212 {
213 if (!_decoded && (_encodedForm != null))
214 {
215 // decode();
216 }
217
218 _encodedForm = null;
219 }
220
221 public void setPropertyFlags(int propertyFlags)
222 {
223 _hasBeenUpdated = true;
224 clearEncodedForm();
225 _propertyFlags = propertyFlags;
226 }
227
228 public int getPropertyFlags()
229 {
230 return _propertyFlags;
231 }
232
233 public void writePropertyListPayload(ByteBuffer buffer)
234 {
235 if (_encodedForm != null)
236 {
237 buffer.put(_encodedForm);
238 }
239 else
240 {
241 if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
242 {
243 EncodingUtils.writeShortStringBytes(buffer, _contentType);
244 }
245
246 if ((_propertyFlags & ENCONDING_MASK) != 0)
247 {
248 EncodingUtils.writeShortStringBytes(buffer, _encoding);
249 }
250
251 if ((_propertyFlags & HEADERS_MASK) != 0)
252 {
253 EncodingUtils.writeFieldTableBytes(buffer, _headers);
254 }
255
256 if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
257 {
258 buffer.put(_deliveryMode);
259 }
260
261 if ((_propertyFlags & PROPRITY_MASK) != 0)
262 {
263 buffer.put(_priority);
264 }
265
266 if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
267 {
268 EncodingUtils.writeShortStringBytes(buffer, _correlationId);
269 }
270
271 if ((_propertyFlags & REPLY_TO_MASK) != 0)
272 {
273 EncodingUtils.writeShortStringBytes(buffer, _replyTo);
274 }
275
276 if ((_propertyFlags & EXPIRATION_MASK) != 0)
277 {
278 if (_expiration == 0L)
279 {
280 EncodingUtils.writeShortStringBytes(buffer, ZERO_STRING);
281 }
282 else
283 {
284 EncodingUtils.writeShortStringBytes(buffer, String.valueOf(_expiration));
285 }
286 }
287
288 if ((_propertyFlags & MESSAGE_ID_MASK) != 0)
289 {
290 EncodingUtils.writeShortStringBytes(buffer, _messageId);
291 }
292
293 if ((_propertyFlags & TIMESTAMP_MASK) != 0)
294 {
295 EncodingUtils.writeTimestamp(buffer, _timestamp);
296 }
297
298 if ((_propertyFlags & TYPE_MASK) != 0)
299 {
300 EncodingUtils.writeShortStringBytes(buffer, _type);
301 }
302
303 if ((_propertyFlags & USER_ID_MASK) != 0)
304 {
305 EncodingUtils.writeShortStringBytes(buffer, _userId);
306 }
307
308 if ((_propertyFlags & APPLICATION_ID_MASK) != 0)
309 {
310 EncodingUtils.writeShortStringBytes(buffer, _appId);
311 }
312
313 if ((_propertyFlags & CLUSTER_ID_MASK) != 0)
314 {
315 EncodingUtils.writeShortStringBytes(buffer, _clusterId);
316 }
317 }
318 }
319
320 public void populatePropertiesFromBuffer(ByteBuffer buffer, int propertyFlags, int size) throws AMQFrameDecodingException
321 {
322 _propertyFlags = propertyFlags;
323
324 if (_logger.isDebugEnabled())
325 {
326 _logger.debug("Property flags: " + _propertyFlags);
327 }
328
329 decode(buffer);
330 /*_encodedForm = new byte[size];
331 buffer.get(_encodedForm, 0, size);
332 _decoded = false;
333 _decodedHeaders = false;
334 _decodedContentType = false;*/
335 }
336
337 private void decode(ByteBuffer buffer)
338 {
339 // ByteBuffer buffer = ByteBuffer.wrap(_encodedForm);
340 int pos = buffer.position();
341 try
342 {
343 if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
344 {
345 _contentType = EncodingUtils.readAMQShortString(buffer);
346 }
347
348 if ((_propertyFlags & ENCONDING_MASK) != 0)
349 {
350 _encoding = EncodingUtils.readAMQShortString(buffer);
351 }
352
353 if ((_propertyFlags & HEADERS_MASK) != 0)
354 {
355 _headers = EncodingUtils.readFieldTable(buffer);
356 }
357
358 if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
359 {
360 _deliveryMode = buffer.get();
361 }
362
363 if ((_propertyFlags & PROPRITY_MASK) != 0)
364 {
365 _priority = buffer.get();
366 }
367
368 if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
369 {
370 _correlationId = EncodingUtils.readAMQShortString(buffer);
371 }
372
373 if ((_propertyFlags & REPLY_TO_MASK) != 0)
374 {
375 _replyTo = EncodingUtils.readAMQShortString(buffer);
376 }
377
378 if ((_propertyFlags & EXPIRATION_MASK) != 0)
379 {
380 _expiration = EncodingUtils.readLongAsShortString(buffer);
381 }
382
383 if ((_propertyFlags & MESSAGE_ID_MASK) != 0)
384 {
385 _messageId = EncodingUtils.readAMQShortString(buffer);
386 }
387
388 if ((_propertyFlags & TIMESTAMP_MASK) != 0)
389 {
390 _timestamp = EncodingUtils.readTimestamp(buffer);
391 }
392
393 if ((_propertyFlags & TYPE_MASK) != 0)
394 {
395 _type = EncodingUtils.readAMQShortString(buffer);
396 }
397
398 if ((_propertyFlags & USER_ID_MASK) != 0)
399 {
400 _userId = EncodingUtils.readAMQShortString(buffer);
401 }
402
403 if ((_propertyFlags & APPLICATION_ID_MASK) != 0)
404 {
405 _appId = EncodingUtils.readAMQShortString(buffer);
406 }
407
408 if ((_propertyFlags & CLUSTER_ID_MASK) != 0)
409 {
410 _clusterId = EncodingUtils.readAMQShortString(buffer);
411 }
412 }
413 catch (AMQFrameDecodingException e)
414 {
415 throw new RuntimeException("Error in content header data: " + e, e);
416 }
417
418 final int endPos = buffer.position();
419 buffer.position(pos);
420 final int len = endPos - pos;
421 _encodedForm = new byte[len];
422 final int limit = buffer.limit();
423 buffer.limit(endPos);
424 buffer.get(_encodedForm, 0, len);
425 buffer.limit(limit);
426 buffer.position(endPos);
427 _decoded = true;
428 }
429
430 private void decodeUpToHeaders()
431 {
432 ByteBuffer buffer = ByteBuffer.wrap(_encodedForm);
433 try
434 {
435 if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
436 {
437 byte length = buffer.get();
438 buffer.skip(length);
439 }
440
441 if ((_propertyFlags & ENCONDING_MASK) != 0)
442 {
443 byte length = buffer.get();
444 buffer.skip(length);
445 }
446
447 if ((_propertyFlags & HEADERS_MASK) != 0)
448 {
449 _headers = EncodingUtils.readFieldTable(buffer);
450
451 }
452
453 _decodedHeaders = true;
454 }
455 catch (AMQFrameDecodingException e)
456 {
457 throw new RuntimeException("Error in content header data: " + e, e);
458 }
459 }
460
461 private void decodeUpToContentType()
462 {
463 ByteBuffer buffer = ByteBuffer.wrap(_encodedForm);
464
465 if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
466 {
467 _contentType = EncodingUtils.readAMQShortString(buffer);
468 }
469
470 _decodedContentType = true;
471 }
472
473 private void decodeIfNecessary()
474 {
475 if (!_decoded)
476 {
477 // decode();
478 }
479 }
480
481 private void decodeHeadersIfNecessary()
482 {
483 if (!_decoded && !_decodedHeaders)
484 {
485 decodeUpToHeaders();
486 }
487 }
488
489 private void decodeContentTypeIfNecessary()
490 {
491 if (!_decoded && !_decodedContentType)
492 {
493 decodeUpToContentType();
494 }
495 }
496
497 public AMQShortString getContentType()
498 {
499 decodeContentTypeIfNecessary();
500
501 return _contentType;
502 }
503
504 public String getContentTypeAsString()
505 {
506 decodeContentTypeIfNecessary();
507
508 return (_contentType == null) ? null : _contentType.toString();
509 }
510
511 public void setContentType(AMQShortString contentType)
512 {
513 _hasBeenUpdated = true;
514 clearEncodedForm();
515 _propertyFlags |= (CONTENT_TYPE_MASK);
516 _contentType = contentType;
517 }
518
519 public void setContentType(String contentType)
520 {
521 _hasBeenUpdated = true;
522 setContentType((contentType == null) ? null : new AMQShortString(contentType));
523 }
524
525 public String getEncodingAsString()
526 {
527
528 return (getEncoding() == null) ? null : getEncoding().toString();
529 }
530
531 public AMQShortString getEncoding()
532 {
533 decodeIfNecessary();
534
535 return _encoding;
536 }
537
538 public void setEncoding(String encoding)
539 {
540 _hasBeenUpdated = true;
541 clearEncodedForm();
542 _propertyFlags |= ENCONDING_MASK;
543 _encoding = (encoding == null) ? null : new AMQShortString(encoding);
544 }
545
546 public void setEncoding(AMQShortString encoding)
547 {
548 _hasBeenUpdated = true;
549 clearEncodedForm();
550 _propertyFlags |= ENCONDING_MASK;
551 _encoding = encoding;
552 }
553
554 public FieldTable getHeaders()
555 {
556 decodeHeadersIfNecessary();
557
558 if (_headers == null)
559 {
560 setHeaders(FieldTableFactory.newFieldTable());
561 }
562
563 return _headers;
564 }
565
566 public void setHeaders(FieldTable headers)
567 {
568 _hasBeenUpdated = true;
569 clearEncodedForm();
570 _propertyFlags |= HEADERS_MASK;
571 _headers = headers;
572 }
573
574 public byte getDeliveryMode()
575 {
576 decodeIfNecessary();
577
578 return _deliveryMode;
579 }
580
581 public void setDeliveryMode(byte deliveryMode)
582 {
583 clearEncodedForm();
584 _propertyFlags |= DELIVERY_MODE_MASK;
585 _deliveryMode = deliveryMode;
586 }
587
588 public byte getPriority()
589 {
590 decodeIfNecessary();
591
592 return _priority;
593 }
594
595 public void setPriority(byte priority)
596 {
597 clearEncodedForm();
598 _propertyFlags |= PROPRITY_MASK;
599 _priority = priority;
600 }
601
602 public AMQShortString getCorrelationId()
603 {
604 decodeIfNecessary();
605
606 return _correlationId;
607 }
608
609 public String getCorrelationIdAsString()
610 {
611 decodeIfNecessary();
612
613 return (_correlationId == null) ? null : _correlationId.toString();
614 }
615
616 public void setCorrelationId(String correlationId)
617 {
618 _hasBeenUpdated = true;
619 setCorrelationId((correlationId == null) ? null : new AMQShortString(correlationId));
620 }
621
622 public void setCorrelationId(AMQShortString correlationId)
623 {
624 _hasBeenUpdated = true;
625 clearEncodedForm();
626 _propertyFlags |= CORRELATION_ID_MASK;
627 _correlationId = correlationId;
628 }
629
630 public String getReplyToAsString()
631 {
632 decodeIfNecessary();
633
634 return (_replyTo == null) ? null : _replyTo.toString();
635 }
636
637 public AMQShortString getReplyTo()
638 {
639 decodeIfNecessary();
640
641 return _replyTo;
642 }
643
644 public void setReplyTo(String replyTo)
645 {
646 _hasBeenUpdated = true;
647 setReplyTo((replyTo == null) ? null : new AMQShortString(replyTo));
648 }
649
650 public void setReplyTo(AMQShortString replyTo)
651 {
652 _hasBeenUpdated = true;
653 clearEncodedForm();
654 _propertyFlags |= REPLY_TO_MASK;
655 _replyTo = replyTo;
656 }
657
658 public long getExpiration()
659 {
660 decodeIfNecessary();
661 return _expiration;
662 }
663
664 public void setExpiration(long expiration)
665 {
666 clearEncodedForm();
667 _propertyFlags |= EXPIRATION_MASK;
668 _expiration = expiration;
669 }
670
671 public AMQShortString getMessageId()
672 {
673 decodeIfNecessary();
674
675 return _messageId;
676 }
677
678 public String getMessageIdAsString()
679 {
680 decodeIfNecessary();
681
682 return (_messageId == null) ? null : _messageId.toString();
683 }
684
685 public void setMessageId(String messageId)
686 {
687 _hasBeenUpdated = true;
688 clearEncodedForm();
689 _propertyFlags |= MESSAGE_ID_MASK;
690 _messageId = (messageId == null) ? null : new AMQShortString(messageId);
691 }
692
693 public void setMessageId(AMQShortString messageId)
694 {
695 _hasBeenUpdated = true;
696 clearEncodedForm();
697 _propertyFlags |= MESSAGE_ID_MASK;
698 _messageId = messageId;
699 }
700
701 public long getTimestamp()
702 {
703 decodeIfNecessary();
704 return _timestamp;
705 }
706
707 public void setTimestamp(long timestamp)
708 {
709 clearEncodedForm();
710 _propertyFlags |= TIMESTAMP_MASK;
711 _timestamp = timestamp;
712 }
713
714 public String getTypeAsString()
715 {
716 decodeIfNecessary();
717
718 return (_type == null) ? null : _type.toString();
719 }
720
721 public AMQShortString getType()
722 {
723 decodeIfNecessary();
724
725 return _type;
726 }
727
728 public void setType(String type)
729 {
730 _hasBeenUpdated = true;
731 setType((type == null) ? null : new AMQShortString(type));
732 }
733
734 public void setType(AMQShortString type)
735 {
736 _hasBeenUpdated = true;
737 clearEncodedForm();
738 _propertyFlags |= TYPE_MASK;
739 _type = type;
740 }
741
742 public String getUserIdAsString()
743 {
744 decodeIfNecessary();
745
746 return (_userId == null) ? null : _userId.toString();
747 }
748
749 public AMQShortString getUserId()
750 {
751 decodeIfNecessary();
752
753 return _userId;
754 }
755
756 public void setUserId(String userId)
757 {
758 setUserId((userId == null) ? null : new AMQShortString(userId));
759 }
760
761 public void setUserId(AMQShortString userId)
762 {
763 _hasBeenUpdated = true;
764 clearEncodedForm();
765 _propertyFlags |= USER_ID_MASK;
766 _userId = userId;
767 }
768
769 public String getAppIdAsString()
770 {
771 decodeIfNecessary();
772
773 return (_appId == null) ? null : _appId.toString();
774 }
775
776 public AMQShortString getAppId()
777 {
778 decodeIfNecessary();
779
780 return _appId;
781 }
782
783 public void setAppId(String appId)
784 {
785 _hasBeenUpdated = true;
786 setAppId((appId == null) ? null : new AMQShortString(appId));
787 }
788
789 public void setAppId(AMQShortString appId)
790 {
791 _hasBeenUpdated = true;
792 clearEncodedForm();
793 _propertyFlags |= APPLICATION_ID_MASK;
794 _appId = appId;
795 _hasBeenUpdated = true;
796 }
797
798 public String getClusterIdAsString()
799 {
800 _hasBeenUpdated = true;
801 decodeIfNecessary();
802 return (_clusterId == null) ? null : _clusterId.toString();
803 }
804
805 public AMQShortString getClusterId()
806 {
807 _hasBeenUpdated = true;
808 decodeIfNecessary();
809 return _clusterId;
810 }
811
812 public void setClusterId(String clusterId)
813 {
814 _hasBeenUpdated = true;
815 setClusterId((clusterId == null) ? null : new AMQShortString(clusterId));
816 }
817
818 public void setClusterId(AMQShortString clusterId)
819 {
820 _hasBeenUpdated = true;
821 clearEncodedForm();
822 _propertyFlags |= CLUSTER_ID_MASK;
823 _clusterId = clusterId;
824 }
825
826 public String toString()
827 {
828 return "reply-to = " + _replyTo + ",propertyFlags = " + _propertyFlags + ",ApplicationID = " + _appId
829 + ",ClusterID = " + _clusterId + ",UserId = " + _userId + ",JMSMessageID = " + _messageId
830 + ",JMSCorrelationID = " + _correlationId + ",JMSDeliveryMode = " + _deliveryMode + ",JMSExpiration = "
831 + _expiration + ",JMSPriority = " + _priority + ",JMSTimestamp = " + _timestamp + ",JMSType = " + _type;
832 }
833
834 }
|