Java tutorial
/** * 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.recommend.service.impl; import com.liferay.asset.kernel.model.AssetEntry; import com.liferay.asset.kernel.model.AssetRenderer; import com.liferay.asset.kernel.service.AssetEntryLocalService; import com.liferay.portal.kernel.bean.BeanReference; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.json.JSONArray; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.service.ServiceContext; import com.liferay.portal.kernel.service.UserLocalService; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.DateUtil; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.recommend.service.base.RecommendEntityLocalServiceBaseImpl; import com.liferay.recommend.service.util.WikiTextExtractor; import com.liferay.wiki.model.WikiPage; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; /** * The implementation of the recommend entity local service. * * <p> * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link com.liferay.recommend.service.RecommendEntityLocalService} interface. * * <p> * This is a local service. Methods of this service will not have security checks based on the propagated JAAS credentials because this service can only be accessed from within the same VM. * </p> * * @author Brian Wing Shun Chan * @see RecommendEntityLocalServiceBaseImpl * @see com.liferay.recommend.service.RecommendEntityLocalServiceUtil */ public class RecommendEntityLocalServiceImpl extends RecommendEntityLocalServiceBaseImpl { public JSONObject getTopMostViewed(int resultCount, ServiceContext serviceContext) { if (_log.isDebugEnabled()) { _log.debug("getTopMostViewed(" + resultCount + ") called."); } List<AssetEntry> assetEntries = _getMostViewedWikiPageAssets(resultCount); JSONArray recommendationsJSONArray = _createJsonArrayFromWikiPageAssetEntries(serviceContext, assetEntries); JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("topRecommendations", recommendationsJSONArray); return jsonObject; } public JSONObject getTopMostViewedRandomized(int resultCount, int sampleCount, ServiceContext serviceContext) { if (_log.isDebugEnabled()) { _log.debug("getTopMostViewedRanomized(" + resultCount + ", " + sampleCount + ") called."); } List<AssetEntry> assetEntries = _getMostViewedWikiPageAssetsRandomized(resultCount, sampleCount); JSONArray recommendationsJSONArray = _createJsonArrayFromWikiPageAssetEntries(serviceContext, assetEntries); JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put("topRecommendations", recommendationsJSONArray); return jsonObject; } /** * NOTE FOR DEVELOPERS: * * Never reference this class directly. Always use {@link com.liferay.recommend.service.RecommendEntityLocalServiceUtil} to access the recommend entity local service. */ private JSONArray _createJsonArrayFromWikiPageAssetEntries(ServiceContext serviceContext, List<AssetEntry> topViewedEntries) { JSONArray recommendationsJSONArray = JSONFactoryUtil.createJSONArray(); WikiTextExtractor wikiTextExtractor = new WikiTextExtractor(); wikiTextExtractor.setTitleSeparator("|"); for (AssetEntry assetEntry : topViewedEntries) { if (_log.isDebugEnabled()) { _log.debug("Top Entry: " + assetEntry); } AssetRenderer<?> assetRenderer = assetEntry.getAssetRenderer(); if ((assetRenderer != null) && (assetRenderer.getAssetObject() instanceof WikiPage)) { WikiPage wikiPage = (WikiPage) assetRenderer.getAssetObject(); String userPortraitUrl = null; try { ThemeDisplay themeDisplay = new ThemeDisplay(); User user = _userLocalService.fetchUser(assetEntry.getUserId()); userPortraitUrl = user.getPortraitURL(themeDisplay); } catch (PortalException pe) { _log.error("Error while retrieving user portrait URL", pe); } String url = serviceContext.getPortalURL() + "/share/" + _getNormalizedTitle(assetEntry.getTitle()); JSONObject entryJSONObject = JSONFactoryUtil.createJSONObject(); entryJSONObject.put("id", assetEntry.getClassPK()); entryJSONObject.put("userName", assetEntry.getUserName()); entryJSONObject.put("viewCount", assetEntry.getViewCount()); entryJSONObject.put("title", assetEntry.getTitle()); entryJSONObject.put("contentSample", wikiTextExtractor.truncateWikiContent(wikiPage.getContent(), wikiPage.getFormat(), 1000)); entryJSONObject.put("url", url); entryJSONObject.put("userPortraitUrl", userPortraitUrl); recommendationsJSONArray.put(entryJSONObject); } } return recommendationsJSONArray; } private boolean _equalsAny(String text, String[] search) { for (String searchString : search) { if ((searchString != null) && searchString.equals(text)) { return true; } } return false; } private Date _getDateBeforeMonths(int months) { Calendar calendar = new GregorianCalendar(); calendar.setTime(new Date()); calendar.add(Calendar.MONTH, -months); return calendar.getTime(); } private List<AssetEntry> _getMostViewedWikiPageAssets(int resultCount) { List<AssetEntry> wikiPageAssets = _removeRootTitles( _assetEntryLocalService.getTopViewedEntries(WikiPage.class.getCanonicalName(), false, 0, resultCount + _ROOT_TITLES.length + _LOAD_EXTRA_ASSET_ENTRIES)); wikiPageAssets = _removeOldEntries(wikiPageAssets, resultCount); return _truncateList(wikiPageAssets, resultCount); } private List<AssetEntry> _getMostViewedWikiPageAssetsRandomized(int resultCount, int sampleCount) { List<AssetEntry> wikiPageAssets = _removeRootTitles( _assetEntryLocalService.getTopViewedEntries(WikiPage.class.getCanonicalName(), false, 0, sampleCount + _LOAD_EXTRA_ASSET_ENTRIES + _ROOT_TITLES.length)); wikiPageAssets = _removeOldEntries(wikiPageAssets, sampleCount); Collections.shuffle(wikiPageAssets); return _truncateList(wikiPageAssets, resultCount); } private String _getNormalizedTitle(String title) { String normalized = StringUtil.toLowerCase(title); return StringUtil.replace(normalized, _REPLACE, _REPLACE_WITH); } private List<AssetEntry> _removeOldEntries(List<AssetEntry> assetEntries, int minimumEntries) { Date limitDate = _getDateBeforeMonths(_EXCLUDE_ENTRIES_LAST_MODIFIED_BEFORE_MONTHS); long removeCount = assetEntries.stream().filter(x -> x.getModifiedDate().before(limitDate)).count(); if (_log.isDebugEnabled()) { _log.debug("_removeOldEntries: entries=" + assetEntries.size() + ", min=" + minimumEntries + ", limit=\"" + limitDate + "\", removeCount=" + removeCount); } if ((assetEntries.size() - removeCount) >= minimumEntries) { assetEntries.removeIf(x -> x.getModifiedDate().before(limitDate)); if (_log.isDebugEnabled()) { _log.debug("Removed " + removeCount + " entries from list. New size: " + assetEntries.size()); } } else { if (_log.isDebugEnabled()) { _log.debug("Not removing all entries before " + limitDate + ", to keep the minimum number of entries (" + minimumEntries + ")"); } Collections.sort(assetEntries, new Comparator<AssetEntry>() { @Override public int compare(AssetEntry o1, AssetEntry o2) { return DateUtil.compareTo(o2.getModifiedDate(), o1.getModifiedDate()); } }); assetEntries = _truncateList(assetEntries, minimumEntries); Collections.sort(assetEntries, (p1, p2) -> Integer.compare(p2.getViewCount(), p1.getViewCount())); } return assetEntries; } private List<AssetEntry> _removeRootTitles(List<AssetEntry> assetEntries) { List<AssetEntry> res = new ArrayList<>(); for (AssetEntry assetEntry : assetEntries) { if (!_equalsAny(assetEntry.getTitle(), _ROOT_TITLES)) { res.add(assetEntry); } } return res; } private List<AssetEntry> _truncateList(List<AssetEntry> assetList, int resultCount) { if (assetList.size() > resultCount) { return assetList.subList(0, resultCount); } else { return assetList; } } private static final int _EXCLUDE_ENTRIES_LAST_MODIFIED_BEFORE_MONTHS = 6; private static final int _LOAD_EXTRA_ASSET_ENTRIES = 100; private static final char[] _REPLACE = { '\u00e1', '\u00e9', '\u00ed', '\u00fa', '\u00fc', '\u0171', '\u00f3', '\u00f6', '\u0151', '&', '\'', '@', ']', ')', ':', ',', '$', '=', '!', '[', '(', '#', '?', ';', '/', '*', '+', ' ', '\u00a0' }; private static final String[] _REPLACE_WITH = { "a", "e", "i", "u", "u", "u", "o", "o", "o", "<AMPERSAND>", "<APOSTROPHE>", "<AT>", "<CLOSE_BRACKET>", "<CLOSE_PARENTHESIS>", "<COLON>", "<COMMA>", "<DOLLAR>", "<EQUAL>", "<EXCLAMATION>", "<OPEN_BRACKET>", "<OPEN_PARENTHESIS>", "<POUND>", "<QUESTION>", "<SEMICOLON>", "<SLASH>", "<STAR>", "<PLUS>", "+", "%c2%a0" }; private static final String[] _ROOT_TITLES = { "Share", "People", "Excellence", "Learn" }; private static final Log _log = LogFactoryUtil.getLog(RecommendEntityLocalServiceImpl.class); @BeanReference(type = AssetEntryLocalService.class) private AssetEntryLocalService _assetEntryLocalService; @BeanReference(type = UserLocalService.class) private UserLocalService _userLocalService; }