Hi, Awesome work. If you open and attach a patch to our issue tracker then we could start working on merging your change into the main line.
The issue tracker is here: https://issues.apache.org/activemq/browse/AMQNET And this page describes how to create patches: http://activemq.apache.org/contributing.html Regards, Hiram On 8/30/07, semog <[EMAIL PROTECTED]> wrote: > > Hi Peter, > > I have just spent the last week diagnosing and fixing this very problem in > the .NET client. It took me a long time to figure out exactly where the > problem was. There seems to be a disconnect between the concept of "time to > live" and "expiration". "Time to live" is a relative timespan, while > "expiration" is an absolute date/time. In addition, there is a bug in the > DateUtils class when converting between .NET DateTime and Java dates. Here > is the fix that I have come up with. Basically, I fixed the date utility > conversion functions. I then made the concept of "time to live" transparent > to the client API. ActiveMQ seems to require an absolute "expiration" time, > so I hid the translation of that inside the ActiveMQMessage class. > Following are the gist of my changes. I will show the key parts that you > can add, but you may have to change some supplementary files to make the > change complete, but those supplementary changes should be very obvious > (i.e., adding a declaration, or changing the NMSExpiration to > NMSTimeToLive). Try these changes and see if they work for you: > > Here is my new implementation of the DateUtils class. This is a complete > drop-in replacement. The key fix here was the old implementation mixed > calculating ticks with millisecends. Ticks are defined as 100-nanosecond > increments, a calculation error factor of 10,000: > > internal class DateUtils > { > /// <summary> > /// The start of the Windows epoch > /// </summary> > public static readonly DateTime windowsEpoch = new > DateTime(1601, 1, 1, 0, > 0, 0, 0); > /// <summary> > /// The start of the Java epoch > /// </summary> > public static readonly DateTime javaEpoch = new > DateTime(1970, 1, 1, 0, 0, > 0, 0); > > /// <summary> > /// The difference between the Windows epoch and the Java > epoch > /// in milliseconds. > /// </summary> > public static readonly long epochDiff; /* = 1164447360000L; */ > > static DateUtils() > { > epochDiff = (javaEpoch.ToFileTime() - > windowsEpoch.ToFileTime()) > / > TimeSpan.TicksPerMillisecond; > } > > public static long ToJavaTime(DateTime dateTime) > { > return (dateTime.ToFileTime() / > TimeSpan.TicksPerMillisecond) - > epochDiff; > } > > public static DateTime ToDateTime(long javaTime) > { > return DateTime.FromFileTime((javaTime + epochDiff) * > TimeSpan.TicksPerMillisecond); > } > } > > In IMessage.cs, change the interface declaration name for NMSExpiration to > NMSTimeToLive. In the ActiveMQMessage.cs file, add the following member > variable to ActiveMQMessage: > > protected DateTime expirationBaseTime; > > In the same ActiveMQMessage.cs file, change the definition for NMSExpiration > into the following definition for NMSTimeToLive (renaming the property field > at the same time): > > /// <summary> > /// The time in milliseconds that this message should expire in > /// </summary> > public TimeSpan NMSTimeToLive > { > get { > if(0 != Expiration) > { > DateTime expirationTime = > DateUtils.ToDateTime(Expiration); > return expirationTime - > expirationBaseTime; > } > else > { > return TimeSpan.FromMilliseconds(0); > } > } > set { > expirationBaseTime = DateTime.UtcNow; > Expiration = > DateUtils.ToJavaTime(expirationBaseTime + value); > } > } > > I also changed the NMSTimeStamp property as follows. I added a setter > property, which makes things much easier on the client side: > > /// <summary> > /// The timestamp the broker added to the message > /// </summary> > public DateTime NMSTimestamp > { > get { > return DateUtils.ToDateTime(Timestamp); > } > set { > Timestamp = DateUtils.ToJavaTime(value); > } > } > > Now, in the ActiveMQ MessageProducer.cs file, change the Send(...) function > as follows: > > protected void Send(IDestination destination, IMessage > message, bool > persistent, byte priority, TimeSpan timeToLive, bool specifiedTimeToLive) > { > ActiveMQMessage activeMessage = > (ActiveMQMessage)message; > > if (!disableMessageID) > { > MessageId id = new MessageId(); > id.ProducerId = info.ProducerId; > lock (this) > { > id.ProducerSequenceId = > ++messageCounter; > } > > activeMessage.MessageId = id; > } > > activeMessage.ProducerId = info.ProducerId; > activeMessage.FromDestination = destination; > activeMessage.NMSPersistent = persistent; > activeMessage.NMSPriority = priority; > > if (session.Transacted) > { > session.DoStartTransaction(); > activeMessage.TransactionId = > session.TransactionContext.TransactionId; > } > > if (specifiedTimeToLive) > { > activeMessage.NMSTimeToLive = timeToLive; > } > > if (!disableMessageTimestamp) > { > activeMessage.NMSTimestamp = DateTime.UtcNow; > } > > session.DoSend(activeMessage); > } > > Notice that the setting of the NMSTimestamp property does not require > conversion to Java time from .NET time format, as this is taken care of > inside the new setter property. At any level above this where you may have > explicitly set the NMSExpiration property of the message, will need to be > changed to NMSTimeToLive. The NMSTimeToLive property is now correctly and > consistently a timespan, instead of an absolute date/time. These changes > are much more logical to me, and I will continue with my version of the > client. These changes allow my .NET clients to deal compleletly in .NET > date/time format and the conversion to/from Java date/time format is hidden. > > Like I mentioned, you will need to make some trivial changes to MSMQ > implementation and one or two test cases, but those are simple renames. I > hope that this can save you some time. Since I am new to this list, I > haven't found the directions on how to submit these changes back for > possible commit into the actual source code. Perhaps this is the first step > in that process. > > Thanks. Please let me know if you have any questions or need further > assistance in this area. > > - Jim Gomes > > > > PeterNilsson wrote: > > > > Hi, > > > > We have just started setting timeToLive when sending messages with the > > ActiveMQ.Net client. However we get an exception when sending: > > > > mscorlib.dll!System.DateTime.ToFileTimeUtc() + 0xad bytes > > mscorlib.dll!System.DateTime.ToFileTime() + 0x1c bytes > > NMS.ActiveMQ.DLL!ActiveMQ.Util.DateUtils.ToJavaTime(System.DateTime > > dateTime = {0001-01-01 00:00:05}) Line 46 + 0x8 bytes C# > > NMS.ActiveMQ.DLL!ActiveMQ.Util.DateUtils.ToJavaTime(System.TimeSpan > > timeToLive = {00:00:05}) Line 41 + 0x35 bytes C# > > NMS.ActiveMQ.DLL!ActiveMQ.MessageProducer.Send(NMS.IDestination > > destination = {queue://test}, NMS.IMessage message = > > {ActiveMQBytesMessage[ ProducerId= Destination= TransactionId= > > OriginalDestination= MessageId=MessageId[ ProducerId=ProducerId[ > > ConnectionId=a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575 Value=1 SessionId=1 ] > > ProducerSequenceId=1 BrokerSequenceId=0 ] OriginalTransactionId= GroupID= > > GroupSequence=0 CorrelationId=0 Persistent=False Expiration=0 Priority=0 > > ReplyTo=temp-queue://a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575:1 > > Timestamp=128310953802143903 Type= Content=System.Byte[] > > MarshalledProperties= DataStructure= TargetConsumerId= Compressed=False > > RedeliveryCounter=0 BrokerPath= Arrival=0 UserID= RecievedByDFBridge=False > > Droppable=False ]}, bool persistent = false, byte priority = 5, > > System.TimeSpan timeToLive = {00:00:05}, bool specifiedTimeToLive = true) > > Line 88 + 0x17 bytes C# > > NMS.ActiveMQ.DLL!ActiveMQ.MessageProducer.Send(NMS.IDestination > > destination = {queue://test}, NMS.IMessage message = > > {ActiveMQBytesMessage[ ProducerId= Destination= TransactionId= > > OriginalDestination= MessageId=MessageId[ ProducerId=ProducerId[ > > ConnectionId=a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575 Value=1 SessionId=1 ] > > ProducerSequenceId=1 BrokerSequenceId=0 ] OriginalTransactionId= GroupID= > > GroupSequence=0 CorrelationId=0 Persistent=False Expiration=0 Priority=0 > > ReplyTo=temp-queue://a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575:1 > > Timestamp=128310953802143903 Type= Content=System.Byte[] > > MarshalledProperties= DataStructure= TargetConsumerId= Compressed=False > > RedeliveryCounter=0 BrokerPath= Arrival=0 UserID= RecievedByDFBridge=False > > Droppable=False ]}, bool persistent = false, byte priority = 5, > > System.TimeSpan timeToLive = {00:00:05}) Line 62 + 0x27 bytes C# > > > > When looking at the code for MessageProducer it looks like timestamp has > > been omitted from the calculation of expiration: > > > > if (specifiedTimeToLive) { > > activeMessage.Expiration = > > ActiveMQ.Util.DateUtils.ToJavaTime(timeToLive); > > } > > > > It looks like a bug to me, do you agree? > > > > Peter > > > > > > -- > View this message in context: > http://www.nabble.com/ActiveMQ.Net%3A-Client-does-not-include-timestamp-when-calculating-expiration-tf4312287s2354.html#a12412240 > Sent from the ActiveMQ - Dev mailing list archive at Nabble.com. > > -- Regards, Hiram Blog: http://hiramchirino.com
