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.contentanalysis;
017
018import java.util.ArrayList;
019import java.util.Iterator;
020import java.util.List;
021
022import javax.xml.bind.annotation.XmlAccessType;
023import javax.xml.bind.annotation.XmlAccessorType;
024import javax.xml.bind.annotation.XmlElement;
025import javax.xml.bind.annotation.XmlRootElement;
026
027import org.apache.commons.lang3.StringUtils;
028import org.apache.log4j.Logger;
029
030import core.tut.pori.http.ResponseData;
031import core.tut.pori.utils.MediaUrlValidator.MediaType;
032import service.tut.pori.contentanalysis.MediaObject.MediaObjectType;
033
034/**
035 * A list of media objects, which can be directly used as a data for XML response.
036 * 
037 * <h3>XML Example</h3>
038 * 
039 * {@doc.restlet service="[service.tut.pori.contentanalysis.reference.Definitions#SERVICE_CA_REFERENCE_EXAMPLE]" method="[service.tut.pori.contentanalysis.Definitions#ELEMENT_MEDIA_OBJECTLIST]" type="GET" query="" body_uri=""}
040 * 
041 * @see service.tut.pori.contentanalysis.MediaObject
042 */
043@XmlRootElement(name=Definitions.ELEMENT_MEDIA_OBJECTLIST)
044@XmlAccessorType(XmlAccessType.NONE)
045public class MediaObjectList extends ResponseData{
046  private static final Logger LOGGER = Logger.getLogger(MediaObjectList.class);
047  private static final String MEDIA_OBJECT_PARAMETER_DELIMITER = ":"; //like: OBJECT1_VALUE1:OBJECT1_VALUE2...
048  @XmlElement(name = Definitions.ELEMENT_MEDIA_OBJECT)
049  private List<MediaObject> _mediaObjects = null;
050  @XmlElement(name = Definitions.ELEMENT_RESULT_INFO)
051  private ResultInfo _resultInfo = null;
052
053  /**
054   * @return list of photos
055   * @see #addMediaObject(MediaObject)
056   * @see #addMediaObjects(MediaObjectList)
057   */
058  public List<MediaObject> getMediaObjects() {
059    if(_mediaObjects != null && _mediaObjects.size() > 0){
060      return _mediaObjects;
061    }else{
062      return null;
063    }
064  }
065
066  /**
067   * Note: calling this method will clear the list's result info if any is present
068   * 
069   * @param mediaObject 
070   * @see #getMediaObjects()
071   */
072  public void addMediaObject(MediaObject mediaObject){
073    if(_mediaObjects == null){
074      _mediaObjects = new ArrayList<>();
075    }
076    _mediaObjects.add(mediaObject);
077    if(_resultInfo != null){ // if there was a result info, it may now be incorrect
078      LOGGER.debug("Removing possibly incorrect result info.");
079      _resultInfo = null;
080    }
081  }
082  
083  /**
084   * add the media object list to this media object list, empty list is ignored
085   * 
086   * Note: calling this method will clear the list's result info if any is present
087   * 
088   * @param mediaObjects
089   * @see #getMediaObjects()
090   */
091  public void addMediaObjects(MediaObjectList mediaObjects){
092    if(MediaObjectList.isEmpty(mediaObjects)){
093      return;
094    }
095    if(_mediaObjects == null){
096      _mediaObjects = new ArrayList<>();
097    }
098    _mediaObjects.addAll(mediaObjects.getMediaObjects());
099    if(_resultInfo != null){ // if there was a result info, it may now be incorrect
100      LOGGER.debug("Removing possibly incorrect result info.");
101      _resultInfo = null;
102    }
103  }
104  
105  /**
106   * 
107   * @param mediaObjectId non-null id
108   * @return the media object or null if not found
109   */
110  public MediaObject getMediaObject(String mediaObjectId){
111    if(isEmpty()){
112      return null;
113    }
114    for(Iterator<MediaObject> iter = _mediaObjects.iterator(); iter.hasNext();){
115      MediaObject v = iter.next();
116      if(mediaObjectId.equals(v.getMediaObjectId())){
117        return v;
118      }
119    }
120    return null;
121  }
122  
123  /**
124   * 
125   * @return list of media object ids for this list or null if none
126   */
127  public List<String> getMediaObjectIds(){
128    if(isEmpty()){
129      LOGGER.debug("Empty media object list.");
130      return null;
131    }
132    List<String> voids = new ArrayList<>(_mediaObjects.size());
133    for(MediaObject v : _mediaObjects){
134      String mediaObjectId = v.getMediaObjectId();
135      if(StringUtils.isBlank(mediaObjectId)){
136        LOGGER.debug("Ignored media object without id.");
137      }else{
138        voids.add(mediaObjectId);
139      }
140    }
141    return (voids.isEmpty() ? null : voids);
142  }
143
144  /**
145   * 
146   * @param list 
147   * @return true if this list contains no objects, or the list is null
148   */
149  public static boolean isEmpty(MediaObjectList list){
150    if(list == null){
151      return true;
152    }else{
153      return list.isEmpty();
154    }
155  }
156   
157  /**
158   * use the static, only for sub-classing
159   * @return true if the list is empty
160   * @see #isEmpty(MediaObjectList)
161   */
162  protected boolean isEmpty(){
163    return (_mediaObjects == null || _mediaObjects.isEmpty() ? true : false);
164  }
165
166  /**
167   * 
168   * @param objects
169   * @param resultInfo
170   * @return list or null if null or empty list is passed
171   */
172  public static MediaObjectList getMediaObjectList(List<? extends MediaObject> objects, ResultInfo resultInfo){
173    if(objects == null || objects.isEmpty()){
174      LOGGER.debug("Ignored empty list.");
175      return null;
176    }else{
177      MediaObjectList list = new MediaObjectList();
178      list._mediaObjects = new ArrayList<>(objects);
179      list._resultInfo = resultInfo;
180      return list;
181    }
182  }
183
184  /**
185   * <p>Parse given keywords given in following format:</p> 
186   * <pre>keyword:confidence:backendId,keyword:confidence:backendId,...</pre>
187   * <p><em>keyword</em> is required, <em>confidence</em> and <em>backendId</em> are optional.</p>
188   * @param keywords
189   * @return list of media objects based on the keywords or null if none was found
190   */
191  public static MediaObjectList getMediaObjectListFromKeywords(List<String> keywords){
192    List<MediaObject> objects = null;
193    if(keywords != null && !keywords.isEmpty()){
194      objects = new ArrayList<>();
195      for(Iterator<String> iter = keywords.iterator();iter.hasNext();){
196        String[] keywordParts = iter.next().split(MEDIA_OBJECT_PARAMETER_DELIMITER);
197        MediaObject o = new MediaObject(MediaType.PHOTO, MediaObjectType.KEYWORD);
198        o.setValue(keywordParts[0]);
199        if(keywordParts.length > 1){
200          o.setConfidence(Double.valueOf(keywordParts[1]));
201        }
202        if(keywordParts.length > 2){
203          o.setBackendId(Integer.valueOf(keywordParts[2]));
204        }
205        objects.add(o);
206      }  // for
207    }
208    return getMediaObjectList(objects, null);
209  }
210  
211  /**
212   * 
213   * @param list can be null
214   * @return true if the passed list is valid
215   */
216  public static boolean isValid(MediaObjectList list){
217    if(list == null){
218      return false;
219    }else{
220      return list.isValid();
221    }
222  }
223  
224  /**
225   * use the static, only for sub-classing
226   * @return true if the list is valid
227   * @see #isValid(MediaObjectList)
228   */
229  protected boolean isValid(){
230    if(_mediaObjects == null){
231      return false;
232    }else{
233      for(Iterator<MediaObject> iter = _mediaObjects.iterator();iter.hasNext();){
234        if(!iter.next().isValid()){
235          return false;
236        }
237      }
238      return true;
239    }
240  }
241
242  /**
243   * Default data groups: {@value service.tut.pori.contentanalysis.Definitions#DATA_GROUP_RESULT_INFO}
244   * 
245   * @return the resultInfo
246   * @see #setResultInfo(ResultInfo)
247   */
248  public ResultInfo getResultInfo() {
249    return _resultInfo;
250  }
251
252  /**
253   * @param resultInfo the resultInfo to set
254   * @see #getResultInfo()
255   */
256  public void setResultInfo(ResultInfo resultInfo) {
257    _resultInfo = resultInfo;
258  }
259}