Apply patch for AMQNET-554. Suport for message properties, and selectors. Thanks Stephane Ramet!
diff --git a/src/main/csharp/BaseMessage.cs b/src/main/csharp/BaseMessage.cs
index db73f4c..8ea7e31 100644
--- a/src/main/csharp/BaseMessage.cs
+++ b/src/main/csharp/BaseMessage.cs
@@ -1,4 +1,4 @@
-/*
+ /*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
@@ -24,28 +24,9 @@
public class BaseMessage : IMessage
{
- private PrimitiveMap propertiesMap = new PrimitiveMap();
- private IDestination destination;
- private string correlationId;
- private TimeSpan timeToLive;
- private string messageId;
- private MsgDeliveryMode deliveryMode;
- private MsgPriority priority;
- private Destination replyTo;
- private byte[] content;
- private string type;
+ #region Acknowledgement
+
private event AcknowledgeHandler Acknowledger;
- private DateTime timestamp = new DateTime();
- private bool readOnlyMsgBody = false;
-
- public bool ReadOnlyBody
- {
- get { return readOnlyMsgBody; }
- set { readOnlyMsgBody = value; }
- }
-
- // IMessage interface
-
public void Acknowledge()
{
if(null != Acknowledger)
@@ -54,6 +35,27 @@
}
}
+ #endregion
+
+ #region Message body
+
+ private byte[] content;
+ public byte[] Content
+ {
+ get { return content; }
+ set { this.content = value; }
+ }
+
+ private bool readOnlyMsgBody = false;
+ /// <summary>
+ /// Whether the message body is read-only.
+ /// </summary>
+ public bool ReadOnlyBody
+ {
+ get { return readOnlyMsgBody; }
+ set { readOnlyMsgBody = value; }
+ }
+
/// <summary>
/// Clears out the message body. Clearing a message's body does not clear its header
/// values or property entries.
@@ -67,53 +69,72 @@
this.readOnlyMsgBody = false;
}
+ #endregion
+
+ #region Message properties
+
+ private PrimitiveMap propertiesMap = new PrimitiveMap();
+ private MessagePropertyIntercepter propertyHelper;
+ /// <summary>
+ /// Provides access to the message properties (headers)
+ /// </summary>
+ public Apache.NMS.IPrimitiveMap Properties
+ {
+ get
+ {
+ if(propertyHelper == null)
+ {
+ propertyHelper = new Apache.NMS.Util.MessagePropertyIntercepter(
+ this, propertiesMap, this.ReadOnlyProperties);
+ }
+
+ return propertyHelper;
+ }
+ }
+
+ private bool readOnlyMsgProperties = false;
+ /// <summary>
+ /// Whether the message properties is read-only.
+ /// </summary>
+ public virtual bool ReadOnlyProperties
+ {
+ get { return this.readOnlyMsgProperties; }
+
+ set
+ {
+ if(this.propertyHelper != null)
+ {
+ this.propertyHelper.ReadOnly = value;
+ }
+ this.readOnlyMsgProperties = value;
+ }
+ }
+
/// <summary>
/// Clears a message's properties.
- ///
/// The message's header fields and body are not cleared.
/// </summary>
- public virtual void ClearProperties()
+ public void ClearProperties()
{
- propertiesMap.Clear();
+ this.ReadOnlyProperties = false;
+ this.propertiesMap.Clear();
}
- // Properties
-
- public IPrimitiveMap Properties
+ public object GetObjectProperty(string name)
{
- get { return propertiesMap; }
+ return Properties[name];
}
-
- // NMS headers
-
- /// <summary>
- /// The correlation ID used to correlate messages with conversations or long running business processes
- /// </summary>
- public string NMSCorrelationID
+ public void SetObjectProperty(string name, object value)
{
- get { return correlationId; }
- set { correlationId = value; }
+ Properties[name] = value;
}
- /// <summary>
- /// The destination of the message
- /// </summary>
- public IDestination NMSDestination
- {
- get { return destination; }
- set { destination = value; }
- }
+ #endregion
- /// <summary>
- /// The time in milliseconds that this message should expire in
- /// </summary>
- public TimeSpan NMSTimeToLive
- {
- get { return timeToLive; }
- set { timeToLive = value; }
- }
+ #region Message header fields
+ private string messageId;
/// <summary>
/// The message ID which is set by the provider
/// </summary>
@@ -123,6 +144,37 @@
set { messageId = value; }
}
+ private string correlationId;
+ /// <summary>
+ /// The correlation ID used to correlate messages with conversations or long running business processes
+ /// </summary>
+ public string NMSCorrelationID
+ {
+ get { return correlationId; }
+ set { correlationId = value; }
+ }
+
+ private IDestination destination;
+ /// <summary>
+ /// The destination of the message
+ /// </summary>
+ public IDestination NMSDestination
+ {
+ get { return destination; }
+ set { destination = value; }
+ }
+
+ private TimeSpan timeToLive;
+ /// <summary>
+ /// The time in milliseconds that this message should expire in
+ /// </summary>
+ public TimeSpan NMSTimeToLive
+ {
+ get { return timeToLive; }
+ set { timeToLive = value; }
+ }
+
+ private MsgDeliveryMode deliveryMode;
/// <summary>
/// Whether or not this message is persistent
/// </summary>
@@ -132,6 +184,7 @@
set { deliveryMode = value; }
}
+ private MsgPriority priority;
/// <summary>
/// The Priority on this message
/// </summary>
@@ -150,7 +203,7 @@
set { }
}
-
+ private Destination replyTo;
/// <summary>
/// The destination that the consumer of this message should send replies to
/// </summary>
@@ -160,7 +213,7 @@
set { replyTo = (Destination) value; }
}
-
+ private DateTime timestamp = new DateTime();
/// <summary>
/// The timestamp the broker added to the message
/// </summary>
@@ -170,12 +223,7 @@
set { timestamp = value; }
}
- public byte[] Content
- {
- get { return content; }
- set { this.content = value; }
- }
-
+ private string type;
/// <summary>
/// The type name of this message
/// </summary>
@@ -185,15 +233,9 @@
set { type = value; }
}
+ #endregion
- public object GetObjectProperty(string name)
- {
- return null;
- }
-
- public void SetObjectProperty(string name, object value)
- {
- }
+ #region Check access mode
protected void FailIfReadOnlyBody()
{
@@ -205,11 +247,13 @@
protected void FailIfWriteOnlyBody()
{
- if( ReadOnlyBody == false )
+ if(ReadOnlyBody == false)
{
throw new MessageNotReadableException("Message is in Write-Only mode.");
}
}
+
+ #endregion
}
}
diff --git a/src/main/csharp/DefaultMessageConverter.cs b/src/main/csharp/DefaultMessageConverter.cs
index 2aa3438..83097fc 100644
--- a/src/main/csharp/DefaultMessageConverter.cs
+++ b/src/main/csharp/DefaultMessageConverter.cs
@@ -32,12 +32,61 @@
StreamMessage
}
- public class DefaultMessageConverter : IMessageConverter
+ /// <summary>
+ /// This class provides default rules for converting MSMQ to and from
+ /// NMS messages, when the peer system expects or produces compatible
+ /// mappings, typically when the peer system is also implemented on
+ /// Apache.NMS.
+ /// Default mappings are as follows :
+ /// <ul>
+ /// <li>
+ /// the MSMQ Message.AppSetting field is used for specifying the NMS
+ /// message type, as specified by the <c>NMSMessageType</c> enumeration.
+ /// </li>
+ /// <li>
+ /// the MSMQ Message.Extension field is populated with a map
+ /// (a marshalled <c>PrimitiveMap</c>) of message properties.
+ /// </li>
+ /// <li>
+ /// in earlier versions of Apache.NMS.MSMQ, the MSMQ Message.Label
+ /// field was populated with the value of the NMSType field. Setting
+ /// <c>SetLabelAsNMSType</c> to true (the default value) applies that
+ /// same rule, which makes it compatible with existing NMS peers. If
+ /// set to false, the Message.Label field is populated with the value
+ /// of a "Label" property, if it exists, thus making it readable by
+ /// standard management or monitoring tools. The NMSType value is then
+ /// transmitted as a field in the Message.Extension map.
+ /// </li>
+ /// </ul>
+ /// Please note that in earlier versions of Apache.NMS, only one property
+ /// was set in the Message.Extension field : the NMSCorrelationID.
+ /// The native Message.CorrelationId field is not settable, except for
+ /// reply messages explicitely created as such through the MSMQ API.
+ /// Transmission of the correlation id. through a mapped property called
+ /// NMSCorrelationID is therefore maintained.
+ /// When exchanging messages with a non compatible peer, a specific
+ /// message converter must be provided, which should at least be able to
+ /// map message types and define the encoding used for text messages.
+ /// </summary>
+ public class DefaultMessageConverter : IMessageConverterEx
{
+ private bool setLabelAsNMSType = true;
+ public bool SetLabelAsNMSType
+ {
+ get { return setLabelAsNMSType; }
+ set { setLabelAsNMSType = value; }
+ }
+
+ #region Messages
+ /// <summary>
+ /// Converts the specified NMS message to an equivalent MSMQ message.
+ /// </summary>
+ /// <param name="message">NMS message to be converted.</param>
+ /// <result>Converted MSMQ message.</result>
public virtual Message ToMsmqMessage(IMessage message)
{
Message msmqMessage = new Message();
- PrimitiveMap metaData = new PrimitiveMap();
+ PrimitiveMap propertyData = new PrimitiveMap();
ConvertMessageBodyToMSMQ(message, msmqMessage);
@@ -48,32 +97,72 @@
if(message.NMSCorrelationID != null)
{
- metaData.SetString("NMSCorrelationID", message.NMSCorrelationID);
+ propertyData.SetString("NMSCorrelationID", message.NMSCorrelationID);
}
msmqMessage.Recoverable = (message.NMSDeliveryMode == MsgDeliveryMode.Persistent);
- msmqMessage.Priority = ToMessagePriority(message.NMSPriority);
+ msmqMessage.Priority = ToMsmqMessagePriority(message.NMSPriority);
msmqMessage.ResponseQueue = ToMsmqDestination(message.NMSReplyTo);
if(message.NMSType != null)
{
- msmqMessage.Label = message.NMSType;
+ if(SetLabelAsNMSType)
+ {
+ propertyData.SetString("NMSType", message.NMSType);
+ }
+ else
+ {
+ msmqMessage.Label = message.NMSType;
+ }
}
- // Store the NMS meta data in the extension area
- msmqMessage.Extension = metaData.Marshal();
+ // Populate property data
+ foreach(object keyObject in message.Properties.Keys)
+ {
+ string key = (keyObject as string);
+ object val = message.Properties.GetString(key);
+ if(!SetLabelAsNMSType && string.Compare(key, "Label", true) == 0 && val != null)
+ {
+ msmqMessage.Label = val.ToString();
+ }
+ else
+ {
+ propertyData[key] = val;
+ }
+ }
+
+ // Store the NMS property data in the extension area
+ msmqMessage.Extension = propertyData.Marshal();
return msmqMessage;
}
+ /// <summary>
+ /// Converts the specified MSMQ message to an equivalent NMS message
+ /// (including its message body).
+ /// </summary>
+ /// <param name="message">MSMQ message to be converted.</param>
+ /// <result>Converted NMS message.</result>
public virtual IMessage ToNmsMessage(Message message)
{
- BaseMessage answer = CreateNmsMessage(message);
- // Get the NMS meta data from the extension area
- PrimitiveMap metaData = PrimitiveMap.Unmarshal(message.Extension);
+ return ToNmsMessage(message, true);
+ }
+
+ /// <summary>
+ /// Converts the specified MSMQ message to an equivalent NMS message.
+ /// </summary>
+ /// <param name="message">MSMQ message to be converted.</param>
+ /// <param name="convertBody">true if message body should be converted.</param>
+ /// <result>Converted NMS message.</result>
+ public virtual IMessage ToNmsMessage(Message message, bool convertBody)
+ {
+ BaseMessage answer = CreateNmsMessage(message, convertBody);
+
+ // Get the NMS property data from the extension area
+ PrimitiveMap propertyData = PrimitiveMap.Unmarshal(message.Extension);
try
{
answer.NMSMessageId = message.Id;
- answer.NMSCorrelationID = metaData.GetString("NMSCorrelationID");
+ answer.NMSCorrelationID = propertyData.GetString("NMSCorrelationID");
answer.NMSDeliveryMode = (message.Recoverable ? MsgDeliveryMode.Persistent : MsgDeliveryMode.NonPersistent);
answer.NMSDestination = ToNmsDestination(message.DestinationQueue);
}
@@ -83,18 +172,85 @@
try
{
- answer.NMSType = message.Label;
answer.NMSReplyTo = ToNmsDestination(message.ResponseQueue);
answer.NMSTimeToLive = message.TimeToBeReceived;
+ answer.NMSPriority = ToNmsMsgPriority(message.Priority);
}
catch(InvalidOperationException)
{
}
+ try
+ {
+ if(message.Label != null)
+ {
+ if(SetLabelAsNMSType)
+ {
+ answer.NMSType = message.Label;
+ }
+ else
+ {
+ answer.Properties["Label"] = message.Label;
+ }
+ }
+ answer.Properties["LookupId"] = message.LookupId;
+ }
+ catch(InvalidOperationException)
+ {
+ }
+
+ foreach(object keyObject in propertyData.Keys)
+ {
+ try
+ {
+ string key = (keyObject as string);
+ if(string.Compare(key, "NMSType", true) == 0)
+ {
+ answer.NMSType = propertyData.GetString(key);
+ }
+ else if(string.Compare(key, "NMSCorrelationID", true) == 0)
+ {
+ answer.NMSCorrelationID = propertyData.GetString("NMSCorrelationID");
+ }
+ else
+ {
+ answer.Properties[key] = propertyData[key];
+ }
+ }
+ catch(InvalidOperationException)
+ {
+ }
+ }
return answer;
}
- private static MessagePriority ToMessagePriority(MsgPriority msgPriority)
+ #endregion
+
+ #region Message priority
+
+ // Message priorities are defined as follows :
+ // | MSMQ | NMS |
+ // | MessagePriority | MsgPriority |
+ // +--------------------+--------------------+
+ // | Lowest | Lowest |
+ // | VeryLow | VeryLow |
+ // | Low | Low |
+ // | \-> | AboveLow |
+ // | /-> | BelowNormal |
+ // | Normal | Normal |
+ // | AboveNormal | AboveNormal |
+ // | High | High |
+ // | VeryHigh | VeryHigh |
+ // | Highest | Highest |
+ // +--------------------+--------------------+
+
+ /// <summary>
+ /// Converts the specified NMS message priority to an equivalent MSMQ
+ /// message priority.
+ /// </summary>
+ /// <param name="msgPriority">NMS message priority to be converted.</param>
+ /// <result>Converted MSMQ message priority.</result>
+ private static MessagePriority ToMsmqMessagePriority(MsgPriority msgPriority)
{
switch(msgPriority)
{
@@ -127,6 +283,153 @@
}
}
+ /// <summary>
+ /// Converts the specified MSMQ message priority to an equivalent NMS
+ /// message priority.
+ /// </summary>
+ /// <param name="messagePriority">MSMQ message priority to be converted.</param>
+ /// <result>Converted NMS message priority.</result>
+ private static MsgPriority ToNmsMsgPriority(MessagePriority messagePriority)
+ {
+ switch(messagePriority)
+ {
+ case MessagePriority.Lowest:
+ return MsgPriority.Lowest;
+
+ case MessagePriority.VeryLow:
+ return MsgPriority.VeryLow;
+
+ case MessagePriority.Low:
+ return MsgPriority.Low;
+
+ default:
+ case MessagePriority.Normal:
+ return MsgPriority.Normal;
+
+ case MessagePriority.AboveNormal:
+ return MsgPriority.AboveNormal;
+
+ case MessagePriority.High:
+ return MsgPriority.High;
+
+ case MessagePriority.VeryHigh:
+ return MsgPriority.VeryHigh;
+
+ case MessagePriority.Highest:
+ return MsgPriority.Highest;
+ }
+ }
+
+ #endregion
+
+ #region Message creation
+
+ // Conversion of the message body has been separated from the creation
+ // of the NMS message object for performance reasons when using
+ // selectors (selectors handle only message attributes, not message
+ // bodies).
+ // CreateNmsMessage(Message) is maintained for compatibility reasons
+ // with existing clients that may have implemented derived classes,
+ // instead of completely removing the body conversion part from the
+ // method.
+
+ /// <summary>
+ /// Creates an NMS message of appropriate type for the specified MSMQ
+ /// message, and convert the message body.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <result>NMS message created for retrieving the MSMQ message.</result>
+ protected virtual BaseMessage CreateNmsMessage(Message message)
+ {
+ return CreateNmsMessage(message, true);
+ }
+
+ /// <summary>
+ /// Creates an NMS message of appropriate type for the specified MSMQ
+ /// message, and convert the message body if specified.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <param name="convertBody">true if the message body must be
+ /// converted.</param>
+ /// <result>NMS message created for retrieving the MSMQ message.</result>
+ protected virtual BaseMessage CreateNmsMessage(Message message,
+ bool convertBody)
+ {
+ BaseMessage result = null;
+
+ if((int) NMSMessageType.TextMessage == message.AppSpecific)
+ {
+ TextMessage textMessage = new TextMessage();
+
+ if(convertBody)
+ {
+ ConvertTextMessageBodyToNMS(message, textMessage);
+ }
+
+ result = textMessage;
+ }
+ else if((int) NMSMessageType.BytesMessage == message.AppSpecific)
+ {
+ BytesMessage bytesMessage = new BytesMessage();
+
+ if(convertBody)
+ {
+ ConvertBytesMessageBodyToNMS(message, bytesMessage);
+ }
+
+ result = bytesMessage;
+ }
+ else if((int) NMSMessageType.ObjectMessage == message.AppSpecific)
+ {
+ ObjectMessage objectMessage = new ObjectMessage();
+
+ if(convertBody)
+ {
+ ConvertObjectMessageBodyToNMS(message, objectMessage);
+ }
+
+ result = objectMessage;
+ }
+ else if((int) NMSMessageType.MapMessage == message.AppSpecific)
+ {
+ MapMessage mapMessage = new MapMessage();
+
+ if(convertBody)
+ {
+ ConvertMapMessageBodyToNMS(message, mapMessage);
+ }
+
+ result = mapMessage;
+ }
+ else if((int) NMSMessageType.StreamMessage == message.AppSpecific)
+ {
+ StreamMessage streamMessage = new StreamMessage();
+
+ if(convertBody)
+ {
+ ConvertStreamMessageBodyToNMS(message, streamMessage);
+ }
+
+ result = streamMessage;
+ }
+ else
+ {
+ BaseMessage baseMessage = new BaseMessage();
+ result = baseMessage;
+ }
+
+ return result;
+ }
+
+ #endregion
+
+ #region Message body
+
+ /// <summary>
+ /// Converts an NMS message body to the equivalent MSMQ message body.
+ /// </summary>
+ /// <param name="message">Source NMS message.</param>
+ /// <param name="answer">Target MSMQ message.</param>
protected virtual void ConvertMessageBodyToMSMQ(IMessage message, Message answer)
{
if(message is TextMessage)
@@ -172,78 +475,133 @@
}
}
- protected virtual BaseMessage CreateNmsMessage(Message message)
+ /// <summary>
+ /// Converts an MSMQ message body to the equivalent NMS message body.
+ /// </summary>
+ /// <param name="message">Source MSMQ message.</param>
+ /// <param name="answer">Target NMS message.</param>
+ public virtual void ConvertMessageBodyToNMS(Message message, IMessage answer)
{
- BaseMessage result = null;
-
- if((int) NMSMessageType.TextMessage == message.AppSpecific)
+ if(answer is TextMessage)
{
- TextMessage textMessage = new TextMessage();
- string content = String.Empty;
-
- if(message.BodyStream != null && message.BodyStream.Length > 0)
- {
- byte[] buf = null;
- buf = new byte[message.BodyStream.Length];
- message.BodyStream.Read(buf, 0, buf.Length);
- content = Encoding.UTF32.GetString(buf);
- }
-
- textMessage.Text = content;
- result = textMessage;
+ ConvertTextMessageBodyToNMS(message, (TextMessage)answer);
}
- else if((int) NMSMessageType.BytesMessage == message.AppSpecific)
+ else if(answer is BytesMessage)
{
- byte[] buf = null;
-
- if(message.BodyStream != null && message.BodyStream.Length > 0)
- {
- buf = new byte[message.BodyStream.Length];
- message.BodyStream.Read(buf, 0, buf.Length);
- }
-
- BytesMessage bytesMessage = new BytesMessage();
- bytesMessage.Content = buf;
- result = bytesMessage;
+ ConvertBytesMessageBodyToNMS(message, (BytesMessage)answer);
}
- else if((int) NMSMessageType.ObjectMessage == message.AppSpecific)
+ else if(answer is ObjectMessage)
{
- ObjectMessage objectMessage = new ObjectMessage();
-
- objectMessage.Body = message.Body;
- result = objectMessage;
+ ConvertObjectMessageBodyToNMS(message, (ObjectMessage)answer);
}
- else if((int) NMSMessageType.MapMessage == message.AppSpecific)
+ else if(answer is MapMessage)
{
- byte[] buf = null;
-
- if(message.BodyStream != null && message.BodyStream.Length > 0)
- {
- buf = new byte[message.BodyStream.Length];
- message.BodyStream.Read(buf, 0, buf.Length);
- }
-
- MapMessage mapMessage = new MapMessage();
- mapMessage.Body = PrimitiveMap.Unmarshal(buf);
- result = mapMessage;
+ ConvertMapMessageBodyToNMS(message, (MapMessage)answer);
}
- else if((int) NMSMessageType.StreamMessage == message.AppSpecific)
+ else if(answer is StreamMessage)
{
- StreamMessage streamMessage = new StreamMessage();
-
- // TODO: Implement
- result = streamMessage;
- }
- else
- {
- BaseMessage baseMessage = new BaseMessage();
-
- result = baseMessage;
+ ConvertStreamMessageBodyToNMS(message, (StreamMessage)answer);
}
- return result;
+ return;
}
+ /// <summary>
+ /// Converts an MSMQ message body to the equivalent NMS text message
+ /// body.
+ /// </summary>
+ /// <param name="message">Source MSMQ message.</param>
+ /// <param name="answer">Target NMS text message.</param>
+ public virtual void ConvertTextMessageBodyToNMS(Message message,
+ TextMessage answer)
+ {
+ string content = String.Empty;
+
+ if(message.BodyStream != null && message.BodyStream.Length > 0)
+ {
+ byte[] buf = new byte[message.BodyStream.Length];
+ message.BodyStream.Read(buf, 0, buf.Length);
+ content = Encoding.UTF32.GetString(buf);
+ }
+
+ answer.Text = content;
+ }
+
+ /// <summary>
+ /// Converts an MSMQ message body to the equivalent NMS bytes message
+ /// body.
+ /// </summary>
+ /// <param name="message">Source MSMQ message.</param>
+ /// <param name="answer">Target NMS bytes message.</param>
+ public virtual void ConvertBytesMessageBodyToNMS(Message message,
+ BytesMessage answer)
+ {
+ byte[] buf = null;
+
+ if(message.BodyStream != null && message.BodyStream.Length > 0)
+ {
+ buf = new byte[message.BodyStream.Length];
+ message.BodyStream.Read(buf, 0, buf.Length);
+ }
+
+ answer.Content = buf;
+ }
+
+ /// <summary>
+ /// Converts an MSMQ message body to the equivalent NMS object message
+ /// body.
+ /// </summary>
+ /// <param name="message">Source MSMQ message.</param>
+ /// <param name="answer">Target NMS object message.</param>
+ public virtual void ConvertObjectMessageBodyToNMS(Message message,
+ ObjectMessage answer)
+ {
+ answer.Body = message.Body;
+ }
+
+ /// <summary>
+ /// Converts an MSMQ message body to the equivalent NMS map message
+ /// body.
+ /// </summary>
+ /// <param name="message">Source MSMQ message.</param>
+ /// <param name="answer">Target NMS map message.</param>
+ public virtual void ConvertMapMessageBodyToNMS(Message message,
+ MapMessage answer)
+ {
+ byte[] buf = null;
+
+ if(message.BodyStream != null && message.BodyStream.Length > 0)
+ {
+ buf = new byte[message.BodyStream.Length];
+ message.BodyStream.Read(buf, 0, buf.Length);
+ }
+
+ answer.Body = PrimitiveMap.Unmarshal(buf);
+ }
+
+ /// <summary>
+ /// Converts an MSMQ message body to the equivalent NMS stream message
+ /// body.
+ /// </summary>
+ /// <param name="message">Source MSMQ message.</param>
+ /// <param name="answer">Target NMS stream message.</param>
+ public virtual void ConvertStreamMessageBodyToNMS(Message message,
+ StreamMessage answer)
+ {
+ // TODO: Implement
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+ #region Destination
+
+ /// <summary>
+ /// Converts an NMS destination to the equivalent MSMQ destination
+ /// (ie. queue).
+ /// </summary>
+ /// <param name="destination">NMS destination.</param>
+ /// <result>MSMQ queue.</result>
public MessageQueue ToMsmqDestination(IDestination destination)
{
if(null == destination)
@@ -254,6 +612,12 @@
return new MessageQueue((destination as Destination).Path);
}
+ /// <summary>
+ /// Converts an MSMQ destination (ie. queue) to the equivalent NMS
+ /// destination.
+ /// </summary>
+ /// <param name="destinationQueue">MSMQ destination queue.</param>
+ /// <result>NMS destination.</result>
protected virtual IDestination ToNmsDestination(MessageQueue destinationQueue)
{
if(null == destinationQueue)
@@ -263,5 +627,7 @@
return new Queue(destinationQueue.Path);
}
+
+ #endregion
}
}
diff --git a/src/main/csharp/IMessageConverter.cs b/src/main/csharp/IMessageConverter.cs
index 152377b..14c6669 100644
--- a/src/main/csharp/IMessageConverter.cs
+++ b/src/main/csharp/IMessageConverter.cs
@@ -20,15 +20,27 @@
{
public interface IMessageConverter
{
-
- /// <summary>
- /// Method ToMSMQMessageQueue
- /// </summary>
- /// <param name="destination">An IDestination</param>
- /// <returns>A MessageQueue</returns>
- MessageQueue ToMsmqDestination(IDestination destination);
-
+ /// <summary>
+ /// Converts the specified NMS message to an equivalent MSMQ message.
+ /// </summary>
+ /// <param name="message">NMS message to be converted.</param>
+ /// <result>Converted MSMQ message.</result>
Message ToMsmqMessage(IMessage message);
+
+ /// <summary>
+ /// Converts the specified MSMQ message to an equivalent NMS message
+ /// (including its message body).
+ /// </summary>
+ /// <param name="message">MSMQ message to be converted.</param>
+ /// <result>Converted NMS message.</result>
IMessage ToNmsMessage(Message message);
+
+ /// <summary>
+ /// Converts an NMS destination to the equivalent MSMQ destination
+ /// (ie. queue).
+ /// </summary>
+ /// <param name="destination">NMS destination.</param>
+ /// <result>MSMQ queue.</result>
+ MessageQueue ToMsmqDestination(IDestination destination);
}
}
diff --git a/src/main/csharp/IMessageConverterEx.cs b/src/main/csharp/IMessageConverterEx.cs
new file mode 100644
index 0000000..92be928
--- /dev/null
+++ b/src/main/csharp/IMessageConverterEx.cs
@@ -0,0 +1,44 @@
+using System.Messaging;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ
+{
+ /// <summary>
+ /// Extended IMessageConverter interface supporting new methods for
+ /// optimizing message selection through "selectors".
+ /// The original IMessageConverter is maintained for compatibility
+ /// reasons with existing clients implementing it.
+ /// </summary>
+ public interface IMessageConverterEx : IMessageConverter
+ {
+ /// <summary>
+ /// Converts the specified MSMQ message to an equivalent NMS message.
+ /// </summary>
+ /// <param name="message">MSMQ message to be converted.</param>
+ /// <param name="convertBody">true if message body should be converted.</param>
+ /// <result>Converted NMS message.</result>
+ IMessage ToNmsMessage(Message message, bool convertBody);
+
+ /// <summary>
+ /// Converts an MSMQ message body to the equivalent NMS message body.
+ /// </summary>
+ /// <param name="message">Source MSMQ message.</param>
+ /// <param name="answer">Target NMS message.</param>
+ void ConvertMessageBodyToNMS(Message message, IMessage answer);
+ }
+}
diff --git a/src/main/csharp/MessageConsumer.cs b/src/main/csharp/MessageConsumer.cs
index 6961298..eaaed5c 100644
--- a/src/main/csharp/MessageConsumer.cs
+++ b/src/main/csharp/MessageConsumer.cs
@@ -1,6 +1,8 @@
using System;
using System.Messaging;
using System.Threading;
+using Apache.NMS.Util;
+using Apache.NMS.MSMQ.Readers;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -17,12 +19,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-using Apache.NMS.Util;
namespace Apache.NMS.MSMQ
{
/// <summary>
- /// An object capable of receiving messages from some destination
+ /// An object capable of receiving messages from some destination.
/// </summary>
public class MessageConsumer : IMessageConsumer
{
@@ -31,8 +32,6 @@
private readonly Session session;
private readonly AcknowledgementMode acknowledgementMode;
private MessageQueue messageQueue;
- private event MessageListener listener;
- private int listenerCount = 0;
private Thread asyncDeliveryThread = null;
private AutoResetEvent pause = new AutoResetEvent(false);
private Atomic<bool> asyncDelivery = new Atomic<bool>(false);
@@ -44,17 +43,46 @@
set { this.consumerTransformer = value; }
}
- public MessageConsumer(Session session, AcknowledgementMode acknowledgementMode, MessageQueue messageQueue)
+ private IMessageReader reader;
+
+ /// <summary>
+ /// Constructs a message consumer on the specified queue.
+ /// </summary>
+ /// <param name="session">The messaging session.</param>
+ /// <param name="acknowledgementMode">The message acknowledgement mode.</param>
+ /// <param name="messageQueue">The message queue to consume messages from.</param>
+ public MessageConsumer(Session session,
+ AcknowledgementMode acknowledgementMode, MessageQueue messageQueue)
+ : this(session, acknowledgementMode, messageQueue, null)
+ {
+ }
+
+ /// <summary>
+ /// Constructs a message consumer on the specified queue, using a
+ /// selector for filtering incoming messages.
+ /// </summary>
+ /// <param name="session">The messaging session.</param>
+ /// <param name="acknowledgementMode">The message acknowledgement mode.</param>
+ /// <param name="messageQueue">The message queue to consume messages from.</param>
+ /// <param name="selector">The selection criteria.</param>
+ public MessageConsumer(Session session,
+ AcknowledgementMode acknowledgementMode, MessageQueue messageQueue,
+ string selector)
{
this.session = session;
this.acknowledgementMode = acknowledgementMode;
this.messageQueue = messageQueue;
- if(null != this.messageQueue)
+ if(this.messageQueue != null)
{
this.messageQueue.MessageReadPropertyFilter.SetAll();
}
+
+ reader = MessageReaderUtil.CreateMessageReader(
+ messageQueue, session.MessageConverter, selector);
}
+ private int listenerCount = 0;
+ private event MessageListener listener;
public event MessageListener Listener
{
add
@@ -85,32 +113,8 @@
if(messageQueue != null)
{
- Message message;
-
- try
- {
- message = messageQueue.Receive(zeroTimeout);
- }
- catch
- {
- message = null;
- }
-
- if(null == message)
- {
- ReceiveCompletedEventHandler receiveMsg =
- delegate(Object source, ReceiveCompletedEventArgs asyncResult) {
- message = messageQueue.EndReceive(asyncResult.AsyncResult);
- pause.Set();
- };
-
- messageQueue.ReceiveCompleted += receiveMsg;
- messageQueue.BeginReceive();
- pause.WaitOne();
- messageQueue.ReceiveCompleted -= receiveMsg;
- }
-
- nmsMessage = ToNmsMessage(message);
+ nmsMessage = reader.Receive();
+ nmsMessage = TransformMessage(nmsMessage);
}
return nmsMessage;
@@ -122,8 +126,8 @@
if(messageQueue != null)
{
- Message message = messageQueue.Receive(timeout);
- nmsMessage = ToNmsMessage(message);
+ nmsMessage = reader.Receive(timeout);
+ nmsMessage = TransformMessage(nmsMessage);
}
return nmsMessage;
@@ -135,8 +139,8 @@
if(messageQueue != null)
{
- Message message = messageQueue.Receive(zeroTimeout);
- nmsMessage = ToNmsMessage(message);
+ nmsMessage = reader.Receive(zeroTimeout);
+ nmsMessage = TransformMessage(nmsMessage);
}
return nmsMessage;
@@ -226,25 +230,20 @@
session.Connection.HandleException(e);
}
- protected virtual IMessage ToNmsMessage(Message message)
+ protected virtual IMessage TransformMessage(IMessage message)
{
- if(message == null)
- {
- return null;
- }
+ IMessage transformed = message;
- IMessage converted = session.MessageConverter.ToNmsMessage(message);
-
- if(this.ConsumerTransformer != null)
+ if(message != null && this.ConsumerTransformer != null)
{
- IMessage newMessage = ConsumerTransformer(this.session, this, converted);
+ IMessage newMessage = ConsumerTransformer(this.session, this, message);
if(newMessage != null)
{
- converted = newMessage;
+ transformed = newMessage;
}
}
- return converted;
+ return transformed;
}
}
}
diff --git a/src/main/csharp/QueueBrowser.cs b/src/main/csharp/QueueBrowser.cs
index 32752c5..3ff795d 100644
--- a/src/main/csharp/QueueBrowser.cs
+++ b/src/main/csharp/QueueBrowser.cs
@@ -19,6 +19,7 @@
using System.Messaging;
using Apache.NMS;
using Apache.NMS.Util;
+using Apache.NMS.MSMQ.Readers;
namespace Apache.NMS.MSMQ
{
@@ -30,7 +31,17 @@
private readonly Session session;
private MessageQueue messageQueue;
+ private string selector;
+
+ private IMessageReader reader;
+
public QueueBrowser(Session session, MessageQueue messageQueue)
+ : this(session, messageQueue, null)
+ {
+ }
+
+ public QueueBrowser(Session session, MessageQueue messageQueue,
+ string selector)
{
this.session = session;
this.messageQueue = messageQueue;
@@ -39,6 +50,8 @@
this.messageQueue.MessageReadPropertyFilter.SetAll();
}
+ reader = MessageReaderUtil.CreateMessageReader(
+ messageQueue, session.MessageConverter, selector);
}
~QueueBrowser()
@@ -95,7 +108,7 @@
public string MessageSelector
{
- get { throw new NotSupportedException(); }
+ get { return selector; }
}
public IQueue Queue
@@ -107,11 +120,14 @@
{
private readonly Session session;
private readonly MessageEnumerator innerEnumerator;
+ private readonly IMessageReader reader;
- public Enumerator(Session session, MessageQueue messageQueue)
+ public Enumerator(Session session, MessageQueue messageQueue,
+ IMessageReader reader)
{
this.session = session;
this.innerEnumerator = messageQueue.GetMessageEnumerator2();
+ this.reader = reader;
}
public object Current
@@ -124,7 +140,14 @@
public bool MoveNext()
{
- return this.innerEnumerator.MoveNext();
+ while(this.innerEnumerator.MoveNext())
+ {
+ if(reader.Matches(this.innerEnumerator.Current))
+ {
+ return true;
+ }
+ }
+ return false;
}
public void Reset()
@@ -135,7 +158,7 @@
public IEnumerator GetEnumerator()
{
- return new Enumerator(this.session, this.messageQueue);
+ return new Enumerator(this.session, this.messageQueue, this.reader);
}
}
}
diff --git a/src/main/csharp/Readers/AbstractMessageReader.cs b/src/main/csharp/Readers/AbstractMessageReader.cs
new file mode 100644
index 0000000..7874696
--- /dev/null
+++ b/src/main/csharp/Readers/AbstractMessageReader.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Messaging;
+using Apache.NMS.MSMQ;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// Abstract MSMQ message reader. Derived classes support various
+ /// message filtering methods.
+ /// </summary>
+ public abstract class AbstractMessageReader : IMessageReader
+ {
+ protected MessageQueue messageQueue;
+ protected IMessageConverter messageConverter;
+ protected IMessageConverterEx messageConverterEx;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="messageQueue">The MSMQ message queue from which
+ /// messages will be read.</param>
+ /// <param name="messageConverter">A message converter for mapping
+ /// MSMQ messages to NMS messages.</param>
+ public AbstractMessageReader(MessageQueue messageQueue,
+ IMessageConverter messageConverter)
+ {
+ this.messageQueue = messageQueue;
+
+ this.messageConverter = messageConverter;
+ this.messageConverterEx = (messageConverter as IMessageConverterEx);
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available.
+ /// </summary>
+ /// <returns>Peeked message.</returns>
+ public abstract IMessage Peek();
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available or the specified time-out occurs.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Peeked message.</returns>
+ public abstract IMessage Peek(TimeSpan timeSpan);
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by
+ /// the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <returns>Received message.</returns>
+ public abstract IMessage Receive();
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by the
+ /// MessageQueue matching the selection criteria, and waits until either
+ /// a message is available in the queue, or the time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Received message.</returns>
+ public abstract IMessage Receive(TimeSpan timeSpan);
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public abstract IMessage Receive(MessageQueueTransaction transaction);
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public abstract IMessage Receive(TimeSpan timeSpan,
+ MessageQueueTransaction transaction);
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>true if the message matches the selection criteria.</return>
+ public abstract bool Matches(Message message);
+
+ /// <summary>
+ /// Converts an MSMQ message to an NMS message, using the converter
+ /// specified at construction time.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>NMS message.</return>
+ protected IMessage Convert(Message message)
+ {
+ return message == null ? null : messageConverter.ToNmsMessage(message);
+ }
+ }
+}
diff --git a/src/main/csharp/Readers/ByCorrelationIdMessageReader.cs b/src/main/csharp/Readers/ByCorrelationIdMessageReader.cs
new file mode 100644
index 0000000..fad3d1a
--- /dev/null
+++ b/src/main/csharp/Readers/ByCorrelationIdMessageReader.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Messaging;
+using Apache.NMS.MSMQ;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// MSMQ message reader, returning messages matching the specified
+ /// message identifier.
+ /// </summary>
+ public class ByCorrelationIdMessageReader : AbstractMessageReader
+ {
+ private string correlationId;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="messageQueue">The MSMQ message queue from which
+ /// messages will be read.</param>
+ /// <param name="messageConverter">A message converter for mapping
+ /// MSMQ messages to NMS messages.</param>
+ /// <param name="correlationId">The correlation identifier of messages
+ /// to be read.</param>
+ public ByCorrelationIdMessageReader(MessageQueue messageQueue,
+ IMessageConverter messageConverter, string correlationId)
+ : base(messageQueue, messageConverter)
+ {
+ this.correlationId = correlationId;
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available.
+ /// </summary>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek()
+ {
+ return Convert(messageQueue.PeekByCorrelationId(correlationId));
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available or the specified time-out occurs.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek(TimeSpan timeSpan)
+ {
+ return Convert(messageQueue.PeekByCorrelationId(correlationId,
+ timeSpan));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by
+ /// the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive()
+ {
+ return Convert(messageQueue.ReceiveByCorrelationId(correlationId));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by the
+ /// MessageQueue matching the selection criteria, and waits until either
+ /// a message is available in the queue, or the time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan)
+ {
+ return Convert(messageQueue.ReceiveByCorrelationId(correlationId,
+ timeSpan));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(MessageQueueTransaction transaction)
+ {
+ return Convert(messageQueue.ReceiveByCorrelationId(correlationId,
+ transaction));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan,
+ MessageQueueTransaction transaction)
+ {
+ return Convert(messageQueue.ReceiveByCorrelationId(correlationId,
+ timeSpan, transaction));
+ }
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>true if the message matches the selection criteria.</return>
+ public override bool Matches(Message message)
+ {
+ // NB: case-sensitive match
+ return message.CorrelationId == correlationId;
+ }
+ }
+}
diff --git a/src/main/csharp/Readers/ByIdMessageReader.cs b/src/main/csharp/Readers/ByIdMessageReader.cs
new file mode 100644
index 0000000..f981ca8
--- /dev/null
+++ b/src/main/csharp/Readers/ByIdMessageReader.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Messaging;
+using Apache.NMS.MSMQ;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// MSMQ message reader, returning messages matching the specified
+ /// message identifier.
+ /// </summary>
+ public class ByIdMessageReader : AbstractMessageReader
+ {
+ private string messageId;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="messageQueue">The MSMQ message queue from which
+ /// messages will be read.</param>
+ /// <param name="messageConverter">A message converter for mapping
+ /// MSMQ messages to NMS messages.</param>
+ /// <param name="messageId">The message identifier of messages to
+ /// be read.</param>
+ public ByIdMessageReader(MessageQueue messageQueue,
+ IMessageConverter messageConverter, string messageId)
+ : base(messageQueue, messageConverter)
+ {
+ this.messageId = messageId;
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available.
+ /// </summary>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek()
+ {
+ return Convert(messageQueue.PeekById(messageId));
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available or the specified time-out occurs.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek(TimeSpan timeSpan)
+ {
+ return Convert(messageQueue.PeekById(messageId, timeSpan));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by
+ /// the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive()
+ {
+ return Convert(messageQueue.ReceiveById(messageId));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by the
+ /// MessageQueue matching the selection criteria, and waits until either
+ /// a message is available in the queue, or the time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan)
+ {
+ return Convert(messageQueue.ReceiveById(messageId, timeSpan));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(MessageQueueTransaction transaction)
+ {
+ return Convert(messageQueue.ReceiveById(messageId, transaction));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan,
+ MessageQueueTransaction transaction)
+ {
+ return Convert(messageQueue.ReceiveById(messageId, timeSpan,
+ transaction));
+ }
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>true if the message matches the selection criteria.</return>
+ public override bool Matches(Message message)
+ {
+ // NB: case-sensitive match
+ return message.Id == messageId;
+ }
+ }
+}
diff --git a/src/main/csharp/Readers/ByLookupIdMessageReader.cs b/src/main/csharp/Readers/ByLookupIdMessageReader.cs
new file mode 100644
index 0000000..421c52b
--- /dev/null
+++ b/src/main/csharp/Readers/ByLookupIdMessageReader.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Messaging;
+using Apache.NMS.MSMQ;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// MSMQ message reader, returning messages matching the specified
+ /// lookup identifier.
+ /// </summary>
+ public class ByLookupIdMessageReader : AbstractMessageReader
+ {
+ private Int64 lookupId;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="messageQueue">The MSMQ message queue from which
+ /// messages will be read.</param>
+ /// <param name="messageConverter">A message converter for mapping
+ /// MSMQ messages to NMS messages.</param>
+ /// <param name="lookupId">The lookup identifier of the message
+ /// to be read.</param>
+ public ByLookupIdMessageReader(MessageQueue messageQueue,
+ IMessageConverter messageConverter, Int64 lookupId)
+ : base(messageQueue, messageConverter)
+ {
+ this.lookupId = lookupId;
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available.
+ /// </summary>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek()
+ {
+ return Convert(messageQueue.PeekByLookupId(lookupId));
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available or the specified time-out occurs.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek(TimeSpan timeSpan)
+ {
+ // No time-out option for receiving messages by lookup identifiers:
+ // either the message is present in the queue, or the method throws
+ // an exception immediately if the message is not in the queue.
+ return Convert(messageQueue.PeekByLookupId(lookupId));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by
+ /// the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive()
+ {
+ return Convert(messageQueue.ReceiveByLookupId(lookupId));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by the
+ /// MessageQueue matching the selection criteria, and waits until either
+ /// a message is available in the queue, or the time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan)
+ {
+ // No time-out option for receiving messages by lookup identifiers:
+ // either the message is present in the queue, or the method throws
+ // an exception immediately if the message is not in the queue.
+ return Convert(messageQueue.ReceiveByLookupId(lookupId));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(MessageQueueTransaction transaction)
+ {
+ return Convert(messageQueue.ReceiveByLookupId(
+ MessageLookupAction.Current, lookupId, transaction));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan,
+ MessageQueueTransaction transaction)
+ {
+ // No time-out option for receiving messages by lookup identifiers:
+ // either the message is present in the queue, or the method throws
+ // an exception immediately if the message is not in the queue.
+ return Convert(messageQueue.ReceiveByLookupId(
+ MessageLookupAction.Current, lookupId, transaction));
+ }
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>true if the message matches the selection criteria.</return>
+ public override bool Matches(Message message)
+ {
+ return message.LookupId == lookupId;
+ }
+ }
+}
diff --git a/src/main/csharp/Readers/BySelectorMessageReader.cs b/src/main/csharp/Readers/BySelectorMessageReader.cs
new file mode 100644
index 0000000..e7cd5c3
--- /dev/null
+++ b/src/main/csharp/Readers/BySelectorMessageReader.cs
@@ -0,0 +1,290 @@
+using System;
+using System.Messaging;
+using Apache.NMS.MSMQ;
+using Apache.NMS;
+using Apache.NMS.Selector;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// MSMQ message reader, returning messages matching the specified
+ /// selector.
+ /// </summary>
+ public class BySelectorMessageReader : AbstractMessageReader
+ {
+ private string selector;
+ private MessageEvaluationContext evaluationContext;
+ private IBooleanExpression selectionExpression;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="messageQueue">The MSMQ message queue from which
+ /// messages will be read.</param>
+ /// <param name="messageConverter">A message converter for mapping
+ /// MSMQ messages to NMS messages.</param>
+ /// <param name="selector">The selector string.</param>
+ public BySelectorMessageReader(MessageQueue messageQueue,
+ IMessageConverter messageConverter, string selector)
+ : base(messageQueue, messageConverter)
+ {
+ this.selector = selector;
+
+ SelectorParser selectorParser = new SelectorParser();
+ selectionExpression = selectorParser.Parse(selector);
+
+ evaluationContext = new MessageEvaluationContext(null);
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available.
+ /// </summary>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek()
+ {
+ return InternalPeek(DateTime.MaxValue, true);
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available or the specified time-out occurs.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek(TimeSpan timeSpan)
+ {
+ DateTime maxTime = DateTime.Now + timeSpan;
+ return InternalPeek(maxTime, true);
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by
+ /// the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive()
+ {
+ return InternalReceive(DateTime.MaxValue, null);
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by the
+ /// MessageQueue matching the selection criteria, and waits until either
+ /// a message is available in the queue, or the time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan)
+ {
+ return InternalReceive(DateTime.Now + timeSpan, null);
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(MessageQueueTransaction transaction)
+ {
+ return InternalReceive(DateTime.MaxValue, transaction);
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan,
+ MessageQueueTransaction transaction)
+ {
+ return InternalReceive(DateTime.Now + timeSpan, transaction);
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="maxTime">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public IMessage InternalReceive(DateTime maxTime,
+ MessageQueueTransaction transaction)
+ {
+ // In a shared connection / multi-consumer context, the message may
+ // have been consumed by another client, after it was peeked but
+ // before it was peeked by this client. Hence the loop.
+ // (not sure it can be shared AND transactional, though).
+ while(true)
+ {
+ IMessage peekedMessage = InternalPeek(maxTime, false);
+
+ if(peekedMessage == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ long lookupId = peekedMessage.Properties.GetLong("LookupId");
+
+ Message message = (transaction == null ?
+ messageQueue.ReceiveByLookupId(lookupId) :
+ messageQueue.ReceiveByLookupId(
+ MessageLookupAction.Current, lookupId, transaction));
+
+ return Convert(message);
+ }
+ catch(InvalidOperationException exc)
+ {
+ // TODO: filter exceptions, catch only exceptions due to
+ // unknown lookup id.
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue, matching the selection criteria.
+ /// </summary>
+ /// <param name="maxTime">Reception time-out.</param>
+ /// <param name="convertBody">true if message body should be converted.</param>
+ /// <returns>Peeked message.</returns>
+ private IMessage InternalPeek(DateTime maxTime, bool convertBody)
+ {
+ TimeSpan timeSpan = maxTime - DateTime.Now;
+ if(timeSpan <= TimeSpan.Zero)
+ {
+ timeSpan = TimeSpan.Zero;
+ }
+
+ Cursor cursor = messageQueue.CreateCursor();
+
+ PeekAction action = PeekAction.Current;
+
+ while(true)
+ {
+ Message msmqMessage = null;
+
+ try
+ {
+ msmqMessage = messageQueue.Peek(timeSpan, cursor, action);
+ }
+ catch(MessageQueueException exc)
+ {
+ if(exc.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
+ {
+ throw exc;
+ }
+ }
+
+ if(msmqMessage == null)
+ {
+ return null;
+ }
+
+ IMessage nmsMessage = InternalMatch(msmqMessage, convertBody);
+
+ if(nmsMessage != null)
+ {
+ return nmsMessage;
+ }
+
+ action = PeekAction.Next;
+ }
+ }
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria. If matched
+ /// the method returns the converted NMS message. Else it returns null.
+ /// </summary>
+ /// <param name="message">The MSMQ message to check.</param>
+ /// <param name="convertBody">true if the message body should be
+ /// converted.</param>
+ /// <returns>The matching message converted to NMS, or null.</returns>
+ private IMessage InternalMatch(Message message, bool convertBody)
+ {
+ if(messageConverterEx == null)
+ {
+ IMessage nmsMessage = messageConverter.ToNmsMessage(message);
+
+ evaluationContext.Message = nmsMessage;
+
+ if(selectionExpression.Matches(evaluationContext))
+ {
+ return nmsMessage;
+ }
+ }
+ else
+ {
+ // This version converts the message body only for those
+ // messages matching the selection criteria.
+ // Relies on MessageConverterEx for partial conversions.
+ IMessage nmsMessage = messageConverterEx.ToNmsMessage(
+ message, false);
+
+ evaluationContext.Message = nmsMessage;
+
+ if(selectionExpression.Matches(evaluationContext))
+ {
+ if(convertBody)
+ {
+ messageConverterEx.ConvertMessageBodyToNMS(
+ message, nmsMessage);
+ }
+
+ return nmsMessage;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>true if the message matches the selection criteria.</return>
+ public override bool Matches(Message message)
+ {
+ IMessage nmsMessage = messageConverterEx == null ?
+ messageConverter.ToNmsMessage(message) :
+ messageConverterEx.ToNmsMessage(message, false);
+
+ evaluationContext.Message = nmsMessage;
+
+ return selectionExpression.Matches(evaluationContext);
+ }
+ }
+}
diff --git a/src/main/csharp/Readers/IMessageReader.cs b/src/main/csharp/Readers/IMessageReader.cs
new file mode 100644
index 0000000..8168664
--- /dev/null
+++ b/src/main/csharp/Readers/IMessageReader.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Messaging;
+using Apache.NMS.MSMQ;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// MSMQ message reader.
+ /// </summary>
+ public interface IMessageReader
+ {
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available.
+ /// </summary>
+ /// <returns>Peeked message.</returns>
+ IMessage Peek();
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available or the specified time-out occurs.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Peeked message.</returns>
+ IMessage Peek(TimeSpan timeSpan);
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by
+ /// the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <returns>Received message.</returns>
+ IMessage Receive();
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by the
+ /// MessageQueue matching the selection criteria, and waits until either
+ /// a message is available in the queue, or the time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Received message.</returns>
+ IMessage Receive(TimeSpan timeSpan);
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ IMessage Receive(MessageQueueTransaction transaction);
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ IMessage Receive(TimeSpan timeSpan, MessageQueueTransaction transaction);
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>true if the message matches the selection criteria.</return>
+ bool Matches(Message message);
+ }
+}
diff --git a/src/main/csharp/Readers/MessageReaderUtil.cs b/src/main/csharp/Readers/MessageReaderUtil.cs
new file mode 100644
index 0000000..c303965
--- /dev/null
+++ b/src/main/csharp/Readers/MessageReaderUtil.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Messaging;
+using System.Globalization;
+using System.Text.RegularExpressions;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// Utility routines for creating MSMQ message readers.
+ /// </summary>
+ public static class MessageReaderUtil
+ {
+ private static Regex basicSelectorRegex =
+ new Regex(@"^\s*" +
+ @"(NMSMessageId)\s*=\s*'([^']*)'|" +
+ @"(NMSCorrelationId)\s*=\s*'([^']*)'|" +
+ @"(LookupId)\s*=\s*([-+]{0,1}\d+)" +
+ @"\s*$",
+ RegexOptions.IgnoreCase | RegexOptions.Compiled);
+
+ /// <summary>
+ /// Creates a message reader for the specified message selector.
+ /// </summary>
+ /// <param name="messageQueue">The MSMQ message queue from which
+ /// messages will be read.</param>
+ /// <param name="messageConverter">A message converter for mapping
+ /// MSMQ messages to NMS messages.</param>
+ /// <param name="selector">The message selector.</param>
+ /// <return>A reader for the specified selector.</return>
+ public static IMessageReader CreateMessageReader(
+ MessageQueue messageQueue, IMessageConverter messageConverter,
+ string selector)
+ {
+ IMessageReader reader;
+
+ if(string.IsNullOrEmpty(selector))
+ {
+ reader = new NonFilteringMessageReader(messageQueue,
+ messageConverter);
+ }
+ else
+ {
+ Match match = basicSelectorRegex.Match(selector);
+ if(match.Success)
+ {
+ if(!string.IsNullOrEmpty(match.Groups[1].Value))
+ {
+ reader = new ByIdMessageReader(messageQueue,
+ messageConverter, match.Groups[2].Value);
+ }
+ else if(!string.IsNullOrEmpty(match.Groups[3].Value))
+ {
+ reader = new ByCorrelationIdMessageReader(messageQueue,
+ messageConverter, match.Groups[4].Value);
+ }
+ else
+ {
+ Int64 lookupId = Int64.Parse(match.Groups[6].Value,
+ CultureInfo.InvariantCulture);
+
+ reader = new ByLookupIdMessageReader(messageQueue,
+ messageConverter, lookupId);
+ }
+ }
+ else
+ {
+ reader = new BySelectorMessageReader(messageQueue,
+ messageConverter, selector);
+ }
+ }
+
+ return reader;
+ }
+ }
+}
diff --git a/src/main/csharp/Readers/NonFilteringMessageReader.cs b/src/main/csharp/Readers/NonFilteringMessageReader.cs
new file mode 100644
index 0000000..ea98baf
--- /dev/null
+++ b/src/main/csharp/Readers/NonFilteringMessageReader.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Messaging;
+using Apache.NMS.MSMQ;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.MSMQ.Readers
+{
+ /// <summary>
+ /// MSMQ message reader, returning all messages, without filtering.
+ /// </summary>
+ public class NonFilteringMessageReader : AbstractMessageReader
+ {
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="messageQueue">The MSMQ message queue from which
+ /// messages will be read.</param>
+ /// <param name="messageConverter">A message converter for mapping
+ /// MSMQ messages to NMS messages.</param>
+ public NonFilteringMessageReader(MessageQueue messageQueue,
+ IMessageConverter messageConverter)
+ : base(messageQueue, messageConverter)
+ {
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available.
+ /// </summary>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek()
+ {
+ return Convert(messageQueue.Peek());
+ }
+
+ /// <summary>
+ /// Returns without removing (peeks) the first message in the queue
+ /// referenced by this MessageQueue matching the selection criteria.
+ /// The Peek method is synchronous, so it blocks the current thread
+ /// until a message becomes available or the specified time-out occurs.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Peeked message.</returns>
+ public override IMessage Peek(TimeSpan timeSpan)
+ {
+ return Convert(messageQueue.Peek(timeSpan));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by
+ /// the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive()
+ {
+ return Convert(messageQueue.Receive());
+ }
+
+ /// <summary>
+ /// Receives the first message available in the queue referenced by the
+ /// MessageQueue matching the selection criteria, and waits until either
+ /// a message is available in the queue, or the time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan)
+ {
+ return Convert(messageQueue.Receive(timeSpan));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria.
+ /// This call is synchronous, and blocks the current thread of execution
+ /// until a message is available.
+ /// </summary>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(MessageQueueTransaction transaction)
+ {
+ return Convert(messageQueue.Receive(transaction));
+ }
+
+ /// <summary>
+ /// Receives the first message available in the transactional queue
+ /// referenced by the MessageQueue matching the selection criteria,
+ /// and waits until either a message is available in the queue, or the
+ /// time-out expires.
+ /// </summary>
+ /// <param name="timeSpan">Reception time-out.</param>
+ /// <param name="transaction">Transaction.</param>
+ /// <returns>Received message.</returns>
+ public override IMessage Receive(TimeSpan timeSpan,
+ MessageQueueTransaction transaction)
+ {
+ return Convert(messageQueue.Receive(timeSpan, transaction));
+ }
+
+ /// <summary>
+ /// Checks if an MSMQ message matches the selection criteria.
+ /// </summary>
+ /// <param name="message">MSMQ message.</param>
+ /// <return>true if the message matches the selection criteria.</return>
+ public override bool Matches(Message message)
+ {
+ return true;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/ANDExpression.cs b/src/main/csharp/Selector/ANDExpression.cs
new file mode 100644
index 0000000..285efe3
--- /dev/null
+++ b/src/main/csharp/Selector/ANDExpression.cs
@@ -0,0 +1,47 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a logical AND combination of two expressions.
+ /// </summary>
+ public class ANDExpression : LogicExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "AND"; }
+ }
+
+ public ANDExpression(IBooleanExpression left, IBooleanExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ if(lvalue == null) return null;
+ if(!(bool)lvalue) return false;
+
+ object rvalue = Right.Evaluate(message);
+ return rvalue == null ? null : rvalue;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/AlignedNumericValues.cs b/src/main/csharp/Selector/AlignedNumericValues.cs
new file mode 100644
index 0000000..96e2eeb
--- /dev/null
+++ b/src/main/csharp/Selector/AlignedNumericValues.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Globalization;
+using System.Collections.Generic;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A couple of numeric values converted to the type of the largest type.
+ /// </summary>
+ public class AlignedNumericValues
+ {
+ private object left;
+ public object Left
+ {
+ get { return left; }
+ }
+
+ private object right;
+ public object Right
+ {
+ get { return right; }
+ }
+
+ private T type;
+ public T TypeEnum
+ {
+ get { return type; }
+ }
+
+ public Type Type
+ {
+ get { return GetType(type); }
+ }
+
+ public AlignedNumericValues(object lvalue, object rvalue)
+ {
+ if(lvalue == null || rvalue == null)
+ {
+ return;
+ }
+
+ T ltypeEnum = GetTypeEnum(lvalue);
+ T rtypeEnum = GetTypeEnum(rvalue);
+
+ type = targetType[(int)ltypeEnum][(int)rtypeEnum];
+
+ left = (ltypeEnum == type ? lvalue : ConvertValue(lvalue, type));
+ right = (rtypeEnum == type ? rvalue : ConvertValue(rvalue, type));
+ }
+
+ public enum T
+ {
+ SByteType = 0, // Signed 8-bit integer (-128 to 127)
+ ByteType = 1, // Unsigned 8-bit integer (0 to 255)
+ CharType = 2, // Unicode 16-bit character (U+0000 to U+ffff)
+ ShortType = 3, // Signed 16-bit integer (-32 768 to 32 767)
+ UShortType = 4, // Unsigned 16-bit integer (0 to 65 535)
+ IntType = 5, // Signed 32-bit integer (-2 147 483 648 to 2 147 483 647)
+ UIntType = 6, // Unsigned 32-bit integer (0 to 4 294 967 295)
+ LongType = 7, // Signed 64-bit integer (-9 223 372 036 854 775 808 to 9 223 372 036 854 775 807)
+ ULongType = 8, // Unsigned 64-bit integer (0 to 18 446 744 073 709 551 615)
+ FloatType = 9, // 7 digits (±1.5e−45 to ±3.4e38)
+ DoubleType = 10 // 15-16 digits (±5.0e−324 to ±1.7e308)
+ }
+
+ private static Dictionary<Type, T> typeEnums
+ = new Dictionary<Type, T>
+ {
+ { typeof(sbyte ), T.SByteType },
+ { typeof(byte ), T.ByteType },
+ { typeof(char ), T.CharType },
+ { typeof(short ), T.ShortType },
+ { typeof(ushort), T.UShortType },
+ { typeof(int ), T.IntType },
+ { typeof(uint ), T.UIntType },
+ { typeof(long ), T.LongType },
+ { typeof(ulong ), T.ULongType },
+ { typeof(float ), T.FloatType },
+ { typeof(double), T.DoubleType }
+ };
+
+ private static T[][] targetType = new T[][]
+ {
+ // SByteType , ByteType , CharType , ShortType , UShortType, IntType , UIntType , LongType , ULongType , FloatType , DoubleType
+ /*SByteType */new T[] { T.SByteType , T.ShortType , T.IntType , T.ShortType , T.IntType , T.IntType , T.LongType , T.LongType , T.LongType , T.FloatType , T.DoubleType },
+ /*ByteType */new T[] { T.ShortType , T.ByteType , T.UShortType, T.ShortType , T.UShortType, T.IntType , T.UIntType , T.LongType , T.ULongType , T.FloatType , T.DoubleType },
+ /*CharType */new T[] { T.IntType , T.UShortType, T.CharType , T.IntType , T.UShortType, T.IntType , T.LongType , T.LongType , T.ULongType , T.FloatType , T.DoubleType },
+ /*ShortType */new T[] { T.ShortType , T.ShortType , T.IntType , T.ShortType , T.IntType , T.IntType , T.LongType , T.LongType , T.LongType , T.FloatType , T.DoubleType },
+ /*UShortType*/new T[] { T.IntType , T.UShortType, T.UShortType, T.IntType , T.UShortType, T.IntType , T.UIntType , T.LongType , T.ULongType , T.FloatType , T.DoubleType },
+ /*IntType */new T[] { T.IntType , T.IntType , T.IntType , T.IntType , T.IntType , T.IntType , T.LongType , T.LongType , T.LongType , T.FloatType , T.DoubleType },
+ /*UIntType */new T[] { T.LongType , T.UIntType , T.LongType , T.LongType , T.UIntType , T.LongType , T.UIntType , T.LongType , T.ULongType , T.FloatType , T.DoubleType },
+ /*LongType */new T[] { T.LongType , T.LongType , T.LongType , T.LongType , T.LongType , T.LongType , T.LongType , T.LongType , T.LongType , T.FloatType , T.DoubleType },
+ /*ULongType */new T[] { T.LongType , T.ULongType , T.ULongType , T.LongType , T.ULongType , T.LongType , T.ULongType , T.LongType , T.ULongType , T.FloatType , T.DoubleType },
+ /*FloatType */new T[] { T.FloatType , T.FloatType , T.FloatType , T.FloatType , T.FloatType , T.FloatType , T.FloatType , T.FloatType , T.FloatType , T.FloatType , T.DoubleType },
+ /*DoubleType*/new T[] { T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType, T.DoubleType }
+ };
+
+ private T GetTypeEnum(object value)
+ {
+ return GetTypeEnum(value.GetType());
+ }
+
+ private T GetTypeEnum(Type type)
+ {
+ try
+ {
+ return typeEnums[type];
+ }
+ catch
+ {
+ throw new NotSupportedException(
+ string.Format("Unsupported data type {0}.", type));
+ }
+ }
+
+ private Type GetType(T typeEnum)
+ {
+ switch(typeEnum)
+ {
+ case T.SByteType : return typeof(sbyte );
+ case T.ByteType : return typeof(byte );
+ case T.CharType : return typeof(char );
+ case T.ShortType : return typeof(short );
+ case T.UShortType: return typeof(ushort);
+ case T.IntType : return typeof(int );
+ case T.UIntType : return typeof(uint );
+ case T.LongType : return typeof(long );
+ case T.ULongType : return typeof(ulong );
+ case T.FloatType : return typeof(float );
+ case T.DoubleType: return typeof(double);
+ default:
+ throw new NotSupportedException(
+ string.Format("Unsupported data type {0}.", typeEnum));
+ }
+ }
+
+ private object ConvertValue(object value, T targetTypeEnum)
+ {
+ switch(targetTypeEnum)
+ {
+ case T.SByteType : return Convert.ToSByte (value);
+ case T.ByteType : return Convert.ToByte (value);
+ case T.CharType : return Convert.ToChar (value);
+ case T.ShortType : return Convert.ToInt16 (value);
+ case T.UShortType: return Convert.ToUInt16(value);
+ case T.IntType : return Convert.ToInt32 (value);
+ case T.UIntType : return Convert.ToUInt32(value);
+ case T.LongType : return Convert.ToInt64 (value);
+ case T.ULongType : return Convert.ToUInt64(value);
+ case T.FloatType : return Convert.ToSingle(value);
+ case T.DoubleType: return Convert.ToDouble(value);
+ default:
+ throw new NotSupportedException(
+ string.Format("Unsupported data type {0}.", targetTypeEnum));
+ }
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/ArithmeticExpression.cs b/src/main/csharp/Selector/ArithmeticExpression.cs
new file mode 100644
index 0000000..a0524ee
--- /dev/null
+++ b/src/main/csharp/Selector/ArithmeticExpression.cs
@@ -0,0 +1,57 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An expression which performs an operation on two expression values.
+ /// </summary>
+ public abstract class ArithmeticExpression : BinaryExpression
+ {
+ public ArithmeticExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public static IExpression CreatePlus(IExpression left, IExpression right)
+ {
+ return new PlusExpression(left, right);
+ }
+
+ public static IExpression CreateMinus(IExpression left, IExpression right)
+ {
+ return new MinusExpression(left, right);
+ }
+
+ public static IExpression CreateMultiply(IExpression left, IExpression right)
+ {
+ return new MultiplyExpression(left, right);
+ }
+
+ public static IExpression CreateDivide(IExpression left, IExpression right)
+ {
+ return new DivideExpression(left, right);
+ }
+
+ public static IExpression CreateMod(IExpression left, IExpression right)
+ {
+ return new ModExpression(left, right);
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/BinaryExpression.cs b/src/main/csharp/Selector/BinaryExpression.cs
new file mode 100644
index 0000000..9206f8c
--- /dev/null
+++ b/src/main/csharp/Selector/BinaryExpression.cs
@@ -0,0 +1,59 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An expression which performs an operation on two expression values.
+ /// </summary>
+ public abstract class BinaryExpression : IExpression
+ {
+ protected IExpression leftExpression;
+ public IExpression Left
+ {
+ get { return leftExpression; }
+ set { leftExpression = value; }
+ }
+
+ protected IExpression rightExpression;
+ public IExpression Right
+ {
+ get { return rightExpression; }
+ set { rightExpression = value; }
+ }
+
+ protected abstract string ExpressionSymbol
+ {
+ get;
+ }
+
+ public BinaryExpression(IExpression left, IExpression right)
+ {
+ leftExpression = left;
+ rightExpression = right;
+ }
+
+ public abstract object Evaluate(MessageEvaluationContext message);
+
+ public override string ToString()
+ {
+ return "(" + leftExpression.ToString() + " " + ExpressionSymbol + " " + rightExpression.ToString() + ")";
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/BooleanCastExpression.cs b/src/main/csharp/Selector/BooleanCastExpression.cs
new file mode 100644
index 0000000..26a6e9e
--- /dev/null
+++ b/src/main/csharp/Selector/BooleanCastExpression.cs
@@ -0,0 +1,45 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An expression which casts an expression value to a boolean.
+ /// </summary>
+ public class BooleanCastExpression : BooleanUnaryExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return ""; }
+ }
+
+ public BooleanCastExpression(IExpression left)
+ : base(left)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object rvalue = Right.Evaluate(message);
+ if(rvalue == null ) return null;
+ if(rvalue is bool ) return (bool)rvalue;
+ return false;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/BooleanConstantExpression.cs b/src/main/csharp/Selector/BooleanConstantExpression.cs
new file mode 100644
index 0000000..eb6447a
--- /dev/null
+++ b/src/main/csharp/Selector/BooleanConstantExpression.cs
@@ -0,0 +1,38 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// Represents a boolean constant expression.
+ /// </summary>
+ public class BooleanConstantExpression : ConstantExpression, IBooleanExpression
+ {
+ public BooleanConstantExpression(object value)
+ : base(value)
+ {
+ }
+
+ public bool Matches(MessageEvaluationContext message)
+ {
+ object value = Evaluate(message);
+ return value != null && (bool)value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/csharp/Selector/BooleanUnaryExpression.cs b/src/main/csharp/Selector/BooleanUnaryExpression.cs
new file mode 100644
index 0000000..3873050
--- /dev/null
+++ b/src/main/csharp/Selector/BooleanUnaryExpression.cs
@@ -0,0 +1,39 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An expression which performs an operation on one expression value
+ /// and returns a boolean value.
+ /// </summary>
+ public abstract class BooleanUnaryExpression : UnaryExpression, IBooleanExpression
+ {
+ public BooleanUnaryExpression(IExpression left)
+ : base(left)
+ {
+ }
+
+ public bool Matches(MessageEvaluationContext message)
+ {
+ object value = Evaluate(message);
+ return value != null && (bool)value;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/ComparisonExpression.cs b/src/main/csharp/Selector/ComparisonExpression.cs
new file mode 100644
index 0000000..4024271
--- /dev/null
+++ b/src/main/csharp/Selector/ComparisonExpression.cs
@@ -0,0 +1,162 @@
+using System;
+using System.Collections;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a comparison of two or more expressions or objects.
+ /// </summary>
+ public abstract class ComparisonExpression : BinaryExpression, IBooleanExpression
+ {
+ public ComparisonExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ object rvalue = Right.Evaluate(message);
+
+ int? compared = null;
+
+ if(lvalue == null || rvalue == null)
+ {
+ if(lvalue == null && rvalue == null)
+ {
+ compared = 0;
+ }
+ }
+ else
+ {
+ if(lvalue == rvalue)
+ {
+ compared = 0;
+ }
+ else if(lvalue is string && rvalue is string)
+ {
+ compared = ((string)lvalue).CompareTo(rvalue);
+ }
+ else
+ {
+ AlignedNumericValues values = new AlignedNumericValues(lvalue, rvalue);
+
+ switch(values.TypeEnum)
+ {
+ case AlignedNumericValues.T.SByteType : compared = ((sbyte )values.Left).CompareTo((sbyte )values.Right); break;
+ case AlignedNumericValues.T.ByteType : compared = ((byte )values.Left).CompareTo((byte )values.Right); break;
+ case AlignedNumericValues.T.CharType : compared = ((char )values.Left).CompareTo((char )values.Right); break;
+ case AlignedNumericValues.T.ShortType : compared = ((short )values.Left).CompareTo((short )values.Right); break;
+ case AlignedNumericValues.T.UShortType: compared = ((ushort)values.Left).CompareTo((ushort)values.Right); break;
+ case AlignedNumericValues.T.IntType : compared = ((int )values.Left).CompareTo((int )values.Right); break;
+ case AlignedNumericValues.T.UIntType : compared = ((uint )values.Left).CompareTo((uint )values.Right); break;
+ case AlignedNumericValues.T.LongType : compared = ((long )values.Left).CompareTo((long )values.Right); break;
+ case AlignedNumericValues.T.ULongType : compared = ((ulong )values.Left).CompareTo((ulong )values.Right); break;
+ case AlignedNumericValues.T.FloatType : compared = ((float )values.Left).CompareTo((float )values.Right); break;
+ case AlignedNumericValues.T.DoubleType: compared = ((double)values.Left).CompareTo((double)values.Right); break;
+ }
+ }
+ }
+
+ return AsBoolean(compared);
+ }
+
+ public abstract bool AsBoolean(int? compared);
+
+ public bool Matches(MessageEvaluationContext message)
+ {
+ object value = Evaluate(message);
+ return value != null && (bool)value;
+ }
+
+ // Equality expressions
+ public static IBooleanExpression CreateEqual(IExpression left, IExpression right)
+ {
+ return new EqualExpression(left, right, true);
+ }
+
+ public static IBooleanExpression CreateNotEqual(IExpression left, IExpression right)
+ {
+ return new EqualExpression(left, right, false);
+ }
+
+ public static IBooleanExpression CreateIsNull(IExpression left)
+ {
+ return new IsNullExpression(left, true);
+ }
+
+ public static IBooleanExpression CreateIsNotNull(IExpression left)
+ {
+ return new IsNullExpression(left, false);
+ }
+
+ // Binary comparison expressions
+ public static IBooleanExpression CreateGreaterThan(IExpression left, IExpression right)
+ {
+ return new GreaterExpression(left, right);
+ }
+
+ public static IBooleanExpression CreateGreaterThanOrEqual(IExpression left, IExpression right)
+ {
+ return new GreaterOrEqualExpression(left, right);
+ }
+
+ public static IBooleanExpression CreateLesserThan(IExpression left, IExpression right)
+ {
+ return new LesserExpression(left, right);
+ }
+
+ public static IBooleanExpression CreateLesserThanOrEqual(IExpression left, IExpression right)
+ {
+ return new LesserOrEqualExpression(left, right);
+ }
+
+ // Other comparison expressions
+ public static IBooleanExpression CreateLike(IExpression left, string right, string escape)
+ {
+ return new LikeExpression(left, right, escape, true);
+ }
+
+ public static IBooleanExpression CreateNotLike(IExpression left, string right, string escape)
+ {
+ return new LikeExpression(left, right, escape, false);
+ }
+
+ public static IBooleanExpression CreateBetween(IExpression value, IExpression left, IExpression right)
+ {
+ return LogicExpression.CreateAND(CreateGreaterThanOrEqual(value, left), CreateLesserThanOrEqual(value, right));
+ }
+
+ public static IBooleanExpression CreateNotBetween(IExpression value, IExpression left, IExpression right)
+ {
+ return LogicExpression.CreateOR(CreateLesserThan(value, left), CreateGreaterThan(value, right));
+ }
+
+ public static IBooleanExpression CreateIn(IExpression left, ArrayList elements)
+ {
+ return new InExpression(left, elements, true);
+ }
+
+ public static IBooleanExpression CreateNotIn(IExpression left, ArrayList elements)
+ {
+ return new InExpression(left, elements, false);
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/ConstantExpression.cs b/src/main/csharp/Selector/ConstantExpression.cs
new file mode 100644
index 0000000..90dfd69
--- /dev/null
+++ b/src/main/csharp/Selector/ConstantExpression.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Text;
+using System.Globalization;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// Represents a constant expression.
+ /// </summary>
+ public class ConstantExpression : IExpression
+ {
+ private object value;
+ public object Value
+ {
+ get { return value; }
+ }
+
+ public ConstantExpression(object value)
+ {
+ this.value = value;
+ }
+
+ public static ConstantExpression CreateFromDecimal(string text)
+ {
+ // Long integer specified ?
+ object value;
+ if(text.EndsWith("l") || text.EndsWith("L"))
+ {
+ text = text.Substring(0, text.Length - 1);
+ value = Int64.Parse(text, CultureInfo.InvariantCulture);
+ }
+ else
+ {
+ long lvalue = Int64.Parse(text, CultureInfo.InvariantCulture);
+ if(lvalue >= Int32.MinValue && lvalue <= Int32.MaxValue)
+ {
+ value = (int)lvalue;
+ }
+ else
+ {
+ value = lvalue;
+ }
+ }
+ return new ConstantExpression(value);
+ }
+
+ public static ConstantExpression CreateFromHex(string text)
+ {
+ long lvalue = Convert.ToInt64(text.Substring(2), 16);
+
+ object value;
+ if(lvalue >= Int32.MinValue && lvalue <= Int32.MaxValue)
+ {
+ value = (int)lvalue;
+ }
+ else
+ {
+ value = lvalue;
+ }
+ return new ConstantExpression(value);
+ }
+
+
+ public static ConstantExpression CreateFromOctal(string text)
+ {
+ long lvalue = Convert.ToInt64(text, 8);
+
+ object value;
+ if(lvalue >= Int32.MinValue && lvalue <= Int32.MaxValue)
+ {
+ value = (int)lvalue;
+ }
+ else
+ {
+ value = lvalue;
+ }
+ return new ConstantExpression(value);
+ }
+
+ public static ConstantExpression CreateFloat(string text)
+ {
+ double value = Double.Parse(text, CultureInfo.InvariantCulture);
+ return new ConstantExpression(value);
+ }
+
+ public object Evaluate(MessageEvaluationContext message)
+ {
+ return value;
+ }
+
+ public override string ToString()
+ {
+ if(value == null)
+ {
+ return "NULL";
+ }
+ if(value is bool)
+ {
+ return (bool)value ? "TRUE" : "FALSE";
+ }
+ if(value is string)
+ {
+ return EncodeString((string)value);
+ }
+ return value.ToString();
+ }
+
+ public override int GetHashCode()
+ {
+ return (value == null ? 0 : value.GetHashCode());
+ }
+
+ /// <summary>
+ /// Encodes the value of string so that it looks like it would look like
+ /// when it was provided in a selector.
+ /// </summary>
+ /// <param name="s">String to be encoded.</param>
+ /// <return>Encoded string.</return>
+ public static string EncodeString(string s)
+ {
+ StringBuilder b = new StringBuilder();
+ b.Append('\'');
+ for(int c = 0; c < s.Length; c++)
+ {
+ char ch = s[c];
+ if(ch == '\'')
+ {
+ b.Append(ch);
+ }
+ b.Append(ch);
+ }
+ b.Append('\'');
+ return b.ToString();
+ }
+
+ public static readonly BooleanConstantExpression NULL = new BooleanConstantExpression(null);
+ public static readonly BooleanConstantExpression TRUE = new BooleanConstantExpression(true);
+ public static readonly BooleanConstantExpression FALSE = new BooleanConstantExpression(false);
+ }
+}
\ No newline at end of file
diff --git a/src/main/csharp/Selector/DivideExpression.cs b/src/main/csharp/Selector/DivideExpression.cs
new file mode 100644
index 0000000..e280ec8
--- /dev/null
+++ b/src/main/csharp/Selector/DivideExpression.cs
@@ -0,0 +1,67 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a division of two expressions.
+ /// </summary>
+ public class DivideExpression : ArithmeticExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "/"; }
+ }
+
+ public DivideExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ if(lvalue == null) return null;
+
+ object rvalue = Right.Evaluate(message);
+ if(rvalue == null) return null;
+
+ AlignedNumericValues values = new AlignedNumericValues(lvalue, rvalue);
+
+ object result = null;
+
+ switch(values.TypeEnum)
+ {
+ case AlignedNumericValues.T.SByteType : result = (sbyte )values.Left / (sbyte )values.Right; break;
+ case AlignedNumericValues.T.ByteType : result = (byte )values.Left / (byte )values.Right; break;
+ case AlignedNumericValues.T.CharType : result = (char )values.Left / (char )values.Right; break;
+ case AlignedNumericValues.T.ShortType : result = (short )values.Left / (short )values.Right; break;
+ case AlignedNumericValues.T.UShortType: result = (ushort)values.Left / (ushort)values.Right; break;
+ case AlignedNumericValues.T.IntType : result = (int )values.Left / (int )values.Right; break;
+ case AlignedNumericValues.T.UIntType : result = (uint )values.Left / (uint )values.Right; break;
+ case AlignedNumericValues.T.LongType : result = (long )values.Left / (long )values.Right; break;
+ case AlignedNumericValues.T.ULongType : result = (ulong )values.Left / (ulong )values.Right; break;
+ case AlignedNumericValues.T.FloatType : result = (float )values.Left / (float )values.Right; break;
+ case AlignedNumericValues.T.DoubleType: result = (double)values.Left / (double)values.Right; break;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/EqualExpression.cs b/src/main/csharp/Selector/EqualExpression.cs
new file mode 100644
index 0000000..0e9a792
--- /dev/null
+++ b/src/main/csharp/Selector/EqualExpression.cs
@@ -0,0 +1,47 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing an equality or inequality comparison
+ /// of two expressions.
+ /// </summary>
+ public class EqualExpression : ComparisonExpression
+ {
+ private bool notNot;
+
+ protected override string ExpressionSymbol
+ {
+ get { return notNot ? "=" : "<>"; }
+ }
+
+ public EqualExpression(IExpression left, IExpression right, bool notNot)
+ : base(left, right)
+ {
+ this.notNot = notNot;
+ }
+
+ public override bool AsBoolean(int? compared)
+ {
+ bool answer = (compared.HasValue ? compared.Value == 0 : false);
+ return notNot ? answer : !answer;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/GreaterExpression.cs b/src/main/csharp/Selector/GreaterExpression.cs
new file mode 100644
index 0000000..eb264e5
--- /dev/null
+++ b/src/main/csharp/Selector/GreaterExpression.cs
@@ -0,0 +1,42 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a greater than comparison of two expressions.
+ /// </summary>
+ public class GreaterExpression : ComparisonExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return ">"; }
+ }
+
+ public GreaterExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override bool AsBoolean(int? compared)
+ {
+ return compared.HasValue ? compared.Value > 0 : false;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/GreaterOrEqualExpression.cs b/src/main/csharp/Selector/GreaterOrEqualExpression.cs
new file mode 100644
index 0000000..7a456f8
--- /dev/null
+++ b/src/main/csharp/Selector/GreaterOrEqualExpression.cs
@@ -0,0 +1,43 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a greater than or equal comparison
+ /// of two expressions.
+ /// </summary>
+ public class GreaterOrEqualExpression : ComparisonExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return ">="; }
+ }
+
+ public GreaterOrEqualExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override bool AsBoolean(int? compared)
+ {
+ return compared.HasValue ? compared.Value >= 0 : false;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/IBooleanExpression.cs b/src/main/csharp/Selector/IBooleanExpression.cs
new file mode 100644
index 0000000..af6c0f5
--- /dev/null
+++ b/src/main/csharp/Selector/IBooleanExpression.cs
@@ -0,0 +1,35 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An IBooleanExpression is an expression that always
+ /// produces a boolean result.
+ /// </summary>
+ public interface IBooleanExpression : IExpression
+ {
+ /// <summary>
+ /// Checks if expression evaluates to <c>true</c>.
+ /// </summary>
+ /// <param name="message">Evaluation context.</param>
+ /// <return><c>true</c> if the expression evaluates to <c>true</c>.</return>
+ bool Matches(MessageEvaluationContext message);
+ }
+}
diff --git a/src/main/csharp/Selector/IExpression.cs b/src/main/csharp/Selector/IExpression.cs
new file mode 100644
index 0000000..30fb893
--- /dev/null
+++ b/src/main/csharp/Selector/IExpression.cs
@@ -0,0 +1,35 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// Represents an expression
+ /// </summary>
+ public interface IExpression
+ {
+ /// <summary>
+ /// Evaluates the expression.
+ /// </summary>
+ /// <param name="message">Evaluation context.</param>
+ /// <return>The result of the evaluation.</return>
+ object Evaluate(MessageEvaluationContext message);
+ }
+}
+
\ No newline at end of file
diff --git a/src/main/csharp/Selector/InExpression.cs b/src/main/csharp/Selector/InExpression.cs
new file mode 100644
index 0000000..cd2d7ea
--- /dev/null
+++ b/src/main/csharp/Selector/InExpression.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Text;
+using System.Collections;
+using System.Collections.Generic;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A boolean expression which checks if an expression value is
+ /// contained in a list of defined values.
+ /// </summary>
+ public class InExpression : BooleanUnaryExpression
+ {
+ private bool notNot;
+ private ArrayList elements;
+ private HashSet<string> hashset;
+
+ protected override string ExpressionSymbol
+ {
+ get { return notNot ? "IN" : "NOT IN"; }
+ }
+
+ public InExpression(IExpression right, ArrayList elements, bool notNot)
+ : base(right)
+ {
+ this.notNot = notNot;
+
+ this.elements = elements;
+ this.hashset = new HashSet<string>();
+
+ foreach(object element in elements)
+ {
+ hashset.Add((string)element);
+ }
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object rvalue = Right.Evaluate(message);
+
+ bool answer = false;
+ if(rvalue != null && (rvalue is string))
+ {
+ answer = hashset.Contains((string)rvalue);
+ }
+
+ return notNot ? answer : !answer;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder answer = new StringBuilder();
+ answer.Append(Right);
+ answer.Append(" ");
+ answer.Append(ExpressionSymbol);
+ answer.Append(" (");
+
+ for(int i = 0; i < elements.Count; i++)
+ {
+ if(i > 0) answer.Append(", ");
+
+ string s = (string)elements[i];
+
+ answer.Append('\'');
+ for(int c = 0; c < s.Length; c++)
+ {
+ char ch = s[c];
+ if(ch == '\'')
+ {
+ answer.Append(ch);
+ }
+ answer.Append(ch);
+ }
+ answer.Append('\'');
+ }
+
+ answer.Append(")");
+ return answer.ToString();
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/IsNullExpression.cs b/src/main/csharp/Selector/IsNullExpression.cs
new file mode 100644
index 0000000..28d89a2
--- /dev/null
+++ b/src/main/csharp/Selector/IsNullExpression.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Text;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A boolean expression which checks if an expression value is null.
+ /// </summary>
+ public class IsNullExpression : BooleanUnaryExpression
+ {
+ private bool notNot;
+
+ protected override string ExpressionSymbol
+ {
+ get { return notNot ? "IS NULL" : "IS NOT NULL"; }
+ }
+
+ public IsNullExpression(IExpression right, bool notNot)
+ : base(right)
+ {
+ this.notNot = notNot;
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object rvalue = Right.Evaluate(message);
+
+ bool answer = (rvalue == null || rvalue == ConstantExpression.NULL);
+
+ return notNot ? answer : !answer;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder answer = new StringBuilder();
+ answer.Append(Right);
+ answer.Append(" ");
+ answer.Append(ExpressionSymbol);
+ return answer.ToString();
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/LesserExpression.cs b/src/main/csharp/Selector/LesserExpression.cs
new file mode 100644
index 0000000..4be2c9d
--- /dev/null
+++ b/src/main/csharp/Selector/LesserExpression.cs
@@ -0,0 +1,42 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a lesser than comparison of two expressions.
+ /// </summary>
+ public class LesserExpression : ComparisonExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "<"; }
+ }
+
+ public LesserExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override bool AsBoolean(int? compared)
+ {
+ return compared.HasValue ? compared.Value < 0 : false;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/LesserOrEqualExpression.cs b/src/main/csharp/Selector/LesserOrEqualExpression.cs
new file mode 100644
index 0000000..abdc7e5
--- /dev/null
+++ b/src/main/csharp/Selector/LesserOrEqualExpression.cs
@@ -0,0 +1,43 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a lesser than or equal comparison
+ /// of two expressions.
+ /// </summary>
+ public class LesserOrEqualExpression : ComparisonExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "<="; }
+ }
+
+ public LesserOrEqualExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override bool AsBoolean(int? compared)
+ {
+ return compared.HasValue ? compared.Value <= 0 : false;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/LikeExpression.cs b/src/main/csharp/Selector/LikeExpression.cs
new file mode 100644
index 0000000..8317bd6
--- /dev/null
+++ b/src/main/csharp/Selector/LikeExpression.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Globalization;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a string matching comparison.
+ /// </summary>
+ public class LikeExpression : BooleanUnaryExpression
+ {
+ private bool notNot;
+ private Regex pattern;
+
+ protected override string ExpressionSymbol
+ {
+ get { return notNot ? "LIKE" : "NOT LIKE"; }
+ }
+
+ public LikeExpression(IExpression left, string like, string escape, bool notNot)
+ : base(left)
+ {
+ this.notNot = notNot;
+
+ bool doEscape = false;
+ char escapeChar = '%';
+
+ if(escape != null)
+ {
+ if(escape.Length != 1)
+ {
+ throw new ApplicationException("The ESCAPE string litteral is invalid. It can only be one character. Litteral used: " + escape);
+ }
+ doEscape = true;
+ escapeChar = escape[0];
+ }
+
+ StringBuilder temp = new StringBuilder();
+ StringBuilder regexp = new StringBuilder(like.Length * 2);
+ regexp.Append("^"); // The beginning of the input
+ for(int c = 0; c < like.Length; c++)
+ {
+ char ch = like[c];
+ if(doEscape && (ch == escapeChar))
+ {
+ c++;
+ if(c >= like.Length)
+ {
+ // nothing left to escape...
+ break;
+ }
+ temp.Append(like[c]);
+ }
+ else if(ch == '%')
+ {
+ if(temp.Length > 0)
+ {
+ regexp.Append(Regex.Escape(temp.ToString()));
+ temp.Length = 0;
+ }
+ regexp.Append(".*?"); // Do a non-greedy match
+ }
+ else if(c == '_')
+ {
+ if(temp.Length > 0)
+ {
+ regexp.Append(Regex.Escape(temp.ToString()));
+ temp.Length = 0;
+ }
+ regexp.Append("."); // match one
+ }
+ else
+ {
+ temp.Append(ch);
+ }
+ }
+ if(temp.Length > 0)
+ {
+ regexp.Append(Regex.Escape(temp.ToString()));
+ }
+ regexp.Append("$"); // The end of the input
+
+ pattern = new Regex(regexp.ToString(), RegexOptions.Singleline | RegexOptions.Compiled);
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object rvalue = this.Right.Evaluate(message);
+
+ bool answer = false;
+ if(rvalue != null)
+ {
+ if(rvalue is string)
+ {
+ answer = pattern.IsMatch((string)rvalue);
+ }
+ else
+ {
+ //throw new ApplicationException("LIKE can only operate on string identifiers. LIKE attemped on " + rvalue.GetType().ToString());
+ }
+ }
+
+ return notNot ? answer : !answer;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/LogicExpression.cs b/src/main/csharp/Selector/LogicExpression.cs
new file mode 100644
index 0000000..61617a4
--- /dev/null
+++ b/src/main/csharp/Selector/LogicExpression.cs
@@ -0,0 +1,48 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a logical combination of two objects.
+ /// </summary>
+ public abstract class LogicExpression : BinaryExpression, IBooleanExpression
+ {
+ public LogicExpression(IBooleanExpression left, IBooleanExpression right)
+ : base(left, right)
+ {
+ }
+
+ public bool Matches(MessageEvaluationContext message)
+ {
+ object value = Evaluate(message);
+ return value != null && (bool)value;
+ }
+
+ public static IBooleanExpression CreateOR(IBooleanExpression left, IBooleanExpression right)
+ {
+ return new ORExpression(left, right);
+ }
+
+ public static IBooleanExpression CreateAND(IBooleanExpression left, IBooleanExpression right)
+ {
+ return new ANDExpression(left, right);
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/MessageEvaluationContext.cs b/src/main/csharp/Selector/MessageEvaluationContext.cs
new file mode 100644
index 0000000..054d911
--- /dev/null
+++ b/src/main/csharp/Selector/MessageEvaluationContext.cs
@@ -0,0 +1,78 @@
+using System;
+using Apache.NMS;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// MessageEvaluationContext is used to cache selection results.
+ ///
+ /// A message usually has multiple selectors applied against it. Some selector
+ /// have a high cost of evaluating against the message. Those selectors may whish
+ /// to cache evaluation results associated with the message in the
+ /// MessageEvaluationContext.
+ /// </summary>
+ public class MessageEvaluationContext
+ {
+ private IMessage nmsMessage;
+ public IMessage Message
+ {
+ get { return nmsMessage; }
+ set { nmsMessage = value; }
+ }
+
+ public MessageEvaluationContext(IMessage message)
+ {
+ nmsMessage = message;
+ }
+
+ public object GetProperty(string name)
+ {
+ if(name.Length > 3 &&
+ string.Compare(name.Substring(0, 3), "JMS", true) == 0)
+ {
+ if(string.Compare(name, "JMSCorrelationID", true) == 0)
+ {
+ return nmsMessage.NMSCorrelationID;
+ }
+ if(string.Compare(name, "JMSMessageID", true) == 0)
+ {
+ return nmsMessage.NMSMessageId;
+ }
+ if(string.Compare(name, "JMSPriority", true) == 0)
+ {
+ return nmsMessage.NMSPriority;
+ }
+ if(string.Compare(name, "JMSTimestamp", true) == 0)
+ {
+ return nmsMessage.NMSTimestamp;
+ }
+ if(string.Compare(name, "JMSType", true) == 0)
+ {
+ return nmsMessage.NMSType;
+ }
+ if(string.Compare(name, "JMSDeliveryMode", true) == 0)
+ {
+ return nmsMessage.NMSDeliveryMode;
+ }
+ }
+ return nmsMessage.Properties[name];
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/csharp/Selector/MinusExpression.cs b/src/main/csharp/Selector/MinusExpression.cs
new file mode 100644
index 0000000..260e5e8
--- /dev/null
+++ b/src/main/csharp/Selector/MinusExpression.cs
@@ -0,0 +1,67 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a substraction of two expressions.
+ /// </summary>
+ public class MinusExpression : ArithmeticExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "-"; }
+ }
+
+ public MinusExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ if(lvalue == null) return null;
+
+ object rvalue = Right.Evaluate(message);
+ if(rvalue == null) return null;
+
+ AlignedNumericValues values = new AlignedNumericValues(lvalue, rvalue);
+
+ object result = null;
+
+ switch(values.TypeEnum)
+ {
+ case AlignedNumericValues.T.SByteType : result = (sbyte )values.Left - (sbyte )values.Right; break;
+ case AlignedNumericValues.T.ByteType : result = (byte )values.Left - (byte )values.Right; break;
+ case AlignedNumericValues.T.CharType : result = (char )values.Left - (char )values.Right; break;
+ case AlignedNumericValues.T.ShortType : result = (short )values.Left - (short )values.Right; break;
+ case AlignedNumericValues.T.UShortType: result = (ushort)values.Left - (ushort)values.Right; break;
+ case AlignedNumericValues.T.IntType : result = (int )values.Left - (int )values.Right; break;
+ case AlignedNumericValues.T.UIntType : result = (uint )values.Left - (uint )values.Right; break;
+ case AlignedNumericValues.T.LongType : result = (long )values.Left - (long )values.Right; break;
+ case AlignedNumericValues.T.ULongType : result = (ulong )values.Left - (ulong )values.Right; break;
+ case AlignedNumericValues.T.FloatType : result = (float )values.Left - (float )values.Right; break;
+ case AlignedNumericValues.T.DoubleType: result = (double)values.Left - (double)values.Right; break;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/ModExpression.cs b/src/main/csharp/Selector/ModExpression.cs
new file mode 100644
index 0000000..386c08d
--- /dev/null
+++ b/src/main/csharp/Selector/ModExpression.cs
@@ -0,0 +1,67 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a modulo of two expressions.
+ /// </summary>
+ public class ModExpression : ArithmeticExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "%"; }
+ }
+
+ public ModExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ if(lvalue == null) return null;
+
+ object rvalue = Right.Evaluate(message);
+ if(rvalue == null) return null;
+
+ AlignedNumericValues values = new AlignedNumericValues(lvalue, rvalue);
+
+ object result = null;
+
+ switch(values.TypeEnum)
+ {
+ case AlignedNumericValues.T.SByteType : result = (sbyte )values.Left % (sbyte )values.Right; break;
+ case AlignedNumericValues.T.ByteType : result = (byte )values.Left % (byte )values.Right; break;
+ case AlignedNumericValues.T.CharType : result = (char )values.Left % (char )values.Right; break;
+ case AlignedNumericValues.T.ShortType : result = (short )values.Left % (short )values.Right; break;
+ case AlignedNumericValues.T.UShortType: result = (ushort)values.Left % (ushort)values.Right; break;
+ case AlignedNumericValues.T.IntType : result = (int )values.Left % (int )values.Right; break;
+ case AlignedNumericValues.T.UIntType : result = (uint )values.Left % (uint )values.Right; break;
+ case AlignedNumericValues.T.LongType : result = (long )values.Left % (long )values.Right; break;
+ case AlignedNumericValues.T.ULongType : result = (ulong )values.Left % (ulong )values.Right; break;
+ case AlignedNumericValues.T.FloatType : result = (float )values.Left % (float )values.Right; break;
+ case AlignedNumericValues.T.DoubleType: result = (double)values.Left % (double)values.Right; break;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/MultiplyExpression.cs b/src/main/csharp/Selector/MultiplyExpression.cs
new file mode 100644
index 0000000..0009092
--- /dev/null
+++ b/src/main/csharp/Selector/MultiplyExpression.cs
@@ -0,0 +1,67 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a multiplication of two expressions.
+ /// </summary>
+ public class MultiplyExpression : ArithmeticExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "*"; }
+ }
+
+ public MultiplyExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ if(lvalue == null) return null;
+
+ object rvalue = Right.Evaluate(message);
+ if(rvalue == null) return null;
+
+ AlignedNumericValues values = new AlignedNumericValues(lvalue, rvalue);
+
+ object result = null;
+
+ switch(values.TypeEnum)
+ {
+ case AlignedNumericValues.T.SByteType : result = (sbyte )values.Left * (sbyte )values.Right; break;
+ case AlignedNumericValues.T.ByteType : result = (byte )values.Left * (byte )values.Right; break;
+ case AlignedNumericValues.T.CharType : result = (char )values.Left * (char )values.Right; break;
+ case AlignedNumericValues.T.ShortType : result = (short )values.Left * (short )values.Right; break;
+ case AlignedNumericValues.T.UShortType: result = (ushort)values.Left * (ushort)values.Right; break;
+ case AlignedNumericValues.T.IntType : result = (int )values.Left * (int )values.Right; break;
+ case AlignedNumericValues.T.UIntType : result = (uint )values.Left * (uint )values.Right; break;
+ case AlignedNumericValues.T.LongType : result = (long )values.Left * (long )values.Right; break;
+ case AlignedNumericValues.T.ULongType : result = (ulong )values.Left * (ulong )values.Right; break;
+ case AlignedNumericValues.T.FloatType : result = (float )values.Left * (float )values.Right; break;
+ case AlignedNumericValues.T.DoubleType: result = (double)values.Left * (double)values.Right; break;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/NOTExpression.cs b/src/main/csharp/Selector/NOTExpression.cs
new file mode 100644
index 0000000..6d6ef55
--- /dev/null
+++ b/src/main/csharp/Selector/NOTExpression.cs
@@ -0,0 +1,45 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An expression which negates a boolean expression value.
+ /// </summary>
+ public class NOTExpression : BooleanUnaryExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "NOT"; }
+ }
+
+ public NOTExpression(IExpression left)
+ : base(left)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object rvalue = Right.Evaluate(message);
+ if(rvalue == null ) return null;
+ if(rvalue is bool ) return !(bool)rvalue;
+ return null;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/NegateExpression.cs b/src/main/csharp/Selector/NegateExpression.cs
new file mode 100644
index 0000000..0496b6f
--- /dev/null
+++ b/src/main/csharp/Selector/NegateExpression.cs
@@ -0,0 +1,51 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An expression which negates a numeric expression value.
+ /// </summary>
+ public class NegateExpression : UnaryExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "-"; }
+ }
+
+ public NegateExpression(IExpression left)
+ : base(left)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object rvalue = Right.Evaluate(message);
+ if(rvalue == null ) return null;
+ if(rvalue is int ) return -(int )rvalue;
+ if(rvalue is long ) return -(long )rvalue;
+ if(rvalue is double ) return -(double )rvalue;
+ if(rvalue is float ) return -(float )rvalue;
+ if(rvalue is decimal) return -(decimal)rvalue;
+ if(rvalue is short ) return -(short )rvalue;
+ if(rvalue is byte ) return -(byte )rvalue;
+ return null;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/ORExpression.cs b/src/main/csharp/Selector/ORExpression.cs
new file mode 100644
index 0000000..86648bc
--- /dev/null
+++ b/src/main/csharp/Selector/ORExpression.cs
@@ -0,0 +1,46 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing a logical OR combination of two expressions.
+ /// </summary>
+ public class ORExpression : LogicExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "OR"; }
+ }
+
+ public ORExpression(IBooleanExpression left, IBooleanExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ if(lvalue != null && (bool)lvalue) return true;
+
+ object rvalue = Right.Evaluate(message);
+ return rvalue == null ? null : rvalue;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/ParseException.cs b/src/main/csharp/Selector/ParseException.cs
new file mode 100644
index 0000000..f1b6d60
--- /dev/null
+++ b/src/main/csharp/Selector/ParseException.cs
@@ -0,0 +1,197 @@
+/* Generated By:CSharpCC: Do not edit this line. ParseException.cs Version 3.2 */
+/// <summary>
+/// This exception is thrown when parse errors are encountered.
+/// </summary>
+/// <remarks>
+/// You can explicitly create objects of this exception type by
+/// calling the method GenerateParseException in the generated
+/// parser.
+/// <para>
+/// You can modify this class to customize your error reporting
+/// mechanisms so long as you retain the public fields.
+/// </para>
+/// </remarks>
+public class ParseException : System.Exception {
+
+ /**
+ * This constructor is used by the method "GenerateParseException"
+ * in the generated parser. Calling this constructor generates
+ * a new object of this type with the fields "currentToken",
+ * "expectedTokenSequences", and "tokenImage" set. The boolean
+ * flag "specialConstructor" is also set to true to indicate that
+ * this constructor was used to create this object.
+ * This constructor calls its super class with the empty string
+ * to force the "toString" method of parent class "Throwable" to
+ * print the error message in the form:
+ * ParseException: result of getMessage
+ */
+ public ParseException(Token currentTokenVal,
+ int[][] expectedTokenSequencesVal,
+ string[] tokenImageVal
+ ) : base("") {
+ specialConstructor = true;
+ currentToken = currentTokenVal;
+ expectedTokenSequences = expectedTokenSequencesVal;
+ tokenImage = tokenImageVal;
+ }
+
+ /**
+ * The following constructors are for use by you for whatever
+ * purpose you can think of. Constructing the exception in this
+ * manner makes the exception behave in the normal way - i.e., as
+ * documented in the class "Exception". The fields "errorToken",
+ * "expectedTokenSequences", and "tokenImage" do not contain
+ * relevant information. The CSharpCC generated code does not use
+ * these constructors.
+ */
+
+ public ParseException() :
+ base() {
+ specialConstructor = false;
+ }
+
+ public ParseException(string message) :
+ base(message) {
+ specialConstructor = false;
+ }
+
+ /**
+ * This variable determines which constructor was used to create
+ * this object and thereby affects the semantics of the
+ * "getMessage" method (see below).
+ */
+ protected bool specialConstructor;
+
+ /**
+ * This is the last token that has been consumed successfully. If
+ * this object has been created due to a parse error, the token
+ * followng this token will (therefore) be the first error token.
+ */
+ public Token currentToken;
+
+ /**
+ * Each entry in this array is an array of integers. Each array
+ * of integers represents a sequence of tokens (by their ordinal
+ * values) that is expected at this point of the parse.
+ */
+ public int[][] expectedTokenSequences;
+
+ /**
+ * This is a reference to the "tokenImage" array of the generated
+ * parser within which the parse error occurred. This array is
+ * defined in the generated ...Constants interface.
+ */
+ public string[] tokenImage;
+
+ /**
+ * This method has the standard behavior when this object has been
+ * created using the standard constructors. Otherwise, it uses
+ * "currentToken" and "expectedTokenSequences" to generate a parse
+ * error message and returns it. If this object has been created
+ * due to a parse error, and you do not catch it (it gets thrown
+ * from the parser), then this method is called during the printing
+ * of the final stack trace, and hence the correct error message
+ * gets displayed.
+ */
+ public override string Message {
+ get {
+ if (!specialConstructor) {
+ return base.Message;
+ }
+ string expected = "";
+ int maxSize = 0;
+ for (int i = 0; i < expectedTokenSequences.Length; i++) {
+ if (maxSize < expectedTokenSequences[i].Length) {
+ maxSize = expectedTokenSequences[i].Length;
+ }
+ for (int j = 0; j < expectedTokenSequences[i].Length; j++) {
+ expected += tokenImage[expectedTokenSequences[i][j]] + " ";
+ }
+ if (expectedTokenSequences[i][expectedTokenSequences[i].Length - 1] != 0) {
+ expected += "...";
+ }
+ expected += eol + " ";
+ }
+ string retval = "Encountered \"";
+ Token tok = currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0) retval += " ";
+ if (tok.kind == 0) {
+ retval += tokenImage[0];
+ break;
+ }
+ retval += AddEscapes(tok.image);
+ tok = tok.next;
+ }
+ if (currentToken.next.kind == 0) {
+ retval += "\" after line ";
+ } else {
+ retval += "\" at line ";
+ }
+ retval += currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+ retval += "." + eol;
+ if (expectedTokenSequences.Length == 1) {
+ retval += "Was expecting:" + eol + " ";
+ } else {
+ retval += "Was expecting one of:" + eol + " ";
+ }
+ retval += expected;
+ return retval;
+ }
+ }
+
+ /**
+ * The end of line string for this machine.
+ */
+ protected string eol = System.Environment.NewLine;
+
+ /**
+ * Used to convert raw characters to their escaped version
+ * when these raw version cannot be used as part of an ASCII
+ * string literal.
+ */
+ protected string AddEscapes(string str) {
+ System.Text.StringBuilder retval = new System.Text.StringBuilder();
+ char ch;
+ for (int i = 0; i < str.Length; i++) {
+ switch (str[i]) {
+ case '\0' :
+ continue;
+ case '\b':
+ retval.Append("\\b");
+ continue;
+ case '\t':
+ retval.Append("\\t");
+ continue;
+ case '\n':
+ retval.Append("\\n");
+ continue;
+ case '\f':
+ retval.Append("\\f");
+ continue;
+ case '\r':
+ retval.Append("\\r");
+ continue;
+ case '\"':
+ retval.Append("\\\"");
+ continue;
+ case '\'':
+ retval.Append("\\\'");
+ continue;
+ case '\\':
+ retval.Append("\\\\");
+ continue;
+ default:
+ if ((ch = str[i]) < 0x20 || ch > 0x7e) {
+ string s = "0000" + System.Convert.ToString((int)ch, 16);
+ retval.Append("\\u" + s.Substring(s.Length - 4, s.Length - (s.Length - 4)));
+ } else {
+ retval.Append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.ToString();
+ }
+
+}
diff --git a/src/main/csharp/Selector/PlusExpression.cs b/src/main/csharp/Selector/PlusExpression.cs
new file mode 100644
index 0000000..450b653
--- /dev/null
+++ b/src/main/csharp/Selector/PlusExpression.cs
@@ -0,0 +1,68 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// A filter performing an addition of two expressions.
+ /// </summary>
+ public class PlusExpression : ArithmeticExpression
+ {
+ protected override string ExpressionSymbol
+ {
+ get { return "+"; }
+ }
+
+ public PlusExpression(IExpression left, IExpression right)
+ : base(left, right)
+ {
+ }
+
+ public override object Evaluate(MessageEvaluationContext message)
+ {
+ object lvalue = Left.Evaluate(message);
+ if(lvalue == null) return null;
+
+ object rvalue = Right.Evaluate(message);
+ if(lvalue is string) return (string)lvalue + rvalue;
+ if(rvalue == null) return null;
+
+ AlignedNumericValues values = new AlignedNumericValues(lvalue, rvalue);
+
+ object result = null;
+
+ switch(values.TypeEnum)
+ {
+ case AlignedNumericValues.T.SByteType : result = (sbyte )values.Left + (sbyte )values.Right; break;
+ case AlignedNumericValues.T.ByteType : result = (byte )values.Left + (byte )values.Right; break;
+ case AlignedNumericValues.T.CharType : result = (char )values.Left + (char )values.Right; break;
+ case AlignedNumericValues.T.ShortType : result = (short )values.Left + (short )values.Right; break;
+ case AlignedNumericValues.T.UShortType: result = (ushort)values.Left + (ushort)values.Right; break;
+ case AlignedNumericValues.T.IntType : result = (int )values.Left + (int )values.Right; break;
+ case AlignedNumericValues.T.UIntType : result = (uint )values.Left + (uint )values.Right; break;
+ case AlignedNumericValues.T.LongType : result = (long )values.Left + (long )values.Right; break;
+ case AlignedNumericValues.T.ULongType : result = (ulong )values.Left + (ulong )values.Right; break;
+ case AlignedNumericValues.T.FloatType : result = (float )values.Left + (float )values.Right; break;
+ case AlignedNumericValues.T.DoubleType: result = (double)values.Left + (double)values.Right; break;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/PropertyExpression.cs b/src/main/csharp/Selector/PropertyExpression.cs
new file mode 100644
index 0000000..8d00757
--- /dev/null
+++ b/src/main/csharp/Selector/PropertyExpression.cs
@@ -0,0 +1,53 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// Represents a property expression.
+ /// </summary>
+ public class PropertyExpression : IExpression
+ {
+ private string name;
+ public string Name
+ {
+ get { return name; }
+ }
+
+ public PropertyExpression(string name)
+ {
+ this.name = name;
+ }
+
+ public object Evaluate(MessageEvaluationContext message)
+ {
+ return message.GetProperty(name);
+ }
+
+ public override string ToString()
+ {
+ return name;
+ }
+
+ public override int GetHashCode()
+ {
+ return name.GetHashCode();
+ }
+ }
+}
diff --git a/src/main/csharp/Selector/SelectorParser.cs b/src/main/csharp/Selector/SelectorParser.cs
new file mode 100644
index 0000000..92226ac
--- /dev/null
+++ b/src/main/csharp/Selector/SelectorParser.cs
@@ -0,0 +1,1172 @@
+/* Generated By:CSharpCC: Do not edit this line. SelectorParser.cs */
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+
+using Apache.NMS;
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// JMS Selector Parser generated by <a href="https://github.com/deveel/csharpcc">CSharpCC</a>
+ ///
+ /// Do not edit this .cs file directly - it is autogenerated from SelectorParser.csc
+ /// using <c>csharpcc.exe -UNICODE_INPUT=true SelectorParser.csc</c>.
+ ///
+ /// SelectorParser.csc is adapted from
+ /// <a href="https://raw.githubusercontent.com/apache/activemq/activemq-4.0/activemq-core/src/main/grammar/SelectorParser.jj">
+ /// ActiveMQ 4.0 SelectorParser.jj</a>
+ /// </summary>
+ public class SelectorParser : SelectorParserConstants {
+
+ public SelectorParser()
+ : this(new StringReader(""))
+ {
+ }
+
+ public IBooleanExpression Parse(string selector)
+ {
+ this.ReInit(new StringReader(selector));
+
+ try
+ {
+ return this.JmsSelector();
+ }
+ catch(Exception e)
+ {
+ throw new InvalidSelectorException(selector, e);
+ }
+ }
+
+ private IBooleanExpression AsBooleanExpression(IExpression value)
+ {
+ if(value is IBooleanExpression)
+ {
+ return (IBooleanExpression)value;
+ }
+ if(value is PropertyExpression)
+ {
+ return UnaryExpression.CreateBooleanCast(value);
+ }
+ throw new ParseException("IExpression will not result in a boolean value: " + value);
+ }
+
+// ----------------------------------------------------------------------------
+// Grammar
+// ----------------------------------------------------------------------------
+ public IBooleanExpression JmsSelector() {
+ IExpression left = null;
+ left = GetOrExpression();
+ {return AsBooleanExpression(left);}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetOrExpression() {
+ IExpression left;
+ IExpression right;
+ left = GetAndExpression();
+ while (true) {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case OR:
+ ;
+ break;
+ default:
+ goto label_1;
+ }
+ mcc_consume_token(OR);
+ right = GetAndExpression();
+ left = LogicExpression.CreateOR(AsBooleanExpression(left), AsBooleanExpression(right));
+ }label_1: ;
+
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetAndExpression() {
+ IExpression left;
+ IExpression right;
+ left = GetEqualityExpression();
+ while (true) {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case AND:
+ ;
+ break;
+ default:
+ goto label_2;
+ }
+ mcc_consume_token(AND);
+ right = GetEqualityExpression();
+ left = LogicExpression.CreateAND(AsBooleanExpression(left), AsBooleanExpression(right));
+ }label_2: ;
+
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetEqualityExpression() {
+ IExpression left;
+ IExpression right;
+ left = GetComparisonExpression();
+ while (true) {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case IS:
+ case 28:
+ case 29:
+ ;
+ break;
+ default:
+ goto label_3;
+ }
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 28:
+ mcc_consume_token(28);
+ right = GetComparisonExpression();
+ left = ComparisonExpression.CreateEqual(left, right);
+ break;
+ case 29:
+ mcc_consume_token(29);
+ right = GetComparisonExpression();
+ left = ComparisonExpression.CreateNotEqual(left, right);
+ break;
+ default:
+ if (mcc_2_1(2)) {
+ mcc_consume_token(IS);
+ mcc_consume_token(NULL);
+ left = ComparisonExpression.CreateIsNull(left);
+ } else {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case IS:
+ mcc_consume_token(IS);
+ mcc_consume_token(NOT);
+ mcc_consume_token(NULL);
+ left = ComparisonExpression.CreateIsNotNull(left);
+ break;
+ default:
+ mcc_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ break;
+ }
+ }label_3: ;
+
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetComparisonExpression() {
+ IExpression left;
+ IExpression right;
+ IExpression low;
+ IExpression high;
+ string t;
+ string u;
+ ArrayList list;
+ left = GetAddExpression();
+ while (true) {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case NOT:
+ case BETWEEN:
+ case LIKE:
+ case IN:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ ;
+ break;
+ default:
+ goto label_4;
+ }
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 30:
+ mcc_consume_token(30);
+ right = GetAddExpression();
+ left = ComparisonExpression.CreateGreaterThan(left, right);
+ break;
+ case 31:
+ mcc_consume_token(31);
+ right = GetAddExpression();
+ left = ComparisonExpression.CreateGreaterThanOrEqual(left, right);
+ break;
+ case 32:
+ mcc_consume_token(32);
+ right = GetAddExpression();
+ left = ComparisonExpression.CreateLesserThan(left, right);
+ break;
+ case 33:
+ mcc_consume_token(33);
+ right = GetAddExpression();
+ left = ComparisonExpression.CreateLesserThanOrEqual(left, right);
+ break;
+ case LIKE:
+ u = null;
+ mcc_consume_token(LIKE);
+ t = GetStringLitteral();
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case ESCAPE:
+ mcc_consume_token(ESCAPE);
+ u = GetStringLitteral();
+ break;
+ default:
+ ;
+ break;
+ }
+ left = ComparisonExpression.CreateLike(left, t, u);
+ break;
+ default:
+ if (mcc_2_2(2)) {
+ u=null;
+ mcc_consume_token(NOT);
+ mcc_consume_token(LIKE);
+ t = GetStringLitteral();
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case ESCAPE:
+ mcc_consume_token(ESCAPE);
+ u = GetStringLitteral();
+ break;
+ default:
+ ;
+ break;
+ }
+ left = ComparisonExpression.CreateNotLike(left, t, u);
+ } else {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case BETWEEN:
+ mcc_consume_token(BETWEEN);
+ low = GetAddExpression();
+ mcc_consume_token(AND);
+ high = GetAddExpression();
+ left = ComparisonExpression.CreateBetween(left, low, high);
+ break;
+ default:
+ if (mcc_2_3(2)) {
+ mcc_consume_token(NOT);
+ mcc_consume_token(BETWEEN);
+ low = GetAddExpression();
+ mcc_consume_token(AND);
+ high = GetAddExpression();
+ left = ComparisonExpression.CreateNotBetween(left, low, high);
+ } else {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case IN:
+ mcc_consume_token(IN);
+ mcc_consume_token(34);
+ t = GetStringLitteral();
+ list = new ArrayList();
+ list.Add(t);
+ while (true) {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 35:
+ ;
+ break;
+ default:
+ goto label_5;
+ }
+ mcc_consume_token(35);
+ t = GetStringLitteral();
+ list.Add(t);
+ }label_5: ;
+
+ mcc_consume_token(36);
+ left = ComparisonExpression.CreateIn(left, list);
+ break;
+ default:
+ if (mcc_2_4(2)) {
+ mcc_consume_token(NOT);
+ mcc_consume_token(IN);
+ mcc_consume_token(34);
+ t = GetStringLitteral();
+ list = new ArrayList();
+ list.Add(t);
+ while (true) {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 35:
+ ;
+ break;
+ default:
+ goto label_6;
+ }
+ mcc_consume_token(35);
+ t = GetStringLitteral();
+ list.Add(t);
+ }label_6: ;
+
+ mcc_consume_token(36);
+ left = ComparisonExpression.CreateNotIn(left, list);
+ } else {
+ mcc_consume_token(-1);
+ throw new ParseException();
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }label_4: ;
+
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetAddExpression() {
+ IExpression left;
+ IExpression right;
+ left = GetMultiplyExpression();
+ while (true) {
+ if (mcc_2_5(2147483647)) {
+ ;
+ } else {
+ goto label_7;
+ }
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 37:
+ mcc_consume_token(37);
+ right = GetMultiplyExpression();
+ left = ArithmeticExpression.CreatePlus(left, right);
+ break;
+ case 38:
+ mcc_consume_token(38);
+ right = GetMultiplyExpression();
+ left = ArithmeticExpression.CreateMinus(left, right);
+ break;
+ default:
+ mcc_consume_token(-1);
+ throw new ParseException();
+ }
+ }label_7: ;
+
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetMultiplyExpression() {
+ IExpression left;
+ IExpression right;
+ left = GetUnaryExpression();
+ while (true) {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 39:
+ case 40:
+ case 41:
+ ;
+ break;
+ default:
+ goto label_8;
+ }
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 39:
+ mcc_consume_token(39);
+ right = GetUnaryExpression();
+ left = ArithmeticExpression.CreateMultiply(left, right);
+ break;
+ case 40:
+ mcc_consume_token(40);
+ right = GetUnaryExpression();
+ left = ArithmeticExpression.CreateDivide(left, right);
+ break;
+ case 41:
+ mcc_consume_token(41);
+ right = GetUnaryExpression();
+ left = ArithmeticExpression.CreateMod(left, right);
+ break;
+ default:
+ mcc_consume_token(-1);
+ throw new ParseException();
+ }
+ }label_8: ;
+
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetUnaryExpression() {
+ IExpression left = null;
+ if (mcc_2_6(2147483647)) {
+ mcc_consume_token(37);
+ left = GetUnaryExpression();
+ } else {
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case 38:
+ mcc_consume_token(38);
+ left = GetUnaryExpression();
+ left = UnaryExpression.CreateNegate(left);
+ break;
+ case NOT:
+ mcc_consume_token(NOT);
+ left = GetUnaryExpression();
+ left = UnaryExpression.CreateNOT(AsBooleanExpression(left));
+ break;
+ case TRUE:
+ case FALSE:
+ case NULL:
+ case DECIMAL_LITERAL:
+ case HEX_LITERAL:
+ case OCTAL_LITERAL:
+ case FLOATING_POINT_LITERAL:
+ case STRING_LITERAL:
+ case ID:
+ case 34:
+ left = GetPrimaryExpression();
+ break;
+ default:
+ mcc_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public IExpression GetPrimaryExpression() {
+ IExpression left = null;
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case TRUE:
+ case FALSE:
+ case NULL:
+ case DECIMAL_LITERAL:
+ case HEX_LITERAL:
+ case OCTAL_LITERAL:
+ case FLOATING_POINT_LITERAL:
+ case STRING_LITERAL:
+ left = GetLiteral();
+ break;
+ case ID:
+ left = GetVariable();
+ break;
+ case 34:
+ mcc_consume_token(34);
+ left = GetOrExpression();
+ mcc_consume_token(36);
+ break;
+ default:
+ mcc_consume_token(-1);
+ throw new ParseException();
+ }
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public ConstantExpression GetLiteral() {
+ Token t;
+ string s;
+ ConstantExpression left = null;
+ switch ((mcc_ntk==-1)?mcc_mntk():mcc_ntk) {
+ case STRING_LITERAL:
+ s = GetStringLitteral();
+ left = new ConstantExpression(s);
+ break;
+ case DECIMAL_LITERAL:
+ t = mcc_consume_token(DECIMAL_LITERAL);
+ left = ConstantExpression.CreateFromDecimal(t.image);
+ break;
+ case HEX_LITERAL:
+ t = mcc_consume_token(HEX_LITERAL);
+ left = ConstantExpression.CreateFromHex(t.image);
+ break;
+ case OCTAL_LITERAL:
+ t = mcc_consume_token(OCTAL_LITERAL);
+ left = ConstantExpression.CreateFromOctal(t.image);
+ break;
+ case FLOATING_POINT_LITERAL:
+ t = mcc_consume_token(FLOATING_POINT_LITERAL);
+ left = ConstantExpression.CreateFloat(t.image);
+ break;
+ case TRUE:
+ mcc_consume_token(TRUE);
+ left = ConstantExpression.TRUE;
+ break;
+ case FALSE:
+ mcc_consume_token(FALSE);
+ left = ConstantExpression.FALSE;
+ break;
+ case NULL:
+ mcc_consume_token(NULL);
+ left = ConstantExpression.NULL;
+ break;
+ default:
+ mcc_consume_token(-1);
+ throw new ParseException();
+ }
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public string GetStringLitteral() {
+ Token t;
+ StringBuilder rc = new StringBuilder();
+ t = mcc_consume_token(STRING_LITERAL);
+ // Decode the sting value.
+ String image = t.image;
+ for(int c = 1; c < image.Length - 1; c++)
+ {
+ char ch = image[c];
+ if(ch == '\'')
+ {
+ c++;
+ }
+ rc.Append(ch);
+ }
+ {return rc.ToString();}
+ throw new Exception("Missing return statement in function");
+ }
+
+ public PropertyExpression GetVariable() {
+ Token t;
+ PropertyExpression left = null;
+ t = mcc_consume_token(ID);
+ left = new PropertyExpression(t.image);
+ {return left;}
+ throw new Exception("Missing return statement in function");
+ }
+
+ private bool mcc_2_1(int xla) {
+ mcc_la = xla; mcc_lastpos = mcc_scanpos = token;
+ try { return !mcc_3_1(); }
+ catch(LookaheadSuccess) { return true; }
+ }
+
+ private bool mcc_2_2(int xla) {
+ mcc_la = xla; mcc_lastpos = mcc_scanpos = token;
+ try { return !mcc_3_2(); }
+ catch(LookaheadSuccess) { return true; }
+ }
+
+ private bool mcc_2_3(int xla) {
+ mcc_la = xla; mcc_lastpos = mcc_scanpos = token;
+ try { return !mcc_3_3(); }
+ catch(LookaheadSuccess) { return true; }
+ }
+
+ private bool mcc_2_4(int xla) {
+ mcc_la = xla; mcc_lastpos = mcc_scanpos = token;
+ try { return !mcc_3_4(); }
+ catch(LookaheadSuccess) { return true; }
+ }
+
+ private bool mcc_2_5(int xla) {
+ mcc_la = xla; mcc_lastpos = mcc_scanpos = token;
+ try { return !mcc_3_5(); }
+ catch(LookaheadSuccess) { return true; }
+ }
+
+ private bool mcc_2_6(int xla) {
+ mcc_la = xla; mcc_lastpos = mcc_scanpos = token;
+ try { return !mcc_3_6(); }
+ catch(LookaheadSuccess) { return true; }
+ }
+
+ private bool mcc_3R_57() {
+ if (mcc_scan_token(ESCAPE)) return true;
+ if (mcc_3R_36()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_19() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_20()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_21()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_22()) return true;
+ }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_39() {
+ if (mcc_3R_41()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_42()) { mcc_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private bool mcc_3_4() {
+ if (mcc_scan_token(NOT)) return true;
+ if (mcc_scan_token(IN)) return true;
+ if (mcc_scan_token(34)) return true;
+ if (mcc_3R_36()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_59()) { mcc_scanpos = xsp; break; }
+ }
+ if (mcc_scan_token(36)) return true;
+ return false;
+ }
+
+ private bool mcc_3_6() {
+ if (mcc_scan_token(37)) return true;
+ if (mcc_3R_10()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_15() {
+ if (mcc_3R_19()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_36() {
+ if (mcc_scan_token(STRING_LITERAL)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_14() {
+ if (mcc_scan_token(NOT)) return true;
+ if (mcc_3R_10()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_12() {
+ if (mcc_scan_token(37)) return true;
+ if (mcc_3R_10()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_53() {
+ if (mcc_scan_token(IN)) return true;
+ if (mcc_scan_token(34)) return true;
+ if (mcc_3R_36()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_58()) { mcc_scanpos = xsp; break; }
+ }
+ if (mcc_scan_token(36)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_45() {
+ if (mcc_scan_token(IS)) return true;
+ if (mcc_scan_token(NOT)) return true;
+ if (mcc_scan_token(NULL)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_13() {
+ if (mcc_scan_token(38)) return true;
+ if (mcc_3R_10()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_33() {
+ if (mcc_scan_token(NULL)) return true;
+ return false;
+ }
+
+ private bool mcc_3_1() {
+ if (mcc_scan_token(IS)) return true;
+ if (mcc_scan_token(NULL)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_10() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_12()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_13()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_14()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_15()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_44() {
+ if (mcc_scan_token(29)) return true;
+ if (mcc_3R_39()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_32() {
+ if (mcc_scan_token(FALSE)) return true;
+ return false;
+ }
+
+ private bool mcc_3_3() {
+ if (mcc_scan_token(NOT)) return true;
+ if (mcc_scan_token(BETWEEN)) return true;
+ if (mcc_3R_41()) return true;
+ if (mcc_scan_token(AND)) return true;
+ if (mcc_3R_41()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_43() {
+ if (mcc_scan_token(28)) return true;
+ if (mcc_3R_39()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_40() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_43()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_44()) {
+ mcc_scanpos = xsp;
+ if (mcc_3_1()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_45()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_52() {
+ if (mcc_scan_token(BETWEEN)) return true;
+ if (mcc_3R_41()) return true;
+ if (mcc_scan_token(AND)) return true;
+ if (mcc_3R_41()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_31() {
+ if (mcc_scan_token(TRUE)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_56() {
+ if (mcc_scan_token(ESCAPE)) return true;
+ if (mcc_3R_36()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_18() {
+ if (mcc_scan_token(41)) return true;
+ if (mcc_3R_10()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_30() {
+ if (mcc_scan_token(FLOATING_POINT_LITERAL)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_37() {
+ if (mcc_3R_39()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_40()) { mcc_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private bool mcc_3_2() {
+ if (mcc_scan_token(NOT)) return true;
+ if (mcc_scan_token(LIKE)) return true;
+ if (mcc_3R_36()) return true;
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_57()) mcc_scanpos = xsp;
+ return false;
+ }
+
+ private bool mcc_3R_51() {
+ if (mcc_scan_token(LIKE)) return true;
+ if (mcc_3R_36()) return true;
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_56()) mcc_scanpos = xsp;
+ return false;
+ }
+
+ private bool mcc_3R_17() {
+ if (mcc_scan_token(40)) return true;
+ if (mcc_3R_10()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_29() {
+ if (mcc_scan_token(OCTAL_LITERAL)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_16() {
+ if (mcc_scan_token(39)) return true;
+ if (mcc_3R_10()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_11() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_16()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_17()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_18()) return true;
+ }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_38() {
+ if (mcc_scan_token(AND)) return true;
+ if (mcc_3R_37()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_28() {
+ if (mcc_scan_token(HEX_LITERAL)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_9() {
+ if (mcc_3R_10()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_11()) { mcc_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_27() {
+ if (mcc_scan_token(DECIMAL_LITERAL)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_55() {
+ if (mcc_scan_token(38)) return true;
+ if (mcc_3R_9()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_34() {
+ if (mcc_3R_37()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_38()) { mcc_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private bool mcc_3_5() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_scan_token(37)) {
+ mcc_scanpos = xsp;
+ if (mcc_scan_token(38)) return true;
+ }
+ if (mcc_3R_9()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_50() {
+ if (mcc_scan_token(33)) return true;
+ if (mcc_3R_41()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_54() {
+ if (mcc_scan_token(37)) return true;
+ if (mcc_3R_9()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_26() {
+ if (mcc_3R_36()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_49() {
+ if (mcc_scan_token(32)) return true;
+ if (mcc_3R_41()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_59() {
+ if (mcc_scan_token(35)) return true;
+ if (mcc_3R_36()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_46() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_54()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_55()) return true;
+ }
+ return false;
+ }
+
+ private bool mcc_3R_35() {
+ if (mcc_scan_token(OR)) return true;
+ if (mcc_3R_34()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_23() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_26()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_27()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_28()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_29()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_30()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_31()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_32()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_33()) return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_48() {
+ if (mcc_scan_token(31)) return true;
+ if (mcc_3R_41()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_24() {
+ if (mcc_scan_token(ID)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_47() {
+ if (mcc_scan_token(30)) return true;
+ if (mcc_3R_41()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_42() {
+ Token xsp;
+ xsp = mcc_scanpos;
+ if (mcc_3R_47()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_48()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_49()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_50()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_51()) {
+ mcc_scanpos = xsp;
+ if (mcc_3_2()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_52()) {
+ mcc_scanpos = xsp;
+ if (mcc_3_3()) {
+ mcc_scanpos = xsp;
+ if (mcc_3R_53()) {
+ mcc_scanpos = xsp;
+ if (mcc_3_4()) return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_41() {
+ if (mcc_3R_9()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_46()) { mcc_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_25() {
+ if (mcc_3R_34()) return true;
+ Token xsp;
+ while (true) {
+ xsp = mcc_scanpos;
+ if (mcc_3R_35()) { mcc_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private bool mcc_3R_22() {
+ if (mcc_scan_token(34)) return true;
+ if (mcc_3R_25()) return true;
+ if (mcc_scan_token(36)) return true;
+ return false;
+ }
+
+ private bool mcc_3R_21() {
+ if (mcc_3R_24()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_20() {
+ if (mcc_3R_23()) return true;
+ return false;
+ }
+
+ private bool mcc_3R_58() {
+ if (mcc_scan_token(35)) return true;
+ if (mcc_3R_36()) return true;
+ return false;
+ }
+
+ public SelectorParserTokenManager token_source;
+ SimpleCharStream mcc_input_stream;
+ public Token token, mcc_nt;
+ private int mcc_ntk;
+ private Token mcc_scanpos, mcc_lastpos;
+ private int mcc_la;
+ public bool lookingAhead = false;
+ //private bool mcc_semLA;
+
+ public SelectorParser(System.IO.Stream stream) {
+ mcc_input_stream = new SimpleCharStream(stream, 1, 1);
+ token_source = new SelectorParserTokenManager(mcc_input_stream);
+ token = new Token();
+ mcc_ntk = -1;
+ }
+
+ public void ReInit(System.IO.Stream stream) {
+ mcc_input_stream.ReInit(stream, 1, 1);
+ token_source.ReInit(mcc_input_stream);
+ token = new Token();
+ mcc_ntk = -1;
+ }
+
+ public SelectorParser(System.IO.TextReader stream) {
+ mcc_input_stream = new SimpleCharStream(stream, 1, 1);
+ token_source = new SelectorParserTokenManager(mcc_input_stream);
+ token = new Token();
+ mcc_ntk = -1;
+ }
+
+ public void ReInit(System.IO.TextReader stream) {
+ mcc_input_stream.ReInit(stream, 1, 1);
+ token_source.ReInit(mcc_input_stream);
+ token = new Token();
+ mcc_ntk = -1;
+ }
+
+ public SelectorParser(SelectorParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ mcc_ntk = -1;
+ }
+
+ public void ReInit(SelectorParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ mcc_ntk = -1;
+ }
+
+ private Token mcc_consume_token(int kind) {
+ Token oldToken = null;
+ if ((oldToken = token).next != null) token = token.next;
+ else token = token.next = token_source.GetNextToken();
+ mcc_ntk = -1;
+ if (token.kind == kind) {
+ return token;
+ }
+ token = oldToken;
+ throw GenerateParseException();
+ }
+
+ private class LookaheadSuccess : System.Exception { }
+ private LookaheadSuccess mcc_ls = new LookaheadSuccess();
+ private bool mcc_scan_token(int kind) {
+ if (mcc_scanpos == mcc_lastpos) {
+ mcc_la--;
+ if (mcc_scanpos.next == null) {
+ mcc_lastpos = mcc_scanpos = mcc_scanpos.next = token_source.GetNextToken();
+ } else {
+ mcc_lastpos = mcc_scanpos = mcc_scanpos.next;
+ }
+ } else {
+ mcc_scanpos = mcc_scanpos.next;
+ }
+ if (mcc_scanpos.kind != kind) return true;
+ if (mcc_la == 0 && mcc_scanpos == mcc_lastpos) throw mcc_ls;
+ return false;
+ }
+
+ public Token GetNextToken() {
+ if (token.next != null) token = token.next;
+ else token = token.next = token_source.GetNextToken();
+ mcc_ntk = -1;
+ return token;
+ }
+
+ public Token GetToken(int index) {
+ Token t = lookingAhead ? mcc_scanpos : token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null) t = t.next;
+ else t = t.next = token_source.GetNextToken();
+ }
+ return t;
+ }
+
+ private int mcc_mntk() {
+ if ((mcc_nt=token.next) == null)
+ return (mcc_ntk = (token.next=token_source.GetNextToken()).kind);
+ else
+ return (mcc_ntk = mcc_nt.kind);
+ }
+
+ public ParseException GenerateParseException() {
+ Token errortok = token.next;
+ int line = errortok.beginLine, column = errortok.beginColumn;
+ string mess = (errortok.kind == 0) ? tokenImage[0] : errortok.image;
+ return new ParseException("Parse error at line " + line + ", column " + column + ". Encountered: " + mess);
+ }
+
+ public void enable_tracing() {
+ }
+
+ public void disable_tracing() {
+ }
+
+}
+
+}
\ No newline at end of file
diff --git a/src/main/csharp/Selector/SelectorParser.csc b/src/main/csharp/Selector/SelectorParser.csc
new file mode 100644
index 0000000..be05ab8
--- /dev/null
+++ b/src/main/csharp/Selector/SelectorParser.csc
@@ -0,0 +1,589 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ----------------------------------------------------------------------------
+// OPTIONS
+// ----------------------------------------------------------------------------
+options {
+ STATIC = false;
+ UNICODE_INPUT = true;
+
+ // some performance optimizations
+ OPTIMIZE_TOKEN_MANAGER = true;
+ ERROR_REPORTING = false;
+}
+
+// ----------------------------------------------------------------------------
+// PARSER
+// ----------------------------------------------------------------------------
+
+PARSER_BEGIN(SelectorParser)
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+
+using Apache.NMS;
+
+//namespace Apache.NMS.Selector
+//{
+ /// <summary>
+ /// JMS Selector Parser generated by <a href="https://github.com/deveel/csharpcc">CSharpCC</a>
+ ///
+ /// Do not edit this .cs file directly - it is autogenerated from SelectorParser.csc
+ /// using <c>csharpcc.exe -UNICODE_INPUT=true SelectorParser.csc</c>.
+ ///
+ /// SelectorParser.csc is adapted from
+ /// <a href="https://raw.githubusercontent.com/apache/activemq/activemq-4.0/activemq-core/src/main/grammar/SelectorParser.jj">
+ /// ActiveMQ 4.0 SelectorParser.jj</a>
+ /// </summary>
+ public class SelectorParser
+ {
+
+ public SelectorParser()
+ {
+ }
+
+ public IBooleanExpression Parse(string selector)
+ {
+ this.ReInit(new StringReader(selector));
+
+ try
+ {
+ return this.JmsSelector();
+ }
+ catch(Exception e)
+ {
+ throw new InvalidSelectorException(selector, e);
+ }
+ }
+
+ private IBooleanExpression AsBooleanExpression(IExpression value)
+ {
+ if(value is IBooleanExpression)
+ {
+ return (IBooleanExpression)value;
+ }
+ if(value is PropertyExpression)
+ {
+ return UnaryExpression.CreateBooleanCast(value);
+ }
+ throw new ParseException("IExpression will not result in a boolean value: " + value);
+ }
+ }
+
+//}
+
+PARSER_END(SelectorParser)
+
+// ----------------------------------------------------------------------------
+// Tokens
+// ----------------------------------------------------------------------------
+
+/* White Space */
+SPECIAL_TOKEN :
+{
+ " " | "\t" | "\n" | "\r" | "\f"
+}
+
+/* Comments */
+SKIP:
+{
+ <LINE_COMMENT: "--" (~["\n","\r"])* ("\n"|"\r"|"\r\n") >
+}
+
+SKIP:
+{
+ <BLOCK_COMMENT: "/*" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
+}
+
+/* Reserved Words */
+TOKEN [IGNORE_CASE] :
+{
+ < NOT : "NOT">
+ | < AND : "AND">
+ | < OR : "OR">
+ | < BETWEEN : "BETWEEN">
+ | < LIKE : "LIKE">
+ | < ESCAPE : "ESCAPE">
+ | < IN : "IN">
+ | < IS : "IS">
+ | < TRUE : "TRUE" >
+ | < FALSE : "FALSE" >
+ | < NULL : "NULL" >
+ | < XPATH : "XPATH" >
+ | < XQUERY : "XQUERY" >
+}
+
+/* Literals */
+TOKEN [IGNORE_CASE] :
+{
+
+ < DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* (["l","L"])? >
+ | < HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
+ | < OCTAL_LITERAL: "0" (["0"-"7"])* >
+ | < FLOATING_POINT_LITERAL:
+ (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? // matches: 5.5 or 5. or 5.5E10 or 5.E10
+ | "." (["0"-"9"])+ (<EXPONENT>)? // matches: .5 or .5E10
+ | (["0"-"9"])+ <EXPONENT> // matches: 5E10
+ >
+ | < #EXPONENT: "E" (["+","-"])? (["0"-"9"])+ >
+ | < STRING_LITERAL: "'" ( ("''") | ~["'"] )* "'" >
+}
+
+TOKEN [IGNORE_CASE] :
+{
+ < ID : ["a"-"z", "_", "$"] (["a"-"z","0"-"9","_", "$"])* >
+}
+
+// ----------------------------------------------------------------------------
+// Grammar
+// ----------------------------------------------------------------------------
+IBooleanExpression JmsSelector() :
+{
+ IExpression left = null;
+}
+{
+ (
+ left = GetOrExpression()
+ )
+ {
+ return AsBooleanExpression(left);
+ }
+
+}
+
+IExpression GetOrExpression() :
+{
+ IExpression left;
+ IExpression right;
+}
+{
+ (
+ left = GetAndExpression()
+ (
+ <OR> right = GetAndExpression()
+ {
+ left = LogicExpression.CreateOR(AsBooleanExpression(left), AsBooleanExpression(right));
+ }
+ )*
+ )
+ {
+ return left;
+ }
+
+}
+
+
+IExpression GetAndExpression() :
+{
+ IExpression left;
+ IExpression right;
+}
+{
+ (
+ left = GetEqualityExpression()
+ (
+ <AND> right = GetEqualityExpression()
+ {
+ left = LogicExpression.CreateAND(AsBooleanExpression(left), AsBooleanExpression(right));
+ }
+ )*
+ )
+ {
+ return left;
+ }
+}
+
+IExpression GetEqualityExpression() :
+{
+ IExpression left;
+ IExpression right;
+}
+{
+ (
+ left = GetComparisonExpression()
+ (
+
+ "=" right = GetComparisonExpression()
+ {
+ left = ComparisonExpression.CreateEqual(left, right);
+ }
+ |
+ "<>" right = GetComparisonExpression()
+ {
+ left = ComparisonExpression.CreateNotEqual(left, right);
+ }
+ |
+ LOOKAHEAD(2)
+ <IS> <NULL>
+ {
+ left = ComparisonExpression.CreateIsNull(left);
+ }
+ |
+ <IS> <NOT> <NULL>
+ {
+ left = ComparisonExpression.CreateIsNotNull(left);
+ }
+ )*
+ )
+ {
+ return left;
+ }
+}
+
+IExpression GetComparisonExpression() :
+{
+ IExpression left;
+ IExpression right;
+ IExpression low;
+ IExpression high;
+ string t;
+ string u;
+ ArrayList list;
+}
+{
+ (
+ left = GetAddExpression()
+ (
+
+ ">" right = GetAddExpression()
+ {
+ left = ComparisonExpression.CreateGreaterThan(left, right);
+ }
+ |
+ ">=" right = GetAddExpression()
+ {
+ left = ComparisonExpression.CreateGreaterThanOrEqual(left, right);
+ }
+ |
+ "<" right = GetAddExpression()
+ {
+ left = ComparisonExpression.CreateLesserThan(left, right);
+ }
+ |
+ "<=" right = GetAddExpression()
+ {
+ left = ComparisonExpression.CreateLesserThanOrEqual(left, right);
+ }
+ |
+ {
+ u = null;
+ }
+ <LIKE> t = GetStringLitteral()
+ [ <ESCAPE> u = GetStringLitteral() ]
+ {
+ left = ComparisonExpression.CreateLike(left, t, u);
+ }
+ |
+ LOOKAHEAD(2)
+ {
+ u=null;
+ }
+ <NOT> <LIKE> t = GetStringLitteral() [ <ESCAPE> u = GetStringLitteral() ]
+ {
+ left = ComparisonExpression.CreateNotLike(left, t, u);
+ }
+ |
+ <BETWEEN> low = GetAddExpression() <AND> high = GetAddExpression()
+ {
+ left = ComparisonExpression.CreateBetween(left, low, high);
+ }
+ |
+ LOOKAHEAD(2)
+ <NOT> <BETWEEN> low = GetAddExpression() <AND> high = GetAddExpression()
+ {
+ left = ComparisonExpression.CreateNotBetween(left, low, high);
+ }
+ |
+ <IN>
+ "("
+ t = GetStringLitteral()
+ {
+ list = new ArrayList();
+ list.Add(t);
+ }
+ (
+ ","
+ t = GetStringLitteral()
+ {
+ list.Add(t);
+ }
+
+ )*
+ ")"
+ {
+ left = ComparisonExpression.CreateIn(left, list);
+ }
+ |
+ LOOKAHEAD(2)
+ <NOT> <IN>
+ "("
+ t = GetStringLitteral()
+ {
+ list = new ArrayList();
+ list.Add(t);
+ }
+ (
+ ","
+ t = GetStringLitteral()
+ {
+ list.Add(t);
+ }
+
+ )*
+ ")"
+ {
+ left = ComparisonExpression.CreateNotIn(left, list);
+ }
+
+ )*
+ )
+ {
+ return left;
+ }
+}
+
+IExpression GetAddExpression() :
+{
+ IExpression left;
+ IExpression right;
+}
+{
+ left = GetMultiplyExpression()
+ (
+ LOOKAHEAD( ("+"|"-") GetMultiplyExpression())
+ (
+ "+" right = GetMultiplyExpression()
+ {
+ left = ArithmeticExpression.CreatePlus(left, right);
+ }
+ |
+ "-" right = GetMultiplyExpression()
+ {
+ left = ArithmeticExpression.CreateMinus(left, right);
+ }
+ )
+
+ )*
+ {
+ return left;
+ }
+}
+
+IExpression GetMultiplyExpression() :
+{
+ IExpression left;
+ IExpression right;
+}
+{
+ left = GetUnaryExpression()
+ (
+ "*" right = GetUnaryExpression()
+ {
+ left = ArithmeticExpression.CreateMultiply(left, right);
+ }
+ |
+ "/" right = GetUnaryExpression()
+ {
+ left = ArithmeticExpression.CreateDivide(left, right);
+ }
+ |
+ "%" right = GetUnaryExpression()
+ {
+ left = ArithmeticExpression.CreateMod(left, right);
+ }
+
+ )*
+ {
+ return left;
+ }
+}
+
+
+IExpression GetUnaryExpression() :
+{
+ IExpression left = null;
+}
+{
+ (
+ LOOKAHEAD( "+" GetUnaryExpression() )
+ "+" left = GetUnaryExpression()
+ |
+ "-" left = GetUnaryExpression()
+ {
+ left = UnaryExpression.CreateNegate(left);
+ }
+ |
+ <NOT> left = GetUnaryExpression()
+ {
+ left = UnaryExpression.CreateNOT(AsBooleanExpression(left));
+ }
+ |
+ left = GetPrimaryExpression()
+ )
+ {
+ return left;
+ }
+
+}
+
+IExpression GetPrimaryExpression() :
+{
+ IExpression left = null;
+}
+{
+ (
+ left = GetLiteral()
+ |
+ left = GetVariable()
+ |
+ "(" left = GetOrExpression() ")"
+ )
+ {
+ return left;
+ }
+}
+
+
+
+ConstantExpression GetLiteral() :
+{
+ Token t;
+ string s;
+ ConstantExpression left = null;
+}
+{
+ (
+ (
+ s = GetStringLitteral()
+ {
+ left = new ConstantExpression(s);
+ }
+ )
+ |
+ (
+ t = <DECIMAL_LITERAL>
+ {
+ left = ConstantExpression.CreateFromDecimal(t.image);
+ }
+ )
+ |
+ (
+ t = <HEX_LITERAL>
+ {
+ left = ConstantExpression.CreateFromHex(t.image);
+ }
+ )
+ |
+ (
+ t = <OCTAL_LITERAL>
+ {
+ left = ConstantExpression.CreateFromOctal(t.image);
+ }
+ )
+ |
+ (
+ t = <FLOATING_POINT_LITERAL>
+ {
+ left = ConstantExpression.CreateFloat(t.image);
+ }
+ )
+ |
+ (
+ <TRUE>
+ {
+ left = ConstantExpression.TRUE;
+ }
+ )
+ |
+ (
+ <FALSE>
+ {
+ left = ConstantExpression.FALSE;
+ }
+ )
+ |
+ (
+ <NULL>
+ {
+ left = ConstantExpression.NULL;
+ }
+ )
+ )
+ {
+ return left;
+ }
+}
+
+string GetStringLitteral() :
+{
+ Token t;
+ StringBuilder rc = new StringBuilder();
+}
+{
+ t = <STRING_LITERAL>
+ {
+ // Decode the sting value.
+ String image = t.image;
+ for(int c = 1; c < image.Length - 1; c++)
+ {
+ char ch = image[c];
+ if(ch == '\'')
+ {
+ c++;
+ }
+ rc.Append(ch);
+ }
+ return rc.ToString();
+ }
+}
+
+PropertyExpression GetVariable() :
+{
+ Token t;
+ PropertyExpression left = null;
+}
+{
+ (
+ t = <ID>
+ {
+ left = new PropertyExpression(t.image);
+ }
+ )
+ {
+ return left;
+ }
+}
diff --git a/src/main/csharp/Selector/SelectorParserConstants.cs b/src/main/csharp/Selector/SelectorParserConstants.cs
new file mode 100644
index 0000000..5f75539
--- /dev/null
+++ b/src/main/csharp/Selector/SelectorParserConstants.cs
@@ -0,0 +1,75 @@
+/* Generated By:CSharpCC: Do not edit this line. SelectorParserConstants.cs */
+public class SelectorParserConstants {
+
+ public const int EOF = 0;
+ public const int LINE_COMMENT = 6;
+ public const int BLOCK_COMMENT = 7;
+ public const int NOT = 8;
+ public const int AND = 9;
+ public const int OR = 10;
+ public const int BETWEEN = 11;
+ public const int LIKE = 12;
+ public const int ESCAPE = 13;
+ public const int IN = 14;
+ public const int IS = 15;
+ public const int TRUE = 16;
+ public const int FALSE = 17;
+ public const int NULL = 18;
+ public const int XPATH = 19;
+ public const int XQUERY = 20;
+ public const int DECIMAL_LITERAL = 21;
+ public const int HEX_LITERAL = 22;
+ public const int OCTAL_LITERAL = 23;
+ public const int FLOATING_POINT_LITERAL = 24;
+ public const int EXPONENT = 25;
+ public const int STRING_LITERAL = 26;
+ public const int ID = 27;
+
+ public const int DEFAULT = 0;
+
+ public readonly string[] tokenImage = {
+ "<EOF>",
+ "\" \"",
+ "\"\\t\"",
+ "\"\\n\"",
+ "\"\\r\"",
+ "\"\\f\"",
+ "<LINE_COMMENT>",
+ "<BLOCK_COMMENT>",
+ "\"NOT\"",
+ "\"AND\"",
+ "\"OR\"",
+ "\"BETWEEN\"",
+ "\"LIKE\"",
+ "\"ESCAPE\"",
+ "\"IN\"",
+ "\"IS\"",
+ "\"TRUE\"",
+ "\"FALSE\"",
+ "\"NULL\"",
+ "\"XPATH\"",
+ "\"XQUERY\"",
+ "<DECIMAL_LITERAL>",
+ "<HEX_LITERAL>",
+ "<OCTAL_LITERAL>",
+ "<FLOATING_POINT_LITERAL>",
+ "<EXPONENT>",
+ "<STRING_LITERAL>",
+ "<ID>",
+ "\"=\"",
+ "\"<>\"",
+ "\">\"",
+ "\">=\"",
+ "\"<\"",
+ "\"<=\"",
+ "\"(\"",
+ "\",\"",
+ "\")\"",
+ "\"+\"",
+ "\"-\"",
+ "\"*\"",
+ "\"/\"",
+ "\"%\"",
+ };
+
+}
diff --git a/src/main/csharp/Selector/SelectorParserTokenManager.cs b/src/main/csharp/Selector/SelectorParserTokenManager.cs
new file mode 100644
index 0000000..e198265
--- /dev/null
+++ b/src/main/csharp/Selector/SelectorParserTokenManager.cs
@@ -0,0 +1,1042 @@
+/* Generated By:CSharpCC: Do not edit this line. SelectorParserTokenManager.cs */
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+using Apache.NMS;
+
+public class SelectorParserTokenManager : SelectorParserConstants {
+ public System.IO.TextWriter debugStream = Console.Out;
+ public void SetDebugStream(System.IO.TextWriter ds) { debugStream = ds; }
+private int mccStopAtPos(int pos, int kind)
+{
+ mccmatchedKind = kind;
+ mccmatchedPos = pos;
+ return pos + 1;
+}
+private int mccMoveStringLiteralDfa0_0()
+{
+ switch((int)curChar) {
+ case 9:
+ mccmatchedKind = 2;
+ return mccMoveNfa_0(5, 0);
+ case 10:
+ mccmatchedKind = 3;
+ return mccMoveNfa_0(5, 0);
+ case 12:
+ mccmatchedKind = 5;
+ return mccMoveNfa_0(5, 0);
+ case 13:
+ mccmatchedKind = 4;
+ return mccMoveNfa_0(5, 0);
+ case 32:
+ mccmatchedKind = 1;
+ return mccMoveNfa_0(5, 0);
+ case 37:
+ mccmatchedKind = 41;
+ return mccMoveNfa_0(5, 0);
+ case 40:
+ mccmatchedKind = 34;
+ return mccMoveNfa_0(5, 0);
+ case 41:
+ mccmatchedKind = 36;
+ return mccMoveNfa_0(5, 0);
+ case 42:
+ mccmatchedKind = 39;
+ return mccMoveNfa_0(5, 0);
+ case 43:
+ mccmatchedKind = 37;
+ return mccMoveNfa_0(5, 0);
+ case 44:
+ mccmatchedKind = 35;
+ return mccMoveNfa_0(5, 0);
+ case 45:
+ mccmatchedKind = 38;
+ return mccMoveNfa_0(5, 0);
+ case 47:
+ mccmatchedKind = 40;
+ return mccMoveNfa_0(5, 0);
+ case 60:
+ mccmatchedKind = 32;
+ return mccMoveStringLiteralDfa1_0(9126805504L);
+ case 61:
+ mccmatchedKind = 28;
+ return mccMoveNfa_0(5, 0);
+ case 62:
+ mccmatchedKind = 30;
+ return mccMoveStringLiteralDfa1_0(2147483648L);
+ case 65:
+ return mccMoveStringLiteralDfa1_0(512L);
+ case 66:
+ return mccMoveStringLiteralDfa1_0(2048L);
+ case 69:
+ return mccMoveStringLiteralDfa1_0(8192L);
+ case 70:
+ return mccMoveStringLiteralDfa1_0(131072L);
+ case 73:
+ return mccMoveStringLiteralDfa1_0(49152L);
+ case 76:
+ return mccMoveStringLiteralDfa1_0(4096L);
+ case 78:
+ return mccMoveStringLiteralDfa1_0(262400L);
+ case 79:
+ return mccMoveStringLiteralDfa1_0(1024L);
+ case 84:
+ return mccMoveStringLiteralDfa1_0(65536L);
+ case 88:
+ return mccMoveStringLiteralDfa1_0(1572864L);
+ case 97:
+ return mccMoveStringLiteralDfa1_0(512L);
+ case 98:
+ return mccMoveStringLiteralDfa1_0(2048L);
+ case 101:
+ return mccMoveStringLiteralDfa1_0(8192L);
+ case 102:
+ return mccMoveStringLiteralDfa1_0(131072L);
+ case 105:
+ return mccMoveStringLiteralDfa1_0(49152L);
+ case 108:
+ return mccMoveStringLiteralDfa1_0(4096L);
+ case 110:
+ return mccMoveStringLiteralDfa1_0(262400L);
+ case 111:
+ return mccMoveStringLiteralDfa1_0(1024L);
+ case 116:
+ return mccMoveStringLiteralDfa1_0(65536L);
+ case 120:
+ return mccMoveStringLiteralDfa1_0(1572864L);
+ default :
+ return mccMoveNfa_0(5, 0);
+ }
+}
+private int mccMoveStringLiteralDfa1_0(long active0)
+{
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) {
+ return mccMoveNfa_0(5, 0);
+ }
+ switch((int)curChar) {
+ case 61:
+ if ((active0 & 2147483648L) != 0L)
+ {
+ mccmatchedKind = 31;
+ mccmatchedPos = 1;
+ }
+ else if ((active0 & 8589934592L) != 0L)
+ {
+ mccmatchedKind = 33;
+ mccmatchedPos = 1;
+ }
+ break;
+ case 62:
+ if ((active0 & 536870912L) != 0L)
+ {
+ mccmatchedKind = 29;
+ mccmatchedPos = 1;
+ }
+ break;
+ case 65:
+ return mccMoveStringLiteralDfa2_0(active0, 131072L);
+ case 69:
+ return mccMoveStringLiteralDfa2_0(active0, 2048L);
+ case 73:
+ return mccMoveStringLiteralDfa2_0(active0, 4096L);
+ case 78:
+ if ((active0 & 16384L) != 0L)
+ {
+ mccmatchedKind = 14;
+ mccmatchedPos = 1;
+ }
+ return mccMoveStringLiteralDfa2_0(active0, 512L);
+ case 79:
+ return mccMoveStringLiteralDfa2_0(active0, 256L);
+ case 80:
+ return mccMoveStringLiteralDfa2_0(active0, 524288L);
+ case 81:
+ return mccMoveStringLiteralDfa2_0(active0, 1048576L);
+ case 82:
+ if ((active0 & 1024L) != 0L)
+ {
+ mccmatchedKind = 10;
+ mccmatchedPos = 1;
+ }
+ return mccMoveStringLiteralDfa2_0(active0, 65536L);
+ case 83:
+ if ((active0 & 32768L) != 0L)
+ {
+ mccmatchedKind = 15;
+ mccmatchedPos = 1;
+ }
+ return mccMoveStringLiteralDfa2_0(active0, 8192L);
+ case 85:
+ return mccMoveStringLiteralDfa2_0(active0, 262144L);
+ case 97:
+ return mccMoveStringLiteralDfa2_0(active0, 131072L);
+ case 101:
+ return mccMoveStringLiteralDfa2_0(active0, 2048L);
+ case 105:
+ return mccMoveStringLiteralDfa2_0(active0, 4096L);
+ case 110:
+ if ((active0 & 16384L) != 0L)
+ {
+ mccmatchedKind = 14;
+ mccmatchedPos = 1;
+ }
+ return mccMoveStringLiteralDfa2_0(active0, 512L);
+ case 111:
+ return mccMoveStringLiteralDfa2_0(active0, 256L);
+ case 112:
+ return mccMoveStringLiteralDfa2_0(active0, 524288L);
+ case 113:
+ return mccMoveStringLiteralDfa2_0(active0, 1048576L);
+ case 114:
+ if ((active0 & 1024L) != 0L)
+ {
+ mccmatchedKind = 10;
+ mccmatchedPos = 1;
+ }
+ return mccMoveStringLiteralDfa2_0(active0, 65536L);
+ case 115:
+ if ((active0 & 32768L) != 0L)
+ {
+ mccmatchedKind = 15;
+ mccmatchedPos = 1;
+ }
+ return mccMoveStringLiteralDfa2_0(active0, 8192L);
+ case 117:
+ return mccMoveStringLiteralDfa2_0(active0, 262144L);
+ default :
+ break;
+ }
+ return mccMoveNfa_0(5, 1);
+}
+private int mccMoveStringLiteralDfa2_0(long old0, long active0)
+{
+ if (((active0 &= old0)) == 0L)
+ return mccMoveNfa_0(5, 1);
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) {
+ return mccMoveNfa_0(5, 1);
+ }
+ switch((int)curChar) {
+ case 65:
+ return mccMoveStringLiteralDfa3_0(active0, 524288L);
+ case 67:
+ return mccMoveStringLiteralDfa3_0(active0, 8192L);
+ case 68:
+ if ((active0 & 512L) != 0L)
+ {
+ mccmatchedKind = 9;
+ mccmatchedPos = 2;
+ }
+ break;
+ case 75:
+ return mccMoveStringLiteralDfa3_0(active0, 4096L);
+ case 76:
+ return mccMoveStringLiteralDfa3_0(active0, 393216L);
+ case 84:
+ if ((active0 & 256L) != 0L)
+ {
+ mccmatchedKind = 8;
+ mccmatchedPos = 2;
+ }
+ return mccMoveStringLiteralDfa3_0(active0, 2048L);
+ case 85:
+ return mccMoveStringLiteralDfa3_0(active0, 1114112L);
+ case 97:
+ return mccMoveStringLiteralDfa3_0(active0, 524288L);
+ case 99:
+ return mccMoveStringLiteralDfa3_0(active0, 8192L);
+ case 100:
+ if ((active0 & 512L) != 0L)
+ {
+ mccmatchedKind = 9;
+ mccmatchedPos = 2;
+ }
+ break;
+ case 107:
+ return mccMoveStringLiteralDfa3_0(active0, 4096L);
+ case 108:
+ return mccMoveStringLiteralDfa3_0(active0, 393216L);
+ case 116:
+ if ((active0 & 256L) != 0L)
+ {
+ mccmatchedKind = 8;
+ mccmatchedPos = 2;
+ }
+ return mccMoveStringLiteralDfa3_0(active0, 2048L);
+ case 117:
+ return mccMoveStringLiteralDfa3_0(active0, 1114112L);
+ default :
+ break;
+ }
+ return mccMoveNfa_0(5, 2);
+}
+private int mccMoveStringLiteralDfa3_0(long old0, long active0)
+{
+ if (((active0 &= old0)) == 0L)
+ return mccMoveNfa_0(5, 2);
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) {
+ return mccMoveNfa_0(5, 2);
+ }
+ switch((int)curChar) {
+ case 65:
+ return mccMoveStringLiteralDfa4_0(active0, 8192L);
+ case 69:
+ if ((active0 & 4096L) != 0L)
+ {
+ mccmatchedKind = 12;
+ mccmatchedPos = 3;
+ }
+ else if ((active0 & 65536L) != 0L)
+ {
+ mccmatchedKind = 16;
+ mccmatchedPos = 3;
+ }
+ return mccMoveStringLiteralDfa4_0(active0, 1048576L);
+ case 76:
+ if ((active0 & 262144L) != 0L)
+ {
+ mccmatchedKind = 18;
+ mccmatchedPos = 3;
+ }
+ break;
+ case 83:
+ return mccMoveStringLiteralDfa4_0(active0, 131072L);
+ case 84:
+ return mccMoveStringLiteralDfa4_0(active0, 524288L);
+ case 87:
+ return mccMoveStringLiteralDfa4_0(active0, 2048L);
+ case 97:
+ return mccMoveStringLiteralDfa4_0(active0, 8192L);
+ case 101:
+ if ((active0 & 4096L) != 0L)
+ {
+ mccmatchedKind = 12;
+ mccmatchedPos = 3;
+ }
+ else if ((active0 & 65536L) != 0L)
+ {
+ mccmatchedKind = 16;
+ mccmatchedPos = 3;
+ }
+ return mccMoveStringLiteralDfa4_0(active0, 1048576L);
+ case 108:
+ if ((active0 & 262144L) != 0L)
+ {
+ mccmatchedKind = 18;
+ mccmatchedPos = 3;
+ }
+ break;
+ case 115:
+ return mccMoveStringLiteralDfa4_0(active0, 131072L);
+ case 116:
+ return mccMoveStringLiteralDfa4_0(active0, 524288L);
+ case 119:
+ return mccMoveStringLiteralDfa4_0(active0, 2048L);
+ default :
+ break;
+ }
+ return mccMoveNfa_0(5, 3);
+}
+private int mccMoveStringLiteralDfa4_0(long old0, long active0)
+{
+ if (((active0 &= old0)) == 0L)
+ return mccMoveNfa_0(5, 3);
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) {
+ return mccMoveNfa_0(5, 3);
+ }
+ switch((int)curChar) {
+ case 69:
+ if ((active0 & 131072L) != 0L)
+ {
+ mccmatchedKind = 17;
+ mccmatchedPos = 4;
+ }
+ return mccMoveStringLiteralDfa5_0(active0, 2048L);
+ case 72:
+ if ((active0 & 524288L) != 0L)
+ {
+ mccmatchedKind = 19;
+ mccmatchedPos = 4;
+ }
+ break;
+ case 80:
+ return mccMoveStringLiteralDfa5_0(active0, 8192L);
+ case 82:
+ return mccMoveStringLiteralDfa5_0(active0, 1048576L);
+ case 101:
+ if ((active0 & 131072L) != 0L)
+ {
+ mccmatchedKind = 17;
+ mccmatchedPos = 4;
+ }
+ return mccMoveStringLiteralDfa5_0(active0, 2048L);
+ case 104:
+ if ((active0 & 524288L) != 0L)
+ {
+ mccmatchedKind = 19;
+ mccmatchedPos = 4;
+ }
+ break;
+ case 112:
+ return mccMoveStringLiteralDfa5_0(active0, 8192L);
+ case 114:
+ return mccMoveStringLiteralDfa5_0(active0, 1048576L);
+ default :
+ break;
+ }
+ return mccMoveNfa_0(5, 4);
+}
+private int mccMoveStringLiteralDfa5_0(long old0, long active0)
+{
+ if (((active0 &= old0)) == 0L)
+ return mccMoveNfa_0(5, 4);
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) {
+ return mccMoveNfa_0(5, 4);
+ }
+ switch((int)curChar) {
+ case 69:
+ if ((active0 & 8192L) != 0L)
+ {
+ mccmatchedKind = 13;
+ mccmatchedPos = 5;
+ }
+ return mccMoveStringLiteralDfa6_0(active0, 2048L);
+ case 89:
+ if ((active0 & 1048576L) != 0L)
+ {
+ mccmatchedKind = 20;
+ mccmatchedPos = 5;
+ }
+ break;
+ case 101:
+ if ((active0 & 8192L) != 0L)
+ {
+ mccmatchedKind = 13;
+ mccmatchedPos = 5;
+ }
+ return mccMoveStringLiteralDfa6_0(active0, 2048L);
+ case 121:
+ if ((active0 & 1048576L) != 0L)
+ {
+ mccmatchedKind = 20;
+ mccmatchedPos = 5;
+ }
+ break;
+ default :
+ break;
+ }
+ return mccMoveNfa_0(5, 5);
+}
+private int mccMoveStringLiteralDfa6_0(long old0, long active0)
+{
+ if (((active0 &= old0)) == 0L)
+ return mccMoveNfa_0(5, 5);
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) {
+ return mccMoveNfa_0(5, 5);
+ }
+ switch((int)curChar) {
+ case 78:
+ if ((active0 & 2048L) != 0L)
+ {
+ mccmatchedKind = 11;
+ mccmatchedPos = 6;
+ }
+ break;
+ case 110:
+ if ((active0 & 2048L) != 0L)
+ {
+ mccmatchedKind = 11;
+ mccmatchedPos = 6;
+ }
+ break;
+ default :
+ break;
+ }
+ return mccMoveNfa_0(5, 6);
+}
+private void mccCheckNAdd(int state)
+{
+ if (mccrounds[state] != mccround)
+ {
+ mccstateSet[mccnewStateCnt++] = state;
+ mccrounds[state] = mccround;
+ }
+}
+private void mccAddStates(int start, int end)
+{
+ do {
+ mccstateSet[mccnewStateCnt++] = mccnextStates[start];
+ } while (start++ != end);
+}
+private void mccCheckNAddTwoStates(int state1, int state2)
+{
+ mccCheckNAdd(state1);
+ mccCheckNAdd(state2);
+}
+private void mccCheckNAddStates(int start, int end)
+{
+ do {
+ mccCheckNAdd(mccnextStates[start]);
+ } while (start++ != end);
+}
+private void mccCheckNAddStates(int start)
+{
+ mccCheckNAdd(mccnextStates[start]);
+ mccCheckNAdd(mccnextStates[start + 1]);
+}
+static readonly long[] mccbitVec0 = {
+ -2, -1L, -1L, -1L
+};
+static readonly long[] mccbitVec1 = {
+ -1L, -1L, -1L, -1L
+};
+static readonly long[] mccbitVec2 = {
+ 0L, 0L, -1L, -1L
+};
+private int mccMoveNfa_0(int startState, int curPos)
+{
+ int strKind = mccmatchedKind;
+ int strPos = mccmatchedPos;
+ int seenUpto = curPos + 1;
+ input_stream.Backup(seenUpto);
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) { throw new Exception("Internal Error"); }
+ curPos = 0;
+ //int[] nextStates;
+ int startsAt = 0;
+ mccnewStateCnt = 43;
+ int i = 1;
+ mccstateSet[0] = startState;
+ int /*j,*/ kind = Int32.MaxValue;
+ for (;;)
+ {
+ if (++mccround == Int32.MaxValue)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(mccstateSet[--i])
+ {
+ case 5:
+ if ((287948901175001088 & l) != 0L)
+ mccCheckNAddStates(0, 3);
+ else if (curChar == 36)
+ {
+ if (kind > 27)
+ kind = 27;
+ mccCheckNAdd(27);
+ }
+ else if (curChar == 39)
+ mccCheckNAddStates(4, 6);
+ else if (curChar == 46)
+ mccCheckNAdd(17);
+ else if (curChar == 47)
+ mccstateSet[mccnewStateCnt++] = 6;
+ else if (curChar == 45)
+ mccstateSet[mccnewStateCnt++] = 0;
+ if ((287667426198290432 & l) != 0L)
+ {
+ if (kind > 21)
+ kind = 21;
+ mccCheckNAddTwoStates(14, 15);
+ }
+ else if (curChar == 48)
+ {
+ if (kind > 23)
+ kind = 23;
+ mccCheckNAddTwoStates(40, 42);
+ }
+ break;
+ case 0:
+ if (curChar == 45)
+ mccCheckNAddStates(7, 9);
+ break;
+ case 1:
+ if ((-9217 & l) != 0L)
+ mccCheckNAddStates(7, 9);
+ break;
+ case 2:
+ if ((9216 & l) != 0L && kind > 6)
+ kind = 6;
+ break;
+ case 3:
+ if (curChar == 10 && kind > 6)
+ kind = 6;
+ break;
+ case 4:
+ if (curChar == 13)
+ mccstateSet[mccnewStateCnt++] = 3;
+ break;
+ case 6:
+ if (curChar == 42)
+ mccCheckNAddTwoStates(7, 8);
+ break;
+ case 7:
+ if ((-4398046511105 & l) != 0L)
+ mccCheckNAddTwoStates(7, 8);
+ break;
+ case 8:
+ if (curChar == 42)
+ mccCheckNAddStates(10, 12);
+ break;
+ case 9:
+ if ((-145135534866433 & l) != 0L)
+ mccCheckNAddTwoStates(10, 8);
+ break;
+ case 10:
+ if ((-4398046511105 & l) != 0L)
+ mccCheckNAddTwoStates(10, 8);
+ break;
+ case 11:
+ if (curChar == 47 && kind > 7)
+ kind = 7;
+ break;
+ case 12:
+ if (curChar == 47)
+ mccstateSet[mccnewStateCnt++] = 6;
+ break;
+ case 13:
+ if ((287667426198290432 & l) == 0L)
+ break;
+ if (kind > 21)
+ kind = 21;
+ mccCheckNAddTwoStates(14, 15);
+ break;
+ case 14:
+ if ((287948901175001088 & l) == 0L)
+ break;
+ if (kind > 21)
+ kind = 21;
+ mccCheckNAddTwoStates(14, 15);
+ break;
+ case 16:
+ if (curChar == 46)
+ mccCheckNAdd(17);
+ break;
+ case 17:
+ if ((287948901175001088 & l) == 0L)
+ break;
+ if (kind > 24)
+ kind = 24;
+ mccCheckNAddTwoStates(17, 18);
+ break;
+ case 19:
+ if ((43980465111040 & l) != 0L)
+ mccCheckNAdd(20);
+ break;
+ case 20:
+ if ((287948901175001088 & l) == 0L)
+ break;
+ if (kind > 24)
+ kind = 24;
+ mccCheckNAdd(20);
+ break;
+ case 21:
+ case 22:
+ if (curChar == 39)
+ mccCheckNAddStates(4, 6);
+ break;
+ case 23:
+ if (curChar == 39)
+ mccstateSet[mccnewStateCnt++] = 22;
+ break;
+ case 24:
+ if ((-549755813889 & l) != 0L)
+ mccCheckNAddStates(4, 6);
+ break;
+ case 25:
+ if (curChar == 39 && kind > 26)
+ kind = 26;
+ break;
+ case 26:
+ if (curChar != 36)
+ break;
+ if (kind > 27)
+ kind = 27;
+ mccCheckNAdd(27);
+ break;
+ case 27:
+ if ((287948969894477824 & l) == 0L)
+ break;
+ if (kind > 27)
+ kind = 27;
+ mccCheckNAdd(27);
+ break;
+ case 28:
+ if ((287948901175001088 & l) != 0L)
+ mccCheckNAddStates(0, 3);
+ break;
+ case 29:
+ if ((287948901175001088 & l) != 0L)
+ mccCheckNAddTwoStates(29, 30);
+ break;
+ case 30:
+ if (curChar != 46)
+ break;
+ if (kind > 24)
+ kind = 24;
+ mccCheckNAddTwoStates(31, 32);
+ break;
+ case 31:
+ if ((287948901175001088 & l) == 0L)
+ break;
+ if (kind > 24)
+ kind = 24;
+ mccCheckNAddTwoStates(31, 32);
+ break;
+ case 33:
+ if ((43980465111040 & l) != 0L)
+ mccCheckNAdd(34);
+ break;
+ case 34:
+ if ((287948901175001088 & l) == 0L)
+ break;
+ if (kind > 24)
+ kind = 24;
+ mccCheckNAdd(34);
+ break;
+ case 35:
+ if ((287948901175001088 & l) != 0L)
+ mccCheckNAddTwoStates(35, 36);
+ break;
+ case 37:
+ if ((43980465111040 & l) != 0L)
+ mccCheckNAdd(38);
+ break;
+ case 38:
+ if ((287948901175001088 & l) == 0L)
+ break;
+ if (kind > 24)
+ kind = 24;
+ mccCheckNAdd(38);
+ break;
+ case 39:
+ if (curChar != 48)
+ break;
+ if (kind > 23)
+ kind = 23;
+ mccCheckNAddTwoStates(40, 42);
+ break;
+ case 41:
+ if ((287948901175001088 & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ mccstateSet[mccnewStateCnt++] = 41;
+ break;
+ case 42:
+ if ((71776119061217280 & l) == 0L)
+ break;
+ if (kind > 23)
+ kind = 23;
+ mccCheckNAdd(42);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 63);
+ do
+ {
+ switch(mccstateSet[--i])
+ {
+ case 5:
+ case 27:
+ if ((576460745995190270 & l) == 0L)
+ break;
+ if (kind > 27)
+ kind = 27;
+ mccCheckNAdd(27);
+ break;
+ case 1:
+ mccAddStates(7, 9);
+ break;
+ case 7:
+ mccCheckNAddTwoStates(7, 8);
+ break;
+ case 9:
+ case 10:
+ mccCheckNAddTwoStates(10, 8);
+ break;
+ case 15:
+ if ((17592186048512 & l) != 0L && kind > 21)
+ kind = 21;
+ break;
+ case 18:
+ if ((137438953504 & l) != 0L)
+ mccAddStates(13, 14);
+ break;
+ case 24:
+ mccAddStates(4, 6);
+ break;
+ case 32:
+ if ((137438953504 & l) != 0L)
+ mccAddStates(15, 16);
+ break;
+ case 36:
+ if ((137438953504 & l) != 0L)
+ mccAddStates(17, 18);
+ break;
+ case 40:
+ if ((72057594054705152 & l) != 0L)
+ mccCheckNAdd(41);
+ break;
+ case 41:
+ if ((541165879422 & l) == 0L)
+ break;
+ if (kind > 22)
+ kind = 22;
+ mccCheckNAdd(41);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int hiByte = (curChar >> 8);
+ int i1 = hiByte >> 6;
+ long l1 = 1L << (hiByte & 63);
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 63);
+ do
+ {
+ switch(mccstateSet[--i])
+ {
+ case 1:
+ if (mccCanMove_0(hiByte, i1, i2, l1, l2))
+ mccAddStates(7, 9);
+ break;
+ case 7:
+ if (mccCanMove_0(hiByte, i1, i2, l1, l2))
+ mccCheckNAddTwoStates(7, 8);
+ break;
+ case 9:
+ case 10:
+ if (mccCanMove_0(hiByte, i1, i2, l1, l2))
+ mccCheckNAddTwoStates(10, 8);
+ break;
+ case 24:
+ if (mccCanMove_0(hiByte, i1, i2, l1, l2))
+ mccAddStates(4, 6);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != Int32.MaxValue)
+ {
+ mccmatchedKind = kind;
+ mccmatchedPos = curPos;
+ kind = Int32.MaxValue;
+ }
+ ++curPos;
+ if ((i = mccnewStateCnt) == (startsAt = 43 - (mccnewStateCnt = startsAt)))
+ break;
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) { break; }
+ }
+ if (mccmatchedPos > strPos)
+ return curPos;
+
+ int toRet = Math.Max(curPos, seenUpto);
+
+ if (curPos < toRet)
+ for (i = toRet - Math.Min(curPos, seenUpto); i-- > 0; )
+ try { curChar = input_stream.ReadChar(); }
+ catch(System.IO.IOException) { throw new Exception("Internal Error : Please send a bug report."); }
+
+ if (mccmatchedPos < strPos)
+ {
+ mccmatchedKind = strKind;
+ mccmatchedPos = strPos;
+ }
+ else if (mccmatchedPos == strPos && mccmatchedKind > strKind)
+ mccmatchedKind = strKind;
+
+ return toRet;
+}
+static readonly int[] mccnextStates = {
+ 29, 30, 35, 36, 23, 24, 25, 1, 2, 4, 8, 9, 11, 19, 20, 33,
+ 34, 37, 38,
+};
+private static bool mccCanMove_0(int hiByte, int i1, int i2, long l1, long l2)
+{
+ switch(hiByte)
+ {
+ case 0:
+ return ((mccbitVec2[i2] & l2) != 0L);
+ default :
+ if ((mccbitVec0[i1] & l1) != 0L)
+ if ((mccbitVec1[i2] & l2) == 0L)
+ return false;
+ else
+ return true;
+ return false;
+ }
+}
+public static readonly string[] mccstrLiteralImages = {
+"", null, null, null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+null, "=", "<>", ">", ">=", "<", "<=", "(", ",", ")", "+", "-", "*", "/", "%", };
+public static readonly string[] lexStateNames = {
+ "DEFAULT",
+};
+static readonly long[] mcctoToken = {
+ 4398012956417,
+};
+static readonly long[] mcctoSkip = {
+ 254,
+};
+static readonly long[] mcctoSpecial = {
+ 62,
+};
+protected SimpleCharStream input_stream;
+private readonly int[] mccrounds = new int[43];
+private readonly int[] mccstateSet = new int[86];
+protected char curChar;
+public SelectorParserTokenManager(SimpleCharStream stream) {
+ if (SimpleCharStream.staticFlag)
+ throw new System.SystemException("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+ input_stream = stream;
+}
+public SelectorParserTokenManager(SimpleCharStream stream, int lexState)
+ : this(stream) {
+ SwitchTo(lexState);
+}
+public void ReInit(SimpleCharStream stream) {
+ mccmatchedPos = mccnewStateCnt = 0;
+ curLexState = defaultLexState;
+ input_stream = stream;
+ ReInitRounds();
+}
+private void ReInitRounds()
+{
+ int i;
+ mccround = -2147483647;
+ for (i = 43; i-- > 0;)
+ mccrounds[i] = Int32.MinValue;
+}
+public void ReInit(SimpleCharStream stream, int lexState) {
+ ReInit(stream);
+ SwitchTo(lexState);
+}
+public void SwitchTo(int lexState) {
+ if (lexState >= 1 || lexState < 0)
+ throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.InvalidLexicalState);
+ else
+ curLexState = lexState;
+}
+
+protected Token mccFillToken()
+{
+ Token t = Token.NewToken(mccmatchedKind);
+ t.kind = mccmatchedKind;
+ string im = mccstrLiteralImages[mccmatchedKind];
+ t.image = (im == null) ? input_stream.GetImage() : im;
+ t.beginLine = input_stream.BeginLine;
+ t.beginColumn = input_stream.BeginColumn;
+ t.endLine = input_stream.EndLine;
+ t.endColumn = input_stream.EndColumn;
+ return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int mccnewStateCnt;
+int mccround;
+int mccmatchedPos;
+int mccmatchedKind;
+
+public Token GetNextToken() {
+ //int kind;
+ Token specialToken = null;
+ Token matchedToken;
+ int curPos = 0;
+
+for (;;) {
+ try {
+ curChar = input_stream.BeginToken();
+ } catch(System.IO.IOException) {
+ mccmatchedKind = 0;
+ matchedToken = mccFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ }
+
+ mccmatchedKind = Int32.MaxValue;
+ mccmatchedPos = 0;
+ curPos = mccMoveStringLiteralDfa0_0();
+ if (mccmatchedKind != Int32.MaxValue) {
+ if (mccmatchedPos + 1 < curPos)
+ input_stream.Backup(curPos - mccmatchedPos - 1);
+ if ((mcctoToken[mccmatchedKind >> 6] & (1L << (mccmatchedKind & 63))) != 0L) {
+ matchedToken = mccFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ }
+ else
+ {
+ if ((mcctoSpecial[mccmatchedKind >> 6] & (1L << (mccmatchedKind & 63))) != 0L) {
+ matchedToken = mccFillToken();
+ if (specialToken == null)
+ specialToken = matchedToken;
+ else {
+ matchedToken.specialToken = specialToken;
+ specialToken = (specialToken.next = matchedToken);
+ }
+ }
+ goto EOFLoop;
+ }
+ }
+ int error_line = input_stream.EndLine;
+ int error_column = input_stream.EndColumn;
+ string error_after = null;
+ bool EOFSeen = false;
+ try { input_stream.ReadChar(); input_stream.Backup(1); }
+ catch (System.IO.IOException) {
+ EOFSeen = true;
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ if (curChar == '\n' || curChar == '\r') {
+ error_line++;
+ error_column = 0;
+ } else
+ error_column++;
+ }
+ if (!EOFSeen) {
+ input_stream.Backup(1);
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ }
+ throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LexicalError);
+EOFLoop: ;
+ }
+}
+
+}
diff --git a/src/main/csharp/Selector/SimpleCharStream.cs b/src/main/csharp/Selector/SimpleCharStream.cs
new file mode 100644
index 0000000..a49a9da
--- /dev/null
+++ b/src/main/csharp/Selector/SimpleCharStream.cs
@@ -0,0 +1,366 @@
+/* Generated By:CSharpCC: Do not edit this line. SimpleCharStream.cs Version 3.3 */
+/// <summary>
+/// An implementation of interface CharStream, where the stream is assumed to
+/// contain only ASCII characters (without unicode processing).
+/// </summary>
+
+public class SimpleCharStream {
+ public static readonly bool staticFlag = false;
+ int bufsize;
+ int available;
+ int tokenBegin;
+ public int bufpos = -1;
+ protected int[] bufline;
+ protected int[] bufcolumn;
+
+ protected int column = 0;
+ protected int line = 1;
+
+ protected bool prevCharIsCR = false;
+ protected bool prevCharIsLF = false;
+
+ protected System.IO.TextReader inputStream;
+
+ protected char[] buffer;
+ protected int maxNextCharInd = 0;
+ protected int inBuf = 0;
+
+ protected void ExpandBuff(bool wrapAround)
+ {
+ char[] newbuffer = new char[bufsize + 2048];
+ int[] newbufline = new int[bufsize + 2048];
+ int[] newbufcolumn = new int[bufsize + 2048];
+
+ try {
+ if (wrapAround) {
+ System.Array.Copy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.Array.Copy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
+
+ System.Array.Copy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.Array.Copy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
+
+ System.Array.Copy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.Array.Copy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ } else {
+ System.Array.Copy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
+
+ System.Array.Copy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
+
+ System.Array.Copy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ } catch (System.Exception e) {
+ throw new System.SystemException(e.Message);
+ }
+
+
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
+ }
+
+ protected void FillBuff() {
+ if (maxNextCharInd == available) {
+ if (available == bufsize) {
+ if (tokenBegin > 2048) {
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
+ } else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
+ else
+ ExpandBuff(false);
+ } else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
+
+ int i;
+ try {
+ if ((i = inputStream.Read(buffer, maxNextCharInd,
+ available - maxNextCharInd)) == -1) {
+ inputStream.Close();
+ throw new System.IO.IOException();
+ } else
+ maxNextCharInd += i;
+ return;
+ } catch(System.IO.IOException e) {
+ --bufpos;
+ Backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+ public char BeginToken() {
+ tokenBegin = -1;
+ try {
+ char c = ReadChar();
+ tokenBegin = bufpos;
+ return c;
+ } catch (System.IO.EndOfStreamException e) {
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+ protected void UpdateLineColumn(char c) {
+ column++;
+
+ if (prevCharIsLF) {
+ prevCharIsLF = false;
+ line += (column = 1);
+ } else if (prevCharIsCR) {
+ prevCharIsCR = false;
+ if (c == '\n') {
+ prevCharIsLF = true;
+ } else
+ line += (column = 1);
+ }
+
+ switch (c) {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (8 - (column & 07));
+ break;
+ default :
+ break;
+ }
+
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
+ }
+
+ public char ReadChar() {
+ if (inBuf > 0) {
+ --inBuf;
+
+ if (++bufpos == bufsize)
+ bufpos = 0;
+
+ return buffer[bufpos];
+ }
+
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
+ if (bufpos >= maxNextCharInd) {
+ bufpos--;
+ if (bufpos < 0)
+ bufpos += bufsize;
+ throw new System.IO.EndOfStreamException();
+ }
+
+ char c = buffer[bufpos];
+
+ UpdateLineColumn(c);
+ return (c);
+ }
+
+[System.Obsolete("Deprecated - use EndColumn instead.", false)]
+
+ public int Column {
+ get {
+ return bufcolumn[bufpos];
+ }
+ }
+
+[System.Obsolete("Deprecated - use EndLine instead.", false)]
+
+ public int Line {
+ get {
+ return bufline[bufpos];
+ }
+ }
+
+ public int EndColumn {
+ get {
+ return bufcolumn[bufpos];
+ }
+ }
+
+ public int EndLine {
+ get {
+ return bufline[bufpos];
+ }
+ }
+
+ public int BeginColumn {
+ get {
+ return bufcolumn[tokenBegin];
+ }
+ }
+
+ public int BeginLine {
+ get {
+ return bufline[tokenBegin];
+ }
+ }
+
+ public void Backup(int amount) {
+
+ inBuf += amount;
+ if ((bufpos -= amount) < 0)
+ bufpos += bufsize;
+ }
+
+ public SimpleCharStream(System.IO.TextReader dstream, int startline,
+ int startcolumn, int buffersize) {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+
+ public SimpleCharStream(System.IO.TextReader dstream, int startline,
+ int startcolumn) :
+ this(dstream, startline, startcolumn, 4096) {
+ }
+
+ public SimpleCharStream(System.IO.TextReader dstream) :
+ this(dstream, 1, 1, 4096) {
+ }
+ public void ReInit(System.IO.TextReader dstream, int startline,
+ int startcolumn, int buffersize) {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ if (buffer == null || buffersize != buffer.Length) {
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+ prevCharIsLF = prevCharIsCR = false;
+ tokenBegin = inBuf = maxNextCharInd = 0;
+ bufpos = -1;
+ }
+
+ public void ReInit(System.IO.TextReader dstream, int startline,
+ int startcolumn) {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ public void ReInit(System.IO.TextReader dstream) {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ public SimpleCharStream(System.IO.Stream dstream, int startline,
+ int startcolumn, int buffersize) :
+ this(new System.IO.StreamReader(dstream), startline, startcolumn, 4096) {
+ }
+
+ public SimpleCharStream(System.IO.Stream dstream, int startline,
+ int startcolumn) :
+ this(dstream, startline, startcolumn, 4096) {
+ }
+
+ public SimpleCharStream(System.IO.Stream dstream) :
+ this(dstream, 1, 1, 4096) {
+ }
+
+ public void ReInit(System.IO.Stream dstream, int startline,
+ int startcolumn, int buffersize) {
+ ReInit(new System.IO.StreamReader(dstream), startline, startcolumn, 4096);
+ }
+
+ public void ReInit(System.IO.Stream dstream) {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ public void ReInit(System.IO.Stream dstream, int startline,
+ int startcolumn) {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+ public string GetImage() {
+ if (bufpos >= tokenBegin)
+ return new string(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new string(buffer, tokenBegin, bufsize - tokenBegin) +
+ new string(buffer, 0, bufpos + 1);
+ }
+
+ public char[] GetSuffix(int len) {
+ char[] ret = new char[len];
+
+ if ((bufpos + 1) >= len)
+ System.Array.Copy(buffer, bufpos - len + 1, ret, 0, len);
+ else {
+ System.Array.Copy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.Array.Copy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
+
+ return ret;
+ }
+
+ public void Done()
+ {
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
+ }
+
+ /// <summary>
+ /// Method to adjust line and column numbers for the start of a token.
+ /// </summary>
+ public void AdjustBeginLineColumn(int newLine, int newCol) {
+ int start = tokenBegin;
+ int len;
+
+ if (bufpos >= tokenBegin) {
+ len = bufpos - tokenBegin + inBuf + 1;
+ } else {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
+
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
+
+ while (i < len &&
+ bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
+
+ if (i < len) {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
+
+ while (i++ < len) {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
+
+ line = bufline[j];
+ column = bufcolumn[j];
+ }
+
+}
diff --git a/src/main/csharp/Selector/Token.cs b/src/main/csharp/Selector/Token.cs
new file mode 100644
index 0000000..bc5b705
--- /dev/null
+++ b/src/main/csharp/Selector/Token.cs
@@ -0,0 +1,78 @@
+/* Generated By:CSharpCC: Do not edit this line. Token.cs Version 3.0 */
+/// <summary>
+/// Describes the input token stream.
+/// </summary>
+
+public class Token {
+
+ /// <summary>
+ /// Gets an integer that describes the kind of this token.
+ /// </summary>
+ /// <remarks>
+ /// This numbering system is determined by CSharpCCParser, and
+ /// a table of these numbers is stored in the class <see cref="SelectorParserConstants"/>.
+ /// </remarks>
+ public int kind;
+
+ /**
+ * beginLine and beginColumn describe the position of the first character
+ * of this token; endLine and endColumn describe the position of the
+ * last character of this token.
+ */
+ public int beginLine, beginColumn, endLine, endColumn;
+
+ /**
+ * The string image of the token.
+ */
+ public string image;
+
+ /**
+ * A reference to the next regular (non-special) token from the input
+ * stream. If this is the last token from the input stream, or if the
+ * token manager has not read tokens beyond this one, this field is
+ * set to null. This is true only if this token is also a regular
+ * token. Otherwise, see below for a description of the contents of
+ * this field.
+ */
+ public Token next;
+
+ /**
+ * This field is used to access special tokens that occur prior to this
+ * token, but after the immediately preceding regular (non-special) token.
+ * If there are no such special tokens, this field is set to null.
+ * When there are more than one such special token, this field refers
+ * to the last of these special tokens, which in turn refers to the next
+ * previous special token through its specialToken field, and so on
+ * until the first special token (whose specialToken field is null).
+ * The next fields of special tokens refer to other special tokens that
+ * immediately follow it (without an intervening regular token). If there
+ * is no such token, this field is null.
+ */
+ public Token specialToken;
+
+ /**
+ * Returns the image.
+ */
+ public override string ToString() {
+ return image;
+ }
+
+ /**
+ * Returns a new Token object, by default. However, if you want, you
+ * can create and return subclass objects based on the value of ofKind.
+ * Simply add the cases to the switch for all those special cases.
+ * For example, if you have a subclass of Token called IDToken that
+ * you want to create if ofKind is ID, simlpy add something like :
+ *
+ * case MyParserConstants.ID : return new IDToken();
+ *
+ * to the following switch statement. Then you can cast matchedToken
+ * variable to the appropriate type and use it in your lexical actions.
+ */
+ public static Token NewToken(int ofKind) {
+ switch(ofKind) {
+ default : return new Token();
+ }
+ }
+
+}
diff --git a/src/main/csharp/Selector/TokenMgrError.cs b/src/main/csharp/Selector/TokenMgrError.cs
new file mode 100644
index 0000000..b011703
--- /dev/null
+++ b/src/main/csharp/Selector/TokenMgrError.cs
@@ -0,0 +1,130 @@
+/* Generated By:CSharpCC: Do not edit this line. TokenMgrError.cs Version 3.0 */
+public class TokenMgrError : System.SystemException
+{
+ /*
+ * Ordinals for various reasons why an Exceptions of this type can be thrown.
+ */
+
+ /**
+ * Lexical error occured.
+ */
+ internal static readonly int LexicalError = 0;
+
+ /**
+ * An attempt wass made to create a second instance of a static token manager.
+ */
+ internal static readonly int StaticLexerError = 1;
+
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ internal static readonly int InvalidLexicalState = 2;
+
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ internal static readonly int LoopDetected = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their espaced (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static string AddEscapes(string str) {
+ System.Text.StringBuilder retval = new System.Text.StringBuilder();
+ char ch;
+ for (int i = 0; i < str.Length; i++) {
+ switch (str[i]) {
+ case '\0' :
+ continue;
+ case '\b':
+ retval.Append("\\b");
+ continue;
+ case '\t':
+ retval.Append("\\t");
+ continue;
+ case '\n':
+ retval.Append("\\n");
+ continue;
+ case '\f':
+ retval.Append("\\f");
+ continue;
+ case '\r':
+ retval.Append("\\r");
+ continue;
+ case '\"':
+ retval.Append("\\\"");
+ continue;
+ case '\'':
+ retval.Append("\\\'");
+ continue;
+ case '\\':
+ retval.Append("\\\\");
+ continue;
+ default:
+ if ((ch = str[i]) < 0x20 || ch > 0x7e) {
+ string s = "0000" + System.Convert.ToString((int)ch, 16);
+ retval.Append("\\u" + s.Substring(s.Length - 4, s.Length - (s.Length - 4)));
+ } else {
+ retval.Append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.ToString();
+ }
+
+ /**
+ * Returns a detailed message for the Exception when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexicl error
+ * curLexState : lexical state in which this error occured
+ * errorLine : line number when the error occured
+ * errorColumn : column number when the error occured
+ * errorAfter : prefix that was seen before this error occured
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static string GetLexicalError(bool EOFSeen, int lexState, int errorLine, int errorColumn, string errorAfter, char curChar) {
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? "<EOF> " : ("\"" + AddEscapes(curChar.ToString()) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + AddEscapes(errorAfter) + "\"");
+ }
+
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public override string Message {
+ get { return base.Message; }
+ }
+
+ /*
+ * Constructors of various flavors follow.
+ */
+
+ public TokenMgrError() {
+ }
+
+ public TokenMgrError(string message, int reason) :
+ base(message) {
+ errorCode = reason;
+ }
+
+ public TokenMgrError(bool EOFSeen, int lexState, int errorLine, int errorColumn, string errorAfter, char curChar, int reason) :
+ this(GetLexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason) {
+ }
+}
diff --git a/src/main/csharp/Selector/UnaryExpression.cs b/src/main/csharp/Selector/UnaryExpression.cs
new file mode 100644
index 0000000..4ccbbc0
--- /dev/null
+++ b/src/main/csharp/Selector/UnaryExpression.cs
@@ -0,0 +1,66 @@
+using System;
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.NMS.Selector
+{
+ /// <summary>
+ /// An expression which performs an operation on one expression value.
+ /// </summary>
+ public abstract class UnaryExpression : IExpression
+ {
+ protected IExpression rightExpression;
+ public IExpression Right
+ {
+ get { return rightExpression; }
+ set { rightExpression = value; }
+ }
+
+ protected abstract string ExpressionSymbol
+ {
+ get;
+ }
+
+ public UnaryExpression(IExpression left)
+ {
+ this.rightExpression = left;
+ }
+
+ public abstract object Evaluate(MessageEvaluationContext message);
+
+ public override string ToString()
+ {
+ return "(" + ExpressionSymbol + " " + rightExpression.ToString() + ")";
+ }
+
+ public static IExpression CreateNegate(IExpression left)
+ {
+ return new NegateExpression(left);
+ }
+
+ public static IBooleanExpression CreateNOT(IBooleanExpression left)
+ {
+ return new NOTExpression(left);
+ }
+
+ public static IBooleanExpression CreateBooleanCast(IExpression left)
+ {
+ return new BooleanCastExpression(left);
+ }
+ }
+}
diff --git a/src/main/csharp/Session.cs b/src/main/csharp/Session.cs
index 5172c08..b64c6ae 100644
--- a/src/main/csharp/Session.cs
+++ b/src/main/csharp/Session.cs
@@ -70,12 +70,8 @@
public IMessageConsumer CreateConsumer(IDestination destination, string selector, bool noLocal)
{
- if(selector != null)
- {
- throw new NotSupportedException("Selectors are not supported by MSMQ");
- }
MessageQueue queue = MessageConverter.ToMsmqDestination(destination);
- return new MessageConsumer(this, acknowledgementMode, queue);
+ return new MessageConsumer(this, acknowledgementMode, queue, selector);
}
public IMessageConsumer CreateDurableConsumer(ITopic destination, string name, string selector, bool noLocal)
@@ -95,12 +91,8 @@
public IQueueBrowser CreateBrowser(IQueue queue, string selector)
{
- if(selector != null)
- {
- throw new NotSupportedException("Selectors are not supported by MSMQ");
- }
MessageQueue msmqQueue = MessageConverter.ToMsmqDestination(queue);
- return new QueueBrowser(this, msmqQueue);
+ return new QueueBrowser(this, msmqQueue, selector);
}
public IQueue GetQueue(string name)
diff --git a/vs2008-msmq.csproj b/vs2008-msmq.csproj
index 8a20d12..3023e88 100644
--- a/vs2008-msmq.csproj
+++ b/vs2008-msmq.csproj
@@ -75,6 +75,7 @@
<Compile Include="src\main\csharp\DefaultMessageConverter.cs" />
<Compile Include="src\main\csharp\Destination.cs" />
<Compile Include="src\main\csharp\IMessageConverter.cs" />
+ <Compile Include="src\main\csharp\IMessageConverterEx.cs" />
<Compile Include="src\main\csharp\MapMessage.cs" />
<Compile Include="src\main\csharp\MessageConsumer.cs" />
<Compile Include="src\main\csharp\MessageProducer.cs" />
@@ -84,6 +85,52 @@
<Compile Include="src\main\csharp\Session.cs" />
<Compile Include="src\main\csharp\StreamMessage.cs" />
<Compile Include="src\main\csharp\TextMessage.cs" />
+ <Compile Include="src\main\csharp\Readers\AbstractMessageReader.cs" />
+ <Compile Include="src\main\csharp\Readers\ByCorrelationIdMessageReader.cs" />
+ <Compile Include="src\main\csharp\Readers\ByIdMessageReader.cs" />
+ <Compile Include="src\main\csharp\Readers\ByLookupIdMessageReader.cs" />
+ <Compile Include="src\main\csharp\Readers\BySelectorMessageReader.cs" />
+ <Compile Include="src\main\csharp\Readers\IMessageReader.cs" />
+ <Compile Include="src\main\csharp\Readers\MessageReaderUtil.cs" />
+ <Compile Include="src\main\csharp\Readers\NonFilteringMessageReader.cs" />
+ <Compile Include="src\main\csharp\Selector\AlignedNumericValues.cs" />
+ <Compile Include="src\main\csharp\Selector\ANDExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\ArithmeticExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\BinaryExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\BooleanCastExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\BooleanConstantExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\BooleanUnaryExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\ComparisonExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\ConstantExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\DivideExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\EqualExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\GreaterExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\GreaterOrEqualExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\IBooleanExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\IExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\InExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\IsNullExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\LesserExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\LesserOrEqualExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\LikeExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\LogicExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\MessageEvaluationContext.cs" />
+ <Compile Include="src\main\csharp\Selector\MinusExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\ModExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\MultiplyExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\NegateExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\NOTExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\ORExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\ParseException.cs" />
+ <Compile Include="src\main\csharp\Selector\PlusExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\PropertyExpression.cs" />
+ <Compile Include="src\main\csharp\Selector\SelectorParser.cs" />
+ <Compile Include="src\main\csharp\Selector\SelectorParserConstants.cs" />
+ <Compile Include="src\main\csharp\Selector\SelectorParserTokenManager.cs" />
+ <Compile Include="src\main\csharp\Selector\SimpleCharStream.cs" />
+ <Compile Include="src\main\csharp\Selector\Token.cs" />
+ <Compile Include="src\main\csharp\Selector\TokenMgrError.cs" />
+ <Compile Include="src\main\csharp\Selector\UnaryExpression.cs" />
</ItemGroup>
<ItemGroup>
<None Include="keyfile\NMSKey.snk" />