001/**
002 * Copyright 2015 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.fuzzyvisuals;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.Collections;
021import java.util.Iterator;
022import java.util.List;
023import java.util.Random;
024import java.util.Set;
025
026import org.apache.commons.lang3.StringUtils;
027import org.apache.http.client.methods.HttpPost;
028import org.apache.http.entity.StringEntity;
029import org.apache.http.impl.client.BasicResponseHandler;
030import org.apache.http.impl.client.CloseableHttpClient;
031import org.apache.http.impl.client.HttpClients;
032import org.apache.log4j.Logger;
033
034import service.tut.pori.contentanalysis.AsyncTask.TaskStatus;
035import service.tut.pori.contentanalysis.AsyncTask.TaskType;
036import service.tut.pori.contentanalysis.Definitions;
037import service.tut.pori.contentanalysis.MediaObject;
038import service.tut.pori.contentanalysis.MediaObject.ConfirmationStatus;
039import service.tut.pori.contentanalysis.MediaObject.MediaObjectType;
040import core.tut.pori.context.ServiceInitializer;
041import core.tut.pori.utils.HTTPHeaderUtil;
042import core.tut.pori.utils.MediaUrlValidator.MediaType;
043import core.tut.pori.utils.XMLFormatter;
044
045/**
046 * Simple runnable for executing FuzzyAnalysisTask
047 * 
048 * Assumes that the given task is of type {@link service.tut.pori.contentanalysis.AsyncTask.TaskType#ANALYSIS}
049 * 
050 */
051public class FuzzyAnalysisTask implements Runnable {
052  private static final Logger LOGGER = Logger.getLogger(FuzzyAnalysisTask.class);
053  private static final int MAX_MEDIA_ITEMS = 10;
054  private Integer _backendId = null;
055  private String _callbackUri = null;
056  private List<FuzzyMedia> _media = null;
057  private Random _random = null;
058  private Long _taskId = null;
059
060  /**
061   * 
062   * @param backendId
063   * @param callbackUri
064   * @param media
065   * @param taskId
066   * @throws IllegalArgumentException on bad data
067   */
068  public FuzzyAnalysisTask(Integer backendId, String callbackUri, List<FuzzyMedia> media, Long taskId) throws IllegalArgumentException {
069    if(taskId == null){
070      throw new IllegalArgumentException("Invalid "+Definitions.ELEMENT_TASK_ID);
071    }
072    _taskId = taskId;
073    
074    if(backendId == null){
075      throw new IllegalArgumentException("Invalid "+Definitions.ELEMENT_BACKEND_ID+" for task, id : "+_taskId);
076    }
077    _backendId = backendId;
078    if(StringUtils.isBlank(callbackUri)){
079      throw new IllegalArgumentException("Invalid "+Definitions.ELEMENT_CALLBACK_URI+" : "+callbackUri+" for task, id : "+_taskId);
080    }
081    _callbackUri = callbackUri;
082    
083    if(media == null || media.isEmpty()){
084      throw new IllegalArgumentException("No content for task, id : "+_taskId);
085    }
086    for(FuzzyMedia m : media){
087      if(!FuzzyMedia.isValid(m)){
088        throw new IllegalArgumentException("Invalid media, "+Definitions.ELEMENT_GUID+" : "+m.getGUID()+" for task, id : "+_taskId);
089      }
090    }
091    
092    _media = new ArrayList<>(media); // preserve the original list
093    _random = new Random();
094    if(_media.size() > MAX_MEDIA_ITEMS){ // limit the result size to prevent excessive abusing of Google's Translation service
095      media = _media;
096      Collections.shuffle(media, _random); // shuffle to get random items
097      
098      _media = new ArrayList<>(MAX_MEDIA_ITEMS);
099      Iterator<FuzzyMedia> iter = media.iterator();
100      for(int i=0;i<MAX_MEDIA_ITEMS;++i){
101        _media.add(iter.next());
102      }
103    }
104  }
105
106  @Override
107  public void run() {
108    List<FuzzyMedia> results = new ArrayList<>(_media.size());
109    try(FuzzyAnalyzer fa = new FuzzyAnalyzer()){
110      for(FuzzyMedia m : _media){
111        Set<String> words = fa.analyze(m.getUrl());
112        if(words != null){
113          MediaType mediaType = m.getMediaType();
114          String guid = m.getGUID();
115          List<MediaObject> objects = new ArrayList<>(words.size());
116          for(String word : words){
117            MediaObject mo = new MediaObject(mediaType, MediaObjectType.KEYWORD);
118            mo.setBackendId(_backendId);
119            mo.setConfirmationStatus(ConfirmationStatus.CANDIDATE);
120            mo.setValue(word);
121            mo.setOwnerUserId(m.getOwnerUserId());
122            mo.setObjectId(guid+"_"+word);
123            mo.setConfidence(_random.nextInt(100)/100.0);
124            objects.add(mo);
125          } // for
126          
127          results.add(new FuzzyMedia(guid, objects, mediaType));
128        } // if
129      } // for
130    } // try
131    
132    TaskResults tr = new TaskResults(_backendId, _taskId, TaskStatus.COMPLETED, TaskType.ANALYSIS);
133    
134    if(results.isEmpty()){
135      LOGGER.debug("No results for task, id : "+_taskId);
136    }else{
137      tr.setMedia(results);
138    }
139    
140    try(CloseableHttpClient client = HttpClients.createDefault()){
141      HttpPost post = new HttpPost(_callbackUri);
142      FuzzyProperties fp = ServiceInitializer.getPropertyHandler().getSystemProperties(FuzzyProperties.class);
143      String username = fp.getAuthUsername();
144      if(username != null){ // checking either password or username is OK
145        LOGGER.debug("Using authentication...");
146        HTTPHeaderUtil.setHTTPBasicAuthHeader(post, username, fp.getAuthPassword());
147      }
148      
149      post.setEntity(new StringEntity(new XMLFormatter().toString(tr)));
150      
151      LOGGER.debug("Calling POST "+_callbackUri);
152      LOGGER.debug("Server responded : "+client.execute(post, new BasicResponseHandler()));
153    } catch (IOException ex) {
154      LOGGER.error(ex, ex);
155    }
156  }
157}