private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {

        // Check for closing frame
        if (frame instanceof CloseWebSocketFrame) {
            handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
            return;
        }
        if (frame instanceof PingWebSocketFrame) {
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
            return;
        }
        if (!(frame instanceof TextWebSocketFrame)) {
            throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass()
                    .getName()));
        }

        String request = ((TextWebSocketFrame) frame).text();
        if (logger.isLoggable(Level.FINE)) {
            logger.fine(String.format("%s received %s", ctx.channel(), request));
        }
        
        // expecting JSON, parse now
        TreeNode jsonRequest;
        ClientRequest.Type requestType;
        try {
            final JsonParser parser = jsonMapper.getFactory().createParser(request);
            jsonRequest = parser.readValueAsTree();
            requestType = ClientRequest.Type.valueOf(readTextValue(jsonRequest, "r"));
        } catch (Exception e) {
            logger.info("parsing JSON failed for '" + request + "'");
            // TODO return error to client
            return;
        }

        if (requestType == null) {
            logger.info("parsing JSON failed, no 'r' field");
            return;
        }

        switch(requestType) {
            case i:
                retrieveInitialData(ctx);
                break;
            case b:
                retrieveNodesData(ctx, jsonRequest);
                break;
            case u:
                String znode = readTextValue(jsonRequest, "z");
                String data = readTextValue(jsonRequest, "d");
                setNodeData(znode, data);
                break;
            default:
                System.out.println("unknown, unhandled client request = " + request);
        }
    }