001/**
002 * Copyright 2014 Tampere University of Technology, Pori Department
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 */
016package service.tut.pori.facebookjazz.reference;
017
018import java.util.List;
019
020import org.apache.commons.lang3.StringUtils;
021import org.apache.http.client.methods.HttpPost;
022import org.apache.http.entity.StringEntity;
023import org.apache.log4j.Logger;
024
025import service.tut.pori.contentanalysis.AbstractTaskDetails;
026import service.tut.pori.contentanalysis.AsyncTask.TaskStatus;
027import service.tut.pori.contentanalysis.AsyncTask.TaskType;
028import service.tut.pori.contentanalysis.PhotoList;
029import service.tut.pori.contentanalysis.PhotoTaskResponse;
030import service.tut.pori.contentanalysis.MediaObjectList;
031import service.tut.pori.contentanalysis.reference.CAReferenceCore;
032import service.tut.pori.contentanalysis.reference.CAXMLObjectCreator;
033import service.tut.pori.facebookjazz.Definitions;
034import service.tut.pori.facebookjazz.FBFeedbackTaskDetails;
035import service.tut.pori.facebookjazz.FBSummarizationTaskDetails;
036import service.tut.pori.facebookjazz.FBTaskResponse;
037import service.tut.pori.facebookjazz.FacebookComment;
038import service.tut.pori.facebookjazz.FacebookEvent;
039import service.tut.pori.facebookjazz.FacebookExtractor.ContentType;
040import service.tut.pori.facebookjazz.FacebookGroup;
041import service.tut.pori.facebookjazz.FacebookLike;
042import service.tut.pori.facebookjazz.FacebookLocation;
043import service.tut.pori.facebookjazz.FacebookPhotoDescription;
044import service.tut.pori.facebookjazz.FacebookPhotoTag;
045import service.tut.pori.facebookjazz.FacebookProfile;
046import service.tut.pori.facebookjazz.FacebookRelationship;
047import service.tut.pori.facebookjazz.FacebookStatusMessage;
048import service.tut.pori.facebookjazz.FacebookUserDetails;
049import service.tut.pori.facebookjazz.FacebookVideoDescription;
050import service.tut.pori.facebookjazz.WeightModifier;
051import service.tut.pori.facebookjazz.WeightModifierList;
052import core.tut.pori.http.parameters.DataGroups;
053import core.tut.pori.http.parameters.Limits;
054import core.tut.pori.http.parameters.SortOptions;
055import core.tut.pori.users.UserIdentity;
056import core.tut.pori.utils.XMLFormatter;
057
058/**
059 * The reference implementations for FacebookJazz Service.
060 *
061 */
062public final class FBJReferenceCore {
063  private static final FBJXMLObjectCreator CREATOR = new FBJXMLObjectCreator(null);
064  private static final DataGroups DATAGROUPS_BACKEND_RESPONSE = new DataGroups(CAXMLObjectCreator.DATA_GROUP_BACKEND_RESPONSE); // data groups for add task callback
065  private static final Limits DEFAULT_LIMITS = new Limits(0, 0);  // default number of limits for references
066  private static final Logger LOGGER = Logger.getLogger(FBJReferenceCore.class);
067  
068  /**
069   * 
070   */
071  private FBJReferenceCore(){
072    // nothing needed
073  }
074
075  /**
076   * 
077   * @param authenticatedUser
078   * @param dataGroups
079   * @param limits only the amount of results is processed for the limits. This is because the results are randomly generated, and thus have no
080   * order which could be used for paging.
081   * @param sortOptions sort options are ignored. This is because of the complexity of the sort operations performed for randomly generated data.
082   * @return example list of media objects for the given values
083   */
084  public static MediaObjectList retrieveTagsForUser(UserIdentity authenticatedUser, DataGroups dataGroups, Limits limits, SortOptions sortOptions) {
085    LOGGER.info((authenticatedUser == null ? "No logged in user." : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()));  // only notify of the logged in status
086    return CREATOR.createTagList(CREATOR.createBackendId(), dataGroups, limits, authenticatedUser);
087  }
088
089  /**
090   * 
091   * @param authenticatedUser
092   * @param ranks list of ranks in the form of rank=guid:VALUE,guid:VALUE,...
093   */
094  public static void setRank(UserIdentity authenticatedUser, List<String> ranks) {
095    LOGGER.info((authenticatedUser == null ? "No logged in user." : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()));  // only notify of the logged in status
096    if(ranks == null || ranks.isEmpty()){
097      throw new IllegalArgumentException("Failed to process rank parameter.");
098    }
099    
100    for(String r : ranks){
101      String[] parts = r.split(core.tut.pori.http.Definitions.SEPARATOR_URI_QUERY_TYPE_VALUE);
102      if(parts.length != 2){
103        throw new IllegalArgumentException("Failed to process rank parameter: "+r);
104      }
105    }  // for
106  }
107
108  /**
109   * 
110   * @param response
111   */
112  public static void taskFinished(PhotoTaskResponse response) {
113    Integer tBackendId = response.getBackendId();
114    if(tBackendId == null){
115      throw new IllegalArgumentException("Invalid backendId: "+tBackendId);
116    }
117    Long tTaskId = response.getTaskId();
118    if(tTaskId == null){
119      throw new IllegalArgumentException("Invalid taskId: "+tTaskId);
120    }
121    
122    TaskStatus status = response.getStatus();
123    if(status == null){
124      throw new IllegalArgumentException("TaskStatus is invalid or missing.");
125    }
126
127    TaskType type = response.getTaskType();
128    if(type == null){
129      throw new IllegalArgumentException("TaskType is invalid or missing.");
130    }
131
132    try{
133      switch(type){
134        case FACEBOOK_PROFILE_SUMMARIZATION:
135          FBTaskResponse fr = (FBTaskResponse) response;
136          if(!PhotoList.isValid(fr.getPhotoList()) && !MediaObjectList.isValid(fr.getMediaObjects())){
137            LOGGER.warn("No valid media object list or photo list.");
138          }
139          break;
140        case BACKEND_FEEDBACK: // should not have any content, so accept anything
141          break;
142        default:      
143          throw new IllegalArgumentException("Tasks of type: "+type.name()+" are not supported by this validator.");
144      }
145    }catch(ClassCastException ex){
146      LOGGER.debug(ex, ex);
147      throw new IllegalArgumentException("Task content data was not of the expected type.");
148    }
149  }
150
151  /**
152   * 
153   * @param taskDetails
154   */
155  public static void addTask(FBTaskDetails taskDetails) {
156    Integer tBackendId = taskDetails.getBackendId();
157    if(tBackendId == null){
158      throw new IllegalArgumentException("Invalid backendId: "+tBackendId);
159    }
160    Long tTaskId = taskDetails.getTaskId();
161    if(tTaskId == null){
162      throw new IllegalArgumentException("Invalid taskId: "+tTaskId);
163    }
164
165    String uri = taskDetails.getCallbackUri();
166    if(StringUtils.isBlank(uri)){
167      throw new IllegalArgumentException("Invalid callbackUri: "+uri);
168    }
169
170    TaskType type = taskDetails.getTaskType();
171    if(type == null){
172      throw new IllegalArgumentException("TaskType is invalid or missing.");
173    }
174
175    switch(type){
176      case FACEBOOK_PROFILE_SUMMARIZATION:
177        if(taskDetails.getProfile() == null){
178          throw new IllegalArgumentException("Invalid "+Definitions.ELEMENT_FACEBOOK_PROFILE);
179        }
180        addTaskAsyncCallback(taskDetails, CREATOR.createTagList(tBackendId, DATAGROUPS_BACKEND_RESPONSE, DEFAULT_LIMITS, taskDetails.getUserId()));
181        break;
182      case FACEBOOK_PROFILE_SUMMARIZATION_FEEDBACK:
183        if(!MediaObjectList.isValid(taskDetails.getTags())){
184          LOGGER.warn("Invalid media object list.");
185        }
186        addTaskAsyncCallback(taskDetails, null);
187        break;
188      case BACKEND_FEEDBACK: 
189        if(!PhotoList.isValid(taskDetails.getPhotoList())){
190          throw new IllegalArgumentException("Invalid "+service.tut.pori.contentanalysis.Definitions.ELEMENT_PHOTOLIST);
191        }
192        addTaskAsyncCallback(taskDetails, null);
193        break;
194      default:
195        throw new IllegalArgumentException("Tasks of type: "+type.name()+" are not supported by this validator.");
196    }
197  }
198  
199  /**
200   * Call asynchronously the callback given in the details, returning an example task response
201   * 
202   * @param details
203   * @param mediaObjectList
204   * @see service.tut.pori.facebookjazz.FBTaskResponse
205   */
206  public static void addTaskAsyncCallback(AbstractTaskDetails details, MediaObjectList mediaObjectList) {
207    HttpPost post = new HttpPost(details.getCallbackUri());
208    FBTaskResponse r = new FBTaskResponse();
209    r.setBackendId(details.getBackendId());
210    r.setTaskId(details.getTaskId());
211    r.setStatus(TaskStatus.COMPLETED);
212    r.setTaskType(details.getTaskType());
213    r.setMediaObjects(mediaObjectList);
214    post.setEntity(new StringEntity((new XMLFormatter()).toString(r), core.tut.pori.http.Definitions.ENCODING_UTF8));
215
216    CAReferenceCore.executeAsyncCallback(post);
217  }
218
219  /**
220   * 
221   * @param authenticatedUser
222   * @param weightModifierList
223   */
224  public static void setTagWeights(UserIdentity authenticatedUser, WeightModifierList weightModifierList) {
225    LOGGER.info((authenticatedUser == null ? "No logged in user." : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()));  // only notify of the logged in status
226    
227    if(!WeightModifierList.isValid(weightModifierList)){
228      throw new IllegalArgumentException("Invalid "+Definitions.ELEMENT_WEIGHT_MODIFIER_LIST+".");
229    }
230  }
231
232  /**
233   * 
234   * @param authenticatedUser
235   * @param userId
236   * @return example list of weights for the given values
237   */
238  public static WeightModifierList retrieveTagWeights(UserIdentity authenticatedUser, Long userId) {
239    LOGGER.info((authenticatedUser == null ? "No logged in user, with user id filter: "+userId : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()+", with user id filter: "+userId));  // only notify of the logged in status
240    return CREATOR.createWeightModifierList();
241  }
242
243  /**
244   * 
245   * @param authenticatedUser
246   * @param contentTypes
247   * @param synchronize
248   */
249  public static void summarize(UserIdentity authenticatedUser, List<String> contentTypes, boolean synchronize) {
250    LOGGER.info((authenticatedUser == null ? "No logged in user." : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()));  // only notify of the logged in status
251    ContentType.fromString(contentTypes); // throws an exception on invalid values
252  }
253
254  /**
255   * 
256   * @return randomly generated weihgt modifier list
257   */
258  public static WeightModifierList generateWeighModifierList() {
259    return CREATOR.createWeightModifierList();
260  }
261
262  /**
263   * 
264   * @param limits
265   * @return randomly generated task response
266   */
267  public static FBTaskResponse generateTaskResponse(Limits limits) {
268    return CREATOR.createTaskResponse(DATAGROUPS_BACKEND_RESPONSE, limits, null, TaskType.FACEBOOK_PROFILE_SUMMARIZATION);
269  }
270
271  /**
272   * 
273   * @param limits
274   * @return randomly generated task details
275   */
276  public static FBSummarizationTaskDetails generateFBSummarizationTaskDetails(Limits limits) {
277    int likeCount = limits.getMaxItems(Definitions.ELEMENT_LIKE_LIST);
278    if(likeCount >= Limits.DEFAULT_MAX_ITEMS){
279      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_LIKE_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
280      likeCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_LIKE_LIST);
281    }
282    int eventCount = limits.getMaxItems(Definitions.ELEMENT_EVENT_LIST);
283    if(eventCount >= Limits.DEFAULT_MAX_ITEMS){
284      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_EVENT_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
285      eventCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_EVENT_LIST);
286    }
287    int groupCount = limits.getMaxItems(Definitions.ELEMENT_GROUP_LIST);
288    if(groupCount >= Limits.DEFAULT_MAX_ITEMS){
289      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_GROUP_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
290      groupCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_GROUP_LIST);
291    }
292    int photoDescriptionCount = limits.getMaxItems(Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST);
293    if(photoDescriptionCount >= Limits.DEFAULT_MAX_ITEMS){
294      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
295      photoDescriptionCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST);
296    }
297    int videoDescriptionCount = limits.getMaxItems(Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST);
298    if(videoDescriptionCount >= Limits.DEFAULT_MAX_ITEMS){
299      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
300      videoDescriptionCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST);
301    }
302    int statusMessageCount = limits.getMaxItems(Definitions.ELEMENT_STATUS_MESSAGE_LIST);
303    if(statusMessageCount >= Limits.DEFAULT_MAX_ITEMS){
304      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_STATUS_MESSAGE_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
305      statusMessageCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_STATUS_MESSAGE_LIST);
306    }
307    int tagCount = limits.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST);
308    if(tagCount >= Limits.DEFAULT_MAX_ITEMS){
309      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_PHOTO_TAG_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
310      tagCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST);
311    }
312    int commentCount = limits.getMaxItems(Definitions.ELEMENT_COMMENT_LIST);
313    if(commentCount >= Limits.DEFAULT_MAX_ITEMS){
314      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_COMMENT_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
315      commentCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_COMMENT_LIST);
316    }
317    return CREATOR.createFBSummarizationTaskDetails(likeCount, eventCount, groupCount, photoDescriptionCount, videoDescriptionCount, statusMessageCount, tagCount, commentCount);
318  }
319
320  /**
321   * 
322   * @param limits
323   * @return randomly generated task details
324   */
325  public static FBFeedbackTaskDetails generateFBFeedbackTaskDetails(Limits limits) {
326    int objectCount = limits.getMaxItems(service.tut.pori.contentanalysis.Definitions.ELEMENT_MEDIA_OBJECTLIST);
327    if(objectCount >= Limits.DEFAULT_MAX_ITEMS){
328      LOGGER.debug("Reseting limits for "+service.tut.pori.contentanalysis.Definitions.ELEMENT_MEDIA_OBJECTLIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
329      objectCount = DEFAULT_LIMITS.getMaxItems(service.tut.pori.contentanalysis.Definitions.ELEMENT_MEDIA_OBJECTLIST);
330    }
331
332    return CREATOR.createFBFeedbackTaskDetails(objectCount);
333  }
334
335  /**
336   * 
337   * @return randomly generated photo tag
338   */
339  public static FacebookPhotoTag generateFacebookPhotoTag() {
340    return CREATOR.createFacebookPhotoTag();
341  }
342
343  /**
344   * 
345   * @return randomly generated weight modifier
346   */
347  public static WeightModifier generateWeighModifier() {
348    return CREATOR.createWeightModifier(null);
349  }
350
351  /**
352   * 
353   * @return randomly generated comment
354   */
355  public static FacebookComment generateFacebookComment() {
356    return CREATOR.createComment();
357  }
358
359  /**
360   * 
361   * @return randomly generated event
362   */
363  public static FacebookEvent generateFacebookEvent() {
364    return CREATOR.createFacebookEvent();
365  }
366
367  /**
368   * 
369   * @return randomly generated group
370   */
371  public static FacebookGroup generateFacebookGroup() {
372    return CREATOR.createFacebookGroup();
373  }
374
375  /**
376   * 
377   * @return randomly generated location
378   */
379  public static FacebookLocation generateFacebookLocation() {
380    return CREATOR.createFacebookLocation();
381  }
382
383  /**
384   * 
385   * @return randomly generated description
386   */
387  public static FacebookPhotoDescription generateFacebookPhotoDescription() {
388    return CREATOR.createFacebookPhotoDescription(DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_COMMENT_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST));
389  }
390
391  /**
392   * 
393   * @return randomly generated profile
394   */
395  public static FacebookProfile generateFacebookProfile() {
396    return CREATOR.createFacebookProfile(DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_LIKE_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_EVENT_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_GROUP_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_STATUS_MESSAGE_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_COMMENT_LIST));
397  }
398
399  /**
400   * 
401   * @return randomly generated profile
402   */
403  public static FacebookRelationship generateFacebookRelationship() {
404    return CREATOR.createFacebookRelationship();
405  }
406
407  /**
408   * 
409   * @return randomly generated status message
410   */
411  public static FacebookStatusMessage generateFacebookStatusMessage() {
412    return CREATOR.createFacebookStatusMessage(DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_COMMENT_LIST));
413  }
414
415  /**
416   * 
417   * @return randomly generated user details
418   */
419  public static FacebookUserDetails generateFacebookUserDetails() {
420    return CREATOR.createFacebookUserDetails();
421  }
422
423  /**
424   * 
425   * @return randomly generated video description
426   */
427  public static FacebookVideoDescription generateFacebookVideoDescription() {
428    return CREATOR.createFacebookVideoDescription(DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_COMMENT_LIST));
429  }
430
431  /**
432   * 
433   * @return randomly generated like
434   */
435  public static FacebookLike generateFacebookLike() {
436    return CREATOR.createFacebookLike();
437  }
438}