Friday, September 17, 2021

L2CR (Leave it 2 the Compiler/Runtime) Part 1A - Resource management & MDC keys removal

 Foreword

This series is how some trivial development chores can be delegated to the Java Compiler/Runtime. And also an attempt of mine to introduce an acronym. I would call it just Automation, but then I would be bombarded with comments and questions I'd most likely not respond to.

Is there more annoying thing than having to manage resources and worrying about relinquishing them later (besides pointless meetings)?

Java does ease the burden of alocating and dealocating heap objects (dynamic allocated) but still resources like file handlers/buffers and connections must still be dealt with manually. And not closing them after their usage will cause leakage and eventually end in catastrophe the same way as it would in C (native) world.

Even if some resources can be reclaimed by the Garbage Collector, if they are used to often, they will overwhelm it and make the program slow and unresponsive.

Before Java 7 we had to do all by ourselves in the finally block.


	
    try {
      Resource r = acquireSomeResource();
      MDC.put("KEY1", key1Val);
      // Some methods whose logs benefit of being indexed on key1 
    } catch (Exception e) {
      // Handle exception
    } finally {
      if (!r.isFreed()) {
        r.free(); // This assuming that free method won't throw exception
      }
      MDC.remove("KEY1");
    }
  

Obviously, now there is try-with-respurces, which frees us from the burden of having to close/relinquish a resource after it's used as long as it implements the AutoCloseable interface, which they often do. But what does the MDC.put(...) has to do with it? In its case you also have to call MDC.remove("KEY1") in a finally block since not doing so will leave KEY1 with the same value when the server reuses the thread to process another request which means data leakage all the same, surely for this case you can use a Filter that has a finally block to call MDC.clean() leaving the context clean for the next request.

But when outside of the try block, if you have a log call which doesn't need KEY1, it will still have access to this old value which might not be relevant or even misleading. Which brings us to:


	public class MdcKey implements AutoCloseable {
      private final String key;
      
      public MdcKey(String key, String value) {
        this.key = key;
        MDC.put(key, value);
      }
      
      public void close() throws Exception {
        MDC.remove(key)
      }
    }
	
.............AND THEN

    try (Resource r = acquireSomeResource();
      var k = new MdcKey("KEY1", key1Val)) 
    {
      // DO STUFF WITH YOUR RESOURCE
      // Some methods whose logs benefit of being indexed on key1 
    } catch (Exception e) {
      handleException(e);
    }
  

Surely if MDC is used once in a while in your codebase you may argue this will be too much trouble for its worth, which is absolutely true if the developers of your team are experienced and with enough time to use their judgement but if they are too burdened or inexperienced they will likely just copy some existing code with the minimum amount needed of adaptation which means the clutter will carry over to many more places.

L2CR (Leave it 2 the Compiler/Runtime) Part 1A - Resource management & MDC keys removal

 Foreword This series is how some trivial development chores can be delegated to the Java Compiler/Runtime. And also an attempt of mine...