/**
   * Validate fields common to this class and subclasses.
   *
   * @param command article add command (or subclass)
   * @param errors spring errors object to populate
   * @return true if validation completed, false if processing should stop
   */
  protected final boolean validateCommon(ArticleAddCommand command, Errors errors) {

    if (command == null) {
      errors.reject(ERROR_ARTICLE_NULL, "Null data received");
      // do not continue processing, as this will lead to NPEs later
      return false;
    }

    String title = command.getTitle();
    if (title == null || title.trim().length() == 0) {
      errors.rejectValue("title", ERROR_ARTICLE_TITLE_REQUIRED, "title required");
    }

    String permalink = command.getPermalink();
    if (permalink != null && !permalink.matches("[a-z0-9\\-]+")) {
      errors.rejectValue("permalink", ERROR_ARTICLE_PERMALINK_INVALID, "permalink invalid");
    }

    ContentType contentType = command.getContentType();
    if (contentType == null) {
      errors.rejectValue(
          "contentType", ERROR_ARTICLE_CONTENT_TYPE_REQUIRED, "content type required");
    }

    String content = command.getContent();
    if (content == null || content.trim().length() == 0) {
      errors.rejectValue("content", ERROR_ARTICLE_CONTENT_REQUIRED, "content required");
    } else if (contentType != null) {
      // validate the content
      validateContent(
          errors,
          content,
          contentType.getMimeType(),
          "content",
          ERROR_ARTICLE_CONTENT_INVALID,
          "content invalid");
    }

    String summary = command.getSummary();
    if (summary != null) {
      // validate summary
      if (summary.length() > maximumSummaryLength) {
        errors.rejectValue(
            "summary",
            ERROR_ARTICLE_SUMMARY_TOO_LONG,
            new Object[] {new Integer(maximumSummaryLength)},
            "summary too long");
      } else {
        validateContent(
            errors,
            summary,
            contentType.getMimeType(),
            "summary",
            ERROR_ARTICLE_SUMMARY_INVALID,
            "summary invalid");
      }
    }

    return true;
  }
  /**
   * Validates the given command.
   *
   * @param obj {@code ArticleAddCommand} to validate
   * @param errors Spring Errors object to populate
   */
  @Override
  public void validate(Object obj, Errors errors) {
    ArticleAddCommand command = (ArticleAddCommand) obj;

    if (!validateCommon(command, errors)) {
      return;
    }

    if (errors.getFieldErrorCount("permalink") == 0) {
      String permalink = command.getPermalink();
      if (permalink != null) {
        // look for article with the same permalink
        Article prev = articleBusiness.findArticleByPermalink(permalink);
        if (prev != null) {
          errors.rejectValue("permalink", ERROR_ARTICLE_PERMALINK_EXISTS, "permalink exists");
        }
      }
    }
  }