BasicContentHeaderProperties.java
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 = << 15;
085     private static final int ENCONDING_MASK = << 14;
086     private static final int HEADERS_MASK = << 13;
087     private static final int DELIVERY_MODE_MASK = << 12;
088     private static final int PROPRITY_MASK = << 11;
089     private static final int CORRELATION_ID_MASK = << 10;
090     private static final int REPLY_TO_MASK = << 9;
091     private static final int EXPIRATION_MASK = << 8;
092     private static final int MESSAGE_ID_MASK = << 7;
093     private static final int TIMESTAMP_MASK = << 6;
094     private static final int TYPE_MASK = << 5;
095     private static final int USER_ID_MASK = << 4;
096     private static final int APPLICATION_ID_MASK = << 3;
097     private static final int CLUSTER_ID_MASK = << 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_MASK0)
136             {
137                 size += EncodingUtils.encodedShortStringLength(_encoding);
138             }
139 
140             if ((_propertyFlags & HEADERS_MASK0)
141             {
142                 size += EncodingUtils.encodedFieldTableLength(_headers);
143             }
144 
145             if ((_propertyFlags & DELIVERY_MODE_MASK0)
146             {
147                 size += 1;
148             }
149 
150             if ((_propertyFlags & PROPRITY_MASK0)
151             {
152                 size += 1;
153             }
154 
155             if ((_propertyFlags & CORRELATION_ID_MASK0)
156             {
157                 size += EncodingUtils.encodedShortStringLength(_correlationId);
158             }
159 
160             if ((_propertyFlags & REPLY_TO_MASK0)
161             {
162                 size += EncodingUtils.encodedShortStringLength(_replyTo);
163             }
164 
165             if ((_propertyFlags & EXPIRATION_MASK0)
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_MASK0)
178             {
179                 size += EncodingUtils.encodedShortStringLength(_messageId);
180             }
181 
182             if ((_propertyFlags & TIMESTAMP_MASK0)
183             {
184                 size += 8;
185             }
186 
187             if ((_propertyFlags & TYPE_MASK0)
188             {
189                 size += EncodingUtils.encodedShortStringLength(_type);
190             }
191 
192             if ((_propertyFlags & USER_ID_MASK0)
193             {
194                 size += EncodingUtils.encodedShortStringLength(_userId);
195             }
196 
197             if ((_propertyFlags & APPLICATION_ID_MASK0)
198             {
199                 size += EncodingUtils.encodedShortStringLength(_appId);
200             }
201 
202             if ((_propertyFlags & CLUSTER_ID_MASK0)
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 sizethrows 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 == nullnull : _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 == nullnull new AMQShortString(contentType));
523     }
524 
525     public String getEncodingAsString()
526     {
527 
528         return (getEncoding() == nullnull : 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 == nullnull 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 == nullnull : _correlationId.toString();
614     }
615 
616     public void setCorrelationId(String correlationId)
617     {
618          _hasBeenUpdated = true;
619         setCorrelationId((correlationId == nullnull 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 == nullnull : _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 == nullnull 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 == nullnull : _messageId.toString();
683     }
684 
685     public void setMessageId(String messageId)
686     {
687         _hasBeenUpdated = true;
688         clearEncodedForm();
689         _propertyFlags |= MESSAGE_ID_MASK;
690         _messageId = (messageId == nullnull 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 == nullnull : _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 == nullnull 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 == nullnull : _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 == nullnull 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 == nullnull : _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 == nullnull 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 == nullnull : _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 == nullnull 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 }