docs: public void validate() {
      if (time == null) {
        throw new IllegalArgumentException("missing time");
      }
  
      validatePOJO(time, "time");
  
      if (metrics == null || metrics.isEmpty()) {
        throw new IllegalArgumentException("missing or empty metrics");
      }
  
      final Set<String> variable_ids = new HashSet<String>();
      for (Metric metric : metrics) {
        if (variable_ids.contains(metric.getId())) {
          throw new IllegalArgumentException("duplicated metric id: "
              + metric.getId());
        }
        variable_ids.add(metric.getId());
      }
  
      final Set<String> filter_ids = new HashSet<String>();
  
      for (Filter filter : filters) {
        if (filter_ids.contains(filter.getId())) {
          throw new IllegalArgumentException("duplicated filter id: "
              + filter.getId());
        }
        filter_ids.add(filter.getId());
      }
      
      for (Expression expression : expressions) {
        if (variable_ids.contains(expression.getId())) {
          throw new IllegalArgumentException("Duplicated variable or expression id: "
              + expression.getId());
        }
        variable_ids.add(expression.getId());
      }
  
      validateCollection(metrics, "metric");
  
      if (filters != null) {
        validateCollection(filters, "filter");
      }
  
      if (expressions != null) {
        validateCollection(expressions, "expression");
      }
  
      validateFilters();
      
      if (expressions != null) {
        validateCollection(expressions, "expression");
        for (final Expression exp : expressions) {
          if (exp.getVariables() == null) {
            throw new IllegalArgumentException("No variables found for an "
                + "expression?! " + JSON.serializeToString(exp));
          }
          
          for (final String var : exp.getVariables()) {
            if (!variable_ids.contains(var)) {
              throw new IllegalArgumentException("Expression [" + exp.getExpr() 
                + "] was missing input " + var);
            }
          }
        }
      }
    }