/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.knowledgebase.util; import com.liferay.knowledgebase.model.KBArticle; import com.liferay.knowledgebase.model.KBCommentConstants; import com.liferay.knowledgebase.model.KBFolder; import com.liferay.knowledgebase.model.KBFolderConstants; import com.liferay.knowledgebase.service.KBArticleServiceUtil; import com.liferay.knowledgebase.service.KBFolderServiceUtil; import com.liferay.knowledgebase.util.comparator.KBArticleCreateDateComparator; import com.liferay.knowledgebase.util.comparator.KBArticleModifiedDateComparator; import com.liferay.knowledgebase.util.comparator.KBArticlePriorityComparator; import com.liferay.knowledgebase.util.comparator.KBArticleStatusComparator; import com.liferay.knowledgebase.util.comparator.KBArticleTitleComparator; import com.liferay.knowledgebase.util.comparator.KBArticleUserNameComparator; import com.liferay.knowledgebase.util.comparator.KBArticleVersionComparator; import com.liferay.knowledgebase.util.comparator.KBArticleViewCountComparator; import com.liferay.knowledgebase.util.comparator.KBCommentCreateDateComparator; import com.liferay.knowledgebase.util.comparator.KBCommentModifiedDateComparator; import com.liferay.knowledgebase.util.comparator.KBTemplateCreateDateComparator; import com.liferay.knowledgebase.util.comparator.KBTemplateModifiedDateComparator; import com.liferay.knowledgebase.util.comparator.KBTemplateTitleComparator; import com.liferay.knowledgebase.util.comparator.KBTemplateUserNameComparator; import com.liferay.portal.kernel.dao.orm.QueryUtil; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream; import com.liferay.portal.kernel.json.JSONException; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.search.Field; import com.liferay.portal.kernel.search.Sort; import com.liferay.portal.kernel.search.SortFactoryUtil; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.MimeTypesUtil; import com.liferay.portal.kernel.util.OrderByComparator; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.StreamUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.workflow.WorkflowConstants; import com.liferay.portal.model.ModelHintsUtil; import com.liferay.portal.theme.ThemeDisplay; import com.liferay.portal.util.PortalUtil; import com.liferay.portlet.PortalPreferences; import com.liferay.portlet.PortletPreferencesFactoryUtil; import java.io.InputStream; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.portlet.PortletPreferences; import javax.portlet.PortletRequest; import javax.portlet.PortletURL; import javax.portlet.RenderResponse; import javax.servlet.http.HttpServletRequest; /** * @author Peter Shin * @author Brian Wing Shun Chan */ public class KnowledgeBaseUtil { public static void addPortletBreadcrumbEntries( long originalParentResourceClassNameId, long originalParentResourcePrimKey, long parentResourceClassNameId, long parentResourcePrimKey, String mvcPath, HttpServletRequest request, RenderResponse renderResponse) throws PortalException, SystemException { Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put( "originalParentResourceClassNameId", originalParentResourceClassNameId); parameters.put( "originalParentResourcePrimKey", originalParentResourcePrimKey); parameters.put("parentResourceClassNameId", parentResourceClassNameId); parameters.put("parentResourcePrimKey", parentResourcePrimKey); parameters.put("mvcPath", mvcPath); addPortletBreadcrumbEntries(parameters, request, renderResponse); } public static void addPortletBreadcrumbEntries( long parentResourceClassNameId, long parentResourcePrimKey, String mvcPath, HttpServletRequest request, RenderResponse renderResponse) throws PortalException, SystemException { Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("parentResourceClassNameId", parentResourceClassNameId); parameters.put("parentResourcePrimKey", parentResourcePrimKey); parameters.put("mvcPath", mvcPath); addPortletBreadcrumbEntries(parameters, request, renderResponse); } public static List<KBFolder> getAlternateRootKBFolders( long groupId, long kbFolderId) throws PortalException, SystemException { List<KBFolder> kbFolders = KBFolderServiceUtil.getKBFolders( groupId, kbFolderId, QueryUtil.ALL_POS, QueryUtil.ALL_POS); kbFolders = new ArrayList<KBFolder>(kbFolders); Iterator<KBFolder> itr = kbFolders.iterator(); while (itr.hasNext()) { KBFolder kbFolder = itr.next(); if (kbFolder.isEmpty()) { itr.remove(); } } return ListUtil.sort( kbFolders, new Comparator<KBFolder>() { @Override public int compare(KBFolder kbFolder1, KBFolder kbFolder2) { String name1 = kbFolder1.getName(); String name2 = kbFolder2.getName(); return name1.compareTo(name2) * -1; } }); } public static OrderByComparator getKBArticleOrderByComparator( String orderByCol, String orderByType) { if (Validator.isNull(orderByCol) || Validator.isNull(orderByType)) { return null; } boolean ascending = false; if (orderByType.equals("asc")) { ascending = true; } if (orderByCol.equals("create-date")) { return new KBArticleCreateDateComparator(ascending); } else if (orderByCol.equals("modified-date")) { return new KBArticleModifiedDateComparator(ascending); } else if (orderByCol.equals("priority")) { return new KBArticlePriorityComparator(ascending); } else if (orderByCol.equals("status")) { return new KBArticleStatusComparator(ascending); } else if (orderByCol.equals("title")) { return new KBArticleTitleComparator(ascending); } else if (orderByCol.equals("user-name")) { return new KBArticleUserNameComparator(ascending); } else if (orderByCol.equals("version")) { return new KBArticleVersionComparator(ascending); } else if (orderByCol.equals("view-count")) { return new KBArticleViewCountComparator(ascending); } return null; } public static Sort[] getKBArticleSorts( String orderByCol, String orderByType) { if (Validator.isNull(orderByCol) || Validator.isNull(orderByType)) { return SortFactoryUtil.getDefaultSorts(); } boolean reverse = true; if (orderByType.equals("asc")) { reverse = false; } if (orderByCol.equals("create-date")) { String fieldName = Field.CREATE_DATE; return new Sort[] { SortFactoryUtil.create(fieldName, Sort.LONG_TYPE, reverse), SortFactoryUtil.create(null, Sort.SCORE_TYPE, false) }; } else if (orderByCol.equals("modified-date")) { String fieldName = Field.MODIFIED_DATE; return new Sort[] { SortFactoryUtil.create(fieldName, Sort.LONG_TYPE, reverse), SortFactoryUtil.create(null, Sort.SCORE_TYPE, false) }; } else if (orderByCol.equals("score")) { String fieldName = null; return new Sort[] { SortFactoryUtil.create(fieldName, Sort.SCORE_TYPE, !reverse), SortFactoryUtil.create( Field.MODIFIED_DATE, Sort.LONG_TYPE, true) }; } else if (orderByCol.equals("title")) { String fieldName = "titleKeyword"; return new Sort[] { SortFactoryUtil.create(fieldName, Sort.STRING_TYPE, reverse), SortFactoryUtil.create(null, Sort.SCORE_TYPE, false) }; } else if (orderByCol.equals("user-name")) { String fieldName = Field.USER_NAME; return new Sort[] { SortFactoryUtil.create(fieldName, Sort.STRING_TYPE, reverse), SortFactoryUtil.create(null, Sort.SCORE_TYPE, false) }; } return SortFactoryUtil.getDefaultSorts(); } public static String getKBArticleURL( long plid, long resourcePrimKey, int status, String portalURL, boolean maximized) { StringBundler sb = new StringBundler(11); sb.append(portalURL); sb.append(PortalUtil.getPathMain()); sb.append("/portal/knowledge_base/find_kb_article"); sb.append(StringPool.QUESTION); sb.append("plid"); sb.append(StringPool.EQUAL); sb.append(String.valueOf(plid)); sb.append(StringPool.AMPERSAND); sb.append("resourcePrimKey"); sb.append(StringPool.EQUAL); sb.append(String.valueOf(resourcePrimKey)); String url = sb.toString(); if (status != WorkflowConstants.STATUS_APPROVED) { url = url.concat(StringPool.AMPERSAND).concat("status").concat( StringPool.EQUAL).concat(String.valueOf(status)); } if (maximized) { url = url.concat(StringPool.AMPERSAND).concat("maximized").concat( StringPool.EQUAL).concat(String.valueOf(maximized)); } return url; } public static OrderByComparator getKBCommentOrderByComparator( String orderByCol, String orderByType) { if (Validator.isNull(orderByCol) || Validator.isNull(orderByType)) { return null; } boolean ascending = false; if (orderByType.equals("asc")) { ascending = true; } if (orderByCol.equals("create-date")) { return new KBCommentCreateDateComparator(ascending); } else if (orderByCol.equals("modified-date")) { return new KBCommentModifiedDateComparator(ascending); } return null; } public static long getKBFolderId( long parentResourceClassNameId, long parentResourcePrimKey) throws PortalException, SystemException { long kbFolderClassNameId = PortalUtil.getClassNameId( KBFolderConstants.getClassName()); if (parentResourceClassNameId == kbFolderClassNameId) { return parentResourcePrimKey; } KBArticle kbArticle = KBArticleServiceUtil.getLatestKBArticle( parentResourcePrimKey, WorkflowConstants.STATUS_ANY); return kbArticle.getKbFolderId(); } public static OrderByComparator getKBTemplateOrderByComparator( String orderByCol, String orderByType) { if (Validator.isNull(orderByCol) || Validator.isNull(orderByType)) { return null; } boolean ascending = false; if (orderByType.equals("asc")) { ascending = true; } if (orderByCol.equals("create-date")) { return new KBTemplateCreateDateComparator(ascending); } else if (orderByCol.equals("modified-date")) { return new KBTemplateModifiedDateComparator(ascending); } else if (orderByCol.equals("title")) { return new KBTemplateTitleComparator(ascending); } else if (orderByCol.equals("user-name")) { return new KBTemplateUserNameComparator(ascending); } return null; } public static String getMimeType(byte[] bytes, String fileName) { InputStream inputStream = new UnsyncByteArrayInputStream(bytes); try { return MimeTypesUtil.getContentType(inputStream, fileName); } finally { StreamUtil.cleanUp(inputStream); } } public static final int getNextStatus(int status) { if (status == KBCommentConstants.STATUS_IN_PROGRESS) { return KBCommentConstants.STATUS_COMPLETED; } else if (status == KBCommentConstants.STATUS_NEW) { return KBCommentConstants.STATUS_IN_PROGRESS; } else { return KBCommentConstants.STATUS_NONE; } } public static Long[][] getParams(Long[] params) { if (ArrayUtil.isEmpty(params)) { return null; } if (params.length <= _SQL_DATA_MAX_PARAMETERS) { return new Long[][] {new Long[0], params}; } return new Long[][] { ArrayUtil.subset(params, _SQL_DATA_MAX_PARAMETERS, params.length), ArrayUtil.subset(params, 0, _SQL_DATA_MAX_PARAMETERS) }; } public static String getPreferredKBFolderURLTitle( PortalPreferences portalPreferences, String contentRootPrefix) throws JSONException { String preferredKBFolderURLTitle = portalPreferences.getValue( PortletKeys.KNOWLEDGE_BASE_DISPLAY, "preferredKBFolderURLTitle", "{}"); JSONObject jsonObject = JSONFactoryUtil.createJSONObject( preferredKBFolderURLTitle); return jsonObject.getString(contentRootPrefix, StringPool.BLANK); } public static final int getPreviousStatus(int status) { if (status == KBCommentConstants.STATUS_COMPLETED) { return KBCommentConstants.STATUS_IN_PROGRESS; } else if (status == KBCommentConstants.STATUS_IN_PROGRESS) { return KBCommentConstants.STATUS_NEW; } else { return KBCommentConstants.STATUS_NONE; } } public static long getRootResourcePrimKey( PortletRequest portletRequest, long groupId, long resourceClassNameId, long resourcePrimKey) throws PortalException, SystemException { long kbFolderClassNameId = PortalUtil.getClassNameId( KBFolderConstants.getClassName()); if (resourceClassNameId == kbFolderClassNameId) { return getCurrentRootKBFolder( portletRequest, groupId, resourcePrimKey); } return getKBFolderId(resourceClassNameId, resourcePrimKey); } public static final String getStatusLabel(int status) { if (status == KBCommentConstants.STATUS_COMPLETED) { return "resolved"; } else if (status == KBCommentConstants.STATUS_IN_PROGRESS) { return "in-progress"; } else if (status == KBCommentConstants.STATUS_NEW) { return "new"; } else { throw new IllegalArgumentException( String.format("Invalid suggestion status %s", status)); } } public static final String getStatusTransitionLabel(int status) { if (status == KBCommentConstants.STATUS_COMPLETED) { return "resolve"; } else if (status == KBCommentConstants.STATUS_IN_PROGRESS) { return "move-to-in-progress"; } else if (status == KBCommentConstants.STATUS_NEW) { return "move-to-new"; } else { throw new IllegalArgumentException( String.format("Invalid suggestion status %s", status)); } } public static String getUrlTitle(long id, String title) { if (title == null) { return String.valueOf(id); } title = StringUtil.toLowerCase(title.trim()); if (Validator.isNull(title) || Validator.isNumber(title) || title.equals("rss")) { title = String.valueOf(id); } else { title = FriendlyURLNormalizerUtil.normalize( title, _normalizationFriendlyUrlPattern); } return ModelHintsUtil.trimString( KBArticle.class.getName(), "urlTitle", title); } public static boolean isValidUrlTitle(String urlTitle) { Matcher matcher = _validFriendlyUrlPattern.matcher(urlTitle); return matcher.matches(); } public static void setPreferredKBFolderURLTitle( PortalPreferences portalPreferences, String contentRootPrefix, String value) throws JSONException { String preferredKBFolderURLTitle = portalPreferences.getValue( PortletKeys.KNOWLEDGE_BASE_DISPLAY, "preferredKBFolderURLTitle", "{}"); JSONObject jsonObject = JSONFactoryUtil.createJSONObject( preferredKBFolderURLTitle); jsonObject.put(contentRootPrefix, value); portalPreferences.setValue( PortletKeys.KNOWLEDGE_BASE_DISPLAY, "preferredKBFolderURLTitle", jsonObject.toString()); } public static List<KBArticle> sort( long[] resourcePrimKeys, List<KBArticle> kbArticles) { Map<Long, KBArticle> map = new HashMap<Long, KBArticle>(); for (KBArticle kbArticle : kbArticles) { map.put(kbArticle.getResourcePrimKey(), kbArticle); } kbArticles.clear(); for (long resourcePrimKey : resourcePrimKeys) { if (map.containsKey(resourcePrimKey)) { kbArticles.add(map.get(resourcePrimKey)); } } return kbArticles; } public static String[] splitKeywords(String keywords) { Set<String> keywordsSet = new LinkedHashSet<String>(); StringBundler sb = new StringBundler(); for (char c : keywords.toCharArray()) { if (Character.isWhitespace(c)) { if (sb.length() > 0) { keywordsSet.add(sb.toString()); sb = new StringBundler(); } } else if (Character.isLetterOrDigit(c)) { sb.append(c); } else { return new String[] {keywords}; } } if (sb.length() > 0) { keywordsSet.add(sb.toString()); } return StringUtil.split(StringUtil.merge(keywordsSet)); } public static String trimLeadingSlash(String s) { if (Validator.isNull(s)) { return s; } int x = 0; for (char c : s.toCharArray()) { if ((c != CharPool.BACK_SLASH) && (c != CharPool.FORWARD_SLASH)) { break; } x = x + 1; } return s.substring(x, s.length()); } protected static void addPortletBreadcrumbEntries( Map<String, Object> parameters, HttpServletRequest request, RenderResponse renderResponse) throws PortalException, SystemException { PortletURL portletURL = renderResponse.createRenderURL(); for (Map.Entry<String, Object> entry : parameters.entrySet()) { Object value = entry.getValue(); portletURL.setParameter(entry.getKey(), value.toString()); } long kbFolderClassNameId = PortalUtil.getClassNameId( KBFolderConstants.getClassName()); long parentResourceClassNameId = (Long)parameters.get( "parentResourceClassNameId"); long parentResourcePrimKey = (Long)parameters.get( "parentResourcePrimKey"); String mvcPath = (String)parameters.get("mvcPath"); if (parentResourcePrimKey == KBFolderConstants.DEFAULT_PARENT_FOLDER_ID) { ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute( WebKeys.THEME_DISPLAY); PortalUtil.addPortletBreadcrumbEntry( request, themeDisplay.translate("home"), portletURL.toString()); } else if (parentResourceClassNameId == kbFolderClassNameId) { KBFolder kbFolder = KBFolderServiceUtil.getKBFolder( parentResourcePrimKey); addPortletBreadcrumbEntries( kbFolder.getClassNameId(), kbFolder.getParentKBFolderId(), mvcPath, request, renderResponse); PortalUtil.addPortletBreadcrumbEntry( request, kbFolder.getName(), portletURL.toString()); } else { KBArticle kbArticle = KBArticleServiceUtil.getLatestKBArticle( parentResourcePrimKey, WorkflowConstants.STATUS_ANY); addPortletBreadcrumbEntries( kbArticle.getParentResourceClassNameId(), kbArticle.getParentResourcePrimKey(), mvcPath, request, renderResponse); PortalUtil.addPortletBreadcrumbEntry( request, kbArticle.getTitle(), portletURL.toString()); } } private static long getCurrentRootKBFolder( PortletRequest portletRequest, long groupId, long kbFolderId) throws PortalException, SystemException { PortalPreferences portalPreferences = PortletPreferencesFactoryUtil.getPortalPreferences(portletRequest); PortletPreferences portletPreferences = portletRequest.getPreferences(); String contentRootPrefix = GetterUtil.getString( portletPreferences.getValue("contentRootPrefix", null)); String kbFolderURLTitle = getPreferredKBFolderURLTitle( portalPreferences, contentRootPrefix); long childKbFolderId = KBFolderConstants.DEFAULT_PARENT_FOLDER_ID; if (kbFolderURLTitle == null) { List<KBFolder> kbFolders = getAlternateRootKBFolders( groupId, kbFolderId); if (!kbFolders.isEmpty()) { KBFolder kbFolder = kbFolders.get(0); childKbFolderId = kbFolder.getKbFolderId(); } } else { KBFolder kbFolder = KBFolderServiceUtil.fetchKBFolderByUrlTitle( groupId, kbFolderId, kbFolderURLTitle); if (kbFolder != null) { childKbFolderId = kbFolder.getKbFolderId(); } } return childKbFolderId; } private static final int _SQL_DATA_MAX_PARAMETERS = GetterUtil.getInteger( PropsUtil.get(PropsKeys.SQL_DATA_MAX_PARAMETERS)); private static Pattern _normalizationFriendlyUrlPattern = Pattern.compile( "[^a-z0-9_-]"); private static Pattern _validFriendlyUrlPattern = Pattern.compile( "/[a-z0-9_-]+"); }