public void processSubscribe(ServerChannel session, SubscribeMessage msg) {
    String clientID = (String) session.getAttribute(NettyChannel.ATTR_KEY_CLIENTID);
    LOG.debug("SUBSCRIBE client <{}> packetID {}", clientID, msg.getMessageID());

    ClientSession clientSession = m_sessionsStore.sessionForClient(clientID);
    verifyToActivate(clientID, clientSession);
    // ack the client
    SubAckMessage ackMessage = new SubAckMessage();
    ackMessage.setMessageID(msg.getMessageID());

    List<Subscription> newSubscriptions = new ArrayList<>();
    for (SubscribeMessage.Couple req : msg.subscriptions()) {
      AbstractMessage.QOSType qos = AbstractMessage.QOSType.valueOf(req.getQos());
      Subscription newSubscription = new Subscription(clientID, req.getTopicFilter(), qos);
      // boolean valid = subscribeSingleTopic(newSubscription, req.getTopicFilter());
      boolean valid = clientSession.subscribe(req.getTopicFilter(), newSubscription);
      ackMessage.addType(valid ? qos : AbstractMessage.QOSType.FAILURE);
      if (valid) {
        newSubscriptions.add(newSubscription);
      }
    }

    // save session, persist subscriptions from session
    LOG.debug("SUBACK for packetID {}", msg.getMessageID());
    if (LOG.isTraceEnabled()) {
      LOG.trace("subscription tree {}", subscriptions.dumpTree());
    }
    session.write(ackMessage);

    // fire the publish
    for (Subscription subscription : newSubscriptions) {
      subscribeSingleTopic(subscription);
    }
  }