3

Recently, I had the task to implement a research project where I had to read an XML file. XML file contained a list of messages that I had to send to some other system on a specific port. Each message has a type which can be either receive/transmit. Receive means that I have to receive a message from some port and transmit means that I have to send a message. xml represents the message that I have to send/receive. Example of such an XML is as follows

<Messages>
  <Message name="A" xml="A.xml" port="PortA" type="receive" time="0" />
  <Message name="B" xml="B.xml" port="PortA" type="transmit" time="11" />
  <Message name="C" xml="C.xml" port="PortB" type="receive" time="0" />
  <Message name="D" xml="D.xml" port="PortB" type="transmit" time="0" />
</Messages>

To handle this, I used iterator pattern with simple methods like getNextMessage(), hasNextMessage() and loadFile(). This abstraction worked out fine and other classes were not effected if I changed something in my message handling classes (MessageHandler).

As requirements kept on increasing, I had to add more methods to my MessageHandler class to handle complex scenarios. So, I added a few more methods

getNextMessageWithoutIterator() - By default getNextMessage() was internally incrementing a pointer which always pointed to current message being processed. But a requirement came which required me to have knowledge of 1 message ahead (If I was processing Message A then this requirement also needed the knowledge of next Message B). So, this method gives me the next message but without incrementing the pointer/iterator.

incrementToNextReceive() - Since, this was an application communicating between multiple systems, sometimes messages were received earlier than expected. So, my order of processing was disturbed. To handle that, I added this method which internally creates another pointer. This pointer is set to the out of order message. So, when my normal flow will come to this pointer, it will ignore this message because we have already received and processed it.

and a few more. You get the idea that what started as a simple class now has grown to big class trying to facilitate all the possible scenario. Now, recently we decided that the current structure of XML file is not sufficient and we moved to a more complex structure. This example structure is more or less representing what was in the old structure. Transition = receive type message and Send is the transmit type message.

<Sequence>
    <Transition stateName="S0" port="portA" match="A.xml" nextState="S1">
        <Send message="B.xml" port="portA" timeDelta="0" />
    </Transition>
    <Transition stateName="S1" port="portB" match="C.xml" nextState="S2">
        <Send message="D.xml" port="portB" timeDelta="1" />
    </Transition>
</Sequence>

Now, we want to support both types of XML files. The way we access the messages are very different in both XML files. The old structure was sequential where we start from Message A and go till Message Z. But in new structure, the flow of code will enter any Transition that fulfills all the requirements.

Problem: In my code, I was using the MessageHandler at different locations like ProcessMessages. Now, since more requirements kept of adding, MessageHandlar became less abstract and other classes started to depend and know about the internal working of MessageHandler which created dependency. So,

What can be the solution of my current problem. Should I stick to the Iterator Pattern and somehow try to create an abstraction on it. Something like GenericHanlder (interface), and then implement 2 iterators OldMessageHanlder and NewMessageHandler ? But what about the new methods that I implemented to handle extra requirements because those methods will not be part of NewMessageHandler or will be handled in some other way.

Or

I should add an abstraction on ProcessMessages like GenericProcessMessages and implement the interfaces using OldProcessMessages and NewProcessMessages and OldProcessMessage will use the OldMessageHandler and NewProcessMessages will use the NewMessageHandler to process the messages ?

I am still a student and this is a learning experience for me while improving the quality of software. So, any help would be great.

5

If you're going to write an iterator in C++, it should (IMO) follow the norms for C++ iterators in general. In the case of reading data from a file, you can usually do that without writing an actual iterator at all. Instead, you write an operator>> to read a single item from a file (and, if necessary, an operator<< to write a single item to a file).

Then you can use an std::istream_iterator to iterate over an input file (and an std::ostream_iterator for an output file, if needed).

Things like incrementToNextReceive shouldn't be part of the iterator itself at all. Instead you should use something like std::find_if on your input iterator to find the next item that meets whatever criteria you need1.

As far as getNextMessageWithoutIterator goes, that capability comes for free if you use normal C++ iterators. Specifically, advancing the iterator is always decoupled from dereferencing the iterator--advancing uses operator++ and dereferencing uses operator * (though if you need to do both, *++it or *it++ are both normally supported).

As far as your new XML format goes, you could almost certainly implement most of your processing with Boost State Chart. At least based on what you show here, however, this may be overkill--your processing looks simple enough that it may be easier to implement the processing on your own than learn enough about state chart to get it to do the job.


1. Alternatively, consider using a Range class, and create a filtered_range. This is a much larger undertaking if you do it from scratch. If you want it, I'd advise looking at Eric Neibler's Range V3.

  • +1 for C++ iterators. It makes more sense to either directly use the C++ iterators or atleast follows the pattern that they are using because I can see how I can make it generic while still having the same functionality. You are right, my processing is not that complex and I will probably not go with boost. – Behroz Sikander Feb 25 '16 at 9:17
4

The ordering problem can be solved with an Ordering Queue. Just buffer up enough records to get the out of order records into the queue, and dequeue the next one in the proper order. Same with the complex structure; you need a buffer large enough to hold all of the valid Transition points.

getNextMessageWithoutIterator() is just a Peek() function; those are quite common in iterator scenarios. Peek() allows you to see the next record without advancing the pointer.

  • Peek is a great word for getNextMessageWithoutIterator lol. Thanks. For future refernces here is the implementation in Google's Guava library. Your idea of Ordering Queue is also quite good and much better than using pointers. I will consider this. – Behroz Sikander Feb 25 '16 at 9:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.