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.alerts.reference; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Date; 021import java.util.Random; 022import java.util.Set; 023import java.util.UUID; 024 025import org.apache.commons.collections4.IterableUtils; 026import org.apache.commons.lang3.ArrayUtils; 027import org.apache.commons.lang3.RandomUtils; 028import org.apache.commons.text.RandomStringGenerator; 029import org.apache.log4j.Logger; 030 031import core.tut.pori.http.parameters.DataGroups; 032import core.tut.pori.http.parameters.DateIntervalParameter.Interval; 033import core.tut.pori.http.parameters.Limits; 034import core.tut.pori.users.UserIdentity; 035import service.tut.pori.apilta.alerts.datatypes.Alert; 036import service.tut.pori.apilta.alerts.datatypes.AlertList; 037import service.tut.pori.apilta.alerts.datatypes.Location; 038import service.tut.pori.apilta.files.TemporaryTokenHandler; 039import service.tut.pori.apilta.files.datatypes.Definitions; 040import service.tut.pori.apilta.files.datatypes.FileDetails; 041import service.tut.pori.apilta.files.datatypes.FileDetailsList; 042 043/** 044 * 045 * Class that can be used to created example objects/object lists. 046 * 047 */ 048public class AlertsXMLObjectCreator { 049 private static final String IMAGE_URL = "http://otula.pori.tut.fi/d2i/leijona_album_art.jpg"; 050 private static final String IMAGE_URL_MIME_TYPE = "image/jpeg"; 051 private static final Logger LOGGER = Logger.getLogger(AlertsXMLObjectCreator.class); 052 private static final Integer ALERT_RANGE = 100; // in meters 053 private static final int TEXT_LENGTH = 64; 054 private Random _random = null; 055 private RandomStringGenerator _stringGenerator = null; 056 057 /** 058 * 059 * @param seed for random generator, or null to use default (system time in nanoseconds) 060 */ 061 public AlertsXMLObjectCreator(Long seed){ 062 if(seed == null){ 063 seed = System.nanoTime(); 064 } 065 _random = new Random(seed); 066 _stringGenerator = new RandomStringGenerator.Builder().withinRange('a', 'z').build(); 067 } 068 069 /** 070 * @return the random 071 */ 072 public Random getRandom() { 073 return _random; 074 } 075 076 /** 077 * 078 * @param alertGroupId 079 * @param alertType 080 * @param createdFilter 081 * @param dataGroups 082 * @param limits 083 * @param location 084 * @param range 085 * @return alert list 086 */ 087 public AlertList generateAlertList(long[] alertGroupId, Collection<String> alertType, Set<Interval> createdFilter, DataGroups dataGroups, Limits limits, Location location, Double range) { 088 int count = limits.getMaxItems(service.tut.pori.apilta.alerts.datatypes.Definitions.ELEMENT_ALERT_LIST); 089 if(count < 1){ 090 LOGGER.warn("count < 1"); 091 return null; 092 }else if(count >= Limits.DEFAULT_MAX_ITEMS){ 093 LOGGER.debug("Count was "+Limits.DEFAULT_MAX_ITEMS+", using 1."); 094 count = 1; 095 } 096 097 ArrayList<Alert> alerts = new ArrayList<>(count); 098 for(int i=0;i<count;++i){ 099 alerts.add(generateAlert(alertGroupId, alertType, createdFilter, dataGroups, limits, location, range)); 100 } 101 102 AlertList list = new AlertList(); 103 list.setAlerts(alerts); 104 return list; 105 } 106 107 /** 108 * 109 * @param alertGroupId 110 * @param alertType 111 * @param createdFilter 112 * @param dataGroups 113 * @param limits 114 * @param location 115 * @param range 116 * @return alert 117 */ 118 public Alert generateAlert(long[] alertGroupId, Collection<String> alertType, Set<Interval> createdFilter, DataGroups dataGroups, Limits limits, Location location, Double range) { 119 Alert alert = new Alert(); 120 121 ArrayList<Long> ids = new ArrayList<>(1); 122 if(ArrayUtils.isEmpty(alertGroupId)){ 123 ids.add(Math.abs(_random.nextLong())); 124 }else{ 125 ids.add(alertGroupId[_random.nextInt(alertGroupId.length)]); 126 } 127 alert.setAlertGroupIds(ids); 128 129 if(alertType != null && !alertType.isEmpty()){ 130 alert.setAlertType(IterableUtils.get(alertType, _random.nextInt(alertType.size()))); 131 }else{ 132 alert.setAlertType(_stringGenerator.generate(TEXT_LENGTH)); 133 } 134 135 alert.setDescription(_stringGenerator.generate(TEXT_LENGTH)); 136 alert.setUserId(new UserIdentity(Math.abs(_random.nextLong()))); 137 Date created = generateCreatedTimestamp(createdFilter); 138 alert.setCreated(created); 139 alert.setValidUntil(new Date(System.currentTimeMillis()+6000000)); // make sure the alert is still valid by creating the timestamp sometime in the future 140 alert.setLocation(generateLocation(location, range)); 141 alert.setAlertId(UUID.randomUUID().toString()); 142 alert.setRange(ALERT_RANGE); 143 144 if(DataGroups.hasDataGroup(DataGroups.DATA_GROUP_ALL, dataGroups)){ 145 alert.setFiles(generateFileDetailsList(limits)); 146 } 147 148 return alert; 149 } 150 151 /** 152 * 153 * @param source if null, random location is returned 154 * @param range 155 * @return randomly generated location located within the given range of the location source 156 */ 157 public Location generateLocation(Location source, Double range) { 158 Location location = new Location(); 159 if(source == null){ 160 if(range != null){ 161 LOGGER.debug("Ignoring range because of null source."); 162 } 163 location.setLatitude(_random.nextDouble()*181-90); 164 location.setLongitude(_random.nextDouble()*361-180); 165 }else{ 166 Double sourceHeading = source.getHeading(); 167 double heading = Math.toRadians(sourceHeading == null ? _random.nextInt(360) : sourceHeading); 168 double r = (range == null ? _random.nextInt(service.tut.pori.apilta.alerts.Definitions.DEFAULT_RANGE.intValue()) : range); 169 170 double lat = source.getLatitude(); 171 double lon = source.getLongitude(); 172 173 lat += Math.cos(heading) * r; 174 if(lat < -90){ // simply limit the value in case invalid coordinate is generated 175 lat = -90; 176 }else if(lat > 90){ 177 lat = 90; 178 } 179 180 lon += Math.sin(heading) * r; 181 if(lon < -180){ // simply limit the value in case invalid coordinate is generated 182 lon = -180; 183 }else if(lon > 180){ 184 lon = 180; 185 } 186 187 location.setLatitude(lat); 188 location.setLongitude(lon); 189 } 190 return location; 191 } 192 193 /** 194 * 195 * @param limits 196 * @return randomly generated file details list 197 */ 198 public FileDetailsList generateFileDetailsList(Limits limits) { 199 int count = limits.getMaxItems(Definitions.ELEMENT_FILE_DETAILS_LIST); 200 if(count < 1){ 201 LOGGER.warn("count < 1"); 202 return null; 203 }else if(count >= Limits.DEFAULT_MAX_ITEMS){ 204 LOGGER.debug("Count was "+Limits.DEFAULT_MAX_ITEMS+", using 1."); 205 count = 1; 206 } 207 208 ArrayList<FileDetails> details = new ArrayList<>(count); 209 for(int i=0;i<count;++i){ 210 details.add(generateFileDetails()); 211 } 212 FileDetailsList list = new FileDetailsList(); 213 list.setFiles(details); 214 return list; 215 } 216 217 /** 218 * 219 * @return randomly generated file details 220 */ 221 public FileDetails generateFileDetails() { 222 FileDetails details = new FileDetails(); 223 details.setGUID(UUID.randomUUID().toString()); 224 details.setMimeType(IMAGE_URL_MIME_TYPE); 225 details.setUrl(IMAGE_URL); 226 details.setValidUntil(generateValidUntil()); 227 return details; 228 } 229 230 /** 231 * 232 * @param createdFilter If multiple values are given, the interval will be selected randomly from the given values. If null, a random time between unix epoch and the current time is selected 233 * @return randomly generate date between UNIX epoch and current time 234 */ 235 public Date generateCreatedTimestamp(Set<Interval> createdFilter) { 236 if(createdFilter == null || createdFilter.isEmpty()){ 237 return new Date(RandomUtils.nextLong(0, System.currentTimeMillis())); 238 }else{ 239 Interval interval = IterableUtils.get(createdFilter, _random.nextInt(createdFilter.size())); 240 return new Date(RandomUtils.nextLong(interval.getStart().getTime(), interval.getEnd().getTime())); 241 } 242 } 243 244 /** 245 * 246 * @return timestamp sometime in the future 247 */ 248 public Date generateValidUntil() { 249 return new Date(TemporaryTokenHandler.CACHE_VALIDITY*1000+System.currentTimeMillis()); 250 } 251 252 /** 253 * 254 * @return randomly generated GUID 255 */ 256 public String createGUID() { 257 return UUID.randomUUID().toString(); 258 } 259}