AMQMessageDelegate_0_10.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 
022 package org.apache.qpid.client.message;
023 
024 import org.apache.commons.collections.map.ReferenceMap;
025 import org.apache.qpid.client.*;
026 import org.apache.qpid.framing.ContentHeaderProperties;
027 import org.apache.qpid.framing.BasicContentHeaderProperties;
028 import org.apache.qpid.framing.AMQShortString;
029 import org.apache.qpid.framing.FieldTable;
030 import org.apache.qpid.AMQException;
031 import org.apache.qpid.AMQPInvalidClassException;
032 import org.apache.qpid.jms.Message;
033 import org.apache.qpid.url.BindingURL;
034 import org.apache.qpid.url.AMQBindingURL;
035 import org.apache.mina.common.ByteBuffer;
036 import org.apache.qpid.transport.*;
037 
038 import javax.jms.Destination;
039 import javax.jms.JMSException;
040 import javax.jms.MessageNotWriteableException;
041 import javax.jms.MessageFormatException;
042 import javax.jms.DeliveryMode;
043 import java.util.*;
044 import java.util.concurrent.ConcurrentHashMap;
045 import java.net.URISyntaxException;
046 import java.nio.charset.Charset;
047 import org.apache.qpid.exchange.ExchangeDefaults;
048 
049 public class AMQMessageDelegate_0_10 implements AMQMessageDelegate
050 {
051     private static final Map<ReplyTo, Destination> _destinationCache = Collections.synchronizedMap(new ReferenceMap());
052 
053     public static final String JMS_TYPE = "x-jms-type";
054 
055 
056     private boolean _readableProperties = false;
057 
058     private Destination _destination;
059 
060 
061     private MessageProperties _messageProps;
062     private DeliveryProperties _deliveryProps;
063     /** If the acknowledge mode is CLIENT_ACKNOWLEDGE the session is required */
064     private AMQSession _session;
065     private final long _deliveryTag;
066 
067     private static Map<AMQShortString,Integer> _exchangeTypeMap = new ConcurrentHashMap<AMQShortString, Integer>();
068     private static Map<String,Integer> _exchangeTypeStringMap = new ConcurrentHashMap<String, Integer>();
069     private static Map<String, Integer> _exchangeTypeToDestinationType = new ConcurrentHashMap<String, Integer>();;
070 
071     static
072     {
073         _exchangeTypeMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME, AMQDestination.QUEUE_TYPE);
074         _exchangeTypeMap.put(AMQShortString.EMPTY_STRING, AMQDestination.QUEUE_TYPE);
075         _exchangeTypeMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
076         _exchangeTypeMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME, AMQDestination.TOPIC_TYPE);
077 
078         _exchangeTypeStringMap.put(ExchangeDefaults.DIRECT_EXCHANGE_NAME.toString(), AMQDestination.QUEUE_TYPE);
079         _exchangeTypeStringMap.put("", AMQDestination.QUEUE_TYPE);
080         _exchangeTypeStringMap.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
081         _exchangeTypeStringMap.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
082 
083 
084         _exchangeTypeToDestinationType.put(ExchangeDefaults.DIRECT_EXCHANGE_CLASS.toString(), AMQDestination.QUEUE_TYPE);
085         _exchangeTypeToDestinationType.put(ExchangeDefaults.TOPIC_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
086         _exchangeTypeToDestinationType.put(ExchangeDefaults.FANOUT_EXCHANGE_NAME.toString(), AMQDestination.TOPIC_TYPE);
087     }
088 
089     protected AMQMessageDelegate_0_10()
090     {
091         this(new MessageProperties()new DeliveryProperties(), -1);
092         _readableProperties = false;
093     }
094 
095     protected AMQMessageDelegate_0_10(long deliveryTag, MessageProperties messageProps, DeliveryProperties deliveryProps, AMQShortString exchange,
096                                       AMQShortString routingKeythrows AMQException
097     {
098         this(messageProps, deliveryProps, deliveryTag);
099 
100 
101         AMQDestination dest;
102 
103         dest = generateDestination(exchange, routingKey);
104         setJMSDestination(dest);
105     }
106 
107     private AMQDestination generateDestination(AMQShortString exchange, AMQShortString routingKey)
108     {
109         AMQDestination dest;
110         switch(getExchangeType(exchange))
111         {
112             case AMQDestination.QUEUE_TYPE:
113                 dest = new AMQQueue(exchange, routingKey, routingKey);
114                 break;
115             case  AMQDestination.TOPIC_TYPE:
116                 dest = new AMQTopic(exchange, routingKey, null);
117                 break;
118             default:
119                 dest = new AMQUndefinedDestination(exchange, routingKey, null);
120 
121         }
122 
123         return dest;
124     }
125 
126     private int getExchangeType(AMQShortString exchange)
127     {
128         Integer type = _exchangeTypeMap.get(exchange == null ? AMQShortString.EMPTY_STRING : exchange);
129 
130         if(type == null)
131         {
132             return AMQDestination.UNKNOWN_TYPE;
133         }
134 
135 
136         return type;
137     }
138 
139 
140     public static void updateExchangeTypeMapping(Header header, org.apache.qpid.transport.Session session)
141     {
142         DeliveryProperties deliveryProps = header.get(DeliveryProperties.class);
143         if(deliveryProps != null)
144         {
145             String exchange = deliveryProps.getExchange();
146 
147             if(exchange != null && !_exchangeTypeStringMap.containsKey(exchange))
148             {
149 
150                 AMQShortString exchangeShortString = new AMQShortString(exchange);
151                 Future<ExchangeQueryResult> future =
152                                 session.exchangeQuery(exchange.toString());
153                 ExchangeQueryResult res = future.get();
154 
155                 Integer type = _exchangeTypeToDestinationType.get(res.getType());
156                 if(type == null)
157                 {
158                     type = AMQDestination.UNKNOWN_TYPE;
159                 }
160                 _exchangeTypeStringMap.put(exchange, type);
161                 _exchangeTypeMap.put(exchangeShortString, type);
162 
163             }
164         }
165     }
166 
167     protected AMQMessageDelegate_0_10(MessageProperties messageProps, DeliveryProperties deliveryProps, long deliveryTag)
168     {
169         _messageProps = messageProps;
170         _deliveryProps = deliveryProps;
171         _deliveryTag = deliveryTag;
172         _readableProperties = (_messageProps != null);
173 
174     }
175 
176 
177     public String getJMSMessageID() throws JMSException
178     {
179         UUID id = _messageProps.getMessageId();
180         return id == null null "ID:" + id;
181     }
182 
183     public void setJMSMessageID(String messageIdthrows JMSException
184     {
185         if(messageId == null)
186         {
187             _messageProps.clearMessageId();
188         }
189         else
190         {
191             if(messageId.startsWith("ID:"))
192             {
193                 try
194                 {
195                     _messageProps.setMessageId(UUID.fromString(messageId.substring(3)));
196                 }
197                 catch(IllegalArgumentException ex)
198                 {
199                     throw new JMSException("MessageId '"+messageId+"' is not of the correct format, it must be ID: followed by a UUID");
200                 }
201             }
202             else
203             {
204                 throw new JMSException("MessageId '"+messageId+"' is not of the correct format, it must be ID: followed by a UUID");
205             }
206         }
207     }
208 
209     public void setJMSMessageID(UUID messageIdthrows JMSException
210     {
211         if(messageId == null)
212         {
213             _messageProps.clearMessageId();
214         }
215         else
216         {
217             _messageProps.setMessageId(messageId);
218         }
219     }
220 
221 
222     public long getJMSTimestamp() throws JMSException
223     {
224         return _deliveryProps.getTimestamp();
225     }
226 
227     public void setJMSTimestamp(long timestampthrows JMSException
228     {
229         _deliveryProps.setTimestamp(timestamp);
230     }
231 
232     public byte[] getJMSCorrelationIDAsBytes() throws JMSException
233     {
234         return _messageProps.getCorrelationId();
235     }
236 
237     public void setJMSCorrelationIDAsBytes(byte[] bytesthrows JMSException
238     {
239         _messageProps.setCorrelationId(bytes);
240     }
241 
242     public void setJMSCorrelationID(String correlationIdthrows JMSException
243     {
244 
245         setJMSCorrelationIDAsBytes(correlationId == null null : correlationId.getBytes());
246     }
247 
248     public String getJMSCorrelationID() throws JMSException
249     {
250 
251         byte[] correlationIDAsBytes = getJMSCorrelationIDAsBytes();
252         return correlationIDAsBytes == null null new String(correlationIDAsBytes);
253     }
254 
255     public Destination getJMSReplyTo()
256     {
257         ReplyTo replyTo = _messageProps.getReplyTo();
258 
259         if (replyTo == null)
260         {
261             return null;
262         }
263         else
264         {
265             Destination dest = _destinationCache.get(replyTo);
266             if (dest == null)
267             {
268                 String exchange = replyTo.getExchange();
269                 String routingKey = replyTo.getRoutingKey();
270 
271                 dest = generateDestination(exchange == null null new AMQShortString(exchange),
272                         routingKey == null null new AMQShortString(routingKey));
273 
274 
275 
276 
277 
278                 _destinationCache.put(replyTo, dest);
279             }
280 
281             return dest;
282         }
283     }
284 
285     public void setJMSReplyTo(Destination destinationthrows JMSException
286     {
287         if (destination == null)
288         {
289             _messageProps.setReplyTo(null);
290             return;
291         }
292 
293         if (!(destination instanceof AMQDestination))
294         {
295             throw new IllegalArgumentException(
296                 "ReplyTo destination may only be an AMQDestination - passed argument was type " + destination.getClass());
297         }
298 
299         final AMQDestination amqd = (AMQDestinationdestination;
300 
301         final ReplyTo replyTo = new ReplyTo(amqd.getExchangeName().toString(), amqd.getRoutingKey().toString());
302         _destinationCache.put(replyTo, destination);
303         _messageProps.setReplyTo(replyTo);
304 
305     }
306 
307     public Destination getJMSDestination() throws JMSException
308     {
309         return _destination;
310     }
311 
312     public void setJMSDestination(Destination destination)
313     {
314         _destination = destination;
315     }
316 
317     public void setContentType(String contentType)
318     {
319         _messageProps.setContentType(contentType);
320     }
321 
322     public String getContentType()
323     {
324         return _messageProps.getContentType();
325     }
326 
327     public void setEncoding(String encoding)
328     {
329         if(encoding == null || encoding.length() == 0)
330         {
331             _messageProps.clearContentEncoding();
332         }
333         else
334         {
335             _messageProps.setContentEncoding(encoding);
336         }
337     }
338 
339     public String getEncoding()
340     {
341         return _messageProps.getContentEncoding();
342     }
343 
344     public String getReplyToString()
345     {
346         Destination replyTo = getJMSReplyTo();
347         if(replyTo != null)
348         {
349             return ((AMQDestination)replyTo).toURL();
350         }
351         else
352         {
353             return null;
354         }
355 
356     }
357 
358     public int getJMSDeliveryMode() throws JMSException
359     {
360 
361         MessageDeliveryMode deliveryMode = _deliveryProps.getDeliveryMode();
362         if(deliveryMode != null)
363         {
364             switch(deliveryMode)
365             {
366                 case PERSISTENT :
367                     return DeliveryMode.PERSISTENT;
368                 case NON_PERSISTENT:
369                     return DeliveryMode.NON_PERSISTENT;
370                 default:
371                     throw new JMSException("Unknown Message Delivery Mode: " + _deliveryProps.getDeliveryMode());
372             }
373         }
374         else
375         {
376             return Message.DEFAULT_DELIVERY_MODE;
377         }
378 
379     }
380 
381     public void setJMSDeliveryMode(int deliveryModethrows JMSException
382     {
383         switch(deliveryMode)
384         {
385             case DeliveryMode.PERSISTENT:
386                 _deliveryProps.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
387                 break;
388             case DeliveryMode.NON_PERSISTENT:
389                 _deliveryProps.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
390                 break;
391             default:
392                 throw new JMSException("Unknown JMS Delivery Mode: " + deliveryMode);
393         }
394 
395     }
396 
397 
398     public String getJMSType() throws JMSException
399     {
400         if(getApplicationHeaders().containsKey(JMS_TYPE))
401         {
402             return getStringProperty(JMS_TYPE);
403         }
404         else
405         {
406             return null;
407         }
408     }
409 
410     private Map<String, Object> getApplicationHeaders()
411     {
412         Map<String, Object> map = _messageProps.getApplicationHeaders();
413         return map == null ? Collections.EMPTY_MAP : map;
414     }
415 
416     public void setJMSType(String typethrows JMSException
417     {
418         Map<String, Object> headers = _messageProps.getApplicationHeaders();
419         if(type == null)
420         {
421             if(headers != null)
422             {
423                 headers.remove(JMS_TYPE);
424             }
425         }
426         else
427         {
428             if(headers == null)
429             {
430                 headers = new HashMap<String,Object>();
431                 _messageProps.setApplicationHeaders(headers);
432 
433             }
434             headers.put(JMS_TYPE, type);
435         }
436     }
437 
438     public long getJMSExpiration() throws JMSException
439     {
440         return _deliveryProps.getExpiration();
441     }
442 
443     public void setJMSExpiration(long lthrows JMSException
444     {
445         _deliveryProps.setExpiration(l);
446     }
447 
448 
449 
450     public boolean propertyExists(String propertyNamethrows JMSException
451     {
452         return getApplicationHeaders().containsKey(propertyName);
453     }
454 
455     public boolean getBooleanProperty(String propertyNamethrows JMSException
456     {
457         checkPropertyName(propertyName);
458 
459         Object o = getApplicationHeaders().get(propertyName);
460 
461         if(instanceof Boolean)
462         {
463             return ((Boolean)o).booleanValue();
464         }
465         else if(instanceof String)
466         {
467             return Boolean.valueOf((Stringo).booleanValue();
468         }
469         else if(getApplicationHeaders().containsKey(propertyName))
470         {
471             throw new MessageFormatException("getBooleanProperty(\""+propertyName+"\") failed as value is not boolean: " + o);
472         }
473         else
474         {
475             return Boolean.valueOf(null);
476         }
477     }
478 
479     public byte getByteProperty(String propertyNamethrows JMSException
480     {
481         checkPropertyName(propertyName);
482 
483         Map<String, Object> propertyMap = getApplicationHeaders();
484 
485         Object o = propertyMap.get(propertyName);
486 
487         if(instanceof Byte)
488         {
489             return ((Byte)o).byteValue();
490         }
491         else if(instanceof String)
492         {
493             return Byte.valueOf((Stringo).byteValue();
494         }
495         else if(getApplicationHeaders().containsKey(propertyName))
496         {
497             throw new MessageFormatException("getByteProperty(\""+propertyName+"\") failed as value is not a byte: " + o);
498         }
499         else
500         {
501             return Byte.valueOf(null);
502         }
503     }
504 
505     public short getShortProperty(String propertyNamethrows JMSException
506     {
507         checkPropertyName(propertyName);
508 
509         Map<String, Object> propertyMap = getApplicationHeaders();
510 
511         Object o = propertyMap.get(propertyName);
512 
513         if(instanceof Short)
514         {
515             return ((Short)o).shortValue();
516         }
517         else
518         {
519             try
520             {
521                 return Short.valueOf(getByteProperty(propertyName));
522             }
523             catch(MessageFormatException e)
524             {
525                 throw new MessageFormatException("getShortProperty(\""+propertyName+"\") failed as value is not a short: " + o);
526             }
527         }
528 
529 
530     }
531 
532     public int getIntProperty(String propertyNamethrows JMSException
533     {
534         checkPropertyName(propertyName);
535 
536         Map<String, Object> propertyMap = getApplicationHeaders();
537 
538         Object o = propertyMap.get(propertyName);
539 
540         if(instanceof Integer)
541         {
542             return ((Integer)o).intValue();
543         }
544         else
545         {
546             try
547             {
548                 return Integer.valueOf(getShortProperty(propertyName));
549             }
550             catch(MessageFormatException e)
551             {
552                 throw new MessageFormatException("getIntProperty(\""+propertyName+"\") failed as value is not an int: " + o);
553             }
554 
555         }
556     }
557 
558     public long getLongProperty(String propertyNamethrows JMSException
559     {
560         checkPropertyName(propertyName);
561 
562         Map<String, Object> propertyMap = getApplicationHeaders();
563 
564         Object o = propertyMap.get(propertyName);
565 
566         if(instanceof Long)
567         {
568             return ((Long)o).longValue();
569         }
570         else
571         {
572             try
573             {
574                 return Long.valueOf(getIntProperty(propertyName));
575             }
576             catch(MessageFormatException e)
577             {
578                 throw new MessageFormatException("getLongProperty(\""+propertyName+"\") failed as value is not a long: " + o);
579             }
580 
581         }
582     }
583 
584     public float getFloatProperty(String propertyNamethrows JMSException
585     {
586         checkPropertyName(propertyName);
587         Map<String, Object> propertyMap = getApplicationHeaders();
588 
589         Object o = propertyMap.get(propertyName);
590 
591         if(instanceof Float)
592         {
593             return ((Float)o).floatValue();
594         }
595         else if(instanceof String)
596         {
597             return Float.valueOf((Stringo).floatValue();
598         }
599         else if(getApplicationHeaders().containsKey(propertyName))
600         {
601             throw new MessageFormatException("getFloatProperty(\""+propertyName+"\") failed as value is not a float: " + o);
602         }
603         else
604         {
605             return Float.valueOf(null);
606         }
607 
608     }
609 
610     public double getDoubleProperty(String propertyNamethrows JMSException
611     {
612         checkPropertyName(propertyName);
613 
614         Map<String, Object> propertyMap = getApplicationHeaders();
615 
616         Object o = propertyMap.get(propertyName);
617 
618         if(instanceof Double)
619         {
620             return ((Double)o).doubleValue();
621         }
622         else
623         {
624             try
625             {
626                 return Double.valueOf(getFloatProperty(propertyName));
627             }
628             catch(MessageFormatException e)
629             {
630                 throw new MessageFormatException("getDoubleProperty(\""+propertyName+"\") failed as value is not a double: " + o);
631             }
632 
633         }
634     }
635 
636     public String getStringProperty(String propertyNamethrows JMSException
637     {
638         if (propertyName.equals(CustomJMSXProperty.JMSXUserID.toString()))
639         {
640             return new String(_messageProps.getUserId());
641         }
642         else
643         {
644             checkPropertyName(propertyName);
645             Map<String, Object> propertyMap = getApplicationHeaders();
646 
647             Object o = propertyMap.get(propertyName);
648 
649             if(instanceof String)
650             {
651                 return (Stringo;
652             }
653             else if(o == null)
654             {
655                 return null;
656             }
657             else if(o.getClass().isArray())
658             {
659                 throw new MessageFormatException("getString(\""+propertyName+"\") failed as value of type " + o.getClass()" is an array.");
660             }
661             else
662             {
663                 return String.valueOf(o);
664             }
665 
666         }
667     }
668 
669     public Object getObjectProperty(String propertyNamethrows JMSException
670     {
671         checkPropertyName(propertyName);
672         Map<String, Object> propertyMap = getApplicationHeaders();
673 
674         return propertyMap.get(propertyName);
675 
676     }
677 
678     public Enumeration getPropertyNames() throws JMSException
679     {
680         return java.util.Collections.enumeration(getApplicationHeaders().keySet());
681     }
682 
683     public void setBooleanProperty(String propertyName, boolean bthrows JMSException
684     {
685         checkPropertyName(propertyName);
686         checkWritableProperties();
687         setApplicationHeader(propertyName, b);
688     }
689 
690     public void setByteProperty(String propertyName, byte bthrows JMSException
691     {
692         checkPropertyName(propertyName);
693         checkWritableProperties();
694         setApplicationHeader(propertyName, b);
695     }
696 
697     public void setShortProperty(String propertyName, short ithrows JMSException
698     {
699         checkPropertyName(propertyName);
700         checkWritableProperties();
701         setApplicationHeader(propertyName, i);
702     }
703 
704     public void setIntProperty(String propertyName, int ithrows JMSException
705     {
706         checkPropertyName(propertyName);
707         checkWritableProperties();
708         setApplicationHeader(propertyName, i);
709     }
710 
711     public void setLongProperty(String propertyName, long lthrows JMSException
712     {
713         checkPropertyName(propertyName);
714         checkWritableProperties();
715         setApplicationHeader(propertyName, l);
716     }
717 
718     public void setFloatProperty(String propertyName, float fthrows JMSException
719     {
720         checkPropertyName(propertyName);
721         checkWritableProperties();
722         setApplicationHeader(propertyName, f);
723     }
724 
725     public void setDoubleProperty(String propertyName, double vthrows JMSException
726     {
727         checkPropertyName(propertyName);
728         checkWritableProperties();
729         setApplicationHeader(propertyName, v);
730     }
731 
732     public void setStringProperty(String propertyName, String valuethrows JMSException
733     {
734         checkPropertyName(propertyName);
735         checkWritableProperties();
736         setApplicationHeader(propertyName, value);
737     }
738 
739     private static final Set<Class> ALLOWED = new HashSet();
740     static
741     {
742         ALLOWED.add(Boolean.class);
743         ALLOWED.add(Byte.class);
744         ALLOWED.add(Short.class);
745         ALLOWED.add(Integer.class);
746         ALLOWED.add(Long.class);
747         ALLOWED.add(Float.class);
748         ALLOWED.add(Double.class);
749         ALLOWED.add(Character.class);
750         ALLOWED.add(String.class);
751         ALLOWED.add(byte[].class);
752     }
753 
754     public void setObjectProperty(String propertyName, Object objectthrows JMSException
755     {
756         checkPropertyName(propertyName);
757         checkWritableProperties();
758         if (object != null && !ALLOWED.contains(object.getClass()))
759         {
760             throw new MessageFormatException
761                 (String.format
762                  ("Cannot set a %s, allowed property types are: %s",
763                   object.getClass(), ALLOWED));
764         }
765         setApplicationHeader(propertyName, object);
766     }
767 
768     private void setApplicationHeader(String propertyName, Object object)
769     {
770         Map<String, Object> headers = _messageProps.getApplicationHeaders();
771         if(headers == null)
772         {
773             headers = new HashMap<String,Object>();
774             _messageProps.setApplicationHeaders(headers);
775         }
776         headers.put(propertyName, object);
777     }
778 
779     public void removeProperty(String propertyNamethrows JMSException
780     {
781         Map<String, Object> headers = _messageProps.getApplicationHeaders();
782         if(headers != null)
783         {
784             headers.remove(propertyName);
785         }
786     }
787 
788 
789 
790     protected void checkWritableProperties() throws MessageNotWriteableException
791     {
792         if (_readableProperties)
793         {
794             throw new MessageNotWriteableException("You need to call clearProperties() to make the message writable");
795         }
796     }
797 
798 
799     public int getJMSPriority() throws JMSException
800     {
801         MessageDeliveryPriority messageDeliveryPriority = _deliveryProps.getPriority();
802         return messageDeliveryPriority == null ? Message.DEFAULT_PRIORITY : messageDeliveryPriority.getValue();
803     }
804 
805     public void setJMSPriority(int ithrows JMSException
806     {
807         _deliveryProps.setPriority(MessageDeliveryPriority.get((short)i));
808     }
809 
810     public void clearProperties() throws JMSException
811     {
812         if(!getApplicationHeaders().isEmpty())
813         {
814             getApplicationHeaders().clear();
815         }
816 
817         _readableProperties = false;
818     }
819 
820 
821     public void acknowledgeThis() throws JMSException
822     {
823         // the JMS 1.1 spec says in section 3.6 that calls to acknowledge are ignored when client acknowledge
824         // is not specified. In our case, we only set the session field where client acknowledge mode is specified.
825         if (_session != null)
826         {
827             if (_session.getAMQConnection().isClosed())
828             {
829                 throw new javax.jms.IllegalStateException("Connection is already closed");
830             }
831 
832             // we set multiple to true here since acknowledgement implies acknowledge of all previous messages
833             // received on the session
834             _session.acknowledgeMessage(_deliveryTag, true);
835         }
836     }
837 
838     public void acknowledge() throws JMSException
839     {
840         if (_session != null)
841         {
842             _session.acknowledge();
843         }
844     }
845 
846 
847      /**
848      * The session is set when CLIENT_ACKNOWLEDGE mode is used so that the CHANNEL ACK can be sent when the user calls
849      * acknowledge()
850      *
851      @param s the AMQ session that delivered this message
852      */
853     public void setAMQSession(AMQSession s)
854     {
855         _session = s;
856     }
857 
858     public AMQSession getAMQSession()
859     {
860         return _session;
861     }
862 
863     /**
864      * Get the AMQ message number assigned to this message
865      *
866      @return the message number
867      */
868     public long getDeliveryTag()
869     {
870         return _deliveryTag;
871     }
872 
873 
874 
875 
876 
877 
878     protected void checkPropertyName(CharSequence propertyName)
879     {
880         if (propertyName == null)
881         {
882             throw new IllegalArgumentException("Property name must not be null");
883         }
884         else if (propertyName.length() == 0)
885         {
886             throw new IllegalArgumentException("Property name must not be the empty string");
887         }
888 
889         checkIdentiferFormat(propertyName);
890     }
891 
892     protected void checkIdentiferFormat(CharSequence propertyName)
893     {
894 //        JMS requirements 3.5.1 Property Names
895 //        Identifiers:
896 //        - An identifier is an unlimited-length character sequence that must begin
897 //          with a Java identifier start character; all following characters must be Java
898 //          identifier part characters. An identifier start character is any character for
899 //          which the method Character.isJavaIdentifierStart returns true. This includes
900 //          '_' and '$'. An identifier part character is any character for which the
901 //          method Character.isJavaIdentifierPart returns true.
902 //        - Identifiers cannot be the names NULL, TRUE, or FALSE.
903 //          Identifiers cannot be NOT, AND, OR, BETWEEN, LIKE, IN, IS, or
904 //          ESCAPE.
905 //          Identifiers are either header field references or property references. The
906 //          type of a property value in a message selector corresponds to the type
907 //          used to set the property. If a property that does not exist in a message is
908 //          referenced, its value is NULL. The semantics of evaluating NULL values
909 //          in a selector are described in Section 3.8.1.2, Null Values.
910 //          The conversions that apply to the get methods for properties do not
911 //          apply when a property is used in a message selector expression. For
912 //          example, suppose you set a property as a string value, as in the
913 //          following:
914 //              myMessage.setStringProperty("NumberOfOrders", "2");
915 //          The following expression in a message selector would evaluate to false,
916 //          because a string cannot be used in an arithmetic expression:
917 //          "NumberOfOrders > 1"
918 //          Identifiers are case sensitive.
919 //          Message header field references are restricted to JMSDeliveryMode,
920 //          JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and
921 //          JMSType. JMSMessageID, JMSCorrelationID, and JMSType values may be
922 //          null and if so are treated as a NULL value.
923 
924         if (Boolean.getBoolean("strict-jms"))
925         {
926             // JMS start character
927             if (!(Character.isJavaIdentifierStart(propertyName.charAt(0))))
928             {
929                 throw new IllegalArgumentException("Identifier '" + propertyName + "' does not start with a valid JMS identifier start character");
930             }
931 
932             // JMS part character
933             int length = propertyName.length();
934             for (int c = 1; c < length; c++)
935             {
936                 if (!(Character.isJavaIdentifierPart(propertyName.charAt(c))))
937                 {
938                     throw new IllegalArgumentException("Identifier '" + propertyName + "' contains an invalid JMS identifier character");
939                 }
940             }
941 
942             // JMS invalid names
943             if ((propertyName.equals("NULL")
944                  || propertyName.equals("TRUE")
945                  || propertyName.equals("FALSE")
946                  || propertyName.equals("NOT")
947                  || propertyName.equals("AND")
948                  || propertyName.equals("OR")
949                  || propertyName.equals("BETWEEN")
950                  || propertyName.equals("LIKE")
951                  || propertyName.equals("IN")
952                  || propertyName.equals("IS")
953                  || propertyName.equals("ESCAPE")))
954             {
955                 throw new IllegalArgumentException("Identifier '" + propertyName + "' is not allowed in JMS");
956             }
957         }
958 
959     }
960 
961 
962     public MessageProperties getMessageProperties()
963     {
964         return _messageProps;
965     }
966 
967 
968     public DeliveryProperties getDeliveryProperties()
969     {
970         return _deliveryProps;
971     }
972 
973 }