001    /**
002     * Copyright (c) 2000-2011 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.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.StringBundler;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.StringUtil;
025    import com.liferay.portal.kernel.util.Tuple;
026    import com.liferay.portal.model.Group;
027    import com.liferay.portal.model.Lock;
028    import com.liferay.portal.model.User;
029    import com.liferay.portal.util.PortalUtil;
030    import com.liferay.portlet.asset.model.AssetEntry;
031    import com.liferay.portlet.social.NoSuchActivityCounterException;
032    import com.liferay.portlet.social.model.SocialAchievement;
033    import com.liferay.portlet.social.model.SocialActivity;
034    import com.liferay.portlet.social.model.SocialActivityCounter;
035    import com.liferay.portlet.social.model.SocialActivityCounterConstants;
036    import com.liferay.portlet.social.model.SocialActivityCounterDefinition;
037    import com.liferay.portlet.social.model.SocialActivityDefinition;
038    import com.liferay.portlet.social.model.SocialActivityLimit;
039    import com.liferay.portlet.social.model.SocialActivityProcessor;
040    import com.liferay.portlet.social.service.SocialActivityCounterLocalService;
041    import com.liferay.portlet.social.service.base.SocialActivityCounterLocalServiceBaseImpl;
042    import com.liferay.portlet.social.service.persistence.SocialActivityCounterFinderUtil;
043    import com.liferay.portlet.social.util.SocialCounterPeriodUtil;
044    
045    import java.util.Arrays;
046    import java.util.Collections;
047    import java.util.HashMap;
048    import java.util.List;
049    import java.util.Map;
050    
051    /**
052     * @author Zsolt Berentey
053     */
054    public class SocialActivityCounterLocalServiceImpl
055            extends SocialActivityCounterLocalServiceBaseImpl {
056    
057            public SocialActivityCounter addActivityCounter(
058                            long groupId, long classNameId, long classPK, String name,
059                            int ownerType, int currentValue, int totalValue)
060                    throws PortalException, SystemException {
061    
062                    SocialActivityCounter activityCounter = null;
063    
064                    String lockKey = getLockKey(
065                            groupId, classNameId, classPK, name, ownerType);
066    
067                    Lock lock = null;
068    
069                    while (true) {
070                            try {
071                                    lock = lockLocalService.lock(
072                                            SocialActivityCounter.class.getName(), lockKey,
073                                            lockKey, false);
074                            }
075                            catch (Exception e) {
076                                    if (_log.isWarnEnabled()) {
077                                            _log.warn(
078                                                    "Unable to acquire activity counter lock. Retrying.");
079                                    }
080    
081                                    continue;
082                            }
083    
084                            activityCounter = fetchLatestActivityCounter(
085                                    groupId, classNameId, classPK, name, ownerType, false);
086    
087                            if (activityCounter == null) {
088                                    if (!lock.isNew()) {
089                                            continue;
090                                    }
091    
092                                    Group group = groupPersistence.findByPrimaryKey(groupId);
093    
094                                    long activityCounterId = counterLocalService.increment();
095    
096                                    activityCounter = socialActivityCounterPersistence.create(
097                                            activityCounterId);
098    
099                                    activityCounter.setGroupId(groupId);
100                                    activityCounter.setCompanyId(group.getCompanyId());
101                                    activityCounter.setClassNameId(classNameId);
102                                    activityCounter.setClassPK(classPK);
103                                    activityCounter.setName(name);
104                                    activityCounter.setOwnerType(ownerType);
105                                    activityCounter.setCurrentValue(currentValue);
106                                    activityCounter.setTotalValue(totalValue);
107                                    activityCounter.setStartPeriod(
108                                            SocialCounterPeriodUtil.getStartPeriod());
109                                    activityCounter.setEndPeriod(
110                                            SocialActivityCounterConstants.END_PERIOD_UNDEFINED);
111    
112                                    socialActivityCounterPersistence.update(activityCounter, false);
113                            }
114    
115                            if (lock.isNew()) {
116                                    lockLocalService.unlock(
117                                            SocialActivityCounter.class.getName(), lockKey);
118                            }
119    
120                            break;
121                    }
122    
123                    return activityCounter;
124            }
125    
126            public void addActivityCounters(SocialActivity activity)
127                    throws PortalException, SystemException {
128    
129                    if (!socialActivitySettingLocalService.isEnabled(
130                                    activity.getGroupId(), activity.getClassNameId())) {
131    
132                            return;
133                    }
134    
135                    User user = userPersistence.findByPrimaryKey(activity.getUserId());
136    
137                    SocialActivityDefinition activityDefinition =
138                            socialActivitySettingLocalService.getActivityDefinition(
139                                    activity.getGroupId(), activity.getClassName(),
140                                    activity.getType());
141    
142                    if ((activityDefinition == null) || !activityDefinition.isEnabled()) {
143                            return;
144                    }
145    
146                    SocialActivityProcessor activityProcessor =
147                            activityDefinition.getActivityProcessor();
148    
149                    if (activityProcessor != null) {
150                            activityProcessor.processActivity(activity);
151                    }
152    
153                    AssetEntry assetEntry = activity.getAssetEntry();
154    
155                    User assetEntryUser = userPersistence.findByPrimaryKey(
156                            assetEntry.getUserId());
157    
158                    for (SocialActivityCounterDefinition activityCounterDefinition :
159                                    activityDefinition.getActivityCounterDefinitions()) {
160    
161                            if (addActivityCounter(
162                                            user, assetEntryUser, activityCounterDefinition) &&
163                                    checkActivityLimit(user, activity, activityCounterDefinition)) {
164    
165                                    incrementActivityCounter(
166                                            activity.getGroupId(), user, activity.getAssetEntry(),
167                                            activityCounterDefinition);
168                            }
169                    }
170    
171                    for (SocialAchievement achievement :
172                                    activityDefinition.getAchievements()) {
173    
174                            achievement.processActivity(activity);
175                    }
176    
177                    if (!user.isDefaultUser() && user.isActive()) {
178                            incrementActivityCounter(
179                                    activity.getGroupId(),
180                                    PortalUtil.getClassNameId(User.class.getName()),
181                                    activity.getUserId(),
182                                    SocialActivityCounterConstants.NAME_USER_ACTIVITIES,
183                                    SocialActivityCounterConstants.TYPE_ACTOR, 1,
184                                    SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM);
185                    }
186    
187                    if (!assetEntryUser.isDefaultUser() && assetEntryUser.isActive()) {
188                            incrementActivityCounter(
189                                    activity.getGroupId(), activity.getClassNameId(),
190                                    activity.getClassPK(),
191                                    SocialActivityCounterConstants.NAME_ASSET_ACTIVITIES,
192                                    SocialActivityCounterConstants.TYPE_ASSET, 1,
193                                    SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM);
194                    }
195            }
196    
197            public void deleteActivityCounters(AssetEntry assetEntry)
198                    throws PortalException, SystemException {
199    
200                    if (assetEntry == null) {
201                            return;
202                    }
203    
204                    SocialActivityCounter latestContributionActivityCounter =
205                            fetchLatestActivityCounter(
206                                    assetEntry.getGroupId(),
207                                    PortalUtil.getClassNameId(User.class.getName()),
208                                    assetEntry.getUserId(),
209                                    SocialActivityCounterConstants.NAME_CONTRIBUTION,
210                                    SocialActivityCounterConstants.TYPE_CREATOR);
211    
212                    SocialActivityCounter latestPopularityActivityCounter =
213                            fetchLatestActivityCounter(
214                                    assetEntry.getGroupId(), assetEntry.getClassNameId(),
215                                    assetEntry.getClassPK(),
216                                    SocialActivityCounterConstants.NAME_POPULARITY,
217                                    SocialActivityCounterConstants.TYPE_ASSET);
218    
219                    if ((latestContributionActivityCounter != null) &&
220                            (latestPopularityActivityCounter != null)) {
221    
222                            int startPeriod = SocialCounterPeriodUtil.getStartPeriod();
223    
224                            if (latestContributionActivityCounter.getStartPeriod() !=
225                                            startPeriod) {
226    
227                                    latestContributionActivityCounter = addNewPeriod(
228                                            latestContributionActivityCounter,
229                                            SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM);
230                            }
231    
232                            if (latestPopularityActivityCounter.getStartPeriod() ==
233                                            startPeriod) {
234    
235                                    latestContributionActivityCounter.setCurrentValue(
236                                            latestContributionActivityCounter.getCurrentValue() -
237                                                    latestPopularityActivityCounter.getCurrentValue());
238                            }
239    
240                            latestContributionActivityCounter.setTotalValue(
241                                    latestContributionActivityCounter.getTotalValue() -
242                                            latestPopularityActivityCounter.getTotalValue());
243    
244                            socialActivityCounterPersistence.update(
245                                    latestContributionActivityCounter, false);
246                    }
247    
248                    deleteActivityCounters(
249                            assetEntry.getClassNameId(), assetEntry.getClassPK());
250    
251                    socialActivityLimitPersistence.removeByC_C(
252                            assetEntry.getClassNameId(), assetEntry.getClassPK());
253            }
254    
255            public void deleteActivityCounters(long classNameId, long classPK)
256                    throws SystemException {
257    
258                    socialActivityCounterPersistence.removeByC_C(classNameId, classPK);
259            }
260    
261            public SocialActivityCounter fetchLatestActivityCounter(
262                            long groupId, long classNameId, long classPK, String name,
263                            int ownerType)
264                    throws SystemException {
265    
266                    return fetchLatestActivityCounter(
267                            groupId, classNameId, classPK, name, ownerType, true);
268            }
269    
270            public SocialActivityCounter fetchLatestActivityCounter(
271                            long groupId, long classNameId, long classPK, String name,
272                            int ownerType, boolean retrieveFromCache)
273                    throws SystemException {
274    
275                    return socialActivityCounterPersistence.fetchByG_C_C_N_O_E(
276                            groupId, classNameId, classPK, name, ownerType,
277                            SocialActivityCounterConstants.END_PERIOD_UNDEFINED,
278                            retrieveFromCache);
279            }
280    
281            public SocialActivityCounter getLatestActivityCounter(
282                            long groupId, long classNameId, long classPK, String name,
283                            int ownerType)
284                    throws NoSuchActivityCounterException, SystemException {
285    
286                    return socialActivityCounterPersistence.findByG_C_C_N_O_E(
287                            groupId, classNameId, classPK, name, ownerType,
288                            SocialActivityCounterConstants.END_PERIOD_UNDEFINED);
289            }
290    
291            public List<SocialActivityCounter> getOffsetActivityCounterDistribution(
292                            long groupId, String name, int startOffset, int endOffset)
293                    throws SystemException {
294    
295                    int startPeriod = SocialCounterPeriodUtil.getStartPeriod(startOffset);
296                    int endPeriod = SocialCounterPeriodUtil.getEndPeriod(endOffset);
297    
298                    return getPeriodActivityCounterDistribution(
299                            groupId, name, startPeriod, endPeriod);
300            }
301    
302            public List<SocialActivityCounter> getOffsetActivityCounters(
303                            long groupId, String name, int startOffset, int endOffset)
304                    throws SystemException {
305    
306                    int startPeriod = SocialCounterPeriodUtil.getStartPeriod(startOffset);
307                    int endPeriod = SocialCounterPeriodUtil.getEndPeriod(endOffset);
308    
309                    return getPeriodActivityCounters(groupId, name, startPeriod, endPeriod);
310            }
311    
312            public List<SocialActivityCounter> getPeriodActivityCounterDistribution(
313                            long groupId, String name, int startPeriod, int endPeriod)
314                    throws SystemException {
315    
316                    int offset = SocialCounterPeriodUtil.getOffset(endPeriod);
317    
318                    int periodLength = SocialCounterPeriodUtil.getPeriodLength(offset);
319    
320                    return socialActivityCounterFinder.findAC_ByG_N_S_E_2(
321                            groupId, name, startPeriod, endPeriod, periodLength);
322            }
323    
324            public List<SocialActivityCounter> getPeriodActivityCounters(
325                            long groupId, String name, int startPeriod, int endPeriod)
326                    throws SystemException {
327    
328                    int offset = SocialCounterPeriodUtil.getOffset(endPeriod);
329    
330                    int periodLength = SocialCounterPeriodUtil.getPeriodLength(offset);
331    
332                    return socialActivityCounterFinder.findAC_ByG_N_S_E_1(
333                            groupId, name, startPeriod, endPeriod, periodLength);
334            }
335    
336            public int getUserActivityCounters(long groupId, String[] rankingNames)
337                    throws SystemException {
338    
339                    return SocialActivityCounterFinderUtil.countU_ByG_N(
340                            groupId, rankingNames);
341            }
342    
343            public List<Tuple> getUserActivityCounters(
344                            long groupId, String[] rankingNames, String[] selectedNames,
345                            int start, int end)
346                    throws SystemException {
347    
348                    List<Long> userIds = socialActivityCounterFinder.findU_ByG_N(
349                            groupId, rankingNames, start, end);
350    
351                    if (userIds.isEmpty()) {
352                            return Collections.emptyList();
353                    }
354    
355                    Tuple[] userActivityCounters = new Tuple[userIds.size()];
356    
357                    List<SocialActivityCounter> activityCounters =
358                            SocialActivityCounterFinderUtil.findAC_By_G_C_C_N_S_E(
359                                    groupId, userIds, selectedNames, QueryUtil.ALL_POS,
360                                    QueryUtil.ALL_POS);
361    
362                    long userId = 0;
363                    Map<String, SocialActivityCounter> activityCountersMap = null;
364    
365                    for (SocialActivityCounter activityCounter : activityCounters) {
366                            if (userId != activityCounter.getClassPK()) {
367                                    userId = activityCounter.getClassPK();
368                                    activityCountersMap =
369                                            new HashMap<String, SocialActivityCounter>();
370    
371                                    Tuple userActivityCounter = new Tuple(
372                                            userId, activityCountersMap);
373    
374                                    for (int i = 0; i < userIds.size(); i++) {
375                                            long curUserId = userIds.get(i);
376    
377                                            if (userId == curUserId) {
378                                                    userActivityCounters[i] = userActivityCounter;
379    
380                                                    break;
381                                            }
382                                    }
383                            }
384    
385                            activityCountersMap.put(activityCounter.getName(), activityCounter);
386                    }
387    
388                    return Arrays.asList(userActivityCounters);
389            }
390    
391            public void incrementUserAchievementCounter(long userId, long groupId)
392                    throws PortalException, SystemException {
393    
394                    incrementActivityCounter(
395                            groupId, PortalUtil.getClassNameId(User.class.getName()), userId,
396                            SocialActivityCounterConstants.NAME_USER_ACHIEVEMENTS,
397                            SocialActivityCounterConstants.TYPE_ACTOR, 1,
398                            SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM);
399            }
400    
401            protected boolean addActivityCounter(
402                    User user, User assetEntryUser,
403                    SocialActivityCounterDefinition activityCounterDefinition) {
404    
405                    if ((user.isDefaultUser() || !user.isActive()) &&
406                            (activityCounterDefinition.getOwnerType() !=
407                                    SocialActivityCounterConstants.TYPE_ASSET)) {
408    
409                            return false;
410                    }
411    
412                    if ((assetEntryUser.isDefaultUser() || !assetEntryUser.isActive()) &&
413                            (activityCounterDefinition.getOwnerType() !=
414                                    SocialActivityCounterConstants.TYPE_ACTOR)) {
415    
416                            return false;
417                    }
418    
419                    if (!activityCounterDefinition.isEnabled() ||
420                            (activityCounterDefinition.getIncrement() == 0)) {
421    
422                            return false;
423                    }
424    
425                    String name = activityCounterDefinition.getName();
426    
427                    if ((user.getUserId() == assetEntryUser.getUserId()) &&
428                            (name.equals(SocialActivityCounterConstants.NAME_CONTRIBUTION) ||
429                             name.equals(SocialActivityCounterConstants.NAME_POPULARITY))) {
430    
431                            return false;
432                    }
433    
434                    return true;
435            }
436    
437            protected SocialActivityCounter addNewPeriod(
438                            SocialActivityCounter activityCounter, int periodLength)
439                    throws PortalException, SystemException {
440    
441                    if (activityCounter == null) {
442                            return null;
443                    }
444    
445                    if (periodLength ==
446                                    SocialActivityCounterConstants.PERIOD_LENGTH_SYSTEM) {
447    
448                            activityCounter.setEndPeriod(
449                                    SocialCounterPeriodUtil.getStartPeriod() - 1);
450                    }
451                    else {
452                            activityCounter.setEndPeriod(
453                                    activityCounter.getStartPeriod() + periodLength - 1);
454                    }
455    
456                    socialActivityCounterPersistence.update(activityCounter, false);
457    
458                    return addActivityCounter(
459                            activityCounter.getGroupId(), activityCounter.getClassNameId(),
460                            activityCounter.getClassPK(), activityCounter.getName(),
461                            activityCounter.getOwnerType(), 0, activityCounter.getTotalValue());
462            }
463    
464            protected boolean checkActivityLimit(
465                            User user, SocialActivity activity,
466                            SocialActivityCounterDefinition activityCounterDefinition)
467                    throws PortalException, SystemException {
468    
469                    if (activityCounterDefinition.getLimitValue() == 0) {
470                            return true;
471                    }
472    
473                    long classPK = activity.getClassPK();
474    
475                    String name = activityCounterDefinition.getName();
476    
477                    if (name.equals(SocialActivityCounterConstants.NAME_PARTICIPATION)) {
478                            classPK = 0;
479                    }
480    
481                    SocialActivityLimit activityLimit =
482                            socialActivityLimitPersistence.fetchByG_U_C_C_A_A(
483                                    activity.getGroupId(), user.getUserId(),
484                                    activity.getClassNameId(), classPK, activity.getType(),
485                                    activityCounterDefinition.getName());
486    
487                    if (activityLimit == null) {
488                            try {
489                                    activityLimit =
490                                            socialActivityLimitLocalService.addActivityLimit(
491                                                    user.getUserId(), activity.getGroupId(),
492                                                    activity.getClassNameId(), classPK, activity.getType(),
493                                                    activityCounterDefinition.getName(),
494                                                    activityCounterDefinition.getLimitPeriod());
495                            }
496                            catch (SystemException se) {
497                                    activityLimit =
498                                            socialActivityLimitPersistence.fetchByG_U_C_C_A_A(
499                                                    activity.getGroupId(), user.getUserId(),
500                                                    activity.getClassNameId(), classPK, activity.getType(),
501                                                    activityCounterDefinition.getName());
502    
503                                    if (activityLimit == null) {
504                                            throw se;
505                                    }
506                            }
507                    }
508    
509                    int count = activityLimit.getCount(
510                            activityCounterDefinition.getLimitPeriod());
511    
512                    if (count < activityCounterDefinition.getLimitValue()) {
513                            activityLimit.setCount(
514                                    activityCounterDefinition.getLimitPeriod(), count + 1);
515    
516                            socialActivityLimitPersistence.update(activityLimit, false);
517    
518                            return true;
519                    }
520    
521                    return false;
522            }
523    
524            protected String getLockKey(
525                    long groupId, long classNameId, long classPK, String name,
526                    int ownerType) {
527    
528                    StringBundler sb = new StringBundler(7);
529    
530                    sb.append(StringUtil.toHexString(groupId));
531                    sb.append(StringPool.POUND);
532                    sb.append(StringUtil.toHexString(classNameId));
533                    sb.append(StringPool.POUND);
534                    sb.append(StringUtil.toHexString(classPK));
535                    sb.append(StringPool.POUND);
536                    sb.append(name);
537    
538                    return sb.toString();
539            }
540    
541            protected void incrementActivityCounter(
542                            long groupId, long classNameId, long classPK, String name,
543                            int ownerType, int increment, int periodLength)
544                    throws PortalException, SystemException {
545    
546                    SocialActivityCounter activityCounter = fetchLatestActivityCounter(
547                            groupId, classNameId, classPK, name, ownerType);
548    
549                    if (activityCounter == null) {
550                            activityCounter = addActivityCounter(
551                                    groupId, classNameId, classPK, name, ownerType, 0, 0);
552    
553                            if (periodLength > 0) {
554                                    activityCounter.setStartPeriod(
555                                            SocialCounterPeriodUtil.getActivityDay());
556                            }
557                    }
558    
559                    if (!activityCounter.isActivePeriod(periodLength)) {
560                            activityCounter = addNewPeriod(activityCounter, periodLength);
561                    }
562    
563                    activityCounter.setCurrentValue(
564                            activityCounter.getCurrentValue() + increment);
565                    activityCounter.setTotalValue(
566                            activityCounter.getTotalValue() + increment);
567    
568                    socialActivityCounterPersistence.update(activityCounter, false);
569            }
570    
571            protected void incrementActivityCounter(
572                            long groupId, User user, AssetEntry assetEntry,
573                            SocialActivityCounterDefinition activityCounterDefinition)
574                    throws PortalException, SystemException {
575    
576                    int ownerType = activityCounterDefinition.getOwnerType();
577                    long userClassNameId = PortalUtil.getClassNameId(User.class.getName());
578    
579                    if (ownerType == SocialActivityCounterConstants.TYPE_ACTOR) {
580                            incrementActivityCounter(
581                                    groupId, userClassNameId, user.getUserId(),
582                                    activityCounterDefinition.getName(), ownerType,
583                                    activityCounterDefinition.getIncrement(),
584                                    activityCounterDefinition.getPeriodLength());
585                    }
586                    else if (ownerType == SocialActivityCounterConstants.TYPE_ASSET) {
587                            incrementActivityCounter(
588                                    groupId, assetEntry.getClassNameId(), assetEntry.getClassPK(),
589                                    activityCounterDefinition.getName(), ownerType,
590                                    activityCounterDefinition.getIncrement(),
591                                    activityCounterDefinition.getPeriodLength());
592                    }
593                    else {
594                            incrementActivityCounter(
595                                    groupId, userClassNameId, assetEntry.getUserId(),
596                                    activityCounterDefinition.getName(), ownerType,
597                                    activityCounterDefinition.getIncrement(),
598                                    activityCounterDefinition.getPeriodLength());
599                    }
600            }
601    
602            private static Log _log = LogFactoryUtil.getLog(
603                    SocialActivityCounterLocalService.class);
604    
605    }