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.twitterjazz.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.twitterjazz.Definitions;
034import service.tut.pori.twitterjazz.TwitterExtractor.ContentType;
035import service.tut.pori.twitterjazz.TwitterLocation;
036import service.tut.pori.twitterjazz.TwitterPhotoDescription;
037import service.tut.pori.twitterjazz.TwitterPhotoTag;
038import service.tut.pori.twitterjazz.TwitterProfile;
039import service.tut.pori.twitterjazz.TwitterStatusMessage;
040import service.tut.pori.twitterjazz.TwitterSummarizationTaskDetails;
041import service.tut.pori.twitterjazz.TwitterTaskResponse;
042import service.tut.pori.twitterjazz.TwitterUserDetails;
043import service.tut.pori.twitterjazz.TwitterVideoDescription;
044import core.tut.pori.http.parameters.DataGroups;
045import core.tut.pori.http.parameters.Limits;
046import core.tut.pori.http.parameters.SortOptions;
047import core.tut.pori.users.UserIdentity;
048import core.tut.pori.utils.XMLFormatter;
049
050/**
051 * The reference implementations for TwitterJazz Service.
052 *
053 */
054public final class TJReferenceCore {
055  private static final TJXMLObjectCreator CREATOR = new TJXMLObjectCreator(null);
056  private static final DataGroups DATAGROUPS_BACKEND_RESPONSE = new DataGroups(CAXMLObjectCreator.DATA_GROUP_BACKEND_RESPONSE); // data groups for add task callback
057  private static final Limits DEFAULT_LIMITS = new Limits(0, 0);  // default number of limits for references
058  private static final Logger LOGGER = Logger.getLogger(TJReferenceCore.class); 
059
060  /**
061   * 
062   */
063  private TJReferenceCore(){
064    // nothing needed
065  }
066
067  /**
068   * 
069   * @param response
070   */
071  public static void taskFinished(PhotoTaskResponse response) {
072    Integer tBackendId = response.getBackendId();
073    if(tBackendId == null){
074      throw new IllegalArgumentException("Invalid backendId: "+tBackendId);
075    }
076    Long tTaskId = response.getTaskId();
077    if(tTaskId == null){
078      throw new IllegalArgumentException("Invalid taskId: "+tTaskId);
079    }
080
081    TaskStatus status = response.getStatus();
082    if(status == null){
083      throw new IllegalArgumentException("TaskStatus is invalid or missing.");
084    }
085
086    TaskType type = response.getTaskType();
087    if(type == null){
088      throw new IllegalArgumentException("TaskType is invalid or missing.");
089    }
090
091    try{
092      switch(type){
093        case TWITTER_PROFILE_SUMMARIZATION:
094          TwitterTaskResponse fr = (TwitterTaskResponse) response;
095          if(!PhotoList.isValid(fr.getPhotoList()) && !MediaObjectList.isValid(fr.getMediaObjects())){
096            throw new IllegalArgumentException("No content.");
097          }
098          break;
099        case BACKEND_FEEDBACK: // should not have any content, so accept anything
100          break;
101        default:      
102          throw new IllegalArgumentException("Tasks of type: "+type.name()+" are not supported by this validator.");
103      }
104    }catch(ClassCastException ex){
105      LOGGER.debug(ex, ex);
106      throw new IllegalArgumentException("Task content data was not of the expected type.");
107    }
108  }
109
110  /**
111   * 
112   * @param taskDetails
113   */
114  public static void addTask(TwitterTaskDetails taskDetails) {
115    Integer tBackendId = taskDetails.getBackendId();
116    if(tBackendId == null){
117      throw new IllegalArgumentException("Invalid backendId: "+tBackendId);
118    }
119    Long tTaskId = taskDetails.getTaskId();
120    if(tTaskId == null){
121      throw new IllegalArgumentException("Invalid taskId: "+tTaskId);
122    }
123
124    String uri = taskDetails.getCallbackUri();
125    if(StringUtils.isBlank(uri)){
126      throw new IllegalArgumentException("Invalid callbackUri: "+uri);
127    }
128
129    TaskType type = taskDetails.getTaskType();
130    if(type == null){
131      throw new IllegalArgumentException("TaskType is invalid or missing.");
132    }
133
134    switch(type){
135      case TWITTER_PROFILE_SUMMARIZATION:
136        if(taskDetails.getProfile() == null){
137          throw new IllegalArgumentException("Invalid "+Definitions.ELEMENT_TWITTER_PROFILE);
138        }
139        addTaskAsyncCallback(taskDetails, CREATOR.createTagList(tBackendId, DATAGROUPS_BACKEND_RESPONSE, DEFAULT_LIMITS, taskDetails.getUserId()));
140        break;
141      case BACKEND_FEEDBACK:
142        if(!PhotoList.isValid(taskDetails.getPhotoList())){
143          throw new IllegalArgumentException("Invalid "+service.tut.pori.contentanalysis.Definitions.ELEMENT_PHOTOLIST);
144        }
145        addTaskAsyncCallback(taskDetails, null);
146        break;
147      default:
148        throw new IllegalArgumentException("Tasks of type: "+type.name()+" are not supported by this validator.");
149    }
150  }
151
152  /**
153   * Call asynchronously the callback given in the details, returning an example task response
154   * 
155   * @param details
156   * @param mediaObjectList
157   * @see service.tut.pori.twitterjazz.TwitterTaskResponse
158   */
159  public static void addTaskAsyncCallback(AbstractTaskDetails details, MediaObjectList mediaObjectList){
160    HttpPost post = new HttpPost(details.getCallbackUri());
161    TwitterTaskResponse r = new TwitterTaskResponse();
162    r.setBackendId(details.getBackendId());
163    r.setTaskId(details.getTaskId());
164    r.setStatus(TaskStatus.COMPLETED);
165    r.setTaskType(details.getTaskType());
166    r.setMediaObjects(mediaObjectList);
167    post.setEntity(new StringEntity((new XMLFormatter()).toString(r), core.tut.pori.http.Definitions.ENCODING_UTF8));
168
169    CAReferenceCore.executeAsyncCallback(post);
170  }
171
172  /**
173   * 
174   * @param authenticatedUser
175   * @param dataGroups
176   * @param limits only the amount of results is processed for the limits. This is because the results are randomly generated, and thus have no
177   * order which could be used for paging.
178   * @param sortOptions sort options are ignored. This is because of the complexity of the sort operations performed for randomly generated data.
179   * @return media object list
180   */
181  public static MediaObjectList retrieveTagsForUser(UserIdentity authenticatedUser, DataGroups dataGroups, Limits limits, SortOptions sortOptions) {
182    LOGGER.info((authenticatedUser == null ? "No logged in user." : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()));  // only notify of the logged in status
183    return CREATOR.createTagList(CREATOR.createBackendId(), dataGroups, limits, authenticatedUser);
184  }
185
186  /**
187   * 
188   * @param authenticatedUser
189   * @param ranks list of ranks in the form of rank=guid:VALUE,guid:VALUE,...
190   */
191  public static void setRank(UserIdentity authenticatedUser, List<String> ranks) {
192    LOGGER.info((authenticatedUser == null ? "No logged in user." : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()));  // only notify of the logged in status
193    if(ranks == null || ranks.isEmpty()){
194      throw new IllegalArgumentException("Failed to process rank parameter.");
195    }
196
197    for(String r : ranks){
198      String[] parts = r.split(core.tut.pori.http.Definitions.SEPARATOR_URI_QUERY_TYPE_VALUE);
199      if(parts.length != 2){
200        throw new IllegalArgumentException("Failed to process rank parameter: "+r);
201      }
202    }  // for
203  }
204
205  /**
206   * 
207   * @param authenticatedUser
208   * @param contentTypes
209   * @param screenNames
210   * @param synchronize
211   */
212  public static void summarize(UserIdentity authenticatedUser, List<String> contentTypes, List<String> screenNames, boolean synchronize) {
213    LOGGER.info((authenticatedUser == null ? "No logged in user." : "Ignoring the logged in user, id: "+authenticatedUser.getUserId()));  // only notify of the logged in status
214    ContentType.fromString(contentTypes); // throws an exception on invalid values
215  }
216
217  /**
218   * 
219   * @param limits
220   * @return randomly generated task response
221   */
222  public static TwitterTaskResponse generateTaskResponse(Limits limits) {
223    return CREATOR.createTwitterTaskResponse(DATAGROUPS_BACKEND_RESPONSE, limits, null, TaskType.TWITTER_PROFILE_SUMMARIZATION);
224  }
225
226  /**
227   * 
228   * @param limits
229   * @return randomly generated task details
230   */
231  public static TwitterSummarizationTaskDetails generateTwitterSummarizationTaskDetails(Limits limits) {
232    int photoDescriptionCount = limits.getMaxItems(Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST);
233    if(photoDescriptionCount >= Limits.DEFAULT_MAX_ITEMS){
234      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
235      photoDescriptionCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST);
236    }
237    int videoDescriptionCount = limits.getMaxItems(Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST);
238    if(videoDescriptionCount >= Limits.DEFAULT_MAX_ITEMS){
239      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
240      videoDescriptionCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST);
241    }
242    int statusMessageCount = limits.getMaxItems(Definitions.ELEMENT_STATUS_MESSAGE_LIST);
243    if(statusMessageCount >= Limits.DEFAULT_MAX_ITEMS){
244      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_STATUS_MESSAGE_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
245      statusMessageCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_STATUS_MESSAGE_LIST);
246    }
247    int tagCount = limits.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST);
248    if(tagCount >= Limits.DEFAULT_MAX_ITEMS){
249      LOGGER.debug("Reseting limits for "+Definitions.ELEMENT_PHOTO_TAG_LIST+": max items was "+Limits.DEFAULT_MAX_ITEMS);
250      tagCount = DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST);
251    }
252    return CREATOR.createTwitterSummarizationTaskDetails(photoDescriptionCount, statusMessageCount, videoDescriptionCount, tagCount);
253  }
254
255  /**
256   * 
257   * @return randomly generated location
258   */
259  public static TwitterLocation generateTwitterLocation() {
260    return CREATOR.createTwitterLocation();
261  }
262
263  /**
264   * 
265   * @return randomly generated photo description
266   */
267  public static TwitterPhotoDescription generateTwitterPhotoDescription() {
268    return CREATOR.createTwitterPhotoDescription(DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST));
269  }
270
271  /**
272   * 
273   * @return randomly generated photo tag
274   */
275  public static TwitterPhotoTag generateTwitterPhotoTag() {
276    return CREATOR.createTwitterPhotoTag();
277  }
278
279  /**
280   * 
281   * @return randomly generated profile
282   */
283  public static TwitterProfile generateTwitterProfile() {
284    return CREATOR.createTwitterProfile(DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_DESCRIPTION_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_STATUS_MESSAGE_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_VIDEO_DESCRIPTION_LIST), DEFAULT_LIMITS.getMaxItems(Definitions.ELEMENT_PHOTO_TAG_LIST));
285  }
286
287  /**
288   * 
289   * @return randomly generated status message
290   */
291  public static TwitterStatusMessage generateTwitterStatusMessage() {
292    return CREATOR.createTwitterStatusMessage();
293  }
294
295  /**
296   * 
297   * @return randomly generated user details
298   */
299  public static TwitterUserDetails generateTwitterUserDetails() {
300    return CREATOR.createTwitterUserDetails();
301  }
302
303  /**
304   * 
305   * @return randomly generated video description
306   */
307  public static TwitterVideoDescription generateTwitterVideoDescription() {
308    return CREATOR.createTwitterVideoDescription();
309  }
310}