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