001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.social.service.impl;
016    
017    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
018    import com.liferay.portal.kernel.cache.PortalCache;
019    import com.liferay.portal.kernel.dao.orm.QueryUtil;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.lock.LockProtectedAction;
022    import com.liferay.portal.kernel.transaction.Propagation;
023    import com.liferay.portal.kernel.transaction.Transactional;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.Tuple;
027    import com.liferay.portal.model.Group;
028    import com.liferay.portal.model.User;
029    import com.liferay.portal.util.PortalUtil;
030    import com.liferay.portal.util.PropsValues;
031    import com.liferay.portlet.asset.model.AssetEntry;
032    import com.liferay.portlet.social.model.SocialAchievement;
033    import com.liferay.portlet.social.model.SocialActivity;
034    import com.liferay.portlet.social.model.SocialActivityConstants;
035    import com.liferay.portlet.social.model.SocialActivityCounter;
036    import com.liferay.portlet.social.model.SocialActivityCounterConstants;
037    import com.liferay.portlet.social.model.SocialActivityCounterDefinition;
038    import com.liferay.portlet.social.model.SocialActivityDefinition;
039    import com.liferay.portlet.social.model.SocialActivityLimit;
040    import com.liferay.portlet.social.model.SocialActivityProcessor;
041    import com.liferay.portlet.social.model.impl.SocialActivityImpl;
042    import com.liferay.portlet.social.service.base.SocialActivityCounterLocalServiceBaseImpl;
043    import com.liferay.portlet.social.service.persistence.SocialActivityCounterFinder;
044    import com.liferay.portlet.social.util.SocialCounterPeriodUtil;
045    
046    import java.util.ArrayList;
047    import java.util.Arrays;
048    import java.util.Collections;
049    import java.util.HashMap;
050    import java.util.List;
051    import java.util.Map;
052    
053    /**
054     * The social activity counter local service. This service is responsible for
055     * creating and/or incrementing counters in response to an activity. It also
056     * provides methods for querying activity counters within a time period.
057     *
058     * <p>
059     * Under normal circumstances only the {@link
060     * #addActivityCounters(SocialActivity)} should be called directly and even that
061     * is usually not necessary as it is automatically called by the social activity
062     * service.
063     * </p>
064     *
065     * @author Zsolt Berentey
066     * @author Shuyang Zhou
067     */
068    public class SocialActivityCounterLocalServiceImpl
069            extends SocialActivityCounterLocalServiceBaseImpl {
070    
071            /**
072             * Adds an activity counter with a default period length.
073             *
074             * <p>
075             * This method uses the lock service to guard against multiple threads
076             * trying to insert the same counter because this service is called
077             * asynchronously from the social activity service.
078             * </p>
079             *
080             * @param      groupId the primary key of the group
081             * @param      classNameId the primary key of the entity's class this
082             *             counter belongs to
083             * @param      classPK the primary key of the entity this counter belongs to
084             * @param      name the counter's name
085             * @param      ownerType the counter's owner type. Acceptable values are
086             *             <code>TYPE_ACTOR</code>, <code>TYPE_ASSET</code> and
087             *             <code>TYPE_CREATOR</code> defined in {@link
088             *             SocialActivityCounterConstants}.
089             * @param      currentValue the counter's current value (optionally
090             *             <code>0</code>)
091             * @param      totalValue the counter's total value (optionally
092             *             <code>0</code>)
093             * @param      startPeriod the counter's start period
094             * @param      endPeriod the counter's end period
095             * @return     the added activity counter
096             * @throws     PortalException if the group or the previous activity counter
097             *             could not be found
098             * @deprecated As of 6.2.0, replaced by {@link #addActivityCounter(long,
099             *             long, long, String, int, int, long, int)}
100             */
101            @Deprecated
102            @Override
103            public SocialActivityCounter addActivityCounter(
104                            long groupId, long classNameId, long classPK, String name,
105                            int ownerType, int currentValue, int totalValue, int startPeriod,
106                            int endPeriod)
107                    throws PortalException {
108    
109                    return addActivityCounter(
110                            groupId, classNameId, classPK, name, ownerType, totalValue, 0, 0);
111            }
112    
113            /**
114             * Adds an activity counter specifying a previous activity and period
115             * length.
116             *
117             * <p>
118             * This method uses the lock service to guard against multiple threads
119             * trying to insert the same counter because this service is called
120             * asynchronously from the social activity service.
121             * </p>
122             *
123             * @param      groupId the primary key of the group
124             * @param      classNameId the primary key of the entity's class this
125             *             counter belongs to
126             * @param      classPK the primary key of the entity this counter belongs to
127             * @param      name the counter name
128             * @param      ownerType the counter's owner type. Acceptable values are
129             *             <code>TYPE_ACTOR</code>, <code>TYPE_ASSET</code> and
130             *             <code>TYPE_CREATOR</code> defined in {@link
131             *             SocialActivityCounterConstants}.
132             * @param      currentValue the current value of the counter (optionally
133             *             <code>0</code>)
134             * @param      totalValue the counter's total value (optionally
135             *             <code>0</code>)
136             * @param      startPeriod the counter's start period
137             * @param      endPeriod the counter's end period
138             * @param      previousActivityCounterId the primary key of the activity
139             *             counter for the previous time period (optionally
140             *             <code>0</code>, if this is the first)
141             * @param      periodLength the period length in days,
142             *             <code>PERIOD_LENGTH_INFINITE</code> for never ending counters
143             *             or <code>PERIOD_LENGTH_SYSTEM</code> for the period length
144             *             defined in <code>portal-ext.properties</code>. For more
145             *             information see {@link SocialActivityCounterConstants}.
146             * @return     the added activity counter
147             * @throws     PortalException if the group or the previous activity counter
148             *             could not be found
149             * @deprecated As of 6.2.0, replaced by {@link #addActivityCounter(long,
150             *             long, long, String, int, int, long, int)}
151             */
152            @Deprecated
153            @Override
154            public SocialActivityCounter addActivityCounter(
155                            long groupId, long classNameId, long classPK, String name,
156                            int ownerType, int currentValue, int totalValue, int startPeriod,
157                            int endPeriod, long previousActivityCounterId, int periodLength)
158                    throws PortalException {
159    
160                    return addActivityCounter(
161                            groupId, classNameId, classPK, name, ownerType, totalValue,
162                            previousActivityCounterId, periodLength);
163            }
164    
165            /**
166             * Adds an activity counter specifying a previous activity and period
167             * length.
168             *
169             * <p>
170             * This method uses the lock service to guard against multiple threads
171             * trying to insert the same counter because this service is called
172             * asynchronously from the social activity service.
173             * </p>
174             *
175             * @param  groupId the primary key of the group
176             * @param  classNameId the primary key of the entity's class this counter
177             *         belongs to
178             * @param  classPK the primary key of the entity this counter belongs to
179             * @param  name the counter name
180             * @param  ownerType the counter's owner type. Acceptable values are
181             *         <code>TYPE_ACTOR</code>, <code>TYPE_ASSET</code> and
182             *         <code>TYPE_CREATOR</code> defined in {@link
183             *         SocialActivityCounterConstants}.
184             * @param  totalValue the counter's total value (optionally <code>0</code>)
185             * @param  previousActivityCounterId the primary key of the activity counter
186             *         for the previous time period (optionally <code>0</code>, if this
187             *         is the first)
188             * @param  periodLength the period length in days,
189             *         <code>PERIOD_LENGTH_INFINITE</code> for never ending counters or
190             *         <code>PERIOD_LENGTH_SYSTEM</code> for the period length defined
191             *         in <code>portal-ext.properties</code>. For more information see
192             *         {@link SocialActivityCounterConstants}.
193             * @return the added activity counter
194             * @throws PortalException if the group or the previous activity counter
195             *         could not be found
196             */
197            @Override
198            @Transactional(propagation = Propagation.REQUIRES_NEW)
199            public SocialActivityCounter addActivityCounter(
200                            long groupId, long classNameId, long classPK, String name,
201                            int ownerType, int totalValue, long previousActivityCounterId,
202                            int periodLength)
203                    throws PortalException {
204    
205                    SocialActivityCounter activityCounter = null;
206    
207                    if (previousActivityCounterId != 0) {
208                            activityCounter = socialActivityCounterPersistence.findByPrimaryKey(
209                                    previousActivityCounterId);
210    
211                            if (periodLength ==
212                                            SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM) {
213    
214                                    activityCounter.setEndPeriod(
215                                            SocialCounterPeriodUtil.getStartPeriod() - 1);
216                            }
217                            else {
218                                    activityCounter.setEndPeriod(
219                                            activityCounter.getStartPeriod() + periodLength - 1);
220                            }
221    
222                            socialActivityCounterPersistence.update(activityCounter);
223                    }
224    
225                    activityCounter = socialActivityCounterPersistence.fetchByG_C_C_N_O_E(
226                            groupId, classNameId, classPK, name, ownerType,
227                            SocialActivityCounterConstants.END_PERIOD_UNDEFINED, false);
228    
229                    if (activityCounter != null) {
230                            return activityCounter;
231                    }
232    
233                    Group group = groupPersistence.findByPrimaryKey(groupId);
234    
235                    long activityCounterId = counterLocalService.increment();
236    
237                    activityCounter = socialActivityCounterPersistence.create(
238                            activityCounterId);
239    
240                    activityCounter.setGroupId(groupId);
241                    activityCounter.setCompanyId(group.getCompanyId());
242                    activityCounter.setClassNameId(classNameId);
243                    activityCounter.setClassPK(classPK);
244                    activityCounter.setName(name);
245                    activityCounter.setOwnerType(ownerType);
246                    activityCounter.setTotalValue(totalValue);
247    
248                    if (periodLength ==
249                                    SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM) {
250    
251                            activityCounter.setStartPeriod(
252                                    SocialCounterPeriodUtil.getStartPeriod());
253                    }
254                    else {
255                            activityCounter.setStartPeriod(
256                                    SocialCounterPeriodUtil.getActivityDay());
257                    }
258    
259                    activityCounter.setEndPeriod(
260                            SocialActivityCounterConstants.END_PERIOD_UNDEFINED);
261                    activityCounter.setActive(true);
262    
263                    socialActivityCounterPersistence.update(activityCounter);
264    
265                    return activityCounter;
266            }
267    
268            /**
269             * Adds or increments activity counters related to an activity.
270             *
271             * </p>
272             * This method is called asynchronously from the social activity service
273             * when the user performs an activity defined in
274             * </code>liferay-social.xml</code>.
275             * </p>
276             *
277             * <p>
278             * This method first calls the activity processor class, if there is one
279             * defined for the activity, checks for limits and increments all the
280             * counters that belong to the activity. Afterwards, it processes the
281             * activity with respect to achievement classes, if any. Lastly it
282             * increments the built-in <code>user.activities</code> and
283             * <code>asset.activities</code> counters.
284             * </p>
285             *
286             * @param  activity the social activity
287             * @throws PortalException if an expected group or expected previous
288             *         activity counters could not be found
289             */
290            @Override
291            public void addActivityCounters(SocialActivity activity)
292                    throws PortalException {
293    
294                    if (!socialActivitySettingLocalService.isEnabled(
295                                    activity.getGroupId(), activity.getClassNameId())) {
296    
297                            return;
298                    }
299    
300                    if (!socialActivitySettingLocalService.isEnabled(
301                                    activity.getGroupId(), activity.getClassNameId(),
302                                    activity.getClassPK())) {
303    
304                            return;
305                    }
306    
307                    if ((activity.getType() ==
308                                    SocialActivityConstants.TYPE_MOVE_ATTACHMENT_TO_TRASH) ||
309                            (activity.getType() ==
310                                    SocialActivityConstants.TYPE_MOVE_TO_TRASH)) {
311    
312                            disableActivityCounters(
313                                    activity.getClassNameId(), activity.getClassPK());
314    
315                            return;
316                    }
317    
318                    if ((activity.getType() ==
319                                    SocialActivityConstants.TYPE_RESTORE_ATTACHMENT_FROM_TRASH) ||
320                            (activity.getType() ==
321                                    SocialActivityConstants.TYPE_RESTORE_FROM_TRASH)) {
322    
323                            enableActivityCounters(
324                                    activity.getClassNameId(), activity.getClassPK());
325    
326                            return;
327                    }
328    
329                    User user = userPersistence.findByPrimaryKey(activity.getUserId());
330    
331                    SocialActivityDefinition activityDefinition =
332                            socialActivitySettingLocalService.getActivityDefinition(
333                                    activity.getGroupId(), activity.getClassName(),
334                                    activity.getType());
335    
336                    if ((activityDefinition == null) ||
337                            !activityDefinition.isCountersEnabled()) {
338    
339                            return;
340                    }
341    
342                    SocialActivityProcessor activityProcessor =
343                            activityDefinition.getActivityProcessor();
344    
345                    if (activityProcessor != null) {
346                            activityProcessor.processActivity(activity);
347                    }
348    
349                    AssetEntry assetEntry = activity.getAssetEntry();
350    
351                    User assetEntryUser = userPersistence.findByPrimaryKey(
352                            assetEntry.getUserId());
353    
354                    List<SocialActivityCounter> activityCounters = new ArrayList<>();
355    
356                    for (SocialActivityCounterDefinition activityCounterDefinition :
357                                    activityDefinition.getActivityCounterDefinitions()) {
358    
359                            if (isAddActivityCounter(
360                                            user, assetEntryUser, assetEntry,
361                                            activityCounterDefinition)) {
362    
363                                    SocialActivityCounter activityCounter = addActivityCounter(
364                                            activity.getGroupId(), user, activity,
365                                            activityCounterDefinition);
366    
367                                    activityCounters.add(activityCounter);
368                            }
369                    }
370    
371                    SocialActivityCounter assetActivitiesCounter = null;
372    
373                    if (!assetEntryUser.isDefaultUser() && assetEntryUser.isActive() &&
374                            assetEntry.isVisible()) {
375    
376                            assetActivitiesCounter = addAssetActivitiesCounter(activity);
377                    }
378    
379                    SocialActivityCounter userActivitiesCounter = null;
380    
381                    if (!user.isDefaultUser() && user.isActive()) {
382                            userActivitiesCounter = addUserActivitiesCounter(activity);
383                    }
384    
385                    for (SocialActivityCounter activityCounter : activityCounters) {
386                            SocialActivityCounterDefinition activityCounterDefinition =
387                                    activityDefinition.getActivityCounterDefinition(
388                                            activityCounter.getName());
389    
390                            if (checkActivityLimit(user, activity, activityCounterDefinition)) {
391                                    incrementActivityCounter(
392                                            activityCounter, activityCounterDefinition);
393                            }
394                    }
395    
396                    if (assetActivitiesCounter != null) {
397                            incrementActivityCounter(
398                                    assetActivitiesCounter,
399                                    _assetActivitiesActivityCounterDefinition);
400                    }
401    
402                    if (userActivitiesCounter != null) {
403                            incrementActivityCounter(
404                                    userActivitiesCounter,
405                                    _userActivitiesActivityCounterDefinition);
406                    }
407    
408                    for (SocialAchievement achievement :
409                                    activityDefinition.getAchievements()) {
410    
411                            achievement.processActivity(activity);
412                    }
413            }
414    
415            /**
416             * Creates an activity counter with a default period length, adding it into
417             * the database.
418             *
419             * @param      groupId the primary key of the group
420             * @param      classNameId the primary key of the entity's class this
421             *             counter belongs to
422             * @param      classPK the primary key of the entity this counter belongs to
423             * @param      name the counter's name
424             * @param      ownerType the counter's owner type. Acceptable values are
425             *             <code>TYPE_ACTOR</code>, <code>TYPE_ASSET</code> and
426             *             <code>TYPE_CREATOR</code> defined in {@link
427             *             SocialActivityCounterConstants}.
428             * @param      currentValue the counter's current value (optionally
429             *             <code>0</code>)
430             * @param      totalValue the counter's total value (optionally
431             *             <code>0</code>)
432             * @param      startPeriod the counter's start period
433             * @param      endPeriod the counter's end period
434             * @return     the created activity counter
435             * @throws     PortalException if the group or a previous activity counter
436             *             could not be found
437             * @deprecated As of 6.2.0, replaced by {@link #addActivityCounter(long,
438             *             long, long, String, int, int, long, int)}
439             */
440            @Deprecated
441            @Override
442            @Transactional(propagation = Propagation.REQUIRES_NEW)
443            public SocialActivityCounter createActivityCounter(
444                            long groupId, long classNameId, long classPK, String name,
445                            int ownerType, int currentValue, int totalValue, int startPeriod,
446                            int endPeriod)
447                    throws PortalException {
448    
449                    return addActivityCounter(
450                            groupId, classNameId, classPK, name, ownerType, totalValue, 0, 0);
451            }
452    
453            /**
454             * Creates an activity counter, adding it into the database.
455             *
456             * <p>
457             * This method actually creates the counter in the database. It requires a
458             * new transaction so that other threads can find the new counter when the
459             * lock in the calling method is released.
460             * </p>
461             *
462             * @param      groupId the primary key of the group
463             * @param      classNameId the primary key of the entity's class this
464             *             counter belongs to
465             * @param      classPK the primary key of the entity this counter belongs to
466             * @param      name the counter's name
467             * @param      ownerType the counter's owner type. Acceptable values are
468             *             <code>TYPE_ACTOR</code>, <code>TYPE_ASSET</code> and
469             *             <code>TYPE_CREATOR</code> defined in {@link
470             *             SocialActivityCounterConstants}.
471             * @param      currentValue the counter's current value (optionally
472             *             <code>0</code>)
473             * @param      totalValue the counter's total value of the counter
474             *             (optionally <code>0</code>)
475             * @param      startPeriod the counter's start period
476             * @param      endPeriod the counter's end period
477             * @param      previousActivityCounterId the primary key of the activity
478             *             counter for the previous time period (optionally
479             *             <code>0</code>, if this is the first)
480             * @param      periodLength the period length in days,
481             *             <code>PERIOD_LENGTH_INFINITE</code> for never ending counters
482             *             or <code>PERIOD_LENGTH_SYSTEM</code> for the period length
483             *             defined in <code>portal-ext.properties</code>. For more
484             *             information see {@link SocialActivityConstants}.
485             * @return     the created activity counter
486             * @throws     PortalException if the group or the previous activity counter
487             *             could not be found
488             * @deprecated As of 6.2.0, replaced by {@link #addActivityCounter(long,
489             *             long, long, String, int, int, long, int)}
490             */
491            @Deprecated
492            @Override
493            @Transactional(propagation = Propagation.REQUIRES_NEW)
494            public SocialActivityCounter createActivityCounter(
495                            long groupId, long classNameId, long classPK, String name,
496                            int ownerType, int currentValue, int totalValue, int startPeriod,
497                            int endPeriod, long previousActivityCounterId, int periodLength)
498                    throws PortalException {
499    
500                    return addActivityCounter(
501                            groupId, classNameId, classPK, name, ownerType, totalValue,
502                            previousActivityCounterId, periodLength);
503            }
504    
505            /**
506             * Deletes all activity counters, limits, and settings related to the asset.
507             *
508             * <p>
509             * This method subtracts the asset's popularity from the owner's
510             * contribution points. It also creates a new contribution period if the
511             * latest one does not belong to the current period.
512             * </p>
513             *
514             * @param  assetEntry the asset entry
515             * @throws PortalException if the new contribution counter could not be
516             *         created
517             */
518            @Override
519            public void deleteActivityCounters(AssetEntry assetEntry)
520                    throws PortalException {
521    
522                    if (assetEntry == null) {
523                            return;
524                    }
525    
526                    adjustUserContribution(assetEntry, false);
527    
528                    socialActivityCounterPersistence.removeByC_C(
529                            assetEntry.getClassNameId(), assetEntry.getClassPK());
530    
531                    socialActivityLimitPersistence.removeByC_C(
532                            assetEntry.getClassNameId(), assetEntry.getClassPK());
533    
534                    socialActivitySettingLocalService.deleteActivitySetting(
535                            assetEntry.getGroupId(), assetEntry.getClassName(),
536                            assetEntry.getClassPK());
537    
538                    clearFinderCache();
539            }
540    
541            /**
542             * Deletes all activity counters, limits, and settings related to the entity
543             * identified by the class name ID and class primary key.
544             *
545             * @param  classNameId the primary key of the entity's class
546             * @param  classPK the primary key of the entity
547             * @throws PortalException if the entity is an asset and its owner's
548             *         contribution counter could not be updated
549             */
550            @Override
551            public void deleteActivityCounters(long classNameId, long classPK)
552                    throws PortalException {
553    
554                    String className = PortalUtil.getClassName(classNameId);
555    
556                    if (!className.equals(User.class.getName())) {
557                            AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
558                                    className, classPK);
559    
560                            deleteActivityCounters(assetEntry);
561                    }
562                    else {
563                            socialActivityCounterPersistence.removeByC_C(classNameId, classPK);
564    
565                            socialActivityLimitPersistence.removeByUserId(classPK);
566                    }
567    
568                    clearFinderCache();
569            }
570    
571            /**
572             * Deletes all activity counters for the entity identified by the class name
573             * and class primary key.
574             *
575             * @param  className the entity's class name
576             * @param  classPK the primary key of the entity
577             * @throws PortalException if the entity is an asset and its owner's
578             *         contribution counter could not be updated
579             */
580            @Override
581            public void deleteActivityCounters(String className, long classPK)
582                    throws PortalException {
583    
584                    if (!className.equals(User.class.getName())) {
585                            AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
586                                    className, classPK);
587    
588                            deleteActivityCounters(assetEntry);
589                    }
590                    else {
591                            long classNameId = classNameLocalService.getClassNameId(className);
592    
593                            socialActivityCounterPersistence.removeByC_C(classNameId, classPK);
594    
595                            socialActivityLimitPersistence.removeByUserId(classPK);
596                    }
597    
598                    clearFinderCache();
599            }
600    
601            /**
602             * Disables all the counters of an asset identified by the class name ID and
603             * class primary key.
604             *
605             * <p>
606             * This method is used by the recycle bin to disable all counters of assets
607             * put into the recycle bin. It adjusts the owner's contribution score.
608             * </p>
609             *
610             * @param  classNameId the primary key of the asset's class
611             * @param  classPK the primary key of the asset
612             * @throws PortalException if the asset owner's contribution counter could
613             *         not be updated
614             */
615            @Override
616            public void disableActivityCounters(long classNameId, long classPK)
617                    throws PortalException {
618    
619                    String className = PortalUtil.getClassName(classNameId);
620    
621                    disableActivityCounters(className, classPK);
622            }
623    
624            /**
625             * Disables all the counters of an asset identified by the class name and
626             * class primary key.
627             *
628             * <p>
629             * This method is used by the recycle bin to disable all counters of assets
630             * put into the recycle bin. It adjusts the owner's contribution score.
631             * </p>
632             *
633             * @param  className the asset's class name
634             * @param  classPK the primary key of the asset
635             * @throws PortalException if the asset owner's contribution counter could
636             *         not be updated
637             */
638            @Override
639            public void disableActivityCounters(String className, long classPK)
640                    throws PortalException {
641    
642                    AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
643                            className, classPK);
644    
645                    if (assetEntry == null) {
646                            return;
647                    }
648    
649                    List<SocialActivityCounter> activityCounters =
650                            socialActivityCounterPersistence.findByC_C(
651                                    assetEntry.getClassNameId(), classPK);
652    
653                    adjustUserContribution(assetEntry, false);
654    
655                    for (SocialActivityCounter activityCounter : activityCounters) {
656                            if (activityCounter.isActive()) {
657                                    activityCounter.setActive(false);
658    
659                                    socialActivityCounterPersistence.update(activityCounter);
660                            }
661                    }
662    
663                    clearFinderCache();
664            }
665    
666            /**
667             * Enables all activity counters of an asset identified by the class name ID
668             * and class primary key.
669             *
670             * <p>
671             * This method is used by the recycle bin to enable all counters of assets
672             * restored from the recycle bin. It adjusts the owner's contribution score.
673             * </p>
674             *
675             * @param  classNameId the primary key of the asset's class
676             * @param  classPK the primary key of the asset
677             * @throws PortalException if the asset owner's contribution counter could
678             *         not be updated
679             */
680            @Override
681            public void enableActivityCounters(long classNameId, long classPK)
682                    throws PortalException {
683    
684                    String className = PortalUtil.getClassName(classNameId);
685    
686                    enableActivityCounters(className, classPK);
687            }
688    
689            /**
690             * Enables all the counters of an asset identified by the class name and
691             * class primary key.
692             *
693             * <p>
694             * This method is used by the recycle bin to enable all counters of assets
695             * restored from the recycle bin. It adjusts the owner's contribution score.
696             * </p>
697             *
698             * @param  className the asset's class name
699             * @param  classPK the primary key of the asset
700             * @throws PortalException if the asset owner's contribution counter could
701             *         not be updated
702             */
703            @Override
704            public void enableActivityCounters(String className, long classPK)
705                    throws PortalException {
706    
707                    AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
708                            className, classPK);
709    
710                    if (assetEntry == null) {
711                            return;
712                    }
713    
714                    List<SocialActivityCounter> activityCounters =
715                            socialActivityCounterPersistence.findByC_C(
716                                    assetEntry.getClassNameId(), classPK);
717    
718                    adjustUserContribution(assetEntry, true);
719    
720                    for (SocialActivityCounter activityCounter : activityCounters) {
721                            if (!activityCounter.isActive()) {
722                                    activityCounter.setActive(true);
723    
724                                    socialActivityCounterPersistence.update(activityCounter);
725                            }
726                    }
727    
728                    clearFinderCache();
729            }
730    
731            /**
732             * Returns the activity counter with the given name, owner, and end period
733             * that belong to the given entity.
734             *
735             * @param  groupId the primary key of the group
736             * @param  classNameId the primary key of the entity's class
737             * @param  classPK the primary key of the entity
738             * @param  name the counter name
739             * @param  ownerType the owner type
740             * @param  endPeriod the end period, <code>-1</code> for the latest one
741             * @return the matching activity counter
742             */
743            @Override
744            public SocialActivityCounter fetchActivityCounterByEndPeriod(
745                    long groupId, long classNameId, long classPK, String name,
746                    int ownerType, int endPeriod) {
747    
748                    return socialActivityCounterPersistence.fetchByG_C_C_N_O_E(
749                            groupId, classNameId, classPK, name, ownerType, endPeriod);
750            }
751    
752            /**
753             * Returns the activity counter with the given name, owner, and start period
754             * that belong to the given entity.
755             *
756             * @param  groupId the primary key of the group
757             * @param  classNameId the primary key of the entity's class
758             * @param  classPK the primary key of the entity
759             * @param  name the counter name
760             * @param  ownerType the owner type
761             * @param  startPeriod the start period
762             * @return the matching activity counter
763             */
764            @Override
765            public SocialActivityCounter fetchActivityCounterByStartPeriod(
766                    long groupId, long classNameId, long classPK, String name,
767                    int ownerType, int startPeriod) {
768    
769                    return socialActivityCounterPersistence.fetchByG_C_C_N_O_S(
770                            groupId, classNameId, classPK, name, ownerType, startPeriod);
771            }
772    
773            /**
774             * Returns the latest activity counter with the given name and owner that
775             * belong to the given entity.
776             *
777             * @param  groupId the primary key of the group
778             * @param  classNameId the primary key of the entity's class
779             * @param  classPK the primary key of the entity
780             * @param  name the counter name
781             * @param  ownerType the owner type
782             * @return the matching activity counter
783             */
784            @Override
785            public SocialActivityCounter fetchLatestActivityCounter(
786                    long groupId, long classNameId, long classPK, String name,
787                    int ownerType) {
788    
789                    return socialActivityCounterPersistence.fetchByG_C_C_N_O_E(
790                            groupId, classNameId, classPK, name, ownerType,
791                            SocialActivityCounterConstants.END_PERIOD_UNDEFINED);
792            }
793    
794            /**
795             * Returns all the activity counters with the given name and period offsets.
796             *
797             * <p>
798             * The start and end offsets can belong to different periods. This method
799             * groups the counters by name and returns the sum of their current values.
800             * </p>
801             *
802             * @param  groupId the primary key of the group
803             * @param  name the counter name
804             * @param  startOffset the offset for the start period
805             * @param  endOffset the offset for the end period
806             * @return the matching activity counters
807             */
808            @Override
809            public List<SocialActivityCounter> getOffsetActivityCounters(
810                    long groupId, String name, int startOffset, int endOffset) {
811    
812                    int startPeriod = SocialCounterPeriodUtil.getStartPeriod(startOffset);
813                    int endPeriod = SocialCounterPeriodUtil.getEndPeriod(endOffset);
814    
815                    return getPeriodActivityCounters(groupId, name, startPeriod, endPeriod);
816            }
817    
818            /**
819             * Returns the distribution of the activity counters with the given name and
820             * period offsets.
821             *
822             * <p>
823             * The start and end offsets can belong to different periods. This method
824             * groups the counters by their owner entity (usually some asset) and
825             * returns a counter for each entity class with the sum of the counters'
826             * current values.
827             * </p>
828             *
829             * @param  groupId the primary key of the group
830             * @param  name the counter name
831             * @param  startOffset the offset for the start period
832             * @param  endOffset the offset for the end period
833             * @return the distribution of matching activity counters
834             */
835            @Override
836            public List<SocialActivityCounter> getOffsetDistributionActivityCounters(
837                    long groupId, String name, int startOffset, int endOffset) {
838    
839                    int startPeriod = SocialCounterPeriodUtil.getStartPeriod(startOffset);
840                    int endPeriod = SocialCounterPeriodUtil.getEndPeriod(endOffset);
841    
842                    return getPeriodDistributionActivityCounters(
843                            groupId, name, startPeriod, endPeriod);
844            }
845    
846            /**
847             * Returns all the activity counters with the given name and time period.
848             *
849             * <p>
850             * The start and end period values can belong to different periods. This
851             * method groups the counters by name and returns the sum of their current
852             * values.
853             * </p>
854             *
855             * @param  groupId the primary key of the group
856             * @param  name the counter name
857             * @param  startPeriod the start period
858             * @param  endPeriod the end period
859             * @return the matching activity counters
860             */
861            @Override
862            public List<SocialActivityCounter> getPeriodActivityCounters(
863                    long groupId, String name, int startPeriod, int endPeriod) {
864    
865                    if (endPeriod == SocialActivityCounterConstants.END_PERIOD_UNDEFINED) {
866                            endPeriod = SocialCounterPeriodUtil.getEndPeriod();
867                    }
868    
869                    int offset = SocialCounterPeriodUtil.getOffset(endPeriod);
870    
871                    int periodLength = SocialCounterPeriodUtil.getPeriodLength(offset);
872    
873                    return socialActivityCounterFinder.findAC_ByG_N_S_E_1(
874                            groupId, name, startPeriod, endPeriod, periodLength);
875            }
876    
877            /**
878             * Returns the distribution of activity counters with the given name and
879             * time period.
880             *
881             * <p>
882             * The start and end period values can belong to different periods. This
883             * method groups the counters by their owner entity (usually some asset) and
884             * returns a counter for each entity class with the sum of the counters'
885             * current values.
886             * </p>
887             *
888             * @param  groupId the primary key of the group
889             * @param  name the counter name
890             * @param  startPeriod the start period
891             * @param  endPeriod the end period
892             * @return the distribution of matching activity counters
893             */
894            @Override
895            public List<SocialActivityCounter> getPeriodDistributionActivityCounters(
896                    long groupId, String name, int startPeriod, int endPeriod) {
897    
898                    int offset = SocialCounterPeriodUtil.getOffset(endPeriod);
899    
900                    int periodLength = SocialCounterPeriodUtil.getPeriodLength(offset);
901    
902                    return socialActivityCounterFinder.findAC_ByG_N_S_E_2(
903                            groupId, name, startPeriod, endPeriod, periodLength);
904            }
905    
906            /**
907             * Returns the range of tuples that contain users and a list of activity
908             * counters.
909             *
910             * <p>
911             * The counters returned for each user are passed to this method in the
912             * selectedNames array. The method also accepts an array of counter names
913             * that are used to rank the users.
914             * </p>
915             *
916             * <p>
917             * Useful when paginating results. Returns a maximum of <code>end -
918             * start</code> instances. <code>start</code> and <code>end</code> are not
919             * primary keys, they are indexes in the result set. Thus, <code>0</code>
920             * refers to the first result in the set. Setting both <code>start</code>
921             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
922             * result set.
923             * </p>
924             *
925             * @param  groupId the primary key of the group
926             * @param  rankingNames the ranking counter names
927             * @param  selectedNames the counter names that will be returned with each
928             *         user
929             * @param  start the lower bound of the range of results
930             * @param  end the upper bound of the range of results (not inclusive)
931             * @return the range of matching tuples
932             */
933            @Override
934            public List<Tuple> getUserActivityCounters(
935                    long groupId, String[] rankingNames, String[] selectedNames, int start,
936                    int end) {
937    
938                    List<Long> userIds = socialActivityCounterFinder.findU_ByG_N(
939                            groupId, rankingNames, start, end);
940    
941                    if (userIds.isEmpty()) {
942                            return Collections.emptyList();
943                    }
944    
945                    Tuple[] userActivityCounters = new Tuple[userIds.size()];
946    
947                    List<SocialActivityCounter> activityCounters =
948                            socialActivityCounterFinder.findAC_By_G_C_C_N_S_E(
949                                    groupId, userIds, selectedNames, QueryUtil.ALL_POS,
950                                    QueryUtil.ALL_POS);
951    
952                    long userId = 0;
953                    Map<String, SocialActivityCounter> activityCountersMap = null;
954    
955                    for (SocialActivityCounter activityCounter : activityCounters) {
956                            if (userId != activityCounter.getClassPK()) {
957                                    userId = activityCounter.getClassPK();
958                                    activityCountersMap = new HashMap<>();
959    
960                                    Tuple userActivityCounter = new Tuple(
961                                            userId, activityCountersMap);
962    
963                                    for (int i = 0; i < userIds.size(); i++) {
964                                            long curUserId = userIds.get(i);
965    
966                                            if (userId == curUserId) {
967                                                    userActivityCounters[i] = userActivityCounter;
968    
969                                                    break;
970                                            }
971                                    }
972                            }
973    
974                            activityCountersMap.put(activityCounter.getName(), activityCounter);
975                    }
976    
977                    return Arrays.asList(userActivityCounters);
978            }
979    
980            /**
981             * Returns the number of users having a rank based on the given counters.
982             *
983             * @param  groupId the primary key of the group
984             * @param  rankingNames the ranking counter names
985             * @return the number of matching users
986             */
987            @Override
988            public int getUserActivityCountersCount(
989                    long groupId, String[] rankingNames) {
990    
991                    return socialActivityCounterFinder.countU_ByG_N(groupId, rankingNames);
992            }
993    
994            /**
995             * Increments the <code>user.achievements</code> counter for a user.
996             *
997             * <p>
998             * This method should be used by an external achievement class when the
999             * users unlocks an achievement.
1000             * </p>
1001             *
1002             * @param  userId the primary key of the user
1003             * @param  groupId the primary key of the group
1004             * @throws PortalException if the group or an expected previous activity
1005             *         counter could not be found
1006             */
1007            @Override
1008            public void incrementUserAchievementCounter(long userId, long groupId)
1009                    throws PortalException {
1010    
1011                    User user = userPersistence.findByPrimaryKey(userId);
1012    
1013                    SocialActivityCounter activityCounter = addActivityCounter(
1014                            groupId, user, new SocialActivityImpl(),
1015                            _userAchievementsActivityCounterDefinition);
1016    
1017                    incrementActivityCounter(
1018                            activityCounter, _userAchievementsActivityCounterDefinition);
1019            }
1020    
1021            protected SocialActivityCounter addActivityCounter(
1022                            final long groupId, final User user, final SocialActivity activity,
1023                            final SocialActivityCounterDefinition activityCounterDefinition)
1024                    throws PortalException {
1025    
1026                    int ownerType = activityCounterDefinition.getOwnerType();
1027    
1028                    long classNameId = getClassNameId(activity.getAssetEntry(), ownerType);
1029                    long classPK = getClassPK(user, activity.getAssetEntry(), ownerType);
1030    
1031                    SocialActivityCounter activityCounter = fetchLatestActivityCounter(
1032                            groupId, classNameId, classPK, activityCounterDefinition.getName(),
1033                            ownerType);
1034    
1035                    if (activityCounter == null) {
1036                            activityCounter = lockProtectedAddActivityCounter(
1037                                    groupId, classNameId, classPK,
1038                                    activityCounterDefinition.getName(), ownerType, 0, 0,
1039                                    activityCounterDefinition.getPeriodLength());
1040                    }
1041                    else if (!activityCounter.isActivePeriod(
1042                                            activityCounterDefinition.getPeriodLength())) {
1043    
1044                            activityCounter = lockProtectedAddActivityCounter(
1045                                    groupId, classNameId, classPK,
1046                                    activityCounterDefinition.getName(), ownerType,
1047                                    activityCounter.getTotalValue(),
1048                                    activityCounter.getActivityCounterId(),
1049                                    activityCounterDefinition.getPeriodLength());
1050                    }
1051    
1052                    if (activityCounterDefinition.getLimitValue() > 0) {
1053                            SocialActivityLimit activityLimit =
1054                                    socialActivityLimitPersistence.fetchByG_U_C_C_A_A(
1055                                            groupId, user.getUserId(), activity.getClassNameId(),
1056                                            getLimitClassPK(activity, activityCounterDefinition),
1057                                            activity.getType(), activityCounterDefinition.getName());
1058    
1059                            if (activityLimit == null) {
1060                                    lockProtectedGetActivityLimit(
1061                                            groupId, user, activity, activityCounterDefinition);
1062                            }
1063                    }
1064    
1065                    return activityCounter;
1066            }
1067    
1068            protected SocialActivityCounter addAssetActivitiesCounter(
1069                            SocialActivity activity)
1070                    throws PortalException {
1071    
1072                    User user = userPersistence.findByPrimaryKey(activity.getUserId());
1073    
1074                    return addActivityCounter(
1075                            activity.getGroupId(), user, activity,
1076                            _assetActivitiesActivityCounterDefinition);
1077            }
1078    
1079            protected SocialActivityCounter addUserActivitiesCounter(
1080                            SocialActivity activity)
1081                    throws PortalException {
1082    
1083                    User user = userPersistence.findByPrimaryKey(activity.getUserId());
1084    
1085                    return addActivityCounter(
1086                            activity.getGroupId(), user, activity,
1087                            _userActivitiesActivityCounterDefinition);
1088            }
1089    
1090            protected void adjustUserContribution(AssetEntry assetEntry, boolean enable)
1091                    throws PortalException {
1092    
1093                    if (assetEntry == null) {
1094                            return;
1095                    }
1096    
1097                    SocialActivityCounter latestPopularityActivityCounter =
1098                            fetchLatestActivityCounter(
1099                                    assetEntry.getGroupId(), assetEntry.getClassNameId(),
1100                                    assetEntry.getClassPK(),
1101                                    SocialActivityCounterConstants.NAME_POPULARITY,
1102                                    SocialActivityCounterConstants.TYPE_ASSET);
1103    
1104                    if ((latestPopularityActivityCounter == null) ||
1105                            (enable && latestPopularityActivityCounter.isActive()) ||
1106                            (!enable && !latestPopularityActivityCounter.isActive())) {
1107    
1108                            return;
1109                    }
1110    
1111                    int factor = -1;
1112    
1113                    if (enable) {
1114                            factor = 1;
1115                    }
1116    
1117                    SocialActivityCounter latestContributionActivityCounter =
1118                            fetchLatestActivityCounter(
1119                                    assetEntry.getGroupId(),
1120                                    classNameLocalService.getClassNameId(User.class.getName()),
1121                                    assetEntry.getUserId(),
1122                                    SocialActivityCounterConstants.NAME_CONTRIBUTION,
1123                                    SocialActivityCounterConstants.TYPE_CREATOR);
1124    
1125                    if (latestContributionActivityCounter == null) {
1126                            return;
1127                    }
1128    
1129                    int startPeriod = SocialCounterPeriodUtil.getStartPeriod();
1130    
1131                    if (latestContributionActivityCounter.getStartPeriod() != startPeriod) {
1132                            latestContributionActivityCounter = addActivityCounter(
1133                                    latestContributionActivityCounter.getGroupId(),
1134                                    latestContributionActivityCounter.getClassNameId(),
1135                                    latestContributionActivityCounter.getClassPK(),
1136                                    latestContributionActivityCounter.getName(),
1137                                    latestContributionActivityCounter.getOwnerType(), 0,
1138                                    latestContributionActivityCounter.getTotalValue(),
1139                                    SocialCounterPeriodUtil.getStartPeriod(),
1140                                    SocialActivityCounterConstants.END_PERIOD_UNDEFINED,
1141                                    latestContributionActivityCounter.getActivityCounterId(),
1142                                    SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM);
1143                    }
1144    
1145                    if (latestPopularityActivityCounter.getStartPeriod() == startPeriod) {
1146                            latestContributionActivityCounter.setCurrentValue(
1147                                    latestContributionActivityCounter.getCurrentValue() +
1148                                            (latestPopularityActivityCounter.getCurrentValue() *
1149                                                    factor));
1150                    }
1151    
1152                    latestContributionActivityCounter.setTotalValue(
1153                            latestContributionActivityCounter.getTotalValue() +
1154                                    (latestPopularityActivityCounter.getTotalValue() * factor));
1155    
1156                    socialActivityCounterPersistence.update(
1157                            latestContributionActivityCounter);
1158            }
1159    
1160            protected boolean checkActivityLimit(
1161                            User user, SocialActivity activity,
1162                            SocialActivityCounterDefinition activityCounterDefinition)
1163                    throws PortalException {
1164    
1165                    if (activityCounterDefinition.getLimitValue() == 0) {
1166                            return true;
1167                    }
1168    
1169                    long classPK = activity.getClassPK();
1170    
1171                    String name = activityCounterDefinition.getName();
1172    
1173                    if (name.equals(SocialActivityCounterConstants.NAME_PARTICIPATION)) {
1174                            classPK = 0;
1175                    }
1176    
1177                    SocialActivityLimit activityLimit =
1178                            socialActivityLimitPersistence.findByG_U_C_C_A_A(
1179                                    activity.getGroupId(), user.getUserId(),
1180                                    activity.getClassNameId(), classPK, activity.getType(), name);
1181    
1182                    int count = activityLimit.getCount(
1183                            activityCounterDefinition.getLimitPeriod());
1184    
1185                    if (count < activityCounterDefinition.getLimitValue()) {
1186                            activityLimit.setCount(
1187                                    activityCounterDefinition.getLimitPeriod(), count + 1);
1188    
1189                            socialActivityLimitPersistence.update(activityLimit);
1190    
1191                            return true;
1192                    }
1193    
1194                    return false;
1195            }
1196    
1197            protected void clearFinderCache() {
1198                    PortalCache<String, SocialActivityCounter> portalCache =
1199                            MultiVMPoolUtil.getPortalCache(
1200                                    SocialActivityCounterFinder.class.getName());
1201    
1202                    portalCache.removeAll();
1203            }
1204    
1205            protected long getClassNameId(AssetEntry assetEntry, int ownerType) {
1206                    if (ownerType == SocialActivityCounterConstants.TYPE_ASSET) {
1207                            return assetEntry.getClassNameId();
1208                    }
1209    
1210                    return classNameLocalService.getClassNameId(User.class.getName());
1211            }
1212    
1213            protected long getClassPK(User user, AssetEntry assetEntry, int ownerType) {
1214                    if (ownerType == SocialActivityCounterConstants.TYPE_ACTOR) {
1215                            return user.getUserId();
1216                    }
1217    
1218                    if (ownerType == SocialActivityCounterConstants.TYPE_ASSET) {
1219                            return assetEntry.getClassPK();
1220                    }
1221    
1222                    return assetEntry.getUserId();
1223            }
1224    
1225            protected long getLimitClassPK(
1226                    SocialActivity activity,
1227                    SocialActivityCounterDefinition activityCounterDefinition) {
1228    
1229                    String name = activityCounterDefinition.getName();
1230    
1231                    if (name.equals(SocialActivityCounterConstants.NAME_PARTICIPATION)) {
1232                            return 0;
1233                    }
1234    
1235                    return activity.getClassPK();
1236            }
1237    
1238            protected void incrementActivityCounter(
1239                    SocialActivityCounter activityCounter,
1240                    SocialActivityCounterDefinition activityCounterDefinition) {
1241    
1242                    activityCounter.setCurrentValue(
1243                            activityCounter.getCurrentValue() +
1244                                    activityCounterDefinition.getIncrement());
1245                    activityCounter.setTotalValue(
1246                            activityCounter.getTotalValue() +
1247                                    activityCounterDefinition.getIncrement());
1248    
1249                    socialActivityCounterPersistence.update(activityCounter);
1250    
1251                    socialActivityCounterPersistence.clearCache(activityCounter);
1252            }
1253    
1254            protected boolean isAddActivityCounter(
1255                    User user, User assetEntryUser, AssetEntry assetEntry,
1256                    SocialActivityCounterDefinition activityCounterDefinition) {
1257    
1258                    if ((user.isDefaultUser() || !user.isActive()) &&
1259                            (activityCounterDefinition.getOwnerType() !=
1260                                    SocialActivityCounterConstants.TYPE_ASSET)) {
1261    
1262                            return false;
1263                    }
1264    
1265                    if ((assetEntryUser.isDefaultUser() || !assetEntryUser.isActive()) &&
1266                            (activityCounterDefinition.getOwnerType() !=
1267                                    SocialActivityCounterConstants.TYPE_ACTOR)) {
1268    
1269                            return false;
1270                    }
1271    
1272                    if (!activityCounterDefinition.isEnabled() ||
1273                            (activityCounterDefinition.getIncrement() == 0)) {
1274    
1275                            return false;
1276                    }
1277    
1278                    String name = activityCounterDefinition.getName();
1279    
1280                    if ((user.getUserId() == assetEntryUser.getUserId()) &&
1281                            (name.equals(SocialActivityCounterConstants.NAME_CONTRIBUTION) ||
1282                             name.equals(SocialActivityCounterConstants.NAME_POPULARITY))) {
1283    
1284                            return false;
1285                    }
1286    
1287                    if ((activityCounterDefinition.getOwnerType() ==
1288                                    SocialActivityCounterConstants.TYPE_ASSET) &&
1289                            !assetEntry.isVisible()) {
1290    
1291                            return false;
1292                    }
1293    
1294                    return true;
1295            }
1296    
1297            protected SocialActivityCounter lockProtectedAddActivityCounter(
1298                            final long groupId, final long classNameId, final long classPK,
1299                            final String name, final int ownerType, final int totalValue,
1300                            final long previousActivityCounterId, final int periodLength)
1301                    throws PortalException {
1302    
1303                    String lockKey = StringUtil.merge(
1304                            new Object[] {groupId, classNameId, classPK, name, ownerType},
1305                            StringPool.POUND);
1306    
1307                    LockProtectedAction<SocialActivityCounter> lockProtectedAction =
1308                            new LockProtectedAction<SocialActivityCounter>(
1309                                    SocialActivityCounter.class, lockKey,
1310                                    PropsValues.SOCIAL_ACTIVITY_LOCK_TIMEOUT,
1311                                    PropsValues.SOCIAL_ACTIVITY_LOCK_RETRY_DELAY) {
1312    
1313                            @Override
1314                            protected SocialActivityCounter performProtectedAction()
1315                                    throws PortalException {
1316    
1317                                    SocialActivityCounter activityCounter =
1318                                            socialActivityCounterLocalService.addActivityCounter(
1319                                                    groupId, classNameId, classPK, name, ownerType,
1320                                                    totalValue, previousActivityCounterId, periodLength);
1321    
1322                                    return activityCounter;
1323                            }
1324    
1325                    };
1326    
1327                    lockProtectedAction.performAction();
1328    
1329                    return lockProtectedAction.getReturnValue();
1330            }
1331    
1332            protected void lockProtectedGetActivityLimit(
1333                            final long groupId, final User user, final SocialActivity activity,
1334                            final SocialActivityCounterDefinition activityCounterDefinition)
1335                    throws PortalException {
1336    
1337                    final long classPK = getLimitClassPK(
1338                            activity, activityCounterDefinition);
1339    
1340                    String lockKey = StringUtil.merge(
1341                            new Object[] {
1342                                    groupId, user.getUserId(), activity.getClassNameId(), classPK,
1343                                    activity.getType(), activityCounterDefinition.getName()
1344                            },
1345                            StringPool.POUND);
1346    
1347                    LockProtectedAction<SocialActivityLimit> lockProtectedAction =
1348                            new LockProtectedAction<SocialActivityLimit>(
1349                                    SocialActivityLimit.class, lockKey,
1350                                    PropsValues.SOCIAL_ACTIVITY_LOCK_TIMEOUT,
1351                                    PropsValues.SOCIAL_ACTIVITY_LOCK_RETRY_DELAY) {
1352    
1353                            @Override
1354                            protected SocialActivityLimit performProtectedAction()
1355                                    throws PortalException {
1356    
1357                                    SocialActivityLimit activityLimit =
1358                                            socialActivityLimitPersistence.fetchByG_U_C_C_A_A(
1359                                                    groupId, user.getUserId(), activity.getClassNameId(),
1360                                                    classPK, activity.getType(),
1361                                                    activityCounterDefinition.getName());
1362    
1363                                    if (activityLimit == null) {
1364                                            activityLimit =
1365                                                    socialActivityLimitLocalService.addActivityLimit(
1366                                                            user.getUserId(), activity.getGroupId(),
1367                                                            activity.getClassNameId(), classPK,
1368                                                            activity.getType(),
1369                                                            activityCounterDefinition.getName(),
1370                                                            activityCounterDefinition.getLimitPeriod());
1371                                    }
1372    
1373                                    return activityLimit;
1374                            }
1375                    };
1376    
1377                    lockProtectedAction.performAction();
1378    
1379                    socialActivityLimitPersistence.cacheResult(
1380                            lockProtectedAction.getReturnValue());
1381            }
1382    
1383            private final SocialActivityCounterDefinition
1384                    _assetActivitiesActivityCounterDefinition =
1385                            new SocialActivityCounterDefinition(
1386                                    SocialActivityCounterConstants.NAME_ASSET_ACTIVITIES,
1387                                    SocialActivityCounterConstants.TYPE_ASSET);
1388            private final SocialActivityCounterDefinition
1389                    _userAchievementsActivityCounterDefinition =
1390                            new SocialActivityCounterDefinition(
1391                                    SocialActivityCounterConstants.NAME_USER_ACHIEVEMENTS,
1392                                    SocialActivityCounterConstants.TYPE_ACTOR);
1393            private final SocialActivityCounterDefinition
1394                    _userActivitiesActivityCounterDefinition =
1395                            new SocialActivityCounterDefinition(
1396                                    SocialActivityCounterConstants.NAME_USER_ACTIVITIES,
1397                                    SocialActivityCounterConstants.TYPE_ACTOR);
1398    
1399    }