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}