001/** 002 * Copyright 2016 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.apilta.sensors.reference; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.List; 023import java.util.Set; 024import java.util.UUID; 025 026import org.apache.commons.lang3.StringUtils; 027import org.apache.log4j.Logger; 028 029import service.tut.pori.apilta.sensors.datatypes.Measurement; 030import service.tut.pori.apilta.sensors.datatypes.MeasurementList; 031import service.tut.pori.apilta.sensors.datatypes.SensorTask; 032import service.tut.pori.tasks.Definitions; 033import service.tut.pori.tasks.datatypes.TaskBackend; 034import service.tut.pori.tasks.datatypes.TaskBackend.Status; 035import core.tut.pori.http.parameters.DataGroups; 036import core.tut.pori.http.parameters.DateIntervalParameter.Interval; 037import core.tut.pori.http.parameters.Limits; 038import core.tut.pori.users.UserIdentity; 039 040/** 041 * The reference implementations for Content Analysis Service. 042 * 043 */ 044public final class SensorsReferenceCore { 045 private static final int BUFFER_SIZE = 256; 046 private static final SensorsXMLObjectCreator CREATOR = new SensorsXMLObjectCreator(null); 047 private static final DataGroups DATA_GROUPS_TRAFFIC_DATA = new DataGroups(DataGroups.DATA_GROUP_ALL); 048 private static final Logger LOGGER = Logger.getLogger(SensorsReferenceCore.class); 049 050 /** 051 * 052 */ 053 private SensorsReferenceCore(){ 054 // nothing needed 055 } 056 057 /** 058 * 059 * @param limits 060 * @return measurements 061 */ 062 public static MeasurementList generateTrafficData(Limits limits) { 063 MeasurementList datalist = new MeasurementList(); 064 datalist.setMeasurements(CREATOR.generateMeasurementList(null, null, DATA_GROUPS_TRAFFIC_DATA, limits, null)); 065 return datalist; 066 } 067 068 /** 069 * 070 * @param authenticatedUser 071 * @param backendId if null, value is automatically generated 072 * @param taskIds optional ids, one random id will be generated if none is given 073 * @param taskType 074 * @return task details for a submitted task 075 */ 076 public static SensorTask generateTaskDetails(UserIdentity authenticatedUser, Long backendId, Collection<String> taskIds, String taskType) { 077 if(UserIdentity.isValid(authenticatedUser)){ 078 LOGGER.debug("Authenticated user, id: "+authenticatedUser.getUserId()); // simply log the user id for debug 079 } 080 return CREATOR.generateTaskDetails((backendId == null ? Math.abs(CREATOR.getRandom().nextLong()) : backendId), taskIds, taskType); 081 } 082 083 /** 084 * 085 * @param authenticatedUser 086 * @param dataGroups 087 * @param limits 088 * @param taskId 089 * @param taskType 090 * @return task details for a finished task 091 */ 092 public static SensorTask generateTaskResults(UserIdentity authenticatedUser, DataGroups dataGroups, Limits limits, String taskId, String taskType) { 093 if(UserIdentity.isValid(authenticatedUser)){ 094 LOGGER.debug("Authenticated user, id: "+authenticatedUser.getUserId()); // simply log the user id for debug 095 } 096 return CREATOR.generateTaskResults(null, dataGroups, limits, (StringUtils.isBlank(taskId) ? null : Arrays.asList(taskId)), taskType); 097 } 098 099 /** 100 * reference implementation of the method for adding a task to a back end 101 * 102 * Note: this will not call the callback URI with task finished 103 * 104 * @param authenticatedUser 105 * @param task 106 * @throws IllegalArgumentException on invalid task 107 */ 108 public static void addTask(UserIdentity authenticatedUser, SensorTask task) throws IllegalArgumentException { 109 if(UserIdentity.isValid(authenticatedUser)){ 110 LOGGER.debug("Authenticated user, id: "+authenticatedUser.getUserId()); // simply log the user id for debug 111 } 112 113 if(createTask(authenticatedUser, task) == null){ 114 throw new IllegalArgumentException("Invalid task."); 115 } 116 117 List<String> taskId = task.getTaskIds(); 118 if(taskId == null || taskId.size() != 1){ 119 throw new IllegalArgumentException("Task must have exactly one identifier."); 120 } 121 122 if(task.getTaskTypes().contains(Definitions.TASK_TYPE_VIRTUAL)){ 123 throw new IllegalArgumentException("This back end cannot process tasks of type: "+Definitions.TASK_TYPE_VIRTUAL); 124 } 125 126 List<TaskBackend> backends = task.getBackends(); 127 if(backends.size() != 1){ 128 throw new IllegalArgumentException("Only a single back end can be given for add task."); // add task always targeted to a single back end 129 } 130 } 131 132 /** 133 * 134 * @param authenticatedUser 135 * @param task 136 * @throws IllegalArgumentException on invalid task 137 */ 138 public static void taskFinished(UserIdentity authenticatedUser, SensorTask task) throws IllegalArgumentException { 139 if(UserIdentity.isValid(authenticatedUser)){ 140 LOGGER.debug("Authenticated user, id: "+authenticatedUser.getUserId()); // simply log the user id for debug 141 } 142 143 List<String> taskIds = task.getTaskIds(); 144 if(taskIds == null || taskIds.isEmpty()){ 145 throw new IllegalArgumentException("Invalid task: task identifier missing."); 146 } 147 148 if(!SensorTask.isValid(task) || task.getConditions() != null){ // it is enough to check that either conditions or output is not present as the validity is checked through isValid() 149 throw new IllegalArgumentException("Invalid task."); 150 } 151 } 152 153 /** 154 * Note: this will not schedule back end calls even if the task contains back ends (is not virtual) 155 * 156 * @param authenticatedUser 157 * @param task 158 * @return id for the created task 159 * @throws IllegalArgumentException on invalid task 160 */ 161 public static String createTask(UserIdentity authenticatedUser, SensorTask task) throws IllegalArgumentException { 162 Set<String> taskTypes = task.getTaskTypes(); 163 if(taskTypes == null || taskTypes.isEmpty()){ 164 throw new IllegalArgumentException("Invalid task: no task type."); 165 } 166 167 List<TaskBackend> backends = task.getBackends(); 168 if(backends == null){ 169 throw new IllegalArgumentException("Invalid task: no back ends."); 170 } 171 for(TaskBackend backend : backends){ // reset all status information to not started before task validation 172 backend.setStatus(Status.NOT_STARTED); 173 } 174 175 if(UserIdentity.isValid(authenticatedUser)){ 176 LOGGER.debug("Authenticated user, id: "+authenticatedUser.getUserId()); // simply log the user id for debug 177 } 178 179 if(!SensorTask.isValid(task) || task.getConditions() == null || !UserIdentity.isValid(task.getUserId())){ // it is enough to check that either conditions or output exists as the validity is checked through isValid() 180 throw new IllegalArgumentException("Invalid task."); 181 } 182 183 return UUID.randomUUID().toString(); 184 } 185 186 /** 187 * Note: this will not schedule back end calls even if the task contains back ends (is not virtual) 188 * 189 * @param authenticatedUser 190 * @param task 191 * @return id for the created task 192 * @throws IllegalArgumentException on invalid task 193 */ 194 public static String modifyTask(UserIdentity authenticatedUser, SensorTask task) throws IllegalArgumentException { 195 List<String> taskIds = task.getTaskIds(); 196 if(taskIds == null || taskIds.size() != 1){ 197 throw new IllegalArgumentException("The modified task must have exactly one task identifier."); 198 } 199 createTask(authenticatedUser, task); // use create task to validate 200 return taskIds.iterator().next(); 201 } 202 203 /** 204 * 205 * @param authenticatedUser 206 * @param backendId 207 * @param file the contents of the file are simply iterated as raw byte data (all content is discarded) 208 * @return randomly generated guid for the file 209 * @throws IllegalArgumentException on bad data 210 */ 211 @SuppressWarnings("unused") 212 public static String createFile(UserIdentity authenticatedUser, Long backendId, InputStream file) throws IllegalArgumentException { 213 try { 214 byte[] buffer = new byte[BUFFER_SIZE]; 215 while(file.read(buffer) > 0){ 216 // simply discard all data 217 } 218 } catch (IOException ex) { 219 LOGGER.error(ex, ex); 220 throw new IllegalArgumentException("Failed to read file."); 221 } 222 if(UserIdentity.isValid(authenticatedUser)){ 223 LOGGER.debug("Authenticated user, id: "+authenticatedUser.getUserId()); // simply log the user id for debug 224 } 225 return CREATOR.createGUID(); // accept any file, return random GUID 226 } 227 228 /** 229 * 230 * @param authenticatedUser 231 * @param backendIdFilter 232 * @param createdFilter 233 * @param dataGroups 234 * @param limits 235 * @param measurementIdFilter 236 * @param taskIds 237 * @return randomly generated measurement id list 238 */ 239 public static MeasurementList getMeasurements(UserIdentity authenticatedUser, long[] backendIdFilter, Set<Interval> createdFilter, DataGroups dataGroups, Limits limits, List<String> measurementIdFilter, Collection<String> taskIds) { 240 if(UserIdentity.isValid(authenticatedUser)){ 241 LOGGER.debug("Authenticated user, id: "+authenticatedUser.getUserId()); // simply log the user id for debug 242 } 243 244 if(taskIds != null && !taskIds.isEmpty()) { 245 LOGGER.debug("Ignored task identifiers."); 246 } 247 248 List<Measurement> measurements = CREATOR.generateMeasurementList(backendIdFilter, createdFilter, dataGroups, limits, measurementIdFilter); 249 if(measurements == null){ 250 LOGGER.debug("Empty measurement list generated based on the given parameters."); 251 return null; 252 } 253 MeasurementList list = new MeasurementList(); 254 list.setMeasurements(measurements); 255 return list; 256 } 257 258 /** 259 * 260 * @param authenticatedUser 261 * @param backendId 262 * @param dataGroups 263 * @param limits 264 * @param taskIds 265 * @param taskType 266 * @return pseudo-randomly generated task 267 */ 268 @SuppressWarnings("unused") 269 public static SensorTask queryTaskDetails(UserIdentity authenticatedUser, Long backendId, DataGroups dataGroups, Limits limits, List<String> taskIds, String taskType) { 270 if(!DataGroups.isEmpty(dataGroups)) { 271 LOGGER.debug("Ignored data groups."); 272 } 273 return generateTaskDetails(authenticatedUser, backendId, taskIds, taskType); 274 } 275}