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