@Override
  public void render(RenderRequest renderRequest, RenderResponse renderResponse)
      throws IOException, PortletException {

    try {
      ThemeDisplay themeDisplay = (ThemeDisplay) renderRequest.getAttribute(WebKeys.THEME_DISPLAY);

      int status = getStatus(renderRequest);

      renderRequest.setAttribute(WebKeys.KNOWLEDGE_BASE_STATUS, status);

      KBArticle kbArticle = null;

      Tuple resourceTuple = getResourceTuple(renderRequest);

      long resourcePrimKey = (Long) resourceTuple.getObject(1);

      if (resourcePrimKey != KBFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
        long resourceClassNameId = (Long) resourceTuple.getObject(0);

        long kbFolderClassNameId = PortalUtil.getClassNameId(KBFolderConstants.getClassName());

        if (resourceClassNameId == kbFolderClassNameId) {
          PortalPreferences portalPreferences =
              PortletPreferencesFactoryUtil.getPortalPreferences(renderRequest);

          String preferredKBFolderURLTitle =
              portalPreferences.getValue(
                  PortletKeys.KNOWLEDGE_BASE_DISPLAY, "preferredKBFolderURLTitle");

          kbArticle =
              getKBFolderKBArticle(
                  themeDisplay.getScopeGroupId(), resourcePrimKey, preferredKBFolderURLTitle);
        } else {
          kbArticle = KBArticleServiceUtil.fetchLatestKBArticle(resourcePrimKey, status);
        }
      } else {
        long parentResourcePrimKey =
            ParamUtil.getLong(
                renderRequest, "parentResourcePrimKey", KBFolderConstants.DEFAULT_PARENT_FOLDER_ID);

        if (parentResourcePrimKey == KBFolderConstants.DEFAULT_PARENT_FOLDER_ID) {

          List<KBArticle> kbArticles =
              KBArticleLocalServiceUtil.getGroupKBArticles(
                  themeDisplay.getScopeGroupId(),
                  status,
                  0,
                  1,
                  new KBArticlePriorityComparator(true));

          if (!kbArticles.isEmpty()) {
            kbArticle = kbArticles.get(0);
          }
        }
      }

      renderRequest.setAttribute(WebKeys.KNOWLEDGE_BASE_KB_ARTICLE, kbArticle);
    } catch (Exception e) {
      if (e instanceof NoSuchArticleException || e instanceof PrincipalException) {

        SessionErrors.add(renderRequest, e.getClass());

        SessionMessages.add(
            renderRequest,
            PortalUtil.getPortletId(renderRequest)
                + SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE);
      } else {
        throw new PortletException(e);
      }
    }

    super.render(renderRequest, renderResponse);
  }
  protected PortletURL getKBArticleURL(
      long plid, boolean privateLayout, KBArticle kbArticle, HttpServletRequest request)
      throws Exception {

    PortletURL firstMatchPortletURL = null;

    List<Layout> layouts = getCandidateLayouts(plid, privateLayout, kbArticle);

    for (Layout layout : layouts) {
      LayoutTypePortlet layoutTypePortlet = (LayoutTypePortlet) layout.getLayoutType();

      List<Portlet> portlets = layoutTypePortlet.getAllPortlets();

      for (Portlet portlet : portlets) {
        String rootPortletId = PortletConstants.getRootPortletId(portlet.getPortletId());

        if (rootPortletId.equals(PortletKeys.KNOWLEDGE_BASE_DISPLAY)) {
          PortletPreferences portletPreferences =
              PortletPreferencesFactoryUtil.getPortletSetup(
                  layout, portlet.getPortletId(), StringPool.BLANK);

          long kbFolderClassNameId = PortalUtil.getClassNameId(KBFolderConstants.getClassName());

          long resourceClassNameId =
              GetterUtil.getLong(
                  portletPreferences.getValue("resourceClassNameId", null), kbFolderClassNameId);
          long resourcePrimKey =
              GetterUtil.getLong(
                  portletPreferences.getValue("resourcePrimKey", null),
                  KBFolderConstants.DEFAULT_PARENT_FOLDER_ID);

          if (resourceClassNameId == kbFolderClassNameId) {
            if (isParentFolder(resourcePrimKey, kbArticle.getKbFolderId())) {

              return getKBArticleURL(layout.getPlid(), portlet.getPortletId(), kbArticle, request);
            }
          } else if (resourcePrimKey == kbArticle.getResourcePrimKey()) {

            return getKBArticleURL(layout.getPlid(), portlet.getPortletId(), kbArticle, request);
          }

          if (firstMatchPortletURL == null) {
            firstMatchPortletURL =
                getKBArticleURL(layout.getPlid(), portlet.getPortletId(), kbArticle, request);
          }
        }

        if (rootPortletId.equals(PortletKeys.KNOWLEDGE_BASE_SECTION)) {
          PortletPreferences portletPreferences =
              PortletPreferencesFactoryUtil.getPortletSetup(
                  layout, portlet.getPortletId(), StringPool.BLANK);

          String[] kbArticlesSections =
              portletPreferences.getValues("kbArticlesSections", new String[0]);

          KBArticle rootKBArticle =
              KBArticleLocalServiceUtil.fetchLatestKBArticle(
                  kbArticle.getRootResourcePrimKey(), WorkflowConstants.STATUS_APPROVED);

          if (rootKBArticle == null) {
            continue;
          }

          String[] sections = AdminUtil.unescapeSections(rootKBArticle.getSections());

          for (String section : sections) {
            if (!ArrayUtil.contains(kbArticlesSections, section)) {
              continue;
            }

            return getKBArticleURL(layout.getPlid(), portlet.getPortletId(), kbArticle, request);
          }
        }

        if (rootPortletId.equals(PortletKeys.KNOWLEDGE_BASE_ARTICLE)) {
          PortletPreferences portletPreferences =
              PortletPreferencesFactoryUtil.getPortletSetup(
                  layout, portlet.getPortletId(), StringPool.BLANK);

          long resourcePrimKey =
              GetterUtil.getLong(portletPreferences.getValue("resourcePrimKey", null));

          KBArticle selKBArticle =
              KBArticleLocalServiceUtil.fetchLatestKBArticle(
                  resourcePrimKey, WorkflowConstants.STATUS_APPROVED);

          if (selKBArticle == null) {
            continue;
          }

          long rootResourcePrimKey = kbArticle.getRootResourcePrimKey();
          long selRootResourcePrimKey = selKBArticle.getRootResourcePrimKey();

          if (rootResourcePrimKey == selRootResourcePrimKey) {
            return getKBArticleURL(layout.getPlid(), portlet.getPortletId(), kbArticle, request);
          }

          if (firstMatchPortletURL == null) {
            firstMatchPortletURL =
                getKBArticleURL(layout.getPlid(), portlet.getPortletId(), kbArticle, request);
          }
        }
      }
    }

    return firstMatchPortletURL;
  }
  protected Tuple getResourceTuple(RenderRequest renderRequest) throws Exception {

    ThemeDisplay themeDisplay = (ThemeDisplay) renderRequest.getAttribute(WebKeys.THEME_DISPLAY);

    String urlTitle = ParamUtil.getString(renderRequest, "urlTitle");

    if (Validator.isNotNull(urlTitle)) {
      String kbFolderUrlTitle = ParamUtil.getString(renderRequest, "kbFolderUrlTitle");

      KBArticle kbArticle = null;

      if (Validator.isNotNull(kbFolderUrlTitle)) {
        kbArticle =
            KBArticleLocalServiceUtil.fetchKBArticleByUrlTitle(
                themeDisplay.getScopeGroupId(), kbFolderUrlTitle, urlTitle);
      } else {
        kbArticle =
            KBArticleLocalServiceUtil.fetchKBArticleByUrlTitle(
                themeDisplay.getScopeGroupId(),
                KBFolderConstants.DEFAULT_PARENT_FOLDER_ID,
                urlTitle);
      }

      if ((kbArticle != null)
          && KBArticlePermission.contains(
              themeDisplay.getPermissionChecker(), kbArticle, ActionKeys.VIEW)) {

        return new Tuple(kbArticle.getClassNameId(), kbArticle.getResourcePrimKey());
      }
    }

    PortletPreferences portletPreferences = renderRequest.getPreferences();

    long defaultResourcePrimKey =
        GetterUtil.getLong(portletPreferences.getValue("resourcePrimKey", null));

    String mvcPath = ParamUtil.getString(renderRequest, "mvcPath");

    if (((defaultResourcePrimKey == 0) && mvcPath.equals(viewTemplate))
        || mvcPath.equals("/display/select_configuration_article.jsp")) {

      return new Tuple(
          PortalUtil.getClassNameId(KBFolderConstants.getClassName()),
          KBFolderConstants.DEFAULT_PARENT_FOLDER_ID);
    }

    long defaultResourceClassNameId =
        GetterUtil.getLong(portletPreferences.getValue("resourceClassNameId", null));

    long resourceClassNameId =
        ParamUtil.getLong(renderRequest, "resourceClassNameId", defaultResourceClassNameId);

    long resourcePrimKey =
        ParamUtil.getLong(renderRequest, "resourcePrimKey", defaultResourcePrimKey);

    if ((resourcePrimKey == 0) || (resourcePrimKey != defaultResourcePrimKey)) {

      return new Tuple(resourceClassNameId, resourcePrimKey);
    }

    long kbFolderClassNameId = PortalUtil.getClassNameId(KBFolderConstants.getClassName());

    if (resourceClassNameId == kbFolderClassNameId) {
      KBFolder kbFolder = KBFolderLocalServiceUtil.fetchKBFolder(resourcePrimKey);

      if ((kbFolder != null)
          && !KBFolderPermission.contains(
              themeDisplay.getPermissionChecker(),
              themeDisplay.getScopeGroupId(),
              defaultResourcePrimKey,
              ActionKeys.VIEW)) {

        return new Tuple(
            PortalUtil.getClassNameId(KBFolderConstants.getClassName()),
            KBFolderConstants.DEFAULT_PARENT_FOLDER_ID);
      }
    } else {
      KBArticle kbArticle =
          KBArticleLocalServiceUtil.fetchLatestKBArticle(
              defaultResourcePrimKey, WorkflowConstants.STATUS_ANY);

      if ((kbArticle != null)
          && !KBArticlePermission.contains(
              themeDisplay.getPermissionChecker(), defaultResourcePrimKey, ActionKeys.VIEW)) {

        return new Tuple(
            PortalUtil.getClassNameId(KBFolderConstants.getClassName()),
            KBFolderConstants.DEFAULT_PARENT_FOLDER_ID);
      }
    }

    return new Tuple(defaultResourceClassNameId, defaultResourcePrimKey);
  }