/** * 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.portlet.social.service.impl; import com.liferay.asset.kernel.model.AssetEntry; import com.liferay.portal.kernel.cache.MultiVMPoolUtil; import com.liferay.portal.kernel.cache.PortalCache; import com.liferay.portal.kernel.dao.orm.QueryUtil; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.lock.LockProtectedAction; import com.liferay.portal.kernel.model.Group; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.transaction.Propagation; import com.liferay.portal.kernel.transaction.Transactional; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Tuple; import com.liferay.portal.util.PropsValues; import com.liferay.portlet.social.model.impl.SocialActivityImpl; import com.liferay.portlet.social.service.base.SocialActivityCounterLocalServiceBaseImpl; import com.liferay.social.kernel.model.SocialAchievement; import com.liferay.social.kernel.model.SocialActivity; import com.liferay.social.kernel.model.SocialActivityConstants; import com.liferay.social.kernel.model.SocialActivityCounter; import com.liferay.social.kernel.model.SocialActivityCounterConstants; import com.liferay.social.kernel.model.SocialActivityCounterDefinition; import com.liferay.social.kernel.model.SocialActivityDefinition; import com.liferay.social.kernel.model.SocialActivityLimit; import com.liferay.social.kernel.model.SocialActivityProcessor; import com.liferay.social.kernel.service.persistence.SocialActivityCounterFinder; import com.liferay.social.kernel.util.SocialCounterPeriodUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * The social activity counter local service. This service is responsible for * creating and/or incrementing counters in response to an activity. It also * provides methods for querying activity counters within a time period. * * <p> * Under normal circumstances only the {@link * #addActivityCounters(SocialActivity)} should be called directly and even that * is usually not necessary as it is automatically called by the social activity * service. * </p> * * @author Zsolt Berentey * @author Shuyang Zhou */ public class SocialActivityCounterLocalServiceImpl extends SocialActivityCounterLocalServiceBaseImpl { /** * Adds an activity counter specifying a previous activity and period * length. * * <p> * This method uses the lock service to guard against multiple threads * trying to insert the same counter because this service is called * asynchronously from the social activity service. * </p> * * @param groupId the primary key of the group * @param classNameId the primary key of the entity's class this counter * belongs to * @param classPK the primary key of the entity this counter belongs to * @param name the counter name * @param ownerType the counter's owner type. Acceptable values are * <code>TYPE_ACTOR</code>, <code>TYPE_ASSET</code> and * <code>TYPE_CREATOR</code> defined in {@link * SocialActivityCounterConstants}. * @param totalValue the counter's total value (optionally <code>0</code>) * @param previousActivityCounterId the primary key of the activity counter * for the previous time period (optionally <code>0</code>, if this * is the first) * @param periodLength the period length in days, * <code>PERIOD_LENGTH_INFINITE</code> for never ending counters or * <code>PERIOD_LENGTH_SYSTEM</code> for the period length defined * in <code>portal-ext.properties</code>. For more information see * {@link SocialActivityCounterConstants}. * @return the added activity counter */ @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public SocialActivityCounter addActivityCounter( long groupId, long classNameId, long classPK, String name, int ownerType, int totalValue, long previousActivityCounterId, int periodLength) throws PortalException { SocialActivityCounter activityCounter = null; if (previousActivityCounterId != 0) { activityCounter = socialActivityCounterPersistence.findByPrimaryKey( previousActivityCounterId); if (periodLength == SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM) { activityCounter.setEndPeriod( SocialCounterPeriodUtil.getStartPeriod() - 1); } else { activityCounter.setEndPeriod( activityCounter.getStartPeriod() + periodLength - 1); } socialActivityCounterPersistence.update(activityCounter); } activityCounter = socialActivityCounterPersistence.fetchByG_C_C_N_O_E( groupId, classNameId, classPK, name, ownerType, SocialActivityCounterConstants.END_PERIOD_UNDEFINED, false); if (activityCounter != null) { return activityCounter; } Group group = groupPersistence.findByPrimaryKey(groupId); long activityCounterId = counterLocalService.increment(); activityCounter = socialActivityCounterPersistence.create( activityCounterId); activityCounter.setGroupId(groupId); activityCounter.setCompanyId(group.getCompanyId()); activityCounter.setClassNameId(classNameId); activityCounter.setClassPK(classPK); activityCounter.setName(name); activityCounter.setOwnerType(ownerType); activityCounter.setTotalValue(totalValue); if (periodLength == SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM) { activityCounter.setStartPeriod( SocialCounterPeriodUtil.getStartPeriod()); } else { activityCounter.setStartPeriod( SocialCounterPeriodUtil.getActivityDay()); } activityCounter.setEndPeriod( SocialActivityCounterConstants.END_PERIOD_UNDEFINED); activityCounter.setActive(true); socialActivityCounterPersistence.update(activityCounter); return activityCounter; } /** * Adds or increments activity counters related to an activity. * * <p> * This method is called asynchronously from the social activity service * when the user performs an activity defined in * <code>liferay-social.xml</code>. * </p> * * <p> * This method first calls the activity processor class, if there is one * defined for the activity, checks for limits and increments all the * counters that belong to the activity. Afterwards, it processes the * activity with respect to achievement classes, if any. Lastly it * increments the built-in <code>user.activities</code> and * <code>asset.activities</code> counters. * </p> * * @param activity the social activity */ @Override public void addActivityCounters(SocialActivity activity) throws PortalException { if (!socialActivitySettingLocalService.isEnabled( activity.getGroupId(), activity.getClassNameId())) { return; } if (!socialActivitySettingLocalService.isEnabled( activity.getGroupId(), activity.getClassNameId(), activity.getClassPK())) { return; } if ((activity.getType() == SocialActivityConstants.TYPE_MOVE_ATTACHMENT_TO_TRASH) || (activity.getType() == SocialActivityConstants.TYPE_MOVE_TO_TRASH)) { disableActivityCounters( activity.getClassNameId(), activity.getClassPK()); return; } if ((activity.getType() == SocialActivityConstants.TYPE_RESTORE_ATTACHMENT_FROM_TRASH) || (activity.getType() == SocialActivityConstants.TYPE_RESTORE_FROM_TRASH)) { enableActivityCounters( activity.getClassNameId(), activity.getClassPK()); return; } User user = userPersistence.findByPrimaryKey(activity.getUserId()); SocialActivityDefinition activityDefinition = socialActivitySettingLocalService.getActivityDefinition( activity.getGroupId(), activity.getClassName(), activity.getType()); if ((activityDefinition == null) || !activityDefinition.isCountersEnabled()) { return; } SocialActivityProcessor activityProcessor = activityDefinition.getActivityProcessor(); if (activityProcessor != null) { activityProcessor.processActivity(activity); } AssetEntry assetEntry = activity.getAssetEntry(); User assetEntryUser = userPersistence.findByPrimaryKey( assetEntry.getUserId()); List<SocialActivityCounter> activityCounters = new ArrayList<>(); for (SocialActivityCounterDefinition activityCounterDefinition : activityDefinition.getActivityCounterDefinitions()) { if (isAddActivityCounter( user, assetEntryUser, assetEntry, activityCounterDefinition)) { SocialActivityCounter activityCounter = addActivityCounter( activity.getGroupId(), user, activity, activityCounterDefinition); activityCounters.add(activityCounter); } } SocialActivityCounter assetActivitiesCounter = null; if (!assetEntryUser.isDefaultUser() && assetEntryUser.isActive() && assetEntry.isVisible()) { assetActivitiesCounter = addAssetActivitiesCounter(activity); } SocialActivityCounter userActivitiesCounter = null; if (!user.isDefaultUser() && user.isActive()) { userActivitiesCounter = addUserActivitiesCounter(activity); } for (SocialActivityCounter activityCounter : activityCounters) { SocialActivityCounterDefinition activityCounterDefinition = activityDefinition.getActivityCounterDefinition( activityCounter.getName()); if (checkActivityLimit(user, activity, activityCounterDefinition)) { incrementActivityCounter( activityCounter, activityCounterDefinition); } } if (assetActivitiesCounter != null) { incrementActivityCounter( assetActivitiesCounter, _assetActivitiesActivityCounterDefinition); } if (userActivitiesCounter != null) { incrementActivityCounter( userActivitiesCounter, _userActivitiesActivityCounterDefinition); } for (SocialAchievement achievement : activityDefinition.getAchievements()) { achievement.processActivity(activity); } } /** * Deletes all activity counters, limits, and settings related to the asset. * * <p> * This method subtracts the asset's popularity from the owner's * contribution points. It also creates a new contribution period if the * latest one does not belong to the current period. * </p> * * @param assetEntry the asset entry */ @Override public void deleteActivityCounters(AssetEntry assetEntry) throws PortalException { if (assetEntry == null) { return; } adjustUserContribution(assetEntry, false); socialActivityCounterPersistence.removeByC_C( assetEntry.getClassNameId(), assetEntry.getClassPK()); socialActivityLimitPersistence.removeByC_C( assetEntry.getClassNameId(), assetEntry.getClassPK()); socialActivitySettingLocalService.deleteActivitySetting( assetEntry.getGroupId(), assetEntry.getClassName(), assetEntry.getClassPK()); clearFinderCache(); } /** * Deletes all activity counters, limits, and settings related to the entity * identified by the class name ID and class primary key. * * @param classNameId the primary key of the entity's class * @param classPK the primary key of the entity */ @Override public void deleteActivityCounters(long classNameId, long classPK) throws PortalException { String className = PortalUtil.getClassName(classNameId); if (!className.equals(User.class.getName())) { AssetEntry assetEntry = assetEntryLocalService.fetchEntry( className, classPK); deleteActivityCounters(assetEntry); } else { socialActivityCounterPersistence.removeByC_C(classNameId, classPK); socialActivityLimitPersistence.removeByUserId(classPK); } clearFinderCache(); } /** * Deletes all activity counters for the entity identified by the class name * and class primary key. * * @param className the entity's class name * @param classPK the primary key of the entity */ @Override public void deleteActivityCounters(String className, long classPK) throws PortalException { if (!className.equals(User.class.getName())) { AssetEntry assetEntry = assetEntryLocalService.fetchEntry( className, classPK); deleteActivityCounters(assetEntry); } else { long classNameId = classNameLocalService.getClassNameId(className); socialActivityCounterPersistence.removeByC_C(classNameId, classPK); socialActivityLimitPersistence.removeByUserId(classPK); } clearFinderCache(); } /** * Disables all the counters of an asset identified by the class name ID and * class primary key. * * <p> * This method is used by the recycle bin to disable all counters of assets * put into the recycle bin. It adjusts the owner's contribution score. * </p> * * @param classNameId the primary key of the asset's class * @param classPK the primary key of the asset */ @Override public void disableActivityCounters(long classNameId, long classPK) throws PortalException { String className = PortalUtil.getClassName(classNameId); disableActivityCounters(className, classPK); } /** * Disables all the counters of an asset identified by the class name and * class primary key. * * <p> * This method is used by the recycle bin to disable all counters of assets * put into the recycle bin. It adjusts the owner's contribution score. * </p> * * @param className the asset's class name * @param classPK the primary key of the asset */ @Override public void disableActivityCounters(String className, long classPK) throws PortalException { AssetEntry assetEntry = assetEntryLocalService.fetchEntry( className, classPK); if (assetEntry == null) { return; } List<SocialActivityCounter> activityCounters = socialActivityCounterPersistence.findByC_C( assetEntry.getClassNameId(), classPK); adjustUserContribution(assetEntry, false); for (SocialActivityCounter activityCounter : activityCounters) { if (activityCounter.isActive()) { activityCounter.setActive(false); socialActivityCounterPersistence.update(activityCounter); } } clearFinderCache(); } /** * Enables all activity counters of an asset identified by the class name ID * and class primary key. * * <p> * This method is used by the recycle bin to enable all counters of assets * restored from the recycle bin. It adjusts the owner's contribution score. * </p> * * @param classNameId the primary key of the asset's class * @param classPK the primary key of the asset */ @Override public void enableActivityCounters(long classNameId, long classPK) throws PortalException { String className = PortalUtil.getClassName(classNameId); enableActivityCounters(className, classPK); } /** * Enables all the counters of an asset identified by the class name and * class primary key. * * <p> * This method is used by the recycle bin to enable all counters of assets * restored from the recycle bin. It adjusts the owner's contribution score. * </p> * * @param className the asset's class name * @param classPK the primary key of the asset */ @Override public void enableActivityCounters(String className, long classPK) throws PortalException { AssetEntry assetEntry = assetEntryLocalService.fetchEntry( className, classPK); if (assetEntry == null) { return; } List<SocialActivityCounter> activityCounters = socialActivityCounterPersistence.findByC_C( assetEntry.getClassNameId(), classPK); adjustUserContribution(assetEntry, true); for (SocialActivityCounter activityCounter : activityCounters) { if (!activityCounter.isActive()) { activityCounter.setActive(true); socialActivityCounterPersistence.update(activityCounter); } } clearFinderCache(); } /** * Returns the activity counter with the given name, owner, and end period * that belong to the given entity. * * @param groupId the primary key of the group * @param classNameId the primary key of the entity's class * @param classPK the primary key of the entity * @param name the counter name * @param ownerType the owner type * @param endPeriod the end period, <code>-1</code> for the latest one * @return the matching activity counter */ @Override public SocialActivityCounter fetchActivityCounterByEndPeriod( long groupId, long classNameId, long classPK, String name, int ownerType, int endPeriod) { return socialActivityCounterPersistence.fetchByG_C_C_N_O_E( groupId, classNameId, classPK, name, ownerType, endPeriod); } /** * Returns the activity counter with the given name, owner, and start period * that belong to the given entity. * * @param groupId the primary key of the group * @param classNameId the primary key of the entity's class * @param classPK the primary key of the entity * @param name the counter name * @param ownerType the owner type * @param startPeriod the start period * @return the matching activity counter */ @Override public SocialActivityCounter fetchActivityCounterByStartPeriod( long groupId, long classNameId, long classPK, String name, int ownerType, int startPeriod) { return socialActivityCounterPersistence.fetchByG_C_C_N_O_S( groupId, classNameId, classPK, name, ownerType, startPeriod); } /** * Returns the latest activity counter with the given name and owner that * belong to the given entity. * * @param groupId the primary key of the group * @param classNameId the primary key of the entity's class * @param classPK the primary key of the entity * @param name the counter name * @param ownerType the owner type * @return the matching activity counter */ @Override public SocialActivityCounter fetchLatestActivityCounter( long groupId, long classNameId, long classPK, String name, int ownerType) { return socialActivityCounterPersistence.fetchByG_C_C_N_O_E( groupId, classNameId, classPK, name, ownerType, SocialActivityCounterConstants.END_PERIOD_UNDEFINED); } /** * Returns all the activity counters with the given name and period offsets. * * <p> * The start and end offsets can belong to different periods. This method * groups the counters by name and returns the sum of their current values. * </p> * * @param groupId the primary key of the group * @param name the counter name * @param startOffset the offset for the start period * @param endOffset the offset for the end period * @return the matching activity counters */ @Override public List<SocialActivityCounter> getOffsetActivityCounters( long groupId, String name, int startOffset, int endOffset) { int startPeriod = SocialCounterPeriodUtil.getStartPeriod(startOffset); int endPeriod = SocialCounterPeriodUtil.getEndPeriod(endOffset); return getPeriodActivityCounters(groupId, name, startPeriod, endPeriod); } /** * Returns the distribution of the activity counters with the given name and * period offsets. * * <p> * The start and end offsets can belong to different periods. This method * groups the counters by their owner entity (usually some asset) and * returns a counter for each entity class with the sum of the counters' * current values. * </p> * * @param groupId the primary key of the group * @param name the counter name * @param startOffset the offset for the start period * @param endOffset the offset for the end period * @return the distribution of matching activity counters */ @Override public List<SocialActivityCounter> getOffsetDistributionActivityCounters( long groupId, String name, int startOffset, int endOffset) { int startPeriod = SocialCounterPeriodUtil.getStartPeriod(startOffset); int endPeriod = SocialCounterPeriodUtil.getEndPeriod(endOffset); return getPeriodDistributionActivityCounters( groupId, name, startPeriod, endPeriod); } /** * Returns all the activity counters with the given name and time period. * * <p> * The start and end period values can belong to different periods. This * method groups the counters by name and returns the sum of their current * values. * </p> * * @param groupId the primary key of the group * @param name the counter name * @param startPeriod the start period * @param endPeriod the end period * @return the matching activity counters */ @Override public List<SocialActivityCounter> getPeriodActivityCounters( long groupId, String name, int startPeriod, int endPeriod) { if (endPeriod == SocialActivityCounterConstants.END_PERIOD_UNDEFINED) { endPeriod = SocialCounterPeriodUtil.getEndPeriod(); } int offset = SocialCounterPeriodUtil.getOffset(endPeriod); int periodLength = SocialCounterPeriodUtil.getPeriodLength(offset); return socialActivityCounterFinder.findAC_ByG_N_S_E_1( groupId, name, startPeriod, endPeriod, periodLength); } /** * Returns the distribution of activity counters with the given name and * time period. * * <p> * The start and end period values can belong to different periods. This * method groups the counters by their owner entity (usually some asset) and * returns a counter for each entity class with the sum of the counters' * current values. * </p> * * @param groupId the primary key of the group * @param name the counter name * @param startPeriod the start period * @param endPeriod the end period * @return the distribution of matching activity counters */ @Override public List<SocialActivityCounter> getPeriodDistributionActivityCounters( long groupId, String name, int startPeriod, int endPeriod) { int offset = SocialCounterPeriodUtil.getOffset(endPeriod); int periodLength = SocialCounterPeriodUtil.getPeriodLength(offset); return socialActivityCounterFinder.findAC_ByG_N_S_E_2( groupId, name, startPeriod, endPeriod, periodLength); } /** * Returns the range of tuples that contain users and a list of activity * counters. * * <p> * The counters returned for each user are passed to this method in the * selectedNames array. The method also accepts an array of counter names * that are used to rank the users. * </p> * * <p> * Useful when paginating results. Returns a maximum of <code>end - * start</code> instances. <code>start</code> and <code>end</code> are not * primary keys, they are indexes in the result set. Thus, <code>0</code> * refers to the first result in the set. Setting both <code>start</code> * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full * result set. * </p> * * @param groupId the primary key of the group * @param rankingNames the ranking counter names * @param selectedNames the counter names that will be returned with each * user * @param start the lower bound of the range of results * @param end the upper bound of the range of results (not inclusive) * @return the range of matching tuples */ @Override public List<Tuple> getUserActivityCounters( long groupId, String[] rankingNames, String[] selectedNames, int start, int end) { List<Long> userIds = socialActivityCounterFinder.findU_ByG_N( groupId, rankingNames, start, end); if (userIds.isEmpty()) { return Collections.emptyList(); } Tuple[] userActivityCounters = new Tuple[userIds.size()]; List<SocialActivityCounter> activityCounters = socialActivityCounterFinder.findAC_By_G_C_C_N_S_E( groupId, userIds, selectedNames, QueryUtil.ALL_POS, QueryUtil.ALL_POS); long userId = 0; Map<String, SocialActivityCounter> activityCountersMap = null; for (SocialActivityCounter activityCounter : activityCounters) { if (userId != activityCounter.getClassPK()) { userId = activityCounter.getClassPK(); activityCountersMap = new HashMap<>(); Tuple userActivityCounter = new Tuple( userId, activityCountersMap); for (int i = 0; i < userIds.size(); i++) { long curUserId = userIds.get(i); if (userId == curUserId) { userActivityCounters[i] = userActivityCounter; break; } } } activityCountersMap.put(activityCounter.getName(), activityCounter); } return Arrays.asList(userActivityCounters); } /** * Returns the number of users having a rank based on the given counters. * * @param groupId the primary key of the group * @param rankingNames the ranking counter names * @return the number of matching users */ @Override public int getUserActivityCountersCount( long groupId, String[] rankingNames) { return socialActivityCounterFinder.countU_ByG_N(groupId, rankingNames); } /** * Increments the <code>user.achievements</code> counter for a user. * * <p> * This method should be used by an external achievement class when the * users unlocks an achievement. * </p> * * @param userId the primary key of the user * @param groupId the primary key of the group */ @Override public void incrementUserAchievementCounter(long userId, long groupId) throws PortalException { User user = userPersistence.findByPrimaryKey(userId); SocialActivityCounter activityCounter = addActivityCounter( groupId, user, new SocialActivityImpl(), _userAchievementsActivityCounterDefinition); incrementActivityCounter( activityCounter, _userAchievementsActivityCounterDefinition); } protected SocialActivityCounter addActivityCounter( final long groupId, final User user, final SocialActivity activity, final SocialActivityCounterDefinition activityCounterDefinition) throws PortalException { int ownerType = activityCounterDefinition.getOwnerType(); long classNameId = getClassNameId(activity.getAssetEntry(), ownerType); long classPK = getClassPK(user, activity.getAssetEntry(), ownerType); SocialActivityCounter activityCounter = fetchLatestActivityCounter( groupId, classNameId, classPK, activityCounterDefinition.getName(), ownerType); if (activityCounter == null) { activityCounter = lockProtectedAddActivityCounter( groupId, classNameId, classPK, activityCounterDefinition.getName(), ownerType, 0, 0, activityCounterDefinition.getPeriodLength()); } else if (!activityCounter.isActivePeriod( activityCounterDefinition.getPeriodLength())) { activityCounter = lockProtectedAddActivityCounter( groupId, classNameId, classPK, activityCounterDefinition.getName(), ownerType, activityCounter.getTotalValue(), activityCounter.getActivityCounterId(), activityCounterDefinition.getPeriodLength()); } if (activityCounterDefinition.getLimitValue() > 0) { SocialActivityLimit activityLimit = socialActivityLimitPersistence.fetchByG_U_C_C_A_A( groupId, user.getUserId(), activity.getClassNameId(), getLimitClassPK(activity, activityCounterDefinition), activity.getType(), activityCounterDefinition.getName()); if (activityLimit == null) { lockProtectedGetActivityLimit( groupId, user, activity, activityCounterDefinition); } } return activityCounter; } protected SocialActivityCounter addAssetActivitiesCounter( SocialActivity activity) throws PortalException { User user = userPersistence.findByPrimaryKey(activity.getUserId()); return addActivityCounter( activity.getGroupId(), user, activity, _assetActivitiesActivityCounterDefinition); } protected SocialActivityCounter addUserActivitiesCounter( SocialActivity activity) throws PortalException { User user = userPersistence.findByPrimaryKey(activity.getUserId()); return addActivityCounter( activity.getGroupId(), user, activity, _userActivitiesActivityCounterDefinition); } protected void adjustUserContribution(AssetEntry assetEntry, boolean enable) throws PortalException { if (assetEntry == null) { return; } SocialActivityCounter latestPopularityActivityCounter = fetchLatestActivityCounter( assetEntry.getGroupId(), assetEntry.getClassNameId(), assetEntry.getClassPK(), SocialActivityCounterConstants.NAME_POPULARITY, SocialActivityCounterConstants.TYPE_ASSET); if ((latestPopularityActivityCounter == null) || (enable && latestPopularityActivityCounter.isActive()) || (!enable && !latestPopularityActivityCounter.isActive())) { return; } int factor = -1; if (enable) { factor = 1; } SocialActivityCounter latestContributionActivityCounter = fetchLatestActivityCounter( assetEntry.getGroupId(), classNameLocalService.getClassNameId(User.class.getName()), assetEntry.getUserId(), SocialActivityCounterConstants.NAME_CONTRIBUTION, SocialActivityCounterConstants.TYPE_CREATOR); if (latestContributionActivityCounter == null) { return; } int startPeriod = SocialCounterPeriodUtil.getStartPeriod(); if (latestContributionActivityCounter.getStartPeriod() != startPeriod) { latestContributionActivityCounter = addActivityCounter( latestContributionActivityCounter.getGroupId(), latestContributionActivityCounter.getClassNameId(), latestContributionActivityCounter.getClassPK(), latestContributionActivityCounter.getName(), latestContributionActivityCounter.getOwnerType(), latestContributionActivityCounter.getTotalValue(), latestContributionActivityCounter.getActivityCounterId(), SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM); } if (latestPopularityActivityCounter.getStartPeriod() == startPeriod) { latestContributionActivityCounter.setCurrentValue( latestContributionActivityCounter.getCurrentValue() + (latestPopularityActivityCounter.getCurrentValue() * factor)); } latestContributionActivityCounter.setTotalValue( latestContributionActivityCounter.getTotalValue() + (latestPopularityActivityCounter.getTotalValue() * factor)); socialActivityCounterPersistence.update( latestContributionActivityCounter); } protected boolean checkActivityLimit( User user, SocialActivity activity, SocialActivityCounterDefinition activityCounterDefinition) throws PortalException { if (activityCounterDefinition.getLimitValue() == 0) { return true; } long classPK = activity.getClassPK(); String name = activityCounterDefinition.getName(); if (name.equals(SocialActivityCounterConstants.NAME_PARTICIPATION)) { classPK = 0; } SocialActivityLimit activityLimit = socialActivityLimitPersistence.findByG_U_C_C_A_A( activity.getGroupId(), user.getUserId(), activity.getClassNameId(), classPK, activity.getType(), name); int count = activityLimit.getCount( activityCounterDefinition.getLimitPeriod()); if (count < activityCounterDefinition.getLimitValue()) { activityLimit.setCount( activityCounterDefinition.getLimitPeriod(), count + 1); socialActivityLimitPersistence.update(activityLimit); return true; } return false; } protected void clearFinderCache() { PortalCache<String, SocialActivityCounter> portalCache = MultiVMPoolUtil.getPortalCache( SocialActivityCounterFinder.class.getName()); portalCache.removeAll(); } protected long getClassNameId(AssetEntry assetEntry, int ownerType) { if (ownerType == SocialActivityCounterConstants.TYPE_ASSET) { return assetEntry.getClassNameId(); } return classNameLocalService.getClassNameId(User.class.getName()); } protected long getClassPK(User user, AssetEntry assetEntry, int ownerType) { if (ownerType == SocialActivityCounterConstants.TYPE_ACTOR) { return user.getUserId(); } if (ownerType == SocialActivityCounterConstants.TYPE_ASSET) { return assetEntry.getClassPK(); } return assetEntry.getUserId(); } protected long getLimitClassPK( SocialActivity activity, SocialActivityCounterDefinition activityCounterDefinition) { String name = activityCounterDefinition.getName(); if (name.equals(SocialActivityCounterConstants.NAME_PARTICIPATION)) { return 0; } return activity.getClassPK(); } protected void incrementActivityCounter( SocialActivityCounter activityCounter, SocialActivityCounterDefinition activityCounterDefinition) { activityCounter.setCurrentValue( activityCounter.getCurrentValue() + activityCounterDefinition.getIncrement()); activityCounter.setTotalValue( activityCounter.getTotalValue() + activityCounterDefinition.getIncrement()); socialActivityCounterPersistence.update(activityCounter); socialActivityCounterPersistence.clearCache(activityCounter); } protected boolean isAddActivityCounter( User user, User assetEntryUser, AssetEntry assetEntry, SocialActivityCounterDefinition activityCounterDefinition) { if ((user.isDefaultUser() || !user.isActive()) && (activityCounterDefinition.getOwnerType() != SocialActivityCounterConstants.TYPE_ASSET)) { return false; } if ((assetEntryUser.isDefaultUser() || !assetEntryUser.isActive()) && (activityCounterDefinition.getOwnerType() != SocialActivityCounterConstants.TYPE_ACTOR)) { return false; } if (!activityCounterDefinition.isEnabled() || (activityCounterDefinition.getIncrement() == 0)) { return false; } String name = activityCounterDefinition.getName(); if ((user.getUserId() == assetEntryUser.getUserId()) && (name.equals(SocialActivityCounterConstants.NAME_CONTRIBUTION) || name.equals(SocialActivityCounterConstants.NAME_POPULARITY))) { return false; } if ((activityCounterDefinition.getOwnerType() == SocialActivityCounterConstants.TYPE_ASSET) && !assetEntry.isVisible()) { return false; } return true; } protected SocialActivityCounter lockProtectedAddActivityCounter( final long groupId, final long classNameId, final long classPK, final String name, final int ownerType, final int totalValue, final long previousActivityCounterId, final int periodLength) throws PortalException { String lockKey = StringUtil.merge( new Object[] {groupId, classNameId, classPK, name, ownerType}, StringPool.POUND); LockProtectedAction<SocialActivityCounter> lockProtectedAction = new LockProtectedAction<SocialActivityCounter>( SocialActivityCounter.class, lockKey, PropsValues.SOCIAL_ACTIVITY_LOCK_TIMEOUT, PropsValues.SOCIAL_ACTIVITY_LOCK_RETRY_DELAY) { @Override protected SocialActivityCounter performProtectedAction() throws PortalException { SocialActivityCounter activityCounter = socialActivityCounterLocalService.addActivityCounter( groupId, classNameId, classPK, name, ownerType, totalValue, previousActivityCounterId, periodLength); return activityCounter; } }; lockProtectedAction.performAction(); return lockProtectedAction.getReturnValue(); } protected void lockProtectedGetActivityLimit( final long groupId, final User user, final SocialActivity activity, final SocialActivityCounterDefinition activityCounterDefinition) throws PortalException { final long classPK = getLimitClassPK( activity, activityCounterDefinition); String lockKey = StringUtil.merge( new Object[] { groupId, user.getUserId(), activity.getClassNameId(), classPK, activity.getType(), activityCounterDefinition.getName() }, StringPool.POUND); LockProtectedAction<SocialActivityLimit> lockProtectedAction = new LockProtectedAction<SocialActivityLimit>( SocialActivityLimit.class, lockKey, PropsValues.SOCIAL_ACTIVITY_LOCK_TIMEOUT, PropsValues.SOCIAL_ACTIVITY_LOCK_RETRY_DELAY) { @Override protected SocialActivityLimit performProtectedAction() throws PortalException { SocialActivityLimit activityLimit = socialActivityLimitPersistence.fetchByG_U_C_C_A_A( groupId, user.getUserId(), activity.getClassNameId(), classPK, activity.getType(), activityCounterDefinition.getName()); if (activityLimit == null) { activityLimit = socialActivityLimitLocalService.addActivityLimit( user.getUserId(), activity.getGroupId(), activity.getClassNameId(), classPK, activity.getType(), activityCounterDefinition.getName(), activityCounterDefinition.getLimitPeriod()); } return activityLimit; } }; lockProtectedAction.performAction(); socialActivityLimitPersistence.cacheResult( lockProtectedAction.getReturnValue()); } private final SocialActivityCounterDefinition _assetActivitiesActivityCounterDefinition = new SocialActivityCounterDefinition( SocialActivityCounterConstants.NAME_ASSET_ACTIVITIES, SocialActivityCounterConstants.TYPE_ASSET); private final SocialActivityCounterDefinition _userAchievementsActivityCounterDefinition = new SocialActivityCounterDefinition( SocialActivityCounterConstants.NAME_USER_ACHIEVEMENTS, SocialActivityCounterConstants.TYPE_ACTOR); private final SocialActivityCounterDefinition _userActivitiesActivityCounterDefinition = new SocialActivityCounterDefinition( SocialActivityCounterConstants.NAME_USER_ACTIVITIES, SocialActivityCounterConstants.TYPE_ACTOR); }