001/*
002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Arnaud Kervern
018 */
019package org.nuxeo.ecm.rating;
020
021import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QUERY_TYPE_PARAMETER;
022import static org.nuxeo.ecm.rating.api.Constants.LIKE_ASPECT;
023import static org.nuxeo.ecm.rating.api.Constants.RATING_VERB_PREFIX;
024
025import java.io.Serializable;
026import java.util.Collection;
027import java.util.Map;
028
029import javax.persistence.EntityManager;
030import javax.persistence.Query;
031
032import org.apache.commons.logging.Log;
033import org.apache.commons.logging.LogFactory;
034import org.nuxeo.ecm.activity.ActivitiesList;
035import org.nuxeo.ecm.activity.ActivitiesListImpl;
036import org.nuxeo.ecm.activity.Activity;
037import org.nuxeo.ecm.activity.ActivityBuilder;
038import org.nuxeo.ecm.activity.ActivityReply;
039import org.nuxeo.ecm.activity.ActivityStreamFilter;
040import org.nuxeo.ecm.activity.ActivityStreamService;
041import org.nuxeo.ecm.activity.ActivityStreamServiceImpl;
042
043/**
044 * An activity stream filter to handle likes count
045 *
046 * @author <a href="mailto:akervern@nuxeo.com">Arnaud Kervern</a>
047 * @since 5.6
048 */
049public class LikesCountActivityStreamFilter implements ActivityStreamFilter {
050
051    public enum QueryType {
052        GET_DOCUMENTS_COUNT, GET_MINI_MESSAGE_COUNT
053    }
054
055    public static final String ID = "LikesCountActivityStreamFilter";
056
057    public static final String CONTEXT_PARAMETER = "context";
058
059    public static final String ASPECT_PARAMETER = "aspect";
060
061    public static final String OBJECT_PARAMETER = "object";
062
063    public static final String ACTOR_PARAMETER = "actor";
064
065    public static final String FROMDT_PARAMETER = "fromDt";
066
067    public static final String TODT_PARAMETER = "toDt";
068
069    protected static final String VERB_PARAMETER = "verb";
070
071    protected static final String VERB_MINIMESSAGE_PARAMETER = "verbMiniMessage";
072
073    private static final Log log = LogFactory.getLog(LikesCountActivityStreamFilter.class);
074
075    @Override
076    public String getId() {
077        return ID;
078    }
079
080    @Override
081    public boolean isInterestedIn(Activity activity) {
082        return false;
083    }
084
085    @Override
086    public void handleNewActivity(ActivityStreamService activityStreamService, Activity activity) {
087        // Nothing to do for now
088    }
089
090    @Override
091    @Deprecated
092    public void handleRemovedActivities(ActivityStreamService activityStreamService,
093            Collection<Serializable> activityIds) {
094        // Nothing to do for now
095    }
096
097    @Override
098    public void handleRemovedActivities(ActivityStreamService activityStreamService, ActivitiesList activities) {
099    }
100
101    @Override
102    public void handleRemovedActivityReply(ActivityStreamService activityStreamService, Activity activity,
103            ActivityReply activityReply) {
104    }
105
106    @Override
107    public ActivitiesList query(ActivityStreamService activityStreamService, Map<String, Serializable> parameters,
108            long offset, long limit) {
109        QueryType queryType = (QueryType) parameters.get(QUERY_TYPE_PARAMETER);
110        if (queryType == null) {
111            return new ActivitiesListImpl();
112        }
113
114        Query query = null;
115        String queryStr = "";
116        String innerStr = "";
117        EntityManager em = ((ActivityStreamServiceImpl) activityStreamService).getEntityManager();
118        Serializable actor = parameters.get(ACTOR_PARAMETER);
119
120        switch (queryType) {
121        case GET_DOCUMENTS_COUNT:
122            // InnerQuery indicates if the actor has alredy liked or not
123            innerStr = "SELECT COUNT(activity2) FROM Activity activity2 WHERE activity2.verb = :verb";
124            innerStr += " AND activity2.context = :context AND activity2.object = :object";
125            innerStr += " AND activity2.actor = :actor AND activity2.target = activity.target";
126            if (parameters.containsKey(FROMDT_PARAMETER)) {
127                innerStr += " AND activity2.publishedDate BETWEEN :fromDt AND :toDt";
128            }
129            queryStr = "SELECT activity.target, count(activity), (" + innerStr + ") FROM Activity activity";
130            queryStr += " WHERE activity.verb = :verb and activity.context  = :context";
131            queryStr += " AND activity.object = :object";
132            if (parameters.containsKey(FROMDT_PARAMETER)) {
133                queryStr += " AND activity.publishedDate BETWEEN :fromDt AND :toDt";
134            }
135            queryStr += " GROUP BY activity.target ORDER BY COUNT(activity) DESC";
136
137            Serializable object = String.valueOf(parameters.get(OBJECT_PARAMETER));
138            query = em.createQuery(queryStr);
139            query.setParameter(OBJECT_PARAMETER, object);
140
141            break;
142        case GET_MINI_MESSAGE_COUNT:
143            // InnerQuery indicates if the actor has alredy liked or not
144            innerStr = "Select count(likes2) from Activity as likes2 ";
145            innerStr += " where likes.target = likes2.target and likes2.actor = :actor";
146            if (parameters.containsKey(FROMDT_PARAMETER)) {
147                innerStr += " AND likes2.publishedDate BETWEEN :fromDt AND :toDt";
148            }
149            queryStr = "Select likes.target, count(likes), (" + innerStr
150                    + ") from Activity as likes, Activity as minimessage";
151            queryStr += " where concat('activity:', cast(minimessage.id as string)) = likes.target";
152            queryStr += " and minimessage.verb = :verbMiniMessage and minimessage.context  = :context";
153            queryStr += " and likes.verb = :verb";
154            if (parameters.containsKey(FROMDT_PARAMETER)) {
155                queryStr += " AND likes.publishedDate BETWEEN :fromDt AND :toDt";
156            }
157            queryStr += " group by likes.target order by count(likes) desc";
158
159            query = em.createQuery(queryStr);
160            query.setParameter(VERB_MINIMESSAGE_PARAMETER, "minimessage");
161
162            break;
163        default:
164            log.info("Unknown query type: " + queryType);
165            return new ActivitiesListImpl();
166        }
167
168        // Default parameters
169        query.setParameter(CONTEXT_PARAMETER, parameters.get(CONTEXT_PARAMETER));
170        query.setParameter(VERB_PARAMETER, RATING_VERB_PREFIX + LIKE_ASPECT);
171        query.setParameter(ACTOR_PARAMETER, actor);
172        if (parameters.containsKey(FROMDT_PARAMETER)) {
173            query.setParameter(FROMDT_PARAMETER, parameters.get(FROMDT_PARAMETER));
174            query.setParameter(TODT_PARAMETER, parameters.get(TODT_PARAMETER));
175        }
176
177        if (limit > 0) {
178            query.setMaxResults((int) limit);
179        }
180        if (offset > 0) {
181            query.setFirstResult((int) offset);
182        }
183
184        ActivitiesList likesCount = new ActivitiesListImpl();
185        for (Object result : query.getResultList()) {
186            Object[] objects = (Object[]) result;
187            ActivityBuilder ab = new ActivityBuilder().verb(RATING_VERB_PREFIX + LIKE_ASPECT).actor((String) actor).object(
188                    String.valueOf(objects[1])).target((String) objects[0]).context(String.valueOf(objects[2]));
189            likesCount.add(ab.build());
190        }
191
192        return likesCount;
193    }
194}