001/*
002 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Thomas Roger <troger@nuxeo.com>
016 */
017
018package org.nuxeo.ecm.rating;
019
020import static org.nuxeo.ecm.core.schema.FacetNames.SUPER_SPACE;
021import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.ACTOR_PARAMETER;
022import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.ASPECT_PARAMETER;
023import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.CONTEXT_PARAMETER;
024import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QUERY_TYPE_PARAMETER;
025import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.RATING_PARAMETER;
026import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.TARGET_OBJECT_PARAMETER;
027import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_ACTOR_RATINGS_FOR_OBJECT;
028import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_LATEST_RATED_FOR_OBJECT;
029import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_RATED_CHILDREN_FOR_CONTEXT;
030import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_RATINGS_FOR_CANCEL;
031import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_RATINGS_FOR_OBJECT;
032import static org.nuxeo.ecm.rating.api.Constants.RATING_VERB_PREFIX;
033
034import java.io.Serializable;
035import java.util.HashMap;
036import java.util.Map;
037
038import org.apache.commons.lang.exception.ExceptionUtils;
039import org.apache.commons.logging.Log;
040import org.apache.commons.logging.LogFactory;
041import org.nuxeo.ecm.activity.ActivitiesList;
042import org.nuxeo.ecm.activity.Activity;
043import org.nuxeo.ecm.activity.ActivityBuilder;
044import org.nuxeo.ecm.activity.ActivityHelper;
045import org.nuxeo.ecm.activity.ActivityStreamService;
046import org.nuxeo.ecm.core.api.DocumentModel;
047import org.nuxeo.ecm.core.api.IdRef;
048import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
049import org.nuxeo.ecm.rating.api.RatingService;
050import org.nuxeo.runtime.api.Framework;
051import org.nuxeo.runtime.model.DefaultComponent;
052
053/**
054 * Default implementation of {@see RatingService}.
055 *
056 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
057 * @since 5.6
058 */
059public class RatingServiceImpl extends DefaultComponent implements RatingService {
060
061    private static final Log log = LogFactory.getLog(RatingServiceImpl.class);
062
063    @Override
064    public void rate(String username, int rating, String activityObject, String aspect) {
065        Activity activity = new ActivityBuilder().verb(RATING_VERB_PREFIX + aspect).actor(
066                ActivityHelper.createUserActivityObject(username)).target(activityObject).object(String.valueOf(rating)).build();
067        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
068        activityStreamService.addActivity(activity);
069
070        addSuperSpaceRate(activity);
071    }
072
073    @Override
074    public void cancelRate(String username, String activityObject, String aspect) {
075        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
076        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_CANCEL);
077        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
078        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
079        parameters.put(ASPECT_PARAMETER, aspect);
080
081        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
082        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
083        activityStreamService.removeActivities(activities);
084    }
085
086    @Override
087    public void cancelRates(String activityObject, String aspect) {
088        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
089        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_CANCEL);
090        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
091        parameters.put(ASPECT_PARAMETER, aspect);
092
093        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
094        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
095        activityStreamService.removeActivities(activities);
096    }
097
098    @Override
099    public boolean hasUserRated(String username, String activityObject, String aspect) {
100        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
101        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
102        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
103        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
104        parameters.put(ASPECT_PARAMETER, aspect);
105
106        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
107        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
108        return !activities.isEmpty();
109    }
110
111    @Override
112    public long getRatesCount(String activityObject, String aspect) {
113        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
114        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_OBJECT);
115        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
116        parameters.put(ASPECT_PARAMETER, aspect);
117
118        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
119        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
120        return activities.size();
121    }
122
123    @Override
124    public long getRatesCount(String activityObject, int rating, String aspect) {
125        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
126        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_OBJECT);
127        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
128        parameters.put(ASPECT_PARAMETER, aspect);
129        parameters.put(RATING_PARAMETER, Integer.valueOf(rating));
130
131        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
132        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
133        return activities.size();
134    }
135
136    @Override
137    public long getRatesCountForUser(String username, String activityObject, String aspect) {
138        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
139        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
140        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
141        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
142        parameters.put(ASPECT_PARAMETER, aspect);
143
144        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
145        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
146        return activities.size();
147    }
148
149    @Override
150    public long getRatesCountForUser(String username, String activityObject, int rating, String aspect) {
151        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
152        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
153        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
154        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
155        parameters.put(ASPECT_PARAMETER, aspect);
156        parameters.put(RATING_PARAMETER, Integer.valueOf(rating));
157
158        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
159        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
160        return activities.size();
161    }
162
163    @Override
164    public double getAverageRating(String activityObject, String aspect) {
165        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
166        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_OBJECT);
167        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
168        parameters.put(ASPECT_PARAMETER, aspect);
169
170        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
171        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
172        return computeAverage(activities);
173    }
174
175    @Override
176    public double getAverageRatingForUser(String username, String activityObject, String aspect) {
177        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
178        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
179        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
180        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
181        parameters.put(ASPECT_PARAMETER, aspect);
182
183        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
184        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
185        return computeAverage(activities);
186    }
187
188    @Override
189    public ActivitiesList getRatedChildren(String activityObject, int rating, String aspect) {
190        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
191        parameters.put(QUERY_TYPE_PARAMETER, GET_RATED_CHILDREN_FOR_CONTEXT);
192        parameters.put(CONTEXT_PARAMETER, activityObject);
193        parameters.put(ASPECT_PARAMETER, aspect);
194        parameters.put(RATING_PARAMETER, Integer.valueOf(rating));
195
196        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
197        return activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
198    }
199
200    @Override
201    public ActivitiesList getLastestRatedDocByUser(String username, String aspect, int limit) {
202        Map<String, Serializable> parameters = new HashMap<String, Serializable>();
203        parameters.put(QUERY_TYPE_PARAMETER, GET_LATEST_RATED_FOR_OBJECT);
204        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
205        parameters.put(ASPECT_PARAMETER, aspect);
206
207        ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
208        return activityStreamService.query(RatingActivityStreamFilter.ID, parameters, 0, limit);
209    }
210
211    private double computeAverage(ActivitiesList activities) {
212        double average = 0;
213        for (Activity activity : activities) {
214            try {
215                average += Integer.valueOf(activity.getObject()).intValue();
216            } catch (NumberFormatException e) {
217                log.warn(activity.getObject() + " is not a valid rating");
218            }
219        }
220        return average / activities.size();
221    }
222
223    protected void addSuperSpaceRate(final Activity fromActivity) {
224        final String activityObject = fromActivity.getTarget();
225        if (!ActivityHelper.isDocument(activityObject)) {
226            return;
227        }
228
229        final ActivityStreamService activityStreamService = Framework.getLocalService(ActivityStreamService.class);
230        new UnrestrictedSessionRunner(ActivityHelper.getRepositoryName(activityObject)) {
231            @Override
232            public void run() {
233                IdRef docId = new IdRef(ActivityHelper.getDocumentId(activityObject));
234                for (DocumentModel parent : session.getParentDocuments(docId)) {
235                    if (!parent.hasFacet(SUPER_SPACE)) {
236                        continue;
237                    }
238                    Activity activity = new ActivityBuilder(fromActivity).context(
239                            ActivityHelper.createDocumentActivityObject(parent)).build();
240                    activityStreamService.addActivity(activity);
241                }
242            }
243        }.runUnrestricted();
244    }
245}