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