0

I have the issue that I want to be able to capture a set of SNMP messages, and some of them I want to parse to create an instance of a user-defined class. I may for example want to identify whether an SNMP message is a TRAP message, and if it is I want to identify the type of TRAP and create an instance of this type.

Example: SNMP message type: TRAP:ALARM:MINOR_ALARM

In this case I want to instantiate a class of type MinorAlarm, containing the information of the alarm and some well-defined functionality from an interface (like printing the alarm, determining when it happened, ...)

The number of different types will eventually become large and it has to be simple to add new types as well. The current implementation is very limited and messy. It basically consists of a huge if-else statement where only a subset of the types are supported right now.

The name of the specific SNMP type can be obtained from the SNMP message through a string like "1.1.1.0.2.6.22.33" (numbers are completely made up).

I believe that a factory pattern might become too messy here. The guess is that some kind of lookup table would work, but if possible I would like avoid using Reflection (since this will be hard to read and understand).

Some loose thought would be to use some kind of abstract factory with a hierarchical structure. This would resemble the hierarchical structure of the nested structure of the MIB tree. This might be the best idea, but it will still involve digging into some if-else or switch mess. Does anyone have any good ideas how to proceed?

  • A factory isn't an alternative to long, messy selection logic. It's a common way to hide the long, messy selection logic from casual users. The huge if or the complicated look-up table is still there, it's just been banned into a special-purpose class so that you normally don't have to look at it. – Kilian Foth May 3 '17 at 8:50
2

I would try to avoid instantiating new classes per message.

Instead have a generic message type and a collection of type specific Handlers in a Dictionary.

Dictionary<string, IHander> Handlers;

public void ReadMessage(Message m)
{
    var handler = Handlers[m.TypeName];
    if(handler == null) { handler = DefaultHandler;)
    handler.ReadMessage(m);
}

Obviously you can do the same thing with a Dictionary of Factories, but although the handler pattern is more procedural is it more elegant. Not requiring you to create new instances of different classes, call a single method and dispose of them immediately.

Also, you can imagine the case where one Message class has different construction parameters to the others. This pattern allows you to instantiate your Handlers once on startup, where you can specify the construction of each individually. Rather than within the message handling loop where you would require a conditional and extra parameters.

  • This was nice. I like it. I will however need to store the traps as specific classes as well, since I will do more than logging them. These will also be fetched by other functions and there are no database in which to store them. I understand if this strikes you as odd. I think it is odd as well, but I do not have the power to change it. I do however see some ways to modify your example to fit my purpose so thanks! – patrik May 3 '17 at 10:44
0

Add a method to the interface of your abstract factory which checks if a given message-string matches the factory. That way you can put the logic which decides when to use a specific factory into the factory itself and don't need to create a huge if-else tree. This would look something like this:

private List<AbstractMessageFactory> messageFactories = new ArrayList<>();

public void registerMessageFactory(AbstractMessageFactory factory) {
      messageFactories.add(factory);
}

public Message createMessageFromString(String messageString) {

    for (AbstractMessageFactory f: messageFactories) {
          if (f.matches(messageString) {
               return f.createMessage(messageString);
          }
    }

    throw new UnhandledMessageException(messageString);
}

An example of an abstract factory class:

public TrapMessageFactory implements AbstractMessageFactory {

     public matches(String messageString) {
         return messageString.contains("1.1.1.0.2.6.22.33");
     }

     public createMessage(String messageString) {
          return new TrapMessage(messageString);
     }
}

Now you could nest factories like that by having some factories which do the same and delegate to its own list of message factories, which also delegate and so on. This might have performance benefits, because it can reduce some redundant comparisons. But I would still advise against that, because now you can no longer tell under which conditions exactly a given message will be created by just looking at the matches-method of a single factory.

  • This is much cleaner than I had in my mind at first. I will probably use a lookup table instead though. This was useful though so thanks! +1 – patrik May 3 '17 at 10:47

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.