diff --git a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/ActiveTimController.java b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/ActiveTimController.java index a5a35e9be..842c734db 100644 --- a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/ActiveTimController.java +++ b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/ActiveTimController.java @@ -66,17 +66,17 @@ public void InjectDependencies(TimDbTables _timDbTables, SQLNullHandler _sqlNull sqlNullHandler = _sqlNullHandler; } - /** - * Retrieve active TIMs that are expiring within 24 hours. - *

- * Note: TIMs with a start time more than 24 hours in the future - * or an end time less than 24 hours in the future are excluded. - * - * @return List of ActiveTim objects - */ - @RequestMapping(value = "/expiring", method = RequestMethod.GET, produces = "application/json", headers = "Accept=application/json") - public ResponseEntity> GetExpiringActiveTims() { - List activeTims = new ArrayList<>(); + /** + * Retrieve active TIMs that are expiring within 24 hours. + * + * Note: TIMs with a start time more than 24 hours in the future + * or an end time less than 24 hours in the future are excluded. + * + * @return List of ActiveTim objects + */ + @RequestMapping(value = "/expiring", method = RequestMethod.GET, produces = "application/json", headers = "Accept=application/json") + public ResponseEntity> GetExpiringActiveTims() { + List activeTims = new ArrayList<>(); String selectStatement = "SELECT atim.*, tt.type as tim_type_name, tt.description as tim_type_description"; selectStatement += ", t.msg_cnt, t.url_b, t.is_satellite, t.sat_record_id, t.packet_id"; @@ -113,17 +113,7 @@ public ResponseEntity> GetExpiringActiveTims() { activeTim.setFrameType(TravelerInfoType.advisory); } - // set dataFrame content. it's required for the ODE, so if we didn't record it, - // assume Advisory - String serializedContent = rs.getString("DF_CONTENT"); - ContentEnum contentType; - if (serializedContent == null || serializedContent.isEmpty()) { - contentType = ContentEnum.advisory; - } else { - contentType = ContentEnum.fromString(serializedContent); - } - activeTim.setDfContent(contentType); - + activeTim.setDfContent(ContentEnum.advisory); activeTims.add(activeTim); } } catch (Exception e) { @@ -169,16 +159,7 @@ public ResponseEntity GetUpdateModelFromActiveTimId(@PathVariabl activeTim.setFrameType(TravelerInfoType.advisory); } - // set dataFrame content. it's required for the ODE, so if we didn't record it, - // assume Advisory - String serializedContent = rs.getString("DF_CONTENT"); - ContentEnum contentType; - if (serializedContent == null || serializedContent.isEmpty()) { - contentType = ContentEnum.advisory; - } else { - contentType = ContentEnum.fromString(serializedContent); - } - activeTim.setDfContent(contentType); + activeTim.setDfContent(ContentEnum.advisory); } } catch (Exception e) { log.error("Error getting active tim", e); @@ -284,12 +265,11 @@ public ResponseEntity> GetActiveTimIndicesByRsu(@PathVariable Stri List indices = new ArrayList<>(); - String selectStatement = "select tim_rsu.rsu_index from active_tim"; - selectStatement += " inner join tim on active_tim.tim_id = tim.tim_id"; - selectStatement += " inner join tim_rsu on tim_rsu.tim_id = tim.tim_id"; - selectStatement += " inner join rsu on rsu.rsu_id = tim_rsu.rsu_id"; - selectStatement += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; - selectStatement += " where rsu_view.ipv4_address = '" + rsuTarget + "'"; + String selectStatement = "select tim_rsu.rsu_index from active_tim"; + selectStatement += " inner join tim on active_tim.tim_id = tim.tim_id"; + selectStatement += " inner join tim_rsu on tim_rsu.tim_id = tim.tim_id"; + selectStatement += " inner join rsus on rsus.rsu_id = tim_rsu.rsu_id"; + selectStatement += " where rsus.ipv4_address = '" + rsuTarget + "'"; try (Connection connection = dbInteractions.getConnectionPool(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(selectStatement)) { // convert to ActiveTim object @@ -332,7 +312,8 @@ public ResponseEntity> GetActiveTimsByClientIdDirection(@PathVar public ResponseEntity> GetBufferTimsByClientId(@PathVariable String clientId) { List activeTims = new ArrayList<>(); - String query = "select * from active_tim where CLIENT_ID like '" + clientId + "\\%BUFF_-%' ESCAPE '\\'"; + String query = "select * from active_tim where CLIENT_ID like '" + clientId + + "\\%BUFF-%' ESCAPE '\\'"; try (Connection connection = dbInteractions.getConnectionPool(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(query)) { activeTims = getActiveTimFromRS(rs, false); @@ -671,12 +652,11 @@ public ResponseEntity> GetActiveRsuTims() { List results = new ArrayList(); ActiveTim activeTim = null; - String query = "select active_tim.*, rsu_view.ipv4_address, tim_rsu.rsu_index from active_tim"; + String query = "select active_tim.*, rsus.ipv4_address, tim_rsu.rsu_index from active_tim"; query += " inner join tim_rsu on active_tim.tim_id = tim_rsu.tim_id"; - query += " inner join rsu on tim_rsu.rsu_id = rsu.rsu_id"; - query += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; + query += " inner join rsus on tim_rsu.rsu_id = rsus.rsu_id"; query += " where sat_record_id is null"; - query += " order by rsu_view.ipv4_address, tim_rsu.rsu_index"; // Required by ValidateRsus + query += " order by rsus.ipv4_address, tim_rsu.rsu_index"; // Required by ValidateRsus try (Connection connection = dbInteractions.getConnectionPool(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(query)) { // convert to ActiveTim object @@ -728,9 +708,9 @@ public ResponseEntity GetActiveRsuTim(@RequestBody ActiveRsuTimQueryM String query = "select * from active_tim"; query += " inner join tim_rsu on active_tim.tim_id = tim_rsu.tim_id"; - query += " inner join rsu on tim_rsu.rsu_id = rsu.rsu_id"; - query += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; - query += " where ipv4_address = '" + artqm.getIpv4() + "' and client_id = '" + artqm.getClientId() + "' and active_tim.direction = '" + artqm.getDirection() + "'"; + query += " inner join rsus on tim_rsu.rsu_id = rsus.rsu_id"; + query += " where ipv4_address = '" + artqm.getIpv4() + "' and client_id = '" + artqm.getClientId() + + "' and active_tim.direction = '" + artqm.getDirection() + "'"; try (Connection connection = dbInteractions.getConnectionPool(); Statement statement = connection.createStatement(); ResultSet rs = statement.executeQuery(query)) { List activeTims = getActiveTimFromRS(rs, false); @@ -1082,4 +1062,62 @@ private TimUpdateModel buildTimUpdateModelFromResultSet(ResultSet rs) throws SQL timUpdateModel.setUrl(rs.getString("URL")); return timUpdateModel; } + + public TimUpdateModel setPropertiesForActiveTim(ResultSet rs, TimUpdateModel activeTim) throws SQLException { + activeTim.setActiveTimId(rs.getLong("ACTIVE_TIM_ID")); + activeTim.setTimId(rs.getLong("TIM_ID")); + activeTim.setDirection(rs.getString("DIRECTION")); + activeTim.setStartDateTime(rs.getString("TIM_START")); + activeTim.setEndDateTime(rs.getString("TIM_END")); + activeTim.setExpirationDateTime(rs.getString("EXPIRATION_DATE")); + activeTim.setSatRecordId(rs.getString("SAT_RECORD_ID")); + activeTim.setClientId(rs.getString("CLIENT_ID")); + activeTim.setRoute(rs.getString("ROUTE")); + + Coordinate startPoint = null; + Coordinate endPoint = null; + BigDecimal startLat = rs.getBigDecimal("START_LATITUDE"); + BigDecimal startLon = rs.getBigDecimal("START_LONGITUDE"); + if (!rs.wasNull()) { + startPoint = new Coordinate(startLat, startLon); + } + activeTim.setStartPoint(startPoint); + + BigDecimal endLat = rs.getBigDecimal("END_LATITUDE"); + BigDecimal endLon = rs.getBigDecimal("END_LONGITUDE"); + if (!rs.wasNull()) { + endPoint = new Coordinate(endLat, endLon); + } + activeTim.setEndPoint(endPoint); + + activeTim.setStartDate_Timestamp(rs.getTimestamp("TIM_START", UTCCalendar)); + activeTim.setEndDate_Timestamp(rs.getTimestamp("TIM_END", UTCCalendar)); + + // Tim properties + activeTim.setMsgCnt(rs.getInt("MSG_CNT")); + activeTim.setUrlB(rs.getString("URL_B")); + activeTim.setPacketId(rs.getString("PACKET_ID")); + + // Tim Type properties + activeTim.setTimTypeName(rs.getString("TIM_TYPE_NAME")); + activeTim.setTimTypeDescription(rs.getString("TIM_TYPE_DESCRIPTION")); + + // Region Properties + activeTim.setRegionId(rs.getInt("REGION_ID")); + activeTim.setAnchorLat(rs.getBigDecimal("ANCHOR_LAT")); + activeTim.setAnchorLong(rs.getBigDecimal("ANCHOR_LONG")); + + activeTim.setLaneWidth(rs.getBigDecimal("LANE_WIDTH")); + activeTim.setRegionDirection(rs.getString("REGION_DIRECTION")); + activeTim.setDirectionality(rs.getString("DIRECTIONALITY")); + activeTim.setClosedPath(rs.getBoolean("CLOSED_PATH")); + activeTim.setPathId(rs.getInt("PATH_ID")); + activeTim.setRegionDescription(rs.getString("REGION_DESCRIPTION")); + + // DataFrame properties + activeTim.setDataFrameId(rs.getInt("DATA_FRAME_ID")); + activeTim.setDurationTime(rs.getInt("DURATION_TIME")); + activeTim.setUrl(rs.getString("URL")); + return activeTim; + } } diff --git a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/CdotUpstreamPathController.java b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/CdotUpstreamPathController.java new file mode 100644 index 000000000..95fb09781 --- /dev/null +++ b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/CdotUpstreamPathController.java @@ -0,0 +1,392 @@ +package com.trihydro.cvdatacontroller.controller; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; + +import com.trihydro.library.helpers.CdotGisConnector; +import com.trihydro.library.model.Milepost; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.web.client.RestClientException; + +@CrossOrigin +@RestController +@RequestMapping("cdot-upstream-path") +public class CdotUpstreamPathController extends BaseController { + private final CdotGisConnector cdotGisService; + + private final Logger logger = LoggerFactory.getLogger(CdotUpstreamPathController.class); + + public CdotUpstreamPathController(CdotGisConnector cdotGisService) { + this.cdotGisService = cdotGisService; + } + + /** + * Retrieves a buffer path of mileposts for a given route and desired distance. + * + * This method takes a list of path mileposts, a route ID, and a desired distance in miles. + * It fetches all mileposts for the specified route and determines the direction of the path. + * Then, it traverses the mileposts to create a buffer path that meets the desired distance. + * + * Note: The current implementation pulls back the entire route linestring in one request. + * There is a possibility to optimize this by hitting the geo REST service multiple times + * to fetch smaller segments of the route. However, this method will proceed with the current + * implementation unless performance issues are observed. + * + * @param pathMileposts the list of mileposts defining the path + * @param routeId the ID of the route + * @param desiredDistanceInMiles the desired distance for the buffer path in miles + * @return a ResponseEntity containing the buffer path of mileposts or a bad request status if an error occurs + * @throws JsonProcessingException if there is an error processing the JSON response from the geo service + */ + @PostMapping(value = "/get-buffer-for-path/{routeId}/{desiredDistanceInMiles:.+}") + public ResponseEntity> getBufferForPath(@RequestBody List pathMileposts, + @PathVariable String routeId, @PathVariable + double desiredDistanceInMiles) throws + JsonProcessingException { + logger.info("Getting buffer for path with desired distance: {} miles", desiredDistanceInMiles); + List allMileposts; + try { + allMileposts = getMilepostsForRoute(routeId); + } catch (RestClientException e) { + logger.error("Error getting mileposts for route", e); + return ResponseEntity.badRequest().body(null); + } + if (allMileposts == null || allMileposts.isEmpty()) { + logger.warn("No mileposts found for route"); + return ResponseEntity.badRequest().body(null); + } + PathDirection direction; + try { + direction = getPathDirection(pathMileposts, allMileposts); + } catch (NotEnoughMilepostsException e) { + logger.warn("Not enough mileposts in path", e); + return ResponseEntity.badRequest().body(null); + } catch (MilepostNotFoundException e) { + logger.warn("Milepost not found in route", e); + return ResponseEntity.badRequest().body(null); + } + if (direction == null) { + logger.warn("Invalid path direction"); + return ResponseEntity.badRequest().body(null); + } + Milepost firstMilepostInPath = pathMileposts.get(0); + int startIndex = getIndexOfMilepost(allMileposts, firstMilepostInPath); + TraverseContext traverseContext = + new TraverseContext(allMileposts, startIndex, desiredDistanceInMiles, direction); + if (direction == PathDirection.ASCENDING) { + traverseContext.setTraverseStrategy(new DescendingTraverseStrategy()); + } else { + traverseContext.setTraverseStrategy(new AscendingTraverseStrategy()); + } + traverseContext.performTraversal(); + List buffer = traverseContext.getBuffer(); + if (buffer.size() < 2) { + // at least 2 mileposts are needed to create a valid buffer path + logger.warn("Buffer path has less than 2 mileposts"); + return ResponseEntity.badRequest().body(null); + } + double distanceInMiles = traverseContext.getDistanceInMiles(); + if (distanceInMiles < desiredDistanceInMiles) { + logger.warn("Buffer path has less distance than desired distance"); + return ResponseEntity.badRequest().body(null); + } + logger.info("Distance of buffer path: {} miles", distanceInMiles); + if (logger.isDebugEnabled()) { + String geojsonString = convertMilepostsToGeojsonString(buffer); + logger.debug("Geojson string for buffer: {}", geojsonString); + } + return ResponseEntity.ok(buffer); + } + + /** + * Retrieves all mileposts for a given route from the CDOT GIS service. + * + *

This method uses `CdotGisService.getRouteById()` to retrieve the route information + * in JSON format. The JSON response contains all the latitude and longitude points + * in the route. This information is then extracted into the `Milepost` model and + * returned as a list of mileposts.

+ * + * @param routeId the ID of the route to retrieve mileposts for + * @return a list of `Milepost` objects representing the mileposts in the route + * @throws JsonProcessingException if there is an error processing the JSON response + * @throws RestClientException if an error occurs while making the request + */ + public List getMilepostsForRoute(String routeId) throws JsonProcessingException, + RestClientException { + ResponseEntity response = cdotGisService.getRouteById(routeId); + String routeJsonString = response.getBody(); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(routeJsonString); + JsonNode pathNode = rootNode.path("features").get(0).path("geometry").path("paths").get(0); + List mileposts = new ArrayList<>(); + for (JsonNode node : pathNode) { + Milepost milepost = new Milepost(); + milepost.setCommonName(routeId); + BigDecimal latitude = new BigDecimal(node.get(1).asText()).setScale(14, RoundingMode.HALF_UP); + BigDecimal longitude = + new BigDecimal(node.get(0).asText()).setScale(14, RoundingMode.HALF_UP); + milepost.setLatitude(latitude); + milepost.setLongitude(longitude); + mileposts.add(milepost); + } + return mileposts; + } + + public PathDirection getPathDirection(List pathMileposts, List allMileposts) + throws NotEnoughMilepostsException, MilepostNotFoundException { + if (pathMileposts.size() < 2) { + throw new NotEnoughMilepostsException("Path has less than 2 mileposts"); + } + Milepost firstMilepostInPath = pathMileposts.get(0); + Milepost secondMilepostInPath = pathMileposts.get(1); + int firstMilepostInPathIndex = getIndexOfMilepost(allMileposts, firstMilepostInPath); + if (firstMilepostInPathIndex == -1) { + throw new MilepostNotFoundException("First milepost not found in route"); + } + int secondMilepostInPathIndex = getIndexOfMilepost(allMileposts, secondMilepostInPath); + if (secondMilepostInPathIndex == -1) { + throw new MilepostNotFoundException("Second milepost not found in route"); + } + if (firstMilepostInPathIndex < secondMilepostInPathIndex) { + return PathDirection.ASCENDING; + } else { + return PathDirection.DESCENDING; + } + } + + private int getIndexOfMilepost(List mileposts, Milepost milepost) { + if (milepost.getLatitude() == null || milepost.getLongitude() == null) { + logger.warn("Milepost has null latitude or longitude"); + return -1; + } + BigDecimal latitude = milepost.getLatitude().setScale(14, RoundingMode.HALF_UP); + BigDecimal longitude = milepost.getLongitude().setScale(14, RoundingMode.HALF_UP); + // Roughly a 1-mile starting buffer + BigDecimal latDifference = new BigDecimal(0.015); + BigDecimal lonDifference = new BigDecimal(0.015); + int closestIndex = -1; + for (int i = 0; i < mileposts.size(); i++) { + Milepost currentMilepost = mileposts.get(i); + BigDecimal currentLatitude = currentMilepost.getLatitude().setScale(14, RoundingMode.HALF_UP); + BigDecimal currentLongitude = currentMilepost.getLongitude().setScale(14, + RoundingMode.HALF_UP); + + // If the current milepost is closer, update the closest index + if (latDifference.compareTo(latitude.subtract(currentLatitude).abs()) > 0 + && lonDifference.compareTo(longitude.subtract(currentLongitude).abs()) > 0) { + latDifference = latitude.subtract(currentLatitude).abs(); + lonDifference = longitude.subtract(currentLongitude).abs(); + closestIndex = i; + } + } + return closestIndex; + } + + private String convertMilepostsToGeojsonString(List mileposts) { + StringBuilder geojsonStringBuilder = new StringBuilder(); + geojsonStringBuilder.append( + "{ \"type\": \"FeatureCollection\", \"features\": [{ \"type\": \"Feature\", \"geometry\": { \"type\": \"LineString\", \"coordinates\": ["); + for (int i = 0; i < mileposts.size(); i++) { + Milepost milepost = mileposts.get(i); + geojsonStringBuilder.append("["); + geojsonStringBuilder.append(milepost.getLongitude().toString()); + geojsonStringBuilder.append(", "); + geojsonStringBuilder.append(milepost.getLatitude().toString()); + geojsonStringBuilder.append("]"); + if (i < mileposts.size() - 1) { + geojsonStringBuilder.append(", "); + } + } + geojsonStringBuilder.append("] }, \"properties\": { \"commonName\": \""); + geojsonStringBuilder.append(mileposts.get(0).getCommonName()); + geojsonStringBuilder.append("\" } }] }"); + return geojsonStringBuilder.toString(); + } + + // define path direction enum (ASCENDING, DESCENDING) + public enum PathDirection { + ASCENDING, + DESCENDING + } + + public static class NotEnoughMilepostsException extends Exception { + public NotEnoughMilepostsException(String message) { + super(message); + } + } + + public static class MilepostNotFoundException extends Exception { + public MilepostNotFoundException(String message) { + super(message); + } + } + + /** + * Context class for traversing mileposts to get buffer path + */ + public static class TraverseContext { + private final List allMileposts; + private final int startIndex; + private final double desiredDistanceInMiles; + private final PathDirection direction; + + private TraverseStrategy traverseStrategy; + + private List buffer; + private double distanceInMiles; + + public TraverseContext(List allMileposts, int startIndex, + double desiredDistanceInMiles, PathDirection direction) { + this.allMileposts = allMileposts; + this.startIndex = startIndex; + this.desiredDistanceInMiles = desiredDistanceInMiles; + this.direction = direction; + this.buffer = new ArrayList<>(); + } + + public void performTraversal() { + traverseStrategy.traverse(this); + } + + public List getAllMileposts() { + return allMileposts; + } + + public int getStartIndex() { + return startIndex; + } + + public double getDesiredDistanceInMiles() { + return desiredDistanceInMiles; + } + + public PathDirection getDirection() { + return direction; + } + + public void setTraverseStrategy(TraverseStrategy traverseStrategy) { + this.traverseStrategy = traverseStrategy; + } + + public List getBuffer() { + return buffer; + } + + public void setBuffer(List buffer) { + this.buffer = buffer; + } + + public double getDistanceInMiles() { + return distanceInMiles; + } + + public void setDistanceInMiles(double distanceInMiles) { + this.distanceInMiles = distanceInMiles; + } + } + + /** + * Interface for traverse strategy to get buffer path + */ + public interface TraverseStrategy { + void traverse(TraverseContext context); + } + + /** + * Traverse strategy to get buffer path by traversing the mileposts in ascending + * or descending direction from a starting milepost. + */ + public abstract static class AbstractTraverseStrategy implements TraverseStrategy { + + protected abstract int getNextIndex(int currentIndex); + + /** + * Traverses the mileposts to create a buffer path. + * + * This method iterates through the mileposts starting from the given start index + * and adds them to the buffer until the desired distance in miles is reached. + * + * Note: The current implementation recalculates the total distance of the buffer + * after adding each milepost, which can be inefficient. If performance issues are + * observed, consider optimizing this calculation. + * + * @param context the context containing the mileposts, start index, desired distance, and direction + */ + @Override + public void traverse(TraverseContext context) { + List buffer = new ArrayList<>(); + List allMileposts = context.getAllMileposts(); + int startIndex = context.getStartIndex(); + double desiredDistanceInMiles = context.getDesiredDistanceInMiles(); + double distanceInMiles = 0; + + buffer.add(allMileposts.get(startIndex)); + for (int i = getNextIndex(startIndex); i >= 0 && i < allMileposts.size(); i = getNextIndex(i)) { + distanceInMiles = DistanceCalculator.calculateDistanceInMiles(buffer); + if (distanceInMiles >= desiredDistanceInMiles) { + break; + } + buffer.add(allMileposts.get(i)); + } + context.setBuffer(buffer); + context.setDistanceInMiles(distanceInMiles); + } + } + + /** + * Traverse strategy to get buffer path by traversing the mileposts in ascending + * direction from a starting milepost. + */ + public static class AscendingTraverseStrategy extends AbstractTraverseStrategy { + + @Override + protected int getNextIndex(int currentIndex) { + return currentIndex + 1; + } + } + + /** + * Traverse strategy to get buffer path by traversing the mileposts in descending + * direction from a starting milepost. + */ + public static class DescendingTraverseStrategy extends AbstractTraverseStrategy { + + @Override + protected int getNextIndex(int currentIndex) { + return currentIndex - 1; + } + } + + /** + * Helper class to calculate distance between two points and total distance of a buffer path + */ + public static class DistanceCalculator { + final static int R = 6371000; // Radius of the earth in meters + + public static double calculateDistanceInMiles(List buffer) { + double distanceInMiles = 0; + for (int i = 0; i < buffer.size() - 1; i++) { + Milepost mp1 = buffer.get(i); + Milepost mp2 = buffer.get(i + 1); + double distanceInMeters = mp1.angularDistanceTo(mp2) * R; + distanceInMiles += distanceInMeters / 1609.34; + } + return distanceInMiles; + } + } +} \ No newline at end of file diff --git a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/MilepostController.java b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/MilepostController.java index 5207aa539..55837bbc7 100644 --- a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/MilepostController.java +++ b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/MilepostController.java @@ -7,6 +7,7 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; @@ -18,6 +19,7 @@ import com.trihydro.library.model.Milepost; import com.trihydro.library.model.MilepostBuffer; import com.trihydro.library.model.WydotTim; +import com.trihydro.library.model.SetMilepostCacheRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -37,6 +39,7 @@ public class MilepostController extends BaseController { private MilepostService milepostService; + private final HashMap> milepostCache = new HashMap<>(); @Autowired public void InjectDependencies(MilepostService _milepostService) { @@ -308,6 +311,74 @@ public ResponseEntity> return ResponseEntity.ok(data); } + @RequestMapping(method = RequestMethod.POST, value="/set-milepost-cache") + public ResponseEntity setMilepostCache(@RequestBody SetMilepostCacheRequest milepostCacheBody) { + + if (milepostCacheBody.getMileposts().isEmpty() || milepostCacheBody.getTimID() == null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid Request: please provide a valid milepost list and timID"); + } + if (milepostCache.containsKey(milepostCacheBody.getTimID())) { + utility.logWithDate("Updating milepost cache for timID: " + milepostCacheBody.getTimID()); + } else { + utility.logWithDate("Setting milepost cache for timID: " + milepostCacheBody.getTimID()); + } + milepostCache.put(milepostCacheBody.getTimID(), milepostCacheBody.getMileposts()); + return ResponseEntity.ok("Milepost cache set successfully for timID: " + milepostCacheBody.getTimID()); + } + + @RequestMapping(method = RequestMethod.GET, value="/get-milepost-cache/{timID}") + public ResponseEntity> getMilepostCacheByTimID(@PathVariable String timID) { + List mileposts = new ArrayList<>(); + + if (milepostCache.containsKey(timID)) { + mileposts = milepostCache.get(timID); + utility.logWithDate("Found " + mileposts.size() + " mileposts in cache for timID: " + timID); + return ResponseEntity.ok(milepostCache.get(timID)); + } + + return ResponseEntity.ok(mileposts); + } + + @RequestMapping(method = RequestMethod.DELETE, value="/delete-milepost-cache/{timID}") + public ResponseEntity deleteMilepostCache(@PathVariable String timID) { + utility.logWithDate("Deleting milepost cache for timID: " + timID); + + if (milepostCache.containsKey(timID)) { + milepostCache.remove(timID); + return ResponseEntity.ok("Milepost cache deleted successfully for timID: " + timID); + } + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Milepost cache not found for timID: " + timID); + } + + @RequestMapping(method = RequestMethod.GET, value="/clear-milepost-cache") + public ResponseEntity clearMilepostCache() { + utility.logWithDate("Clearing milepost cache"); + List clientIDs = new ArrayList<>(milepostCache.keySet()); + List activeTimClientIds = getActiveTimClientIds(); + // remove all active TIM IDs from the list of milepost cache TIM IDs + clientIDs.removeAll(activeTimClientIds); + for (String clientID : clientIDs) { + milepostCache.remove(clientID); + } + return ResponseEntity.ok("Milepost cache cleared successfully"); + } + + private List getActiveTimClientIds() { + List activeTimIds = new ArrayList<>(); + String sql = "SELECT client_id FROM active_tim WHERE marked_for_deletion = False"; + try (Connection connection = dbInteractions.getConnectionPool(); + Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery(sql)) { + while (rs.next()) { + String timId = rs.getString("CLIENT_ID"); + activeTimIds.add(timId); + } + } catch (SQLException e) { + utility.logWithDate("Error retrieving active TIM IDs " + e.toString()); // Improved logging + } + return activeTimIds; + } + /** * Rewrite of getMilepostsByStartEndPoint used in testing to cut time on geojson * creation to test continuity diff --git a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/RsuController.java b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/RsuController.java index c4a9fe3b5..a238506e1 100644 --- a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/RsuController.java +++ b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/controller/RsuController.java @@ -37,9 +37,8 @@ public ResponseEntity> SelectAllRsus() { connection = dbInteractions.getConnectionPool(); statement = connection.createStatement(); - // select all RSUs from RSU table - rs = statement.executeQuery( - "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid order by milepost asc"); + // select all RSUs from rsus table + rs = statement.executeQuery("select rsu_id, ST_X(ST_AsText(geography)) as longitude, ST_Y(ST_AsText(geography)) as latitude, ipv4_address, primary_route, milepost from rsus order by milepost asc"); while (rs.next()) { WydotRsu rsu = new WydotRsu(); @@ -47,7 +46,7 @@ public ResponseEntity> SelectAllRsus() { rsu.setRsuTarget(rs.getString("IPV4_ADDRESS")); rsu.setLatitude(rs.getBigDecimal("LATITUDE")); rsu.setLongitude(rs.getBigDecimal("LONGITUDE")); - rsu.setRoute(rs.getString("ROUTE")); + rsu.setRoute(rs.getString("PRIMARY_ROUTE")); rsu.setMilepost(rs.getDouble("MILEPOST")); rsus.add(rsu); } @@ -74,9 +73,9 @@ public ResponseEntity> SelectAllRsus() { return ResponseEntity.ok(rsus); } - @RequestMapping(value = "/selectActiveRSUs", method = RequestMethod.GET, headers = "Accept=application/json") - public ResponseEntity> SelectActiveRsus() { - List rsus = new ArrayList(); + @RequestMapping(method = RequestMethod.GET, value = "/rsus-for-tim/{timId}") + public ResponseEntity> GetFullRsusTimIsOn(@PathVariable Long timId) { + List rsus = new ArrayList(); Connection connection = null; ResultSet rs = null; Statement statement = null; @@ -85,17 +84,26 @@ public ResponseEntity> SelectActiveRsus() { connection = dbInteractions.getConnectionPool(); statement = connection.createStatement(); - // select all RSUs that are labeled as 'Existing' in the WYDOT view rs = statement.executeQuery( - "select rsu.*, rsu_view.latitude, rsu_view.longitude, rsu_view.ipv4_address from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid where rsu_view.status = 'Existing'"); + "select rsus.rsu_id, rsu_credentials.username as update_username, " + + "rsu_credentials.password as update_password, ST_X(ST_AsText(rsus.geography)) " + + "as longitude, ST_Y(ST_AsText(rsus.geography)) as latitude, rsus.ipv4_address, " + + "tim_rsu.rsu_index from rsus inner join rsu_credentials on " + + "rsu_credentials.credential_id = rsus.credential_id inner join tim_rsu on " + + "tim_rsu.rsu_id = rsus.rsu_id where tim_rsu.tim_id = " + timId); while (rs.next()) { - WydotRsu rsu = new WydotRsu(); - // rsu.setRsuId(rs.getInt("rsu_id")); + WydotRsuTim rsu = new WydotRsuTim(); rsu.setRsuTarget(rs.getString("IPV4_ADDRESS")); rsu.setLatitude(rs.getBigDecimal("LATITUDE")); rsu.setLongitude(rs.getBigDecimal("LONGITUDE")); - rsus.add(rsu); + rsu.setIndex(rs.getInt("RSU_INDEX")); + rsu.setRsuUsername(rs.getString("UPDATE_USERNAME")); + rsu.setRsuPassword(rs.getString("UPDATE_PASSWORD")); + // only add unique values in + if (!rsus.contains(rsu)) { + rsus.add(rsu); + } } } catch (SQLException e) { e.printStackTrace(); @@ -118,9 +126,9 @@ public ResponseEntity> SelectActiveRsus() { return ResponseEntity.ok(rsus); } - @RequestMapping(method = RequestMethod.GET, produces = "application/json", value = "/rsus-for-tim/{timId}") - public ResponseEntity> GetFullRsusTimIsOn(@PathVariable Long timId) { - List rsus = new ArrayList(); + @RequestMapping(method = RequestMethod.GET, produces = "application/json", value = "/rsus-by-geometry/{geometry}") + public ResponseEntity> SelectRsusByGeometry(@PathVariable String geometry) { + ArrayList rsus = new ArrayList<>(); Connection connection = null; ResultSet rs = null; Statement statement = null; @@ -129,23 +137,32 @@ public ResponseEntity> GetFullRsusTimIsOn(@PathVariable Long t connection = dbInteractions.getConnectionPool(); statement = connection.createStatement(); - // select all RSUs that are labeled as 'Existing' in the WYDOT view + // select all RSUs from RSU table rs = statement.executeQuery( - "select rsu.*, tim_rsu.rsu_index, rsu_view.latitude, rsu_view.longitude, rsu_view.ipv4_address from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid inner join tim_rsu on tim_rsu.rsu_id = rsu.rsu_id where tim_rsu.tim_id = " - + timId); + "SELECT rsu_id, ST_X(ST_AsText(geography)) as longitude, " + + "ST_Y(ST_AsText(geography)) as latitude, primary_route, milepost, ipv4_address, sc.username, sc.password " + + "FROM rsus " + + "JOIN snmp_credentials AS sc ON rsus.snmp_credential_id = sc.snmp_credential_id " + + "WHERE rsu_id NOT IN (" + + "SELECT rsu_id " + + "FROM rsu_organization AS ro " + + "JOIN organizations AS o ON ro.organization_id = o.organization_id " + + "WHERE o.name = 'Region 1') " + + "AND ST_Intersects(" + + "ST_Buffer(ST_GeomFromText('" + geometry + "'), 1), geography)" + ); while (rs.next()) { - WydotRsuTim rsu = new WydotRsuTim(); + WydotRsu rsu = new WydotRsu(); + rsu.setRsuId(rs.getInt("RSU_ID")); rsu.setRsuTarget(rs.getString("IPV4_ADDRESS")); rsu.setLatitude(rs.getBigDecimal("LATITUDE")); rsu.setLongitude(rs.getBigDecimal("LONGITUDE")); - rsu.setIndex(rs.getInt("RSU_INDEX")); - rsu.setRsuUsername(rs.getString("UPDATE_USERNAME")); - rsu.setRsuPassword(rs.getString("UPDATE_PASSWORD")); - // only add unique values in - if (!rsus.contains(rsu)) { - rsus.add(rsu); - } + rsu.setRoute(rs.getString("PRIMARY_ROUTE")); + rsu.setMilepost(rs.getDouble("MILEPOST")); + rsu.setRsuUsername(rs.getString("USERNAME")); + rsu.setRsuPassword(rs.getString("PASSWORD")); + rsus.add(rsu); } } catch (SQLException e) { e.printStackTrace(); @@ -181,8 +198,7 @@ public ResponseEntity> SelectRsusByRoute(@PathVariable Strin // select all RSUs from RSU table rs = statement.executeQuery( - "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid where rsu_view.route like '%" - + route + "%' and rsu_view.status = 'Existing' order by milepost asc"); + "select rsu_id, ST_X(ST_AsText(geography)) as longitude, ST_Y(ST_AsText(geography)) as latitude, ipv4_address, primary_route, milepost from rsus where primary_route like '%" + route + "%'"); while (rs.next()) { WydotRsu rsu = new WydotRsu(); @@ -257,4 +273,4 @@ public ResponseEntity> GetActiveRsuTimIndexes(@PathVariable Intege } return ResponseEntity.ok(indexes); } -} +} \ No newline at end of file diff --git a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/model/DataControllerConfigProperties.java b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/model/DataControllerConfigProperties.java index 10eca26b1..7dbc5278a 100644 --- a/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/model/DataControllerConfigProperties.java +++ b/cv-data-controller/src/main/java/com/trihydro/cvdatacontroller/model/DataControllerConfigProperties.java @@ -1,9 +1,6 @@ package com.trihydro.cvdatacontroller.model; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Import; -import org.springframework.stereotype.Component; - +import com.trihydro.library.helpers.CdotGisConnector; import com.trihydro.library.helpers.DbInteractions; import com.trihydro.library.helpers.EmailHelper; import com.trihydro.library.helpers.JavaMailSenderImplProvider; @@ -11,13 +8,19 @@ import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.DbInteractionsProps; import com.trihydro.library.model.EmailProps; +import com.trihydro.library.service.RestTemplateProvider; import com.trihydro.library.tables.LoggingTables; import com.trihydro.library.tables.TimDbTables; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; + @Component @ConfigurationProperties("config") @Import({ TimDbTables.class, SQLNullHandler.class, Utility.class, EmailHelper.class, - JavaMailSenderImplProvider.class, LoggingTables.class, DbInteractions.class }) + JavaMailSenderImplProvider.class, LoggingTables.class, DbInteractions.class, + CdotGisConnector.class, RestTemplateProvider.class }) public class DataControllerConfigProperties implements DbInteractionsProps, EmailProps { private String dbUrl; private String dbUsername; diff --git a/cv-data-controller/src/main/resources/application.properties b/cv-data-controller/src/main/resources/application.properties index fe2e64b06..7230c04a7 100644 --- a/cv-data-controller/src/main/resources/application.properties +++ b/cv-data-controller/src/main/resources/application.properties @@ -20,4 +20,6 @@ spring.data.neo4j.uri=bolt://host.docker.internal:6687 # server.ssl.key-store: classpath:keystore.jks # server.ssl.key-store-password: store-password # server.ssl.keyStoreType: JKS -# server.ssl.keyAlias: some-alias \ No newline at end of file +# server.ssl.keyAlias: some-alias + +logging.level.root=INFO \ No newline at end of file diff --git a/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/ActiveTimControllerTest.java b/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/ActiveTimControllerTest.java index b52ca03fb..bf3a2cb49 100644 --- a/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/ActiveTimControllerTest.java +++ b/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/ActiveTimControllerTest.java @@ -57,7 +57,7 @@ private void setupPreparedStatement() { public void GetExpiringActiveTims_SUCCESS() throws SQLException { // Arrange // we only set one property to verify its returned - when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999l); + when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999L); when(mockRs.getInt(any())).thenReturn(0); when(mockRs.getInt("FRAME_TYPE")).thenReturn(FrameType.TravelerInfoType.advisory.ordinal()); String selectStatement = "SELECT atim.*, tt.type as tim_type_name, tt.description as tim_type_description"; @@ -108,8 +108,7 @@ public void GetExpiringActiveTims_FAIL() throws SQLException { public void GetExpiringActiveTims_CorrectContentType() throws SQLException { // Arrange when(mockRs.getString(any())).thenReturn(""); - when(mockRs.getString("DF_CONTENT")).thenReturn("workZone"); - when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999l); + when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999L); // Act ResponseEntity> tums = uut.GetExpiringActiveTims(); @@ -117,14 +116,14 @@ public void GetExpiringActiveTims_CorrectContentType() throws SQLException { // Assert Assertions.assertEquals(HttpStatus.OK, tums.getStatusCode()); Assertions.assertEquals(1, tums.getBody().size()); - Assertions.assertEquals(ContentEnum.workZone, tums.getBody().get(0).getDfContent()); + Assertions.assertEquals(ContentEnum.advisory, tums.getBody().get(0).getDfContent()); } @Test public void GetUpdateModelFromActiveTimId_SUCCESS() throws SQLException { // Arrange // we only set one property to verify its returned - when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999l); + when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999L); when(mockRs.getInt(any())).thenReturn(0); when(mockRs.getInt("FRAME_TYPE")).thenReturn(FrameType.TravelerInfoType.advisory.ordinal()); @@ -140,10 +139,10 @@ public void GetUpdateModelFromActiveTimId_SUCCESS() throws SQLException { selectStatement += " LEFT JOIN data_frame df on atim.tim_id = df.tim_id"; selectStatement += " LEFT JOIN region r on df.data_frame_id = r.data_frame_id"; selectStatement += " LEFT JOIN tim_type tt ON atim.tim_type_id = tt.tim_type_id"; - selectStatement += " WHERE atim.active_tim_id = " + 999l; + selectStatement += " WHERE atim.active_tim_id = " + 999L; // Act - ResponseEntity tum = uut.GetUpdateModelFromActiveTimId(999l); + ResponseEntity tum = uut.GetUpdateModelFromActiveTimId(999L); // Assert Assertions.assertEquals(HttpStatus.OK, tum.getStatusCode()); @@ -159,7 +158,7 @@ public void GetUpdateModelFromActiveTimId_FAIL() throws SQLException { when(mockRs.getLong("ACTIVE_TIM_ID")).thenThrow(new SQLException()); // Act - ResponseEntity tum = uut.GetUpdateModelFromActiveTimId(999l); + ResponseEntity tum = uut.GetUpdateModelFromActiveTimId(999L); // Assert Assertions.assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, tum.getStatusCode()); @@ -172,16 +171,15 @@ public void GetUpdateModelFromActiveTimId_FAIL() throws SQLException { public void GetUpdateModelFromActiveTimId_CorrectContentType() throws SQLException { // Arrange when(mockRs.getString(any())).thenReturn(""); - when(mockRs.getString("DF_CONTENT")).thenReturn("workZone"); - when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999l); + when(mockRs.getLong("ACTIVE_TIM_ID")).thenReturn(999L); // Act - ResponseEntity tum = uut.GetUpdateModelFromActiveTimId(999l); + ResponseEntity tum = uut.GetUpdateModelFromActiveTimId(999L); // Assert Assertions.assertEquals(HttpStatus.OK, tum.getStatusCode()); Assertions.assertNotNull(tum.getBody()); - Assertions.assertEquals(ContentEnum.workZone, tum.getBody().getDfContent()); + Assertions.assertEquals(ContentEnum.advisory, tum.getBody().getDfContent()); } @Test @@ -191,7 +189,7 @@ public void UpdateActiveTim_SatRecordId_FAIL() { doReturn(false).when(mockDbInteractions).updateOrDelete(mockPreparedStatement); // Act - ResponseEntity success = uut.updateActiveTim_SatRecordId(-1l, "asdf"); + ResponseEntity success = uut.updateActiveTim_SatRecordId(-1L, "asdf"); // Assert Assertions.assertFalse(success.getBody(), "UpdateActiveTim_SatRecordId succeeded when it should have failed"); @@ -204,7 +202,7 @@ public void UpdateActiveTim_SatRecordId_SUCCESS() { doReturn(true).when(mockDbInteractions).updateOrDelete(mockPreparedStatement); // Act - ResponseEntity success = uut.updateActiveTim_SatRecordId(-1l, "asdf"); + ResponseEntity success = uut.updateActiveTim_SatRecordId(-1L, "asdf"); // Assert Assertions.assertTrue(success.getBody(), "UpdateActiveTim_SatRecordId failed when it should have succeeded"); @@ -216,7 +214,7 @@ public void UpdateActiveTim_SatRecordId_EXCEPTION() throws SQLException { doThrow(new SQLException()).when(mockDbInteractions).getConnectionPool(); // Act - ResponseEntity success = uut.updateActiveTim_SatRecordId(-1l, "asdf"); + ResponseEntity success = uut.updateActiveTim_SatRecordId(-1L, "asdf"); // Assert Assertions.assertFalse(success.getBody(), "UpdateActiveTim_SatRecordId was successful during an error"); @@ -388,9 +386,8 @@ public void GetActiveTimIndicesByRsu_SUCCESS() throws SQLException { String selectStatement = "select tim_rsu.rsu_index from active_tim"; selectStatement += " inner join tim on active_tim.tim_id = tim.tim_id"; selectStatement += " inner join tim_rsu on tim_rsu.tim_id = tim.tim_id"; - selectStatement += " inner join rsu on rsu.rsu_id = tim_rsu.rsu_id"; - selectStatement += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; - selectStatement += " where rsu_view.ipv4_address = '" + rsuTarget + "'"; + selectStatement += " inner join rsus on rsus.rsu_id = tim_rsu.rsu_id"; + selectStatement += " where rsus.ipv4_address = '" + rsuTarget + "'"; // Act ResponseEntity> data = uut.GetActiveTimIndicesByRsu(rsuTarget); @@ -411,9 +408,8 @@ public void GetActiveTimIndicesByRsu_FAIL() throws SQLException { String selectStatement = "select tim_rsu.rsu_index from active_tim"; selectStatement += " inner join tim on active_tim.tim_id = tim.tim_id"; selectStatement += " inner join tim_rsu on tim_rsu.tim_id = tim.tim_id"; - selectStatement += " inner join rsu on rsu.rsu_id = tim_rsu.rsu_id"; - selectStatement += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; - selectStatement += " where rsu_view.ipv4_address = '" + rsuTarget + "'"; + selectStatement += " inner join rsus on rsus.rsu_id = tim_rsu.rsu_id"; + selectStatement += " where rsus.ipv4_address = '" + rsuTarget + "'"; doThrow(new SQLException()).when(mockRs).getInt("RSU_INDEX"); // Act @@ -431,7 +427,7 @@ public void GetActiveTimIndicesByRsu_FAIL() throws SQLException { public void GetActiveTimsByClientIdDirection_SUCCESS() throws SQLException { // Arrange String clientId = "clientId"; - Long timTypeId = -1l; + Long timTypeId = -1L; String direction = "eastward"; String selectStatement = "select * from active_tim where CLIENT_ID like '" + clientId + "' and TIM_TYPE_ID = " + timTypeId; selectStatement += " and DIRECTION = '" + direction + "'"; @@ -465,7 +461,7 @@ public void GetActiveTimsByClientIdDirection_SUCCESS() throws SQLException { public void GetActiveTimsByClientIdDirection_FAIL() throws SQLException { // Arrange String clientId = "clientId"; - Long timTypeId = -1l; + Long timTypeId = -1L; String direction = "eastward"; String selectStatement = "select * from active_tim where CLIENT_ID like '" + clientId + "' and TIM_TYPE_ID = " + timTypeId; selectStatement += " and DIRECTION = '" + direction + "'"; @@ -487,7 +483,8 @@ public void GetActiveTimsByClientIdDirection_FAIL() throws SQLException { public void GetBufferTimsByClientId_SUCCESS() throws SQLException { // Arrange String clientId = "clientId"; - String selectStatement = "select * from active_tim where CLIENT_ID like '" + clientId + "\\%BUFF_-%' ESCAPE '\\'"; + String selectStatement = "select * from active_tim where CLIENT_ID like '" + clientId + + "\\%BUFF-%' ESCAPE '\\'"; // Act ResponseEntity> data = uut.GetBufferTimsByClientId(clientId); @@ -518,7 +515,8 @@ public void GetBufferTimsByClientId_FAIL() throws SQLException { // Arrange String clientId = "clientId"; - String selectStatement = "select * from active_tim where CLIENT_ID like '" + clientId + "\\%BUFF_-%' ESCAPE '\\'"; + String selectStatement = "select * from active_tim where CLIENT_ID like '" + clientId + + "\\%BUFF-%' ESCAPE '\\'"; doThrow(new SQLException()).when(mockRs).getLong("ACTIVE_TIM_ID"); @@ -536,7 +534,7 @@ public void GetBufferTimsByClientId_FAIL() throws SQLException { @Test public void GetItisCodesForActiveTim_SUCCESS() throws SQLException { // Arrange - Long activeTimId = -1l; + Long activeTimId = -1L; String selectStatement = "select itis_code from active_tim "; selectStatement += "inner join tim on tim.tim_id = active_tim.tim_id "; selectStatement += "inner join data_frame on tim.tim_id = data_frame.tim_id "; @@ -560,7 +558,7 @@ public void GetItisCodesForActiveTim_SUCCESS() throws SQLException { @Test public void GetItisCodesForActiveTim_FAIL() throws SQLException { // Arrange - Long activeTimId = -1l; + Long activeTimId = -1L; String selectStatement = "select itis_code from active_tim inner join tim on tim.tim_id = active_tim.tim_id inner join data_frame on tim.tim_id = data_frame.tim_id inner join data_frame_itis_code on data_frame_itis_code.data_frame_id = data_frame.data_frame_id inner join itis_code on data_frame_itis_code.itis_code_id = itis_code.itis_code_id where active_tim_id = " + activeTimId + " order by data_frame_itis_code.position asc"; @@ -580,7 +578,7 @@ public void GetItisCodesForActiveTim_FAIL() throws SQLException { @Test public void DeleteActiveTim_SUCCESS() throws SQLException { // Arrange - Long activeTimId = -1l; + Long activeTimId = -1L; // Act ResponseEntity data = uut.DeleteActiveTim(activeTimId); @@ -596,7 +594,7 @@ public void DeleteActiveTim_SUCCESS() throws SQLException { @Test public void DeleteActiveTim_FAIL() throws SQLException { // Arrange - Long activeTimId = -1l; + Long activeTimId = -1L; doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, activeTimId); // Act @@ -624,7 +622,7 @@ public void DeleteActiveTimsById_SUCCESS() throws SQLException { Assertions.assertEquals(HttpStatus.OK, data.getStatusCode()); Assertions.assertTrue(data.getBody(), "Fail return on success"); verify(mockConnection).prepareStatement("DELETE FROM ACTIVE_TIM WHERE ACTIVE_TIM_ID in (?)"); - verify(mockPreparedStatement).setLong(1, -1l); + verify(mockPreparedStatement).setLong(1, -1L); verify(mockPreparedStatement).close(); verify(mockConnection).close(); } @@ -634,7 +632,7 @@ public void DeleteActiveTimsById_FAIL() throws SQLException { // Arrange List activeTimIds = new ArrayList<>(); activeTimIds.add(Long.valueOf(-1)); - doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, -1l); + doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, -1L); // Act ResponseEntity data = uut.DeleteActiveTimsById(activeTimIds); @@ -653,7 +651,7 @@ public void GetActiveTimsByIds_SUCCESS() throws SQLException { String query = "select * from active_tim where active_tim_id in (?, ?)"; // Act - var response = uut.GetActiveTimsByIds(Arrays.asList(-1l, -2l)); + var response = uut.GetActiveTimsByIds(Arrays.asList(-1L, -2L)); // Assert Assertions.assertEquals(HttpStatus.OK, response.getStatusCode()); @@ -666,10 +664,10 @@ public void GetActiveTimsByIds_SUCCESS() throws SQLException { public void GetActiveTimsByIds_FAIL() throws SQLException { // Arrange String query = "select * from active_tim where active_tim_id in (?, ?)"; - doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, -1l); + doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, -1L); // Act - var response = uut.GetActiveTimsByIds(Arrays.asList(-1l, -2l)); + var response = uut.GetActiveTimsByIds(Arrays.asList(-1L, -2L)); // Assert Assertions.assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); @@ -697,7 +695,7 @@ public void GetActiveTimsByWydotTim_SUCCESS() throws SQLException { wydotTim.setClientId("clientId"); wydotTim.setDirection("westward"); wydotTims.add(wydotTim); - Long timTypeId = -1l; + Long timTypeId = -1L; String query = "select * from active_tim where TIM_TYPE_ID = ? and ((CLIENT_ID like ? and DIRECTION = ?))"; // Act @@ -735,7 +733,7 @@ public void GetActiveTimsByWydotTim_BothDirections() throws SQLException { wydotTim.setClientId("clientId"); wydotTim.setDirection("B"); wydotTims.add(wydotTim); - Long timTypeId = -1l; + Long timTypeId = -1L; String query = "select * from active_tim where TIM_TYPE_ID = ? and ((CLIENT_ID like ?))"; // Act @@ -772,7 +770,7 @@ public void GetActiveTimsByWydotTim_FAIL() throws SQLException { wydotTim.setClientId("clientId"); wydotTim.setDirection("westward"); wydotTims.add(wydotTim); - Long timTypeId = -1l; + Long timTypeId = -1L; String query = "select * from active_tim where TIM_TYPE_ID = ? and ((CLIENT_ID like ? and DIRECTION = ?))"; doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, timTypeId); @@ -790,7 +788,7 @@ public void GetActiveTimsByWydotTim_FAIL() throws SQLException { @Test public void GetActivesTimByType_SUCCESS() throws SQLException { // Arrange - Long timTypeId = -1l; + Long timTypeId = -1L; String query = "select * from active_tim where TIM_TYPE_ID = " + timTypeId; // Act @@ -822,7 +820,7 @@ public void GetActivesTimByType_SUCCESS() throws SQLException { @Test public void GetActivesTimByType_FAIL() throws SQLException { // Arrange - Long timTypeId = -1l; + Long timTypeId = -1L; String query = "select * from active_tim where TIM_TYPE_ID = " + timTypeId; doThrow(new SQLException()).when(mockRs).getLong("ACTIVE_TIM_ID"); @@ -928,8 +926,7 @@ public void GetActiveRsuTim_SUCCESS() throws SQLException { String ipv4Address = "10.0.0.1"; String query = "select * from active_tim"; query += " inner join tim_rsu on active_tim.tim_id = tim_rsu.tim_id"; - query += " inner join rsu on tim_rsu.rsu_id = rsu.rsu_id"; - query += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; + query += " inner join rsus on tim_rsu.rsu_id = rsus.rsu_id"; query += " where ipv4_address = '" + ipv4Address + "' and client_id = '" + clientId; query += "' and active_tim.direction = '" + direction + "'"; @@ -967,8 +964,7 @@ public void GetActiveRsuTim_FAIL() throws SQLException { String ipv4Address = "10.0.0.1"; String query = "select * from active_tim"; query += " inner join tim_rsu on active_tim.tim_id = tim_rsu.tim_id"; - query += " inner join rsu on tim_rsu.rsu_id = rsu.rsu_id"; - query += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; + query += " inner join rsus on tim_rsu.rsu_id = rsus.rsu_id"; query += " where ipv4_address = '" + ipv4Address + "' and client_id = '" + clientId; query += "' and active_tim.direction = '" + direction + "'"; doThrow(new SQLException()).when(mockStatement).executeQuery(query); @@ -1189,7 +1185,7 @@ public void ResetExpirationDate_SUCCESS() throws SQLException { Assertions.assertEquals(HttpStatus.OK, data.getStatusCode()); Assertions.assertTrue(data.getBody(), "Fail return on success"); verify(mockConnection).prepareStatement("UPDATE ACTIVE_TIM SET EXPIRATION_DATE = NULL WHERE ACTIVE_TIM_ID IN (?)"); - verify(mockPreparedStatement).setLong(1, -1l); + verify(mockPreparedStatement).setLong(1, -1L); verify(mockPreparedStatement).close(); verify(mockConnection).close(); } @@ -1239,7 +1235,7 @@ public void ResetExpirationDate_FAIL() throws SQLException { // Arrange List activeTimIds = new ArrayList<>(); activeTimIds.add(Long.valueOf(-1)); - doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, -1l); + doThrow(new SQLException()).when(mockPreparedStatement).setLong(1, -1L); // Act ResponseEntity data = uut.ResetExpirationDate(activeTimIds); diff --git a/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/CdotUpstreamPathControllerTest.java b/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/CdotUpstreamPathControllerTest.java new file mode 100644 index 000000000..73a7caf36 --- /dev/null +++ b/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/CdotUpstreamPathControllerTest.java @@ -0,0 +1,312 @@ +package com.trihydro.cvdatacontroller.controller; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.trihydro.cvdatacontroller.controller.CdotUpstreamPathController.DistanceCalculator; +import com.trihydro.cvdatacontroller.controller.CdotUpstreamPathController.PathDirection; +import com.trihydro.library.helpers.CdotGisConnector; +import com.trihydro.library.model.Milepost; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +class CdotUpstreamPathControllerTest { + private final String ROUTE_ID = "025A"; // I-25 + private final String PATH_TO_ROUTE_JSON_TEST_DATA = + "src/test/resources/com/trihydro/cvdatacontroller/controller/cdotRouteResponseForI25_First30Mileposts.json"; + + @Mock + CdotGisConnector cdotGisService = Mockito.mock(CdotGisConnector.class); + + @InjectMocks + CdotUpstreamPathController uut; + + List getMockMileposts() throws IOException { + String routeJsonString = + new String(Files.readAllBytes(Paths.get(PATH_TO_ROUTE_JSON_TEST_DATA))); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(routeJsonString); + JsonNode pathNode = rootNode.path("features").get(0).path("geometry").path("paths").get(0); + List mileposts = new ArrayList<>(); + for (JsonNode node : pathNode) { + Milepost milepost = new Milepost(); + milepost.setCommonName(ROUTE_ID); + BigDecimal latitude = new BigDecimal(node.get(1).asText()).setScale(14, RoundingMode.HALF_UP); + BigDecimal longitude = + new BigDecimal(node.get(0).asText()).setScale(14, RoundingMode.HALF_UP); + milepost.setLatitude(latitude); + milepost.setLongitude(longitude); + mileposts.add(milepost); + } + return mileposts; + } + + @BeforeEach + void setUp() { + uut = new CdotUpstreamPathController(cdotGisService); + } + + @Test + void testGetMilepostsForRoute() throws IOException { + // prepare + String routeJsonString = + new String(Files.readAllBytes(Paths.get(PATH_TO_ROUTE_JSON_TEST_DATA))); + ResponseEntity mockResponse = new ResponseEntity<>(routeJsonString, HttpStatus.OK); + when(cdotGisService.getRouteById(ROUTE_ID)).thenReturn(mockResponse); + List expectedMileposts = getMockMileposts(); + + // execute + List mileposts = uut.getMilepostsForRoute(ROUTE_ID); + + // verify + verify(cdotGisService).getRouteById(ROUTE_ID); + Assertions.assertEquals(expectedMileposts.size(), mileposts.size()); + for (int i = 0; i < expectedMileposts.size(); i++) { + Milepost expected = expectedMileposts.get(i); + Milepost actual = mileposts.get(i); + Assertions.assertEquals(expected.getCommonName(), actual.getCommonName()); + Assertions.assertNull(actual.getMilepost()); + Assertions.assertNull(actual.getDirection()); + Assertions.assertEquals(expected.getLatitude(), actual.getLatitude()); + Assertions.assertEquals(expected.getLongitude(), actual.getLongitude()); + } + } + + @Test + void testGetPathDirection_ASCENDING() + throws IOException, CdotUpstreamPathController.MilepostNotFoundException, + CdotUpstreamPathController.NotEnoughMilepostsException { + // prepare + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(0); + Milepost mp2 = allMileposts.get(1); + List pathMileposts = List.of(mp1, mp2); + + // execute + PathDirection direction = uut.getPathDirection(pathMileposts, allMileposts); + + // verify + Assertions.assertEquals(PathDirection.ASCENDING, direction); + } + + @Test + void testGetPathDirection_DESCENDING() + throws IOException, CdotUpstreamPathController.MilepostNotFoundException, + CdotUpstreamPathController.NotEnoughMilepostsException { + // prepare + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(1); + Milepost mp2 = allMileposts.get(0); + List pathMileposts = List.of(mp1, mp2); + + // execute + PathDirection direction = uut.getPathDirection(pathMileposts, allMileposts); + + // verify + Assertions.assertEquals(PathDirection.DESCENDING, direction); + } + + @Test + void testGetPathDirection_NOT_ENOUGH_MILEPOSTS() + throws IOException { + // prepare + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(0); + List pathMileposts = List.of(mp1); + + // execute + assertThrows(CdotUpstreamPathController.NotEnoughMilepostsException.class, () -> { + uut.getPathDirection(pathMileposts, allMileposts); + }); + } + + @Test + void testGetPathDirection_FirstMilepostOfPathNotInAllMileposts() + throws IOException { + // prepare + List allMileposts = getMockMileposts(); + Milepost mp1 = new Milepost(); + mp1.setCommonName(ROUTE_ID); + mp1.setLatitude(new BigDecimal("30.12").setScale(14, RoundingMode.HALF_UP)); + mp1.setLongitude(new BigDecimal("-100.34").setScale(14, RoundingMode.HALF_UP)); + Milepost mp2 = allMileposts.get(1); + List pathMileposts = List.of(mp1, mp2); + + // execute + assertThrows(CdotUpstreamPathController.MilepostNotFoundException.class, () -> { + uut.getPathDirection(pathMileposts, allMileposts); + }); + } + + @Test + void testGetPathDirection_SecondMilepostOfPathNotInAllMileposts() + throws IOException { + // prepare + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(0); + Milepost mp2 = new Milepost(); + mp2.setCommonName(ROUTE_ID); + mp1.setLatitude(new BigDecimal("30.12").setScale(14, RoundingMode.HALF_UP)); + mp1.setLongitude(new BigDecimal("-100.34").setScale(14, RoundingMode.HALF_UP)); + List pathMileposts = List.of(mp1, mp2); + + // execute + assertThrows(CdotUpstreamPathController.MilepostNotFoundException.class, () -> { + uut.getPathDirection(pathMileposts, allMileposts); + }); + } + + @Test + void testGetBufferForPath_Ascending_Success() throws IOException { + // prepare + String routeJsonString = + new String(Files.readAllBytes(Paths.get(PATH_TO_ROUTE_JSON_TEST_DATA))); + ResponseEntity mockResponse = new ResponseEntity<>(routeJsonString, HttpStatus.OK); + when(cdotGisService.getRouteById(ROUTE_ID)).thenReturn(mockResponse); + + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(20); + Milepost mp2 = allMileposts.get(21); + List pathMileposts = List.of(mp1, mp2); + + double desiredDistanceInMiles = 0.5; + + // execute + ResponseEntity> response = + uut.getBufferForPath(pathMileposts, ROUTE_ID, desiredDistanceInMiles); + + // verify + List buffer = response.getBody(); + assert buffer != null; + Assertions.assertFalse(buffer.isEmpty()); + double distanceInMiles = getDistanceInMiles(buffer); + Assertions.assertTrue(distanceInMiles >= + desiredDistanceInMiles); // buffer should be at least as long as desired distance + Assertions.assertTrue(distanceInMiles <= + desiredDistanceInMiles + 1); // buffer should not be much longer than desired distance + } + + @Test + void testGetBufferForPath_Ascending_Failure_EndOfAllMilepostsReached() throws IOException { + // prepare + String routeJsonString = + new String(Files.readAllBytes(Paths.get(PATH_TO_ROUTE_JSON_TEST_DATA))); + ResponseEntity mockResponse = new ResponseEntity<>(routeJsonString, HttpStatus.OK); + when(cdotGisService.getRouteById(ROUTE_ID)).thenReturn(mockResponse); + + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(1); + Milepost mp2 = allMileposts.get(2); + List pathMileposts = List.of(mp1, mp2); + + double desiredDistanceInMiles = 5.0; + + // execute + ResponseEntity> response = + uut.getBufferForPath(pathMileposts, ROUTE_ID, desiredDistanceInMiles); + + // verify + List buffer = response.getBody(); + Assertions.assertNull(buffer); + } + + @Test + void testGetBufferForPath_Descending_Success() throws IOException { + // prepare + String routeJsonString = + new String(Files.readAllBytes(Paths.get(PATH_TO_ROUTE_JSON_TEST_DATA))); + ResponseEntity mockResponse = new ResponseEntity<>(routeJsonString, HttpStatus.OK); + when(cdotGisService.getRouteById(ROUTE_ID)).thenReturn(mockResponse); + + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(1); + Milepost mp2 = allMileposts.get(0); + List pathMileposts = List.of(mp1, mp2); + + double desiredDistanceInMiles = 0.5; + + // execute + ResponseEntity> response = + uut.getBufferForPath(pathMileposts, ROUTE_ID, desiredDistanceInMiles); + + // verify + List buffer = response.getBody(); + assert buffer != null; + Assertions.assertFalse(buffer.isEmpty()); + double distanceInMiles = getDistanceInMiles(buffer); + Assertions.assertTrue(distanceInMiles >= + desiredDistanceInMiles); // buffer should be at least as long as desired distance + Assertions.assertTrue(distanceInMiles <= + desiredDistanceInMiles + 1); // buffer should not be much longer than desired distance + } + + @Test + void testGetBufferForPath_Descending_Failure_EndOfAllMilepostsReached() throws IOException { + // prepare + String routeJsonString = + new String(Files.readAllBytes(Paths.get(PATH_TO_ROUTE_JSON_TEST_DATA))); + ResponseEntity mockResponse = new ResponseEntity<>(routeJsonString, HttpStatus.OK); + when(cdotGisService.getRouteById(ROUTE_ID)).thenReturn(mockResponse); + + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(28); + Milepost mp2 = allMileposts.get(27); + List pathMileposts = List.of(mp1, mp2); + + double desiredDistanceInMiles = 5.0; + + // execute + ResponseEntity> response = + uut.getBufferForPath(pathMileposts, ROUTE_ID, desiredDistanceInMiles); + + // verify + List buffer = response.getBody(); + Assertions.assertNull(buffer); + } + + @Test + void testGetBufferForPath_PathDirectionIsNull() throws IOException { + // prepare + String routeJsonString = + new String(Files.readAllBytes(Paths.get(PATH_TO_ROUTE_JSON_TEST_DATA))); + ResponseEntity mockResponse = new ResponseEntity<>(routeJsonString, HttpStatus.OK); + when(cdotGisService.getRouteById(ROUTE_ID)).thenReturn(mockResponse); + + List allMileposts = getMockMileposts(); + Milepost mp1 = allMileposts.get(0); + List pathMileposts = List.of(mp1); + + int desiredDistanceInMiles = 5; + + // execute + ResponseEntity> response = + uut.getBufferForPath(pathMileposts, ROUTE_ID, desiredDistanceInMiles); + + // verify + List buffer = response.getBody(); + Assertions.assertNull(buffer); + } + + private double getDistanceInMiles(List buffer) { + return DistanceCalculator.calculateDistanceInMiles(buffer); + } + +} \ No newline at end of file diff --git a/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/RsuControllerTest.java b/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/RsuControllerTest.java index 0eaeaa6a6..e220dc46e 100644 --- a/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/RsuControllerTest.java +++ b/cv-data-controller/src/test/java/com/trihydro/cvdatacontroller/controller/RsuControllerTest.java @@ -1,27 +1,26 @@ package com.trihydro.cvdatacontroller.controller; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import com.trihydro.library.model.WydotRsu; -import com.trihydro.library.model.WydotRsuTim; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import com.trihydro.library.model.WydotRsu; +import com.trihydro.library.model.WydotRsuTim; + public class RsuControllerTest extends TestBase { @Test public void SelectAllRsus_SUCCESS() throws SQLException { // Arrange - String selectStatement = "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid order by milepost asc"; + String selectStatement = "select rsu_id, ST_X(ST_AsText(geography)) as longitude, ST_Y(ST_AsText(geography)) as latitude, ipv4_address, primary_route, milepost from rsus order by milepost asc"; // Act ResponseEntity> data = uut.SelectAllRsus(); @@ -33,7 +32,7 @@ public void SelectAllRsus_SUCCESS() throws SQLException { verify(mockRs).getString("IPV4_ADDRESS"); verify(mockRs).getBigDecimal("LATITUDE"); verify(mockRs).getBigDecimal("LONGITUDE"); - verify(mockRs).getString("ROUTE"); + verify(mockRs).getString("PRIMARY_ROUTE"); verify(mockRs).getDouble("MILEPOST"); verify(mockStatement).close(); verify(mockConnection).close(); @@ -43,7 +42,7 @@ public void SelectAllRsus_SUCCESS() throws SQLException { @Test public void SelectAllRsus_FAIL() throws SQLException { // Arrange - String selectStatement = "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid order by milepost asc"; + String selectStatement = "select rsu_id, ST_X(ST_AsText(geography)) as longitude, ST_Y(ST_AsText(geography)) as latitude, ipv4_address, primary_route, milepost from rsus order by milepost asc"; doThrow(new SQLException()).when(mockRs).getInt("RSU_ID"); // Act ResponseEntity> data = uut.SelectAllRsus(); @@ -56,49 +55,15 @@ public void SelectAllRsus_FAIL() throws SQLException { verify(mockRs).close(); } - @Test - public void SelectActiveRsus_SUCCESS() throws SQLException { - // Arrange - String selectStatement = "select rsu.*, rsu_view.latitude, rsu_view.longitude, rsu_view.ipv4_address from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid where rsu_view.status = 'Existing'"; - - // Act - ResponseEntity> data = uut.SelectActiveRsus(); - - // Assert - Assertions.assertEquals(HttpStatus.OK, data.getStatusCode()); - verify(mockStatement).executeQuery(selectStatement); - verify(mockRs).getString("IPV4_ADDRESS"); - verify(mockRs).getBigDecimal("LATITUDE"); - verify(mockRs).getBigDecimal("LONGITUDE"); - verify(mockStatement).close(); - verify(mockConnection).close(); - verify(mockRs).close(); - } - - @Test - public void SelectActiveRsus_FAIL() throws SQLException { - // Arrange - String selectStatement = "select rsu.*, rsu_view.latitude, rsu_view.longitude, rsu_view.ipv4_address from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid where rsu_view.status = 'Existing'"; - doThrow(new SQLException()).when(mockRs).getString("IPV4_ADDRESS"); - - // Act - ResponseEntity> data = uut.SelectActiveRsus(); - - // Assert - Assertions.assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, data.getStatusCode()); - verify(mockStatement).executeQuery(selectStatement); - verify(mockStatement).close(); - verify(mockConnection).close(); - verify(mockRs).close(); - } - @Test public void GetFullRsusTimIsOn_SUCCESS() throws SQLException { // Arrange Long timId = -1l; - String selectStatement = "select rsu.*, tim_rsu.rsu_index, rsu_view.latitude, rsu_view.longitude, rsu_view.ipv4_address "; - selectStatement += "from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid "; - selectStatement += "inner join tim_rsu on tim_rsu.rsu_id = rsu.rsu_id where tim_rsu.tim_id = " + timId; + String selectStatement = "select rsus.rsu_id, rsu_credentials.username as update_username, " + + "rsu_credentials.password as update_password, ST_X(ST_AsText(rsus.geography)) as longitude, " + + "ST_Y(ST_AsText(rsus.geography)) as latitude, rsus.ipv4_address, tim_rsu.rsu_index from rsus " + + "inner join rsu_credentials on rsu_credentials.credential_id = rsus.credential_id inner join " + + "tim_rsu on tim_rsu.rsu_id = rsus.rsu_id where tim_rsu.tim_id = " + timId; // Act ResponseEntity> data = uut.GetFullRsusTimIsOn(timId); @@ -121,8 +86,11 @@ public void GetFullRsusTimIsOn_SUCCESS() throws SQLException { public void GetFullRsusTimIsOn_FAIL() throws SQLException { // Arrange Long timId = -1l; - String selectStatement = "select rsu.*, tim_rsu.rsu_index, rsu_view.latitude, rsu_view.longitude, rsu_view.ipv4_address from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid inner join tim_rsu on tim_rsu.rsu_id = rsu.rsu_id where tim_rsu.tim_id = " - + timId; + String selectStatement = "select rsus.rsu_id, rsu_credentials.username as update_username, " + + "rsu_credentials.password as update_password, ST_X(ST_AsText(rsus.geography)) as longitude, " + + "ST_Y(ST_AsText(rsus.geography)) as latitude, rsus.ipv4_address, tim_rsu.rsu_index from rsus " + + "inner join rsu_credentials on rsu_credentials.credential_id = rsus.credential_id inner join " + + "tim_rsu on tim_rsu.rsu_id = rsus.rsu_id where tim_rsu.tim_id = " + timId; doThrow(new SQLException()).when(mockRs).getString("IPV4_ADDRESS"); // Act @@ -140,8 +108,9 @@ public void GetFullRsusTimIsOn_FAIL() throws SQLException { public void SelectRsusByRoute_SUCCESS() throws SQLException { // Arrange String route = "I80"; - String selectStatement = "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid where rsu_view.route like '%" - + route + "%' and rsu_view.status = 'Existing' order by milepost asc"; + String selectStatement = "select rsu_id, ST_X(ST_AsText(geography)) as longitude, " + + "ST_Y(ST_AsText(geography)) as latitude, ipv4_address, primary_route, milepost from rsus " + + "where primary_route like '%" + route + "%'"; // Act ResponseEntity> data = uut.SelectRsusByRoute(route); @@ -163,8 +132,9 @@ public void SelectRsusByRoute_SUCCESS() throws SQLException { public void SelectRsusByRoute_FAIL() throws SQLException { // Arrange String route = "I80"; - String selectStatement = "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid where rsu_view.route like '%" - + route + "%' and rsu_view.status = 'Existing' order by milepost asc"; + String selectStatement = "select rsu_id, ST_X(ST_AsText(geography)) as longitude, " + + "ST_Y(ST_AsText(geography)) as latitude, ipv4_address, primary_route, milepost from rsus " + + "where primary_route like '%" + route + "%'"; doThrow(new SQLException()).when(mockRs).getInt("RSU_ID"); // Act ResponseEntity> data = uut.SelectRsusByRoute(route); diff --git a/cv-data-controller/src/test/resources/com/trihydro/cvdatacontroller/controller/cdotRouteResponseForI25_First30Mileposts.json b/cv-data-controller/src/test/resources/com/trihydro/cvdatacontroller/controller/cdotRouteResponseForI25_First30Mileposts.json new file mode 100644 index 000000000..7306d9b14 --- /dev/null +++ b/cv-data-controller/src/test/resources/com/trihydro/cvdatacontroller/controller/cdotRouteResponseForI25_First30Mileposts.json @@ -0,0 +1,180 @@ +{ + "displayFieldName": "", + "fieldAliases": { + "OBJECTID": "OBJECTID", + "Route": "Route", + "MMin": "MMin", + "MMax": "MMax", + "SHAPE_Length": "SHAPE_Length" + }, + "geometryType": "esriGeometryPolyline", + "spatialReference": { + "wkid": 4326, + "latestWkid": 4326 + }, + "fields": [ + { + "name": "OBJECTID", + "type": "esriFieldTypeOID", + "alias": "OBJECTID" + }, + { + "name": "Route", + "type": "esriFieldTypeString", + "alias": "Route", + "length": 90 + }, + { + "name": "MMin", + "type": "esriFieldTypeDouble", + "alias": "MMin" + }, + { + "name": "MMax", + "type": "esriFieldTypeDouble", + "alias": "MMax" + }, + { + "name": "SHAPE_Length", + "type": "esriFieldTypeDouble", + "alias": "SHAPE_Length" + } + ], + "features": [ + { + "attributes": { + "OBJECTID": 1, + "Route": "025A", + "MMin": -0, + "MMax": 298.87900000000002, + "SHAPE_Length": 4.4977027441765571 + }, + "geometry": { + "paths": [ + [ + [ + -104.48045588599996, + 36.993878229000074 + ], + [ + -104.48050318099996, + 36.994486232000042 + ], + [ + -104.48065092399997, + 36.995038290000025 + ], + [ + -104.48070509599995, + 36.99524070700005 + ], + [ + -104.48080757499997, + 36.995446935000075 + ], + [ + -104.48084011699996, + 36.995512422000047 + ], + [ + -104.48109407099997, + 36.995913712000061 + ], + [ + -104.48129848999997, + 36.996175908000055 + ], + [ + -104.48187755499998, + 36.996844846000045 + ], + [ + -104.48219789199999, + 36.99729805000004 + ], + [ + -104.48243650499995, + 36.997797080000055 + ], + [ + -104.48248663299995, + 36.997977548000051 + ], + [ + -104.48255274299999, + 36.998345181000047 + ], + [ + -104.48256583299997, + 36.998729557000047 + ], + [ + -104.48252486699994, + 36.999069289000033 + ], + [ + -104.48251842099995, + 36.999122742000054 + ], + [ + -104.48241381599996, + 36.999516043000028 + ], + [ + -104.48041568299999, + 37.005994416000078 + ], + [ + -104.48016812399999, + 37.006796975000043 + ], + [ + -104.48006938599997, + 37.007213985000078 + ], + [ + -104.48000987099999, + 37.007636323000042 + ], + [ + -104.48000904399998, + 37.007642192000048 + ], + [ + -104.47999405199994, + 37.00807076600006 + ], + [ + -104.48002256199999, + 37.008504324000057 + ], + [ + -104.48009628499995, + 37.008939769000051 + ], + [ + -104.48021678199996, + 37.009374874000059 + ], + [ + -104.48030103699995, + 37.009608998000033 + ], + [ + -104.48237161199995, + 37.015362141000026 + ], + [ + -104.48260622599997, + 37.01598049100005 + ], + [ + -104.48277556599999, + 37.016368185000033 + ] + ] + ] + } + } + ] +} \ No newline at end of file diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/factory/KafkaFactory.java b/cv-data-service-library/src/main/java/com/trihydro/library/factory/KafkaFactory.java index b8d1c1a79..b7d19ebb7 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/factory/KafkaFactory.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/factory/KafkaFactory.java @@ -4,23 +4,35 @@ import java.util.List; import java.util.Properties; -import com.trihydro.library.helpers.Utility; - import org.apache.commons.lang3.StringUtils; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.Producer; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +import com.google.common.base.Strings; +import com.trihydro.library.helpers.Utility; + @Component +@ConfigurationProperties("data-service-library.kafka") public class KafkaFactory { - private Utility utility; + private final Utility utility; + private String kafkaType; + private String confluentKey; + private String confluentSecret; + private final Properties kafkaProperties; - @Autowired - public KafkaFactory(Utility _utility) { + public KafkaFactory(Utility _utility) throws IllegalArgumentException { utility = _utility; + kafkaType = getKafkaType(); + + if ("CONFLUENT".equalsIgnoreCase(kafkaType)) { + kafkaProperties = addConfluentProperties(new Properties()); + } else { + kafkaProperties = new Properties(); + } } /** @@ -109,6 +121,8 @@ public Consumer createStringConsumer(String host, String consume props.put("max.poll.records", maxPollRecords.intValue()); } + props.putAll(kafkaProperties); + var consumer = new KafkaConsumer(props); consumer.subscribe(topics); @@ -131,6 +145,51 @@ public Producer createStringProducer(String host) { props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); - return new KafkaProducer(props); + props.putAll(kafkaProperties); + + return new KafkaProducer<>(props); + } + + Properties addConfluentProperties(Properties props) { + String username = getConfluentKey(); + String password = getConfluentSecret(); + + if (Strings.isNullOrEmpty(username) || Strings.isNullOrEmpty(password)) { + throw new IllegalArgumentException("CONFLUENT_KEY and CONFLUENT_SECRET must be set in the environment"); + } + + String auth = "org.apache.kafka.common.security.plain.PlainLoginModule required " + + "username=\"" + username + "\" " + + "password=\"" + password + "\";"; + props.put("sasl.jaas.config", auth); + props.put("ssl.endpoint.identification.algorithm", "https"); + props.put("security.protocol", "SASL_SSL"); + props.put("sasl.mechanism", "PLAIN"); + + return props; + } + + final String getKafkaType() { + return kafkaType; + } + + public String getConfluentKey() { + return confluentKey; + } + + public void setConfluentKey(String confluentKey) { + this.confluentKey = confluentKey; + } + + public String getConfluentSecret() { + return confluentSecret; + } + + public void setConfluentSecret(String confluentSecret) { + this.confluentSecret = confluentSecret; + } + + public void setKafkaType(String kafkaType) { + this.kafkaType = kafkaType; } } \ No newline at end of file diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/helpers/CdotGisConnector.java b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/CdotGisConnector.java new file mode 100644 index 000000000..9271ad75f --- /dev/null +++ b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/CdotGisConnector.java @@ -0,0 +1,54 @@ +package com.trihydro.library.helpers; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; + +import com.trihydro.library.service.RestTemplateProvider; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestClientException; + +@Component +public class CdotGisConnector { + private final String baseUrl = "https://dtdapps.coloradodot.info/arcgis/rest/services/LRS/Routes_withDEC/MapServer/exts/CdotLrsAccessRounded"; + + private final RestTemplateProvider restTemplateProvider; + + private final Logger logger = LoggerFactory.getLogger(CdotGisConnector.class); + + public CdotGisConnector(RestTemplateProvider _restTemplateProvider) { + this.restTemplateProvider = _restTemplateProvider; + } + + public String getBaseUrl() { + return baseUrl; + } + + public RestTemplateProvider getRestTemplateProvider() { + return restTemplateProvider; + } + + /** + * Retrieves the route information from the CDOT GIS service by route ID. + * + *

This method sends a GET request to the CDOT GIS service to retrieve the route information + * in JSON format. The JSON response includes every latitude and longitude point associated + * with the specified route, such as I-25.

+ * + * @param routeId the ID of the route to retrieve + * @return a ResponseEntity containing the JSON response from the CDOT GIS service + * @throws RestClientException if an error occurs while making the request + */ + public ResponseEntity getRouteById(String routeId) throws RestClientException { + String targetUrl = baseUrl + "/Route"; + logger.info("Getting route with ID {} from CDOT GIS service at: {}", routeId, targetUrl); + String params = "?routeId=" + routeId + "&outSR=4326&f=json"; + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", "application/json"); + HttpEntity entity = new HttpEntity<>(headers); + return restTemplateProvider.GetRestTemplate().exchange(targetUrl + params, HttpMethod.GET, entity, String.class); + } +} diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/helpers/CreateBaseTimUtil.java b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/CreateBaseTimUtil.java index 52174c1f5..eab962ed8 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/helpers/CreateBaseTimUtil.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/CreateBaseTimUtil.java @@ -22,10 +22,8 @@ import us.dot.its.jpo.ode.plugin.j2735.OdePosition3D; import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage; import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.DataFrame.MsgId; -import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.DataFrame.RoadSignID; import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.NodeXY; import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; -import us.dot.its.jpo.ode.plugin.j2735.timstorage.MutcdCode.MutcdCodeEnum; @Component public class CreateBaseTimUtil { @@ -42,16 +40,17 @@ public void InjectDependencies(Utility _utility) { * * @param wydotTim The WydotTim object containing the data for the TIM. * @param genProps The TimGenerationProps object containing the generation properties. - * @param content The ContentEnum object representing the content of the TIM. * @param frameType The TravelerInfoType object representing the frame type of the TIM. * @param allMileposts The list of Milepost objects representing all mileposts. * @param reducedMileposts The list of Milepost objects representing reduced mileposts. * @param anchor The Milepost object representing the anchor milepost. * @return The WydotTravelerInputData object containing the built TIM. */ - public WydotTravelerInputData buildTim(WydotTim wydotTim, TimGenerationProps genProps, ContentEnum content, + public WydotTravelerInputData buildTim(WydotTim wydotTim, TimGenerationProps genProps, TravelerInfoType frameType, List allMileposts, List reducedMileposts, Milepost anchor) { + ContentEnum content = ContentEnum.advisory; + // build TIM object with data WydotTravelerInputData timToSend = new WydotTravelerInputData(); OdeTravelerInformationMessage tim = new OdeTravelerInformationMessage(); @@ -77,13 +76,10 @@ public WydotTravelerInputData buildTim(WydotTim wydotTim, TimGenerationProps gen // add itis codes to tim dataFrame.setItems(wydotTim.getItisCodes().toArray(new String[wydotTim.getItisCodes().size()])); - // create anchor for the msgId - OdePosition3D anchorPosition = new OdePosition3D(); - anchorPosition.setLatitude(anchor.getLatitude()); - anchorPosition.setLongitude(anchor.getLongitude()); - - // build msgId - MsgId msgId = buildMsgId(anchorPosition, content, frameType); + // Per CTW guidance, msgId must be populated using furtherInfoID (not roadSignID) + // Since furtherInfoID is not used, set it to the default value of 0 + MsgId msgId = new MsgId(); + msgId.setFurtherInfoID("0"); dataFrame.setMsgId(msgId); // set regions. note that we now support multiple regions in a single TIM package @@ -195,7 +191,7 @@ protected OdeTravelerInformationMessage.DataFrame.Region buildSingleRegion(BigDe region.setDirection(directionString); // heading slice // set path nodes - if (reducedMileposts != null && reducedMileposts.size() > 0) { + if (reducedMileposts != null && !reducedMileposts.isEmpty()) { OdeTravelerInformationMessage.NodeXY[] nodes = buildNodePathFromMileposts(reducedMileposts, anchor); OdeTravelerInformationMessage.DataFrame.Region.Path path = new OdeTravelerInformationMessage.DataFrame.Region.Path(); path.setScale(0); @@ -243,7 +239,7 @@ public String buildHeadingSliceFromMileposts(List allMileposts, OdePos int timDirection = 0; // this is a regular tim, so we need to set the direction normally // path list - change later - if (allMileposts != null && allMileposts.size() > 0) { + if (allMileposts != null && !allMileposts.isEmpty()) { double startLat = anchorPosition.getLatitude().doubleValue(); double startLon = anchorPosition.getLongitude().doubleValue(); for (int j = 0; j < allMileposts.size(); j++) { @@ -266,30 +262,4 @@ public String buildHeadingSliceFromMileposts(List allMileposts, OdePos headingSliceString = StringUtils.reverse(headingSliceString); return headingSliceString; } - - /** - * Builds a message ID based on the provided anchor position, content, and frame type. - * - * @param anchorPosition The anchor position for the road sign. - * @param content The content of the message. - * @param frameType The type of the frame. - * @return The built message ID. - */ - protected MsgId buildMsgId(OdePosition3D anchorPosition, ContentEnum content, TravelerInfoType frameType) { - MsgId msgId = new MsgId(); - RoadSignID roadSignID = new RoadSignID(); - roadSignID.setPosition(anchorPosition); - - // if we are coming in with content=speedLimit and frameType=roadSignage, - // we need to set the mutcdCode to regulatory to display the regulatory signage - if (content == ContentEnum.speedLimit && frameType == TravelerInfoType.roadSignage) { - roadSignID.setMutcdCode(MutcdCodeEnum.regulatory); - } else { - roadSignID.setMutcdCode(MutcdCodeEnum.warning); - } - // set view angle to 360 degrees - roadSignID.setViewAngle("1111111111111111"); - msgId.setRoadSignID(roadSignID); - return msgId; - } } \ No newline at end of file diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/helpers/JsonToJavaConverter.java b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/JsonToJavaConverter.java index 1709b3751..f7b545a90 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/helpers/JsonToJavaConverter.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/JsonToJavaConverter.java @@ -11,9 +11,10 @@ import java.util.List; import java.util.Map; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import lombok.extern.slf4j.Slf4j; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; @@ -256,16 +257,16 @@ public OdeTimPayload convertTimPayloadJsonToJava(String value) { dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.speedLimit.getStringValue())) { sequenceArrNode = contentNode.get(ContentEnum.speedLimit.getStringValue()).get("SEQUENCE"); - dataFrame.setContent(ContentEnum.speedLimit.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.exitService.getStringValue())) { sequenceArrNode = contentNode.get(ContentEnum.exitService.getStringValue()).get("SEQUENCE"); - dataFrame.setContent(ContentEnum.exitService.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.genericSign.getStringValue())) { sequenceArrNode = contentNode.get(ContentEnum.genericSign.getStringValue()).get("SEQUENCE"); - dataFrame.setContent(ContentEnum.genericSign.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.workZone.getStringValue())) { sequenceArrNode = contentNode.get(ContentEnum.workZone.getStringValue()).get("SEQUENCE"); - dataFrame.setContent(ContentEnum.workZone.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } LocalDate now = LocalDate.now(); @@ -475,56 +476,50 @@ public OdeTimPayload convertTmcTimTopicJsonToJava(String value) { dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.speedLimit.getStringValue())) { sequenceArrNode = contentNode.get("speedLimit"); - dataFrame.setContent(ContentEnum.speedLimit.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.exitService.getStringValue())) { sequenceArrNode = contentNode.get("exitService"); - dataFrame.setContent(ContentEnum.exitService.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.genericSign.getStringValue())) { sequenceArrNode = contentNode.get("genericSign"); - dataFrame.setContent(ContentEnum.genericSign.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } else if (contentNode.has(ContentEnum.workZone.getStringValue())) { sequenceArrNode = contentNode.get("workZone"); - dataFrame.setContent(ContentEnum.workZone.getStringValue()); + dataFrame.setContent(ContentEnum.advisory.getStringValue()); } List itemsList = new ArrayList<>(); String item = null; if (sequenceArrNode != null && sequenceArrNode.isArray()) { for (final JsonNode objNode : sequenceArrNode) { - if (objNode.get("item").get("itis") != null) { + if (objNode.get("item").get("itis") != null) item = mapper.treeToValue(objNode.get("item").get("itis"), String.class); - } else if (objNode.get("item").get("text") != null) { + else if (objNode.get("item").get("text") != null) item = mapper.treeToValue(objNode.get("item").get("text"), String.class); - } else { - log.warn("'itis' or 'text' not found in item when converting TMC TIM"); - } - if (!itemsList.contains(item)) { + if (!itemsList.contains(item)) itemsList.add(item); - } } } // ADD NON ARRAY ELEMENT if (sequenceArrNode != null && !sequenceArrNode.isArray()) { - if (sequenceArrNode.get("item").get("itis") != null) { + if (sequenceArrNode.get("item").get("itis") != null) item = mapper.treeToValue(sequenceArrNode.get("item").get("itis"), String.class); - } else if (sequenceArrNode.get("item").get("text") != null) { + else if (sequenceArrNode.get("item").get("text") != null) item = mapper.treeToValue(sequenceArrNode.get("item").get("text"), String.class); - } else { - log.warn("'itis' or 'text' not found in item when converting TMC TIM"); - } itemsList.add(item); } // TravelerInfoType.valueOf(); JsonNode frameTypeNode = travelerDataFrame.get("frameType"); - if (frameTypeNode != null && frameTypeNode.fieldNames().hasNext()) { - TravelerInfoType frameType = TravelerInfoType.valueOf(frameTypeNode.fieldNames().next()); - dataFrame.setFrameType(frameType); - } else { - log.warn("frameType not found in TravelerDataFrame when converting TMC TIM. Defaulting to 'advisory'"); - dataFrame.setFrameType(TravelerInfoType.advisory); + if (frameTypeNode != null) { + if (frameTypeNode.fieldNames().hasNext()) { + TravelerInfoType frameType = TravelerInfoType.valueOf(frameTypeNode.fieldNames().next()); + if (frameType != null) { + dataFrame.setFrameType(frameType); + } + } } JsonNode startTimeNode = travelerDataFrame.get("startTime"); @@ -546,7 +541,9 @@ public OdeTimPayload convertTmcTimTopicJsonToJava(String value) { // it as a region if (geographicalPathNode.isObject()) { // single region - regions.add(getRegion(geographicalPathNode)); + JsonNode regionNode = geographicalPathNode; + Region region = getRegion(regionNode); + regions.add(region); } else if (geographicalPathNode.isArray()) { // multiple regions for (final JsonNode regionNode : geographicalPathNode) { diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/helpers/TimGenerationHelper.java b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/TimGenerationHelper.java index f88afdebd..9a4c4c103 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/helpers/TimGenerationHelper.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/helpers/TimGenerationHelper.java @@ -11,7 +11,6 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.List; @@ -20,7 +19,6 @@ import com.trihydro.library.model.ActiveTimError; import com.trihydro.library.model.ActiveTimHolding; import com.trihydro.library.model.ActiveTimValidationResult; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.Coordinate; import com.trihydro.library.model.Milepost; import com.trihydro.library.model.MilepostBuffer; @@ -56,10 +54,7 @@ import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.DataFrame.MsgId; import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.DataFrame.Region; import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.DataFrame.Region.Path; -import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.DataFrame.RoadSignID; -import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.NodeXY; -import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; -import us.dot.its.jpo.ode.plugin.j2735.timstorage.MutcdCode.MutcdCodeEnum; +import us.dot.its.jpo.ode.plugin.j2735.OdeTravelerInformationMessage.NodeXY;; @Component @Slf4j @@ -352,13 +347,22 @@ private WydotTim getWydotTimFromTum(TimUpdateModel tum) { } private List getAllMps(WydotTim wydotTim) { - List allMps; + List allMps = new ArrayList<>(); log.info("Fetching mileposts for regular TIM with client id: {}", wydotTim.getClientId()); if (wydotTim.getEndPoint() != null) { - allMps = milepostService.getMilepostsByStartEndPointDirection(wydotTim); - log.info("Found {} mileposts between {} and {}", allMps.size(), - gson.toJson(wydotTim.getStartPoint()), gson.toJson(wydotTim.getEndPoint())); + if (wydotTim.getGeometry() != null && wydotTim.getGeometry().size() > 1) { + allMps.addAll(wydotTim.toMileposts()); + milepostService.setMilepostCache(allMps, wydotTim.getClientId()); + } else { + // Check to see if milepost array exists in cache + allMps = milepostService.getMilepostCache(wydotTim.getClientId()); + if (allMps.isEmpty()) { + allMps = milepostService.getMilepostsByStartEndPointDirection(wydotTim); + } + } + utility.logWithDate(String.format("Found %d mileposts between %s and %s", allMps.size(), + gson.toJson(wydotTim.getStartPoint()), gson.toJson(wydotTim.getEndPoint()))); } else { // point incident MilepostBuffer mpb = new MilepostBuffer(); @@ -691,7 +695,7 @@ private OdeTravelerInformationMessage getTim(TimUpdateModel aTim, List boolean resetStartTimes, boolean resetExpirationTime) { String nowAsISO = Instant.now().toString(); - DataFrame dataFrame = getDataFrame(aTim, anchor, resetStartTimes, resetExpirationTime); + DataFrame dataFrame = getDataFrame(aTim, resetStartTimes, resetExpirationTime); // check to see if we have any itis codes // if not, just continue on if (dataFrame.getItems() == null || dataFrame.getItems().length == 0) { @@ -792,9 +796,8 @@ private List sendTim(WydotTravelerInputData timToSend, Tim Long activeTimId, List reduced_mps) { List exceptions = new ArrayList<>(); // try to send to RSU if not a sat TIM and along route with RSUs - if (StringUtils.isBlank(tum.getSatRecordId()) && - Arrays.asList(config.getRsuRoutes()).contains(tum.getRoute())) { - var exMsg = updateAndSendRSU(timToSend, tum); + if (StringUtils.isBlank(tum.getSatRecordId())) { + var exMsg = updateAndSendRSU(timToSend, tum, reduced_mps); if (StringUtils.isNotBlank(exMsg)) { exceptions.add(new ResubmitTimException(activeTimId, exMsg)); } @@ -824,25 +827,12 @@ protected int getNextMessageCount(int currentCount) { return ++currentCount; } - private DataFrame getDataFrame(TimUpdateModel aTim, Milepost anchor, boolean resetStartTimes, + private DataFrame getDataFrame(TimUpdateModel aTim, boolean resetStartTimes, boolean resetExpirationTime) { - // RoadSignID - RoadSignID rsid = new RoadSignID(); - rsid.setPosition(getAnchorPosition(anchor)); - rsid.setViewAngle("1111111111111111"); - - // if we are coming in with content=speedLimit and frameType=roadSignage, - // we need to set the mutcdCode to regulatory to display the regulatory signage - if (aTim.getDfContent() == ContentEnum.speedLimit && - aTim.getFrameType() == TravelerInfoType.roadSignage) { - rsid.setMutcdCode(MutcdCodeEnum.regulatory); - } else { - rsid.setMutcdCode(MutcdCodeEnum.warning); - } // MsgId MsgId msgId = new MsgId(); - msgId.setRoadSignID(rsid); + msgId.setFurtherInfoID("0"); // DataFrame DataFrame df = new DataFrame(); @@ -1010,15 +1000,24 @@ private String getBaseRegionName(TimUpdateModel aTim, String middle) { return regionName; } - private String updateAndSendRSU(WydotTravelerInputData timToSend, TimUpdateModel aTim) { + private String updateAndSendRSU(WydotTravelerInputData timToSend, TimUpdateModel aTim, List mileposts) { String exMsg = ""; List wydotRsus = rsuService.getFullRsusTimIsOn(aTim.getTimId()); List dbRsus = new ArrayList(); if (wydotRsus == null || wydotRsus.size() <= 0) { log.info("No RSUs found for active_tim_id {}", aTim.getActiveTimId()); - dbRsus = rsuService.getRsusByLatLong(aTim.getDirection(), aTim.getStartPoint(), - aTim.getEndPoint(), aTim.getRoute()); + if (mileposts != null && mileposts.size() > 0) { + // use milepost geometry to find RSUs + List coords = new ArrayList(); + for (Milepost mp : mileposts) { + coords.add(new Coordinate(mp.getLatitude(), mp.getLongitude())); + } + dbRsus = rsuService.getRsusByGeometry(coords); + } else { + dbRsus = rsuService.getRsusByLatLong(aTim.getDirection(), aTim.getStartPoint(), aTim.getEndPoint(), + aTim.getRoute()); + } // if no RSUs found if (dbRsus.isEmpty()) { diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/model/SetMilepostCacheRequest.java b/cv-data-service-library/src/main/java/com/trihydro/library/model/SetMilepostCacheRequest.java new file mode 100644 index 000000000..bda604c15 --- /dev/null +++ b/cv-data-service-library/src/main/java/com/trihydro/library/model/SetMilepostCacheRequest.java @@ -0,0 +1,19 @@ +package com.trihydro.library.model; + +import java.util.List; + +public class SetMilepostCacheRequest { + private final List mileposts; + private final String timID; + + public SetMilepostCacheRequest(List mileposts, String timID) { + this.mileposts = mileposts; + this.timID = timID; + } + public List getMileposts() { + return mileposts; + } + public String getTimID() { + return timID; + } +} \ No newline at end of file diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/model/WydotTim.java b/cv-data-service-library/src/main/java/com/trihydro/library/model/WydotTim.java index 1f72a5bbe..700988d3c 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/model/WydotTim.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/model/WydotTim.java @@ -7,38 +7,48 @@ public class WydotTim { - @ApiModelProperty(value = "Expected values are I, D, B", required = true) - private String direction; - @ApiModelProperty(required = true) - private Coordinate startPoint; - @ApiModelProperty(required = true) - private Coordinate endPoint; - @ApiModelProperty(value = "The common name for the selected route", required = true) - private String route; - @ApiModelProperty(required = true) - private List itisCodes; - @ApiModelProperty(required = true) - private String clientId; + @ApiModelProperty(value = "Expected values are I, D, B", required = true) + private String direction; + @ApiModelProperty(required = false) + private Coordinate startPoint; + @ApiModelProperty(required = false) + private Coordinate endPoint; + @ApiModelProperty(value = "The common name for the selected route", required = true) + private String route; + @ApiModelProperty(required = true) + private List itisCodes; + @ApiModelProperty(required = true) + private String clientId; + @ApiModelProperty(required = false) + private List geometry; + @ApiModelProperty(required = false) + private Integer bearing; public WydotTim() { } - public WydotTim(WydotTim o) { - this.direction = o.direction; - if (o.startPoint != null) { - this.startPoint = - new Coordinate(o.startPoint.getLatitude(), o.startPoint.getLongitude()); - } - if (o.endPoint != null) { - this.endPoint = new Coordinate(o.endPoint.getLatitude(), o.endPoint.getLongitude()); - } - this.route = o.route; - if (o.itisCodes != null) { - this.itisCodes = new ArrayList<>(o.itisCodes); - } - this.clientId = o.clientId; - } + public WydotTim(WydotTim o) { + this.direction = o.direction; + if (o.startPoint != null) + this.startPoint = new Coordinate(o.startPoint.getLatitude(), o.startPoint.getLongitude()); + if (o.endPoint != null) + this.endPoint = new Coordinate(o.endPoint.getLatitude(), o.endPoint.getLongitude()); + this.route = o.route; + if (o.itisCodes != null) + this.itisCodes = new ArrayList<>(o.itisCodes); + this.clientId = o.clientId; + if (o.geometry != null) { + this.geometry = new ArrayList<>(o.geometry); + // If geometry is present and has more than one point, set start and end points + if (o.geometry.size() > 1) { + this.startPoint = new Coordinate(o.geometry.get(0).getLatitude(), o.geometry.get(0).getLongitude()); + this.endPoint = new Coordinate(o.geometry.get(o.geometry.size() - 1).getLatitude(), o.geometry.get(o.geometry.size() - 1).getLongitude()); + } + } + if (o.bearing != null) + this.bearing = o.bearing; + } public WydotTim(TimUpdateModel aTim) { setClientId(aTim.getClientId()); @@ -96,7 +106,52 @@ public String getRoute() { return this.route; } - public void setRoute(String route) { - this.route = route; - } + public void setRoute(String route) { + this.route = route; + } + + public List getGeometry() { + return this.geometry; + } + + public void setGeometry(List geometry) { + this.geometry = geometry; + } + + public Integer getBearing() { + return this.bearing; + } + + public void setBearing(Integer bearing) { + this.bearing = bearing; + } + + public boolean isGeometryValid() { + if (this.geometry != null && this.getGeometry().size() > 1) { // must have 2 or more points to be valid + for (Coordinate coord : this.geometry) { + if (!coord.isValid()) { + return false; + } + } + return true; + } else { + return false; + } + } + + public List toMileposts() { + var mileposts = new ArrayList(); + if (isGeometryValid()) { + for (Coordinate coordinate : this.getGeometry()) { + Milepost milepost = new Milepost(); + milepost.setLatitude(coordinate.getLatitude()); + milepost.setLongitude(coordinate.getLongitude()); + milepost.setDirection(this.getDirection()); + milepost.setCommonName(this.getRoute()); + milepost.setMilepost(0.0); + mileposts.add(milepost); + } + } + return mileposts; + } } \ No newline at end of file diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/service/MilepostService.java b/cv-data-service-library/src/main/java/com/trihydro/library/service/MilepostService.java index 15de8a472..2867998b7 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/service/MilepostService.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/service/MilepostService.java @@ -5,6 +5,7 @@ import com.trihydro.library.model.Milepost; import com.trihydro.library.model.MilepostBuffer; import com.trihydro.library.model.WydotTim; +import com.trihydro.library.model.SetMilepostCacheRequest; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; @@ -40,4 +41,65 @@ public List getMilepostsByPointWithBuffer(MilepostBuffer milepostBuffe entity, responseType); return response.getBody(); } + + public String setMilepostCache(List mileposts, String timID) { + String url = String.format("%s/set-milepost-cache", config.getCvRestService()); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + SetMilepostCacheRequest body = new SetMilepostCacheRequest(mileposts, timID); + HttpEntity entity = new HttpEntity(body, headers); + ResponseEntity response = restTemplateProvider.GetRestTemplate().exchange(url, HttpMethod.POST, entity, + String.class); + return response.getBody(); + } + + public List getMilepostCache(String timID) { + String url = String.format("%s/get-milepost-cache/%s", config.getCvRestService(), timID); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity(null, headers); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() {}; + ResponseEntity> response = restTemplateProvider.GetRestTemplate().exchange(url, HttpMethod.GET, + entity, responseType); + return response.getBody(); + } + + public String deleteMilepostCache(String timID) { + String url = String.format("%s/delete-milepost-cache/%s", config.getCvRestService(), timID); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity(null, headers); + ResponseEntity response = restTemplateProvider.GetRestTemplate().exchange(url, HttpMethod.DELETE, entity, + String.class); + return response.getBody(); + } + + public void clearMilepostCache() { + String url = String.format("%s/clear-milepost-cache/", config.getCvRestService()); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity(null, headers); + ParameterizedTypeReference responseType = new ParameterizedTypeReference() {}; + restTemplateProvider.GetRestTemplate().exchange(url, HttpMethod.GET, entity, responseType); + } + + /** + * Retrieves a buffer of mileposts for a given path from the CDOT upstream service. + * + * @param routeId the ID of the route for which the buffer is to be retrieved + * @param desiredDistanceInMiles the desired distance in miles for the buffer + * @param pathMileposts the list of mileposts representing the path + * @return a list of mileposts representing the buffer for the given path + */ + public List getBufferForPath(String routeId, double desiredDistanceInMiles, List pathMileposts) { + String url = String.format("%s/cdot-upstream-path/get-buffer-for-path/%s/%s", config.getCvRestService(), routeId, desiredDistanceInMiles); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity> entity = new HttpEntity<>(pathMileposts, headers); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() { + }; + ResponseEntity> response = restTemplateProvider.GetRestTemplate().exchange(url, HttpMethod.POST, + entity, responseType); + return response.getBody(); + } } diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/service/RsuService.java b/cv-data-service-library/src/main/java/com/trihydro/library/service/RsuService.java index 99bc6977a..590518595 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/service/RsuService.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/service/RsuService.java @@ -6,11 +6,6 @@ import java.util.List; import java.util.stream.Collectors; -import com.trihydro.library.helpers.Utility; -import com.trihydro.library.model.Coordinate; -import com.trihydro.library.model.WydotRsu; -import com.trihydro.library.model.WydotRsuTim; - import org.gavaghan.geodesy.Ellipsoid; import org.gavaghan.geodesy.GeodeticCalculator; import org.gavaghan.geodesy.GeodeticCurve; @@ -19,6 +14,11 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import com.trihydro.library.helpers.Utility; +import com.trihydro.library.model.Coordinate; +import com.trihydro.library.model.WydotRsu; +import com.trihydro.library.model.WydotRsuTim; + @Component public class RsuService extends CvDataServiceLibrary { @@ -43,6 +43,13 @@ public List selectRsusByRoute(String route) { return Arrays.asList(response.getBody()); } + public List selectRsusByGeometry(String geometry) { + String url = String.format("%s/rsus-by-geometry/%s", config.getCvRestService(), geometry); + ResponseEntity response = restTemplateProvider.GetRestTemplate().getForEntity(url, + WydotRsu[].class); + return Arrays.asList(response.getBody()); + } + public List getFullRsusTimIsOn(Long timId) { String url = String.format("%s/rsus-for-tim/%d", config.getCvRestService(), timId); ResponseEntity response = restTemplateProvider.GetRestTemplate().getForEntity(url, @@ -202,6 +209,23 @@ public List getRsusByLatLong(String direction, Coordinate startPoint, return rsus; } + public List getRsusByGeometry(List geometry) { + var coordinateBuilder = new StringBuilder("LINESTRING("); + + for (Coordinate coordinate : geometry) { + coordinateBuilder.append(coordinate.getLongitude()).append(" ").append(coordinate.getLatitude()).append(","); + } + coordinateBuilder.deleteCharAt(coordinateBuilder.length() - 1); + coordinateBuilder.append(")"); + + List rsus = selectRsusByGeometry(coordinateBuilder.toString()); + for (WydotRsu rsu : rsus) { + rsu.setRsuRetries(3); + rsu.setRsuTimeout(5000); + } + return rsus; + } + private List getRsusByRouteWithRetryAndTimeout(String route) { List rsus = selectRsusByRoute(route); for (WydotRsu rsu : rsus) { diff --git a/cv-data-service-library/src/main/java/com/trihydro/library/service/WydotTimService.java b/cv-data-service-library/src/main/java/com/trihydro/library/service/WydotTimService.java index f1ab3b7ca..120d4829e 100644 --- a/cv-data-service-library/src/main/java/com/trihydro/library/service/WydotTimService.java +++ b/cv-data-service-library/src/main/java/com/trihydro/library/service/WydotTimService.java @@ -11,6 +11,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; @@ -29,7 +30,6 @@ import com.trihydro.library.model.ActiveRsuTimQueryModel; import com.trihydro.library.model.ActiveTim; import com.trihydro.library.model.ActiveTimHolding; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.Coordinate; import com.trihydro.library.model.EmailProps; import com.trihydro.library.model.Milepost; @@ -55,6 +55,7 @@ import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; @Component +@Slf4j public class WydotTimService { protected EmailProps emailProps; @@ -113,11 +114,11 @@ public void InjectDependencies(EmailProps _emailProps, OdeProps _odeProps, TimGe DateTimeFormatter utcformatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); public WydotTravelerInputData createTim(WydotTim wydotTim, String timTypeStr, String startDateTime, - String endDateTime, ContentEnum content, TravelerInfoType frameType, List allMileposts, - List reducedMileposts, Milepost anchor) { + String endDateTime, TravelerInfoType frameType, List allMileposts, + List reducedMileposts, Milepost anchor, String dotGnisId) { // build base TIM - WydotTravelerInputData timToSend = createBaseTimUtil.buildTim(wydotTim, genProps, content, frameType, + WydotTravelerInputData timToSend = createBaseTimUtil.buildTim(wydotTim, genProps, frameType, allMileposts, reducedMileposts, anchor); if (timToSend == null) { @@ -147,21 +148,36 @@ public WydotTravelerInputData createTim(WydotTim wydotTim, String timTypeStr, St timToSend.getTim().getDataframes()[0].setDurationTime(120); } - // set PacketId to a random 18 character hex value + // Set PacketId as an 18-character hex string: DOT GNIS ID + random hex suffix Random rand = new Random(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); + if (dotGnisId.equals("000000")) { + throw new IllegalStateException("DOT GNIS ID is set to default value of 000000. This is not a valid GNIS ID and should be changed in the configuration."); + } + sb.append(dotGnisId); while (sb.length() < 18) { sb.append(Integer.toHexString(rand.nextInt())); } - timToSend.getTim().setPacketID(sb.toString().substring(0, 18).toUpperCase()); + timToSend.getTim().setPacketID(sb.substring(0, 18).toUpperCase()); return timToSend; } public List getAllMilepostsForTim(WydotTim wydotTim) { - List milepostsAll = new ArrayList<>(); + List milepostsAll; + + // get mileposts from cache if they exist + milepostsAll = milepostService.getMilepostCache(wydotTim.getClientId()); + if (milepostsAll != null && !milepostsAll.isEmpty()) { + return milepostsAll; + } - if (wydotTim.getEndPoint() != null && wydotTim.getEndPoint().getLatitude() != null + if (wydotTim.isGeometryValid()) { + if (milepostsAll == null) { + milepostsAll = new ArrayList<>(); + } + milepostsAll.addAll(wydotTim.toMileposts()); + } else if (wydotTim.getEndPoint() != null && wydotTim.getEndPoint().getLatitude() != null && wydotTim.getEndPoint().getLongitude() != null) { milepostsAll = milepostService.getMilepostsByStartEndPointDirection(wydotTim); } else { @@ -174,6 +190,11 @@ public List getAllMilepostsForTim(WydotTim wydotTim) { milepostsAll = milepostService.getMilepostsByPointWithBuffer(mpb); } + // cache mileposts + if (milepostsAll != null && !milepostsAll.isEmpty()) { + milepostService.setMilepostCache(milepostsAll, wydotTim.getClientId()); + } + return milepostsAll; } @@ -242,11 +263,20 @@ public void sendTimToRsus(WydotTim wydotTim, WydotTravelerInputData timToSend, S TimType timType, Integer pk, String endDateTime, Coordinate endPoint) { // FIND ALL RSUS TO SEND TO // TODO: should this query a graph db instead to follow with milepost? - List rsus = rsuService.getRsusByLatLong(wydotTim.getDirection(), wydotTim.getStartPoint(), endPoint, + + // if geometry exists, use it to find RSUs + List rsus = new ArrayList<>(); + + if (wydotTim.isGeometryValid()) { + rsus = rsuService.getRsusByGeometry(wydotTim.getGeometry()); + utility.logWithDate("Found " + rsus.size() + " RSUs by geometry"); + } else { + rsus = rsuService.getRsusByLatLong(wydotTim.getDirection(), wydotTim.getStartPoint(), endPoint, wydotTim.getRoute()); + } // if no RSUs found - if (rsus.size() == 0) { + if (rsus.isEmpty()) { utility.logWithDate("No RSUs found to place TIM on, returning"); return; } @@ -259,7 +289,14 @@ public void sendTimToRsus(WydotTim wydotTim, WydotTravelerInputData timToSend, S odeRsu.setRsuIndex(rsu.getRsuIndex()); odeRsu.setRsuTarget(rsu.getRsuTarget()); - // rsuUsername, rsuPassword will take ODE defaults. + + if (rsu.getRsuUsername() != null) { + odeRsu.setRsuUsername(rsu.getRsuUsername()); + } + if (rsu.getRsuPassword() != null) { + odeRsu.setRsuPassword(rsu.getRsuPassword()); + } + odeRsu.setRsuRetries(rsu.getRsuRetries()); odeRsu.setRsuTimeout(rsu.getRsuTimeout()); @@ -381,7 +418,7 @@ public TimDeleteSummary deleteTimsFromRsusAndSdx(List activeTims) { List timRsus = timRsuService.getTimRsusByTimId(activeTim.getTimId()); // get full RSU - if (timRsus.size() > 0) { + if (!timRsus.isEmpty()) { for (TimRsu timRsu : timRsus) { rsu = getRsu(timRsu.getRsuId()); // delete tim off rsu @@ -393,13 +430,14 @@ public TimDeleteSummary deleteTimsFromRsusAndSdx(List activeTims) { } // delete active tim if (activeTimService.deleteActiveTim(activeTim.getActiveTimId())) { + milepostService.deleteMilepostCache(activeTim.getClientId()); returnValue.addSuccessfulRsuDeletions(activeTim.getActiveTimId()); } else { returnValue.addFailedActiveTimDeletions(activeTim.getActiveTimId()); } } - if (satTims != null && satTims.size() > 0) { + if (satTims != null && !satTims.isEmpty()) { // Get the sat_record_id values and active_tim_id values List satRecordIds = satTims.stream().map(ActiveTim::getSatRecordId).collect(Collectors.toList()); List activeSatTimIds = satTims.stream().map(ActiveTim::getActiveTimId).collect(Collectors.toList()); diff --git a/cv-data-service-library/src/main/resources/application.properties b/cv-data-service-library/src/main/resources/application.properties new file mode 100644 index 000000000..352a7edc2 --- /dev/null +++ b/cv-data-service-library/src/main/resources/application.properties @@ -0,0 +1,3 @@ +data-service-library.kafka.confluentKey=someKey +data-service-library.kafka.confluentSecret=someSecret +data-service-library.kafka.kafkaType=LOCAL \ No newline at end of file diff --git a/cv-data-service-library/src/test/java/com/trihydro/library/factory/KafkaFactoryTest.java b/cv-data-service-library/src/test/java/com/trihydro/library/factory/KafkaFactoryTest.java new file mode 100644 index 000000000..1e23a36e6 --- /dev/null +++ b/cv-data-service-library/src/test/java/com/trihydro/library/factory/KafkaFactoryTest.java @@ -0,0 +1,127 @@ +package com.trihydro.library.factory; + +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import org.apache.kafka.clients.consumer.Consumer; +import org.apache.kafka.clients.producer.Producer; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import static org.mockito.ArgumentMatchers.anyString; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.trihydro.library.helpers.Utility; + + +@ExtendWith(MockitoExtension.class) +public class KafkaFactoryTest { + + @Mock + private Utility utility; + + @InjectMocks + private KafkaFactory kafkaFactory; + + @Test + public void testCreateStringConsumerLocal() { + String host = "localhost:9092"; + String consumerGroup = "testGroup"; + String topic = "testTopic"; + + Consumer consumer = kafkaFactory.createStringConsumer(host, consumerGroup, topic); + + assertNotNull(consumer); + verify(utility).logWithDate(anyString()); + } + + @Test + public void testKafkaFactoryConstructorConfluentException() throws Exception { + KafkaFactory kafkaFactoryTest = new KafkaFactory(utility); + assertThrows(IllegalArgumentException.class, () -> { + kafkaFactoryTest.addConfluentProperties(new Properties()); + }); + } + + @Test + public void testKafkaFactoryConstructorConfluent() { + // Create a spy of KafkaFactory + KafkaFactory spyKafkaFactory = spy(new KafkaFactory(utility)); + + // Mock the getKafka() method + doReturn("testKey").when(spyKafkaFactory).getConfluentKey(); + doReturn("testSecret").when(spyKafkaFactory).getConfluentSecret(); + + Properties props = spyKafkaFactory.addConfluentProperties(new Properties()); + + assertNotNull(props); + assertEquals("org.apache.kafka.common.security.plain.PlainLoginModule required username=\"testKey\" password=\"testSecret\";", props.getProperty("sasl.jaas.config")); + assertEquals("https", props.getProperty("ssl.endpoint.identification.algorithm")); + assertEquals("SASL_SSL", props.getProperty("security.protocol")); + assertEquals("PLAIN", props.getProperty("sasl.mechanism")); + } + + @Test + public void testCreateStringConsumerWithProperties() { + String host = "localhost:9092"; + String consumerGroup = "testGroup"; + List topics = Arrays.asList("testTopic1", "testTopic2"); + Integer maxPollInterval = 300000; + Integer maxPollRecords = 500; + + Consumer consumer = kafkaFactory.createStringConsumer(host, consumerGroup, topics, maxPollInterval, maxPollRecords); + + assertNotNull(consumer); + verify(utility).logWithDate(anyString()); + } + + @Test + public void testCreateStringProducerLocal() { + String host = "localhost:9092"; + + Producer producer = kafkaFactory.createStringProducer(host); + + assertNotNull(producer); + } + + @Test + public void testCreateStringConsumerLocalWithInvalidHost() { + String host = ""; + String consumerGroup = "testGroup"; + String topic = "testTopic"; + + assertThrows(IllegalArgumentException.class, () -> { + kafkaFactory.createStringConsumer(host, consumerGroup, topic); + }); + } + + @Test + public void testCreateStringConsumerWithInvalidConsumerGroup() { + String host = "localhost:9092"; + String consumerGroup = ""; + String topic = "testTopic"; + + assertThrows(IllegalArgumentException.class, () -> { + kafkaFactory.createStringConsumer(host, consumerGroup, topic); + }); + } + + @Test + public void testCreateStringConsumerWithInvalidTopics() { + String host = "localhost:9092"; + String consumerGroup = "testGroup"; + List topics = Arrays.asList(); + + assertThrows(IllegalArgumentException.class, () -> { + kafkaFactory.createStringConsumer(host, consumerGroup, topics); + }); + } +} \ No newline at end of file diff --git a/cv-data-service-library/src/test/java/com/trihydro/library/helpers/CdotGisConnectorTest.java b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/CdotGisConnectorTest.java new file mode 100644 index 000000000..b0338c758 --- /dev/null +++ b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/CdotGisConnectorTest.java @@ -0,0 +1,52 @@ +package com.trihydro.library.helpers; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; + +import com.trihydro.library.service.BaseServiceTest; + +class CdotGisConnectorTest extends BaseServiceTest { + + @InjectMocks + private CdotGisConnector uut; + + private final String expectedBaseUrl = "https://dtdapps.coloradodot.info/arcgis/rest/services/LRS/Routes_withDEC/MapServer/exts/CdotLrsAccessRounded"; + + @Test + void testGetBaseUrl() { + Assertions.assertEquals(expectedBaseUrl, uut.getBaseUrl()); + } + + @Test + void testGetRouteById() { + // prepare + String expectedTargetUrl = expectedBaseUrl + "/Route"; + String routeId = "025A"; + int outSR = 4326; + String f = "json"; + String expectedParams = "?routeId=" + routeId + "&outSR=" + outSR + "&f=" + f; + HttpHeaders mockHeaders = new HttpHeaders(); + mockHeaders.set("Accept", "application/json"); + HttpEntity mockEntity = new HttpEntity<>(mockHeaders); + String mockResponseString = "mockResponseString"; + ResponseEntity mockResponse = ResponseEntity.ok(mockResponseString); + when(mockRestTemplate.exchange(expectedTargetUrl + expectedParams, HttpMethod.GET, mockEntity, String.class)).thenReturn(mockResponse); + + // execute + ResponseEntity response = uut.getRouteById(routeId); + + // verify + Assertions.assertEquals(mockResponse.getStatusCode(), response.getStatusCode()); + Assertions.assertEquals(mockResponseString, response.getBody()); + verify(mockRestTemplate).exchange(expectedTargetUrl + expectedParams, HttpMethod.GET, mockEntity, String.class); + } + +} \ No newline at end of file diff --git a/cv-data-service-library/src/test/java/com/trihydro/library/helpers/CreateBaseTimUtilTest.java b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/CreateBaseTimUtilTest.java index 1a445ef04..d90f2e878 100644 --- a/cv-data-service-library/src/test/java/com/trihydro/library/helpers/CreateBaseTimUtilTest.java +++ b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/CreateBaseTimUtilTest.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.List; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.Coordinate; import com.trihydro.library.model.Milepost; import com.trihydro.library.model.WydotTim; @@ -106,11 +105,10 @@ public void buildTim_EndpointSUCCESS() { wydotTim.setItisCodes(itisCodes); wydotTim.setClientId("testclientid"); - var content = ContentEnum.advisory; var frameType = TravelerInfoType.advisory; // Act - var data = uut.buildTim(wydotTim, genProps, content, frameType, allMileposts, milepostsReduced, anchor); + var data = uut.buildTim(wydotTim, genProps, frameType, allMileposts, milepostsReduced, anchor); // Assert // validate dataFrame @@ -118,6 +116,8 @@ public void buildTim_EndpointSUCCESS() { Assertions.assertNotNull(dataFrame); Assertions.assertEquals("advisory", dataFrame.getContent()); Assertions.assertEquals(32000, dataFrame.getDurationTime()); + Assertions.assertEquals("0", dataFrame.getMsgId().getFurtherInfoID()); + Assertions.assertNull(dataFrame.getMsgId().getRoadSignID()); var region = dataFrame.getRegions()[0]; Assertions.assertNotNull(region); @@ -155,11 +155,10 @@ public void buildTim_singlePointSUCCESS() { wydotTim.setItisCodes(itisCodes); wydotTim.setClientId("testclientid"); - var content = ContentEnum.advisory; var frameType = TravelerInfoType.advisory; // Act - var data = uut.buildTim(wydotTim, genProps, content, frameType, allMileposts, milepostsReduced, anchor); + var data = uut.buildTim(wydotTim, genProps, frameType, allMileposts, milepostsReduced, anchor); // Assert // validate dataFrame @@ -167,6 +166,8 @@ public void buildTim_singlePointSUCCESS() { Assertions.assertNotNull(dataFrame); Assertions.assertEquals("advisory", dataFrame.getContent()); Assertions.assertEquals(32000, dataFrame.getDurationTime()); + Assertions.assertEquals("0", dataFrame.getMsgId().getFurtherInfoID()); + Assertions.assertNull(dataFrame.getMsgId().getRoadSignID()); var region = dataFrame.getRegions()[0]; Assertions.assertNotNull(region); @@ -204,11 +205,10 @@ public void buildTim_singleRegion_SUCCESS() { wydotTim.setItisCodes(itisCodes); wydotTim.setClientId("testclientid"); - var content = ContentEnum.advisory; var frameType = TravelerInfoType.advisory; // Act - var data = uut.buildTim(wydotTim, genProps, content, frameType, allMileposts, milepostsReduced, anchor); + var data = uut.buildTim(wydotTim, genProps, frameType, allMileposts, milepostsReduced, anchor); // Assert Assertions.assertEquals(1, data.getTim().getDataframes()[0].getRegions().length); @@ -235,11 +235,10 @@ public void buildTim_twoRegions_SUCCESS() { wydotTim.setItisCodes(itisCodes); wydotTim.setClientId("testclientid"); - var content = ContentEnum.advisory; var frameType = TravelerInfoType.advisory; // Act - var data = uut.buildTim(wydotTim, genProps, content, frameType, allMileposts, milepostsReduced, anchor); + var data = uut.buildTim(wydotTim, genProps, frameType, allMileposts, milepostsReduced, anchor); // Assert Assertions.assertEquals(2, data.getTim().getDataframes()[0].getRegions().length); @@ -278,11 +277,10 @@ public void buildTim_threeRegions_SUCCESS() { wydotTim.setItisCodes(itisCodes); wydotTim.setClientId("testclientid"); - var content = ContentEnum.advisory; var frameType = TravelerInfoType.advisory; // Act - var data = uut.buildTim(wydotTim, genProps, content, frameType, allMileposts, milepostsReduced, anchor); + var data = uut.buildTim(wydotTim, genProps, frameType, allMileposts, milepostsReduced, anchor); // Assert Assertions.assertEquals(3, data.getTim().getDataframes()[0].getRegions().length); diff --git a/cv-data-service-library/src/test/java/com/trihydro/library/helpers/JsonToJavaConverterTest.java b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/JsonToJavaConverterTest.java index e89ca7501..9a36e171d 100644 --- a/cv-data-service-library/src/test/java/com/trihydro/library/helpers/JsonToJavaConverterTest.java +++ b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/JsonToJavaConverterTest.java @@ -252,7 +252,7 @@ public void TestConvertTimPayloadJsonToJava_SpeedLimit() throws IOException, URI // Assert Assertions.assertNotNull(odeTimPayloadTest); Assertions.assertTrue(getTim(odeTimPayloadTest).getDataframes()[0].getItems().length > 0); - Assertions.assertEquals("speedLimit", getTim(odeTimPayloadTest).getDataframes()[0].getContent()); + Assertions.assertEquals("advisory", getTim(odeTimPayloadTest).getDataframes()[0].getContent()); Assertions.assertArrayEquals(new String[] { "13609", "268", "12554", "8720" }, getTim(odeTimPayloadTest).getDataframes()[0].getItems()); } @@ -388,7 +388,7 @@ public void TestConvertTmcTimTopicJsonToJava_HandlesVslContentType() throws IOEx // Assert Assertions.assertNotNull(tim_vsl); - Assertions.assertEquals("speedLimit", getTim(tim_vsl).getDataframes()[0].getContent()); + Assertions.assertEquals("advisory", getTim(tim_vsl).getDataframes()[0].getContent()); Assertions.assertArrayEquals(new String[] { "268", "12604", "8720" }, getTim(tim_vsl).getDataframes()[0].getItems()); @@ -406,7 +406,7 @@ public void TestConvertTmcTimTopicJsonToJava_HandlesVslContentType_MultipleRegio // Assert Assertions.assertNotNull(tim_vsl); - Assertions.assertEquals("speedLimit", getTim(tim_vsl).getDataframes()[0].getContent()); + Assertions.assertEquals("advisory", getTim(tim_vsl).getDataframes()[0].getContent()); Assertions.assertArrayEquals(new String[] { "268", "12604", "8720" }, getTim(tim_vsl).getDataframes()[0].getItems()); @@ -424,7 +424,7 @@ public void TestConvertTmcTimTopicJsonToJava_HandlesParkingContentType() throws // Assert Assertions.assertNotNull(tim_parking); - Assertions.assertEquals("exitService", getTim(tim_parking).getDataframes()[0].getContent()); + Assertions.assertEquals("advisory", getTim(tim_parking).getDataframes()[0].getContent()); Assertions.assertArrayEquals(new String[] { "4104", "11794", "345" }, getTim(tim_parking).getDataframes()[0].getItems()); @@ -442,7 +442,7 @@ public void TestConvertTmcTimTopicJsonToJava_HandlesParkingContentType_MultipleR // Assert Assertions.assertNotNull(tim_parking); - Assertions.assertEquals("exitService", getTim(tim_parking).getDataframes()[0].getContent()); + Assertions.assertEquals("advisory", getTim(tim_parking).getDataframes()[0].getContent()); Assertions.assertArrayEquals(new String[] { "4104", "11794", "345" }, getTim(tim_parking).getDataframes()[0].getItems()); @@ -461,7 +461,7 @@ public void TestConvertTmcTimTopicJsonToJava_HandlesConstructionContentType() th // Assert Assertions.assertNotNull(tim_construction); - Assertions.assertEquals("workZone", getTim(tim_construction).getDataframes()[0].getContent()); + Assertions.assertEquals("advisory", getTim(tim_construction).getDataframes()[0].getContent()); Assertions.assertArrayEquals(new String[] { "1537", "12554", "8728" }, getTim(tim_construction).getDataframes()[0].getItems()); @@ -480,7 +480,7 @@ public void TestConvertTmcTimTopicJsonToJava_HandlesConstructionContentType_Mult // Assert Assertions.assertNotNull(tim_construction); - Assertions.assertEquals("workZone", getTim(tim_construction).getDataframes()[0].getContent()); + Assertions.assertEquals("advisory", getTim(tim_construction).getDataframes()[0].getContent()); Assertions.assertArrayEquals(new String[] { "1537", "12554", "8728" }, getTim(tim_construction).getDataframes()[0].getItems()); diff --git a/cv-data-service-library/src/test/java/com/trihydro/library/helpers/TimGenerationHelperTest.java b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/TimGenerationHelperTest.java index 3f65b8a7d..8de027e45 100644 --- a/cv-data-service-library/src/test/java/com/trihydro/library/helpers/TimGenerationHelperTest.java +++ b/cv-data-service-library/src/test/java/com/trihydro/library/helpers/TimGenerationHelperTest.java @@ -175,6 +175,7 @@ public void resubmitToOde_NoMileposts() { verifyNoInteractions(mockDataFrameService, mockPathNodeXYService, mockRegionService, mockRsuService, mockOdeService, mockActiveTimHoldingService, mockSdwService); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction); } @@ -209,6 +210,7 @@ public void resubmitToOde_DataFrameException() throws Utility.IdenticalPointsExc verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); + verify(mockMilepostService).getMilepostCache(any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService); } @@ -224,8 +226,6 @@ public void resubmitToOde_RsuException() throws Utility.IdenticalPointsException List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); doReturn(new String[] {"1234"}).when(mockDataFrameService) .getItisCodesForDataFrameId(any()); @@ -243,15 +243,15 @@ public void resubmitToOde_RsuException() throws Utility.IdenticalPointsException Assertions.assertEquals(new ResubmitTimException(activeTimId, exMsg), ex); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); + verify(mockRsuService).getRsusByGeometry(any()); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockOdeService, mockActiveTimHoldingService, mockSdwService); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, - mockRsuService); + verify(mockMilepostService).getMilepostCache(any()); + verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService); } @Test @@ -266,8 +266,6 @@ public void resubmitToOde_RsuExistingSuccess() throws Utility.IdenticalPointsExc List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); List wydotRsus = new ArrayList<>(); var wydotRsuTim = new WydotRsuTim(); @@ -294,8 +292,9 @@ public void resubmitToOde_RsuExistingSuccess() throws Utility.IdenticalPointsExc verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, - mockRsuService, mockOdeService); + verify(mockMilepostService).getMilepostCache(any()); + verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, + mockOdeService); } @Test @@ -310,8 +309,6 @@ public void resubmitToOde_RsuNewFailTimQuery() throws Utility.IdenticalPointsExc List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); doReturn(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))).when(mockUtility) .calculateAnchorCoordinate(any(), any()); @@ -320,11 +317,9 @@ public void resubmitToOde_RsuNewFailTimQuery() throws Utility.IdenticalPointsExc var rsu = new WydotRsu(); rsu.setRsuTarget("10.10.10.10"); dbRsus.add(rsu); - doReturn(dbRsus).when(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); - when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn( - null); + doReturn(dbRsus).when(mockRsuService).getRsusByGeometry(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); + when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn(null); // Act var exceptions = uut.resubmitToOde(activeTimIds); @@ -339,15 +334,15 @@ public void resubmitToOde_RsuNewFailTimQuery() throws Utility.IdenticalPointsExc Assertions.assertEquals(new ResubmitTimException(activeTimId, exMsg), ex); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockOdeService).submitTimQuery(isA(WydotRsu.class), isA(Integer.class)); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, - mockRsuService, mockOdeService, mockActiveTimHoldingService); + verify(mockMilepostService).getMilepostCache(any()); + verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, + mockOdeService, mockActiveTimHoldingService); } @Test @@ -362,18 +357,14 @@ public void resubmitToOde_RsuNewFailIndices() throws Utility.IdenticalPointsExce List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); List dbRsus = new ArrayList<>(); var rsu = new WydotRsu(); rsu.setRsuTarget("10.10.10.10"); dbRsus.add(rsu); - doReturn(dbRsus).when(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); - when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn( - new TimQuery()); + doReturn(dbRsus).when(mockRsuService).getRsusByGeometry(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); + when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn(new TimQuery()); when(mockOdeService.findFirstAvailableIndexWithRsuIndex(any())).thenReturn(null); doReturn(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))).when(mockUtility) @@ -391,13 +382,14 @@ public void resubmitToOde_RsuNewFailIndices() throws Utility.IdenticalPointsExce Assertions.assertEquals(new ResubmitTimException(activeTimId, exMsg), ex); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); + verify(mockRsuService).getRsusByGeometry(any()); verify(mockRsuService).getActiveRsuTimIndexes(any()); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockOdeService).submitTimQuery(isA(WydotRsu.class), isA(Integer.class)); verify(mockActiveTimHoldingService).getActiveTimHoldingForRsu(any()); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, @@ -416,18 +408,14 @@ public void resubmitToOde_RsuNewInsertFail() throws Utility.IdenticalPointsExcep List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); List dbRsus = new ArrayList<>(); var rsu = new WydotRsu(); rsu.setRsuTarget("10.10.10.10"); dbRsus.add(rsu); - doReturn(dbRsus).when(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); - when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn( - new TimQuery()); + doReturn(dbRsus).when(mockRsuService).getRsusByGeometry(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); + when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn(new TimQuery()); when(mockOdeService.findFirstAvailableIndexWithRsuIndex(any())).thenReturn(1); doReturn("exception").when(mockOdeService).sendNewTimToRsu(any()); @@ -445,7 +433,7 @@ public void resubmitToOde_RsuNewInsertFail() throws Utility.IdenticalPointsExcep Assertions.assertEquals(new ResubmitTimException(activeTimId, exMsg), ex); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); + verify(mockRsuService).getRsusByGeometry(any()); verify(mockRsuService).getActiveRsuTimIndexes(any()); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockOdeService).submitTimQuery(isA(WydotRsu.class), isA(Integer.class)); @@ -454,6 +442,7 @@ public void resubmitToOde_RsuNewInsertFail() throws Utility.IdenticalPointsExcep verify(mockOdeService).sendNewTimToRsu(any()); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, @@ -472,18 +461,14 @@ public void resubmitToOde_RsuNewSuccess() throws Utility.IdenticalPointsExceptio List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); List dbRsus = new ArrayList<>(); var rsu = new WydotRsu(); rsu.setRsuTarget("10.10.10.10"); dbRsus.add(rsu); - doReturn(dbRsus).when(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); - when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn( - new TimQuery()); + doReturn(dbRsus).when(mockRsuService).getRsusByGeometry(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); + when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn(new TimQuery()); when(mockOdeService.findFirstAvailableIndexWithRsuIndex(any())).thenReturn(1); doReturn(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))).when(mockUtility) @@ -495,7 +480,7 @@ public void resubmitToOde_RsuNewSuccess() throws Utility.IdenticalPointsExceptio // Assert Assertions.assertEquals(0, exceptions.size()); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); + verify(mockRsuService).getRsusByGeometry(any()); verify(mockRsuService).getActiveRsuTimIndexes(any()); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockOdeService).submitTimQuery(isA(WydotRsu.class), isA(Integer.class)); @@ -504,6 +489,7 @@ public void resubmitToOde_RsuNewSuccess() throws Utility.IdenticalPointsExceptio verify(mockOdeService).sendNewTimToRsu(any()); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, @@ -541,6 +527,7 @@ public void resubmitToOde_SdxNewFail() throws Utility.IdenticalPointsException { verify(mockActiveTimHoldingService).insertActiveTimHolding(any()); verifyNoInteractions(mockPathNodeXYService); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); @@ -576,6 +563,7 @@ public void resubmitToOde_SdxNewSuccess() throws Utility.IdenticalPointsExceptio verify(mockOdeService).updateTimOnSdw(any()); verify(mockActiveTimHoldingService).insertActiveTimHolding(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); @@ -741,8 +729,9 @@ public void resubmitToOde_SdxExistingFail() throws Utility.IdenticalPointsExcept verify(mockActiveTimHoldingService).insertActiveTimHolding(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, - mockRsuService, mockOdeService, mockActiveTimHoldingService); + verify(mockMilepostService).getMilepostCache(any()); + verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, + mockOdeService, mockActiveTimHoldingService); } @Test @@ -774,6 +763,7 @@ public void resubmitToOde_SdxExistingSuccess() throws Utility.IdenticalPointsExc verifyNoInteractions(mockPathNodeXYService); verify(mockActiveTimHoldingService).insertActiveTimHolding(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); @@ -812,7 +802,7 @@ public void resubmitToOde_IdenticalPointsException_SuccessfulRecovery() throws U verify(mockActiveTimHoldingService).insertActiveTimHolding(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, + verifyNoMoreInteractions(mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); } @@ -837,7 +827,7 @@ public void resubmitToOde_IdenticalPointsException_FailureToRecover() throws Uti var ex = exceptions.get(0); Assertions.assertEquals(new ResubmitTimException(activeTimId, String.format("Unable to resubmit TIM, identical points found while calculating anchor point for Active_Tim %d", activeTimId)), ex); verifyNoInteractions(mockPathNodeXYService); - verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, + verifyNoMoreInteractions(mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); } @@ -909,6 +899,7 @@ public void updateAndResubmitToOde_noMileposts() { verifyNoInteractions(mockDataFrameService, mockPathNodeXYService, mockRegionService, mockRsuService, mockOdeService, mockActiveTimHoldingService, mockSdwService); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction); } @@ -949,6 +940,7 @@ public void updateAndResubmitToOde_RsuNewTimFail_EndPointMps() Assertions.assertEquals(new ResubmitTimException(activeTimId, exMsg), ex); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockMilepostService, times(2)).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService, times(2)).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService, @@ -987,6 +979,7 @@ public void updateAndResubmitToOde_RsuNewTimFail_EndTimeParse() Assertions.assertEquals(new ResubmitTimException(activeTimId, exMsg), ex); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService, @@ -1030,6 +1023,7 @@ public void updateAndResubmitToOde_RsuNewTimFail_StartPointMps() Assertions.assertEquals(new ResubmitTimException(activeTimId, exMsg), ex); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockMilepostService, times(2)).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService, times(2)).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService); verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService, @@ -1047,10 +1041,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_StartPoint() List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); doReturn(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))).when(mockUtility) .calculateAnchorCoordinate(any(), any()); @@ -1066,9 +1057,8 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_StartPoint() var rsu = new WydotRsu(); rsu.setRsuTarget("10.10.10.10"); dbRsus.add(rsu); - doReturn(dbRsus).when(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); - when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn( - new TimQuery()); + doReturn(dbRsus).when(mockRsuService).getRsusByGeometry(any()); + when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn(new TimQuery()); when(mockOdeService.findFirstAvailableIndexWithRsuIndex(any())).thenReturn(1); // Act @@ -1077,7 +1067,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_StartPoint() // Assert Assertions.assertEquals(0, exceptions.size()); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); + verify(mockRsuService).getRsusByGeometry(any()); verify(mockRsuService).getActiveRsuTimIndexes(any()); verify(mockDataFrameService, times(2)).getItisCodesForDataFrameId(any()); verify(mockOdeService).submitTimQuery(isA(WydotRsu.class), isA(Integer.class)); @@ -1087,6 +1077,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_StartPoint() verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); verify(mockMilepostService, times(2)).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService, times(2)).getMilepostCache(any()); verify(mockMilepostReduction, times(2)).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); @@ -1103,10 +1094,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndPoint() List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); var validationResults = getValidationResults(); var errors = new ArrayList(); @@ -1119,9 +1107,8 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndPoint() var rsu = new WydotRsu(); rsu.setRsuTarget("10.10.10.10"); dbRsus.add(rsu); - doReturn(dbRsus).when(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); - when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn( - new TimQuery()); + doReturn(dbRsus).when(mockRsuService).getRsusByGeometry(any()); + when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn(new TimQuery()); when(mockOdeService.findFirstAvailableIndexWithRsuIndex(any())).thenReturn(1); doReturn(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))).when(mockUtility) @@ -1133,7 +1120,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndPoint() // Assert Assertions.assertEquals(0, exceptions.size()); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); + verify(mockRsuService).getRsusByGeometry(any()); verify(mockRsuService).getActiveRsuTimIndexes(any()); verify(mockDataFrameService, times(2)).getItisCodesForDataFrameId(any()); verify(mockOdeService).submitTimQuery(isA(WydotRsu.class), isA(Integer.class)); @@ -1143,6 +1130,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndPoint() verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); verify(mockMilepostService, times(2)).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService, times(2)).getMilepostCache(any()); verify(mockMilepostReduction, times(2)).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); @@ -1159,10 +1147,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndTime() List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); var validationResults = getValidationResults(); var errors = new ArrayList(); @@ -1174,9 +1159,8 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndTime() var rsu = new WydotRsu(); rsu.setRsuTarget("10.10.10.10"); dbRsus.add(rsu); - doReturn(dbRsus).when(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); - when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn( - new TimQuery()); + doReturn(dbRsus).when(mockRsuService).getRsusByGeometry(any()); + when(mockOdeService.submitTimQuery(isA(WydotRsu.class), isA(Integer.class))).thenReturn(new TimQuery()); when(mockOdeService.findFirstAvailableIndexWithRsuIndex(any())).thenReturn(1); doReturn(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))).when(mockUtility) @@ -1188,7 +1172,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndTime() // Assert Assertions.assertEquals(0, exceptions.size()); verify(mockRsuService).getFullRsusTimIsOn(any()); - verify(mockRsuService).getRsusByLatLong(any(), any(), any(), any()); + verify(mockRsuService).getRsusByGeometry(any()); verify(mockRsuService).getActiveRsuTimIndexes(any()); verify(mockDataFrameService).getItisCodesForDataFrameId(any()); verify(mockOdeService).submitTimQuery(isA(WydotRsu.class), isA(Integer.class)); @@ -1198,6 +1182,7 @@ public void updateAndResubmitToOde_RsuNewTimSuccess_EndTime() verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); @@ -1214,10 +1199,7 @@ public void updateAndResubmitToOde_RsuUpdateTimSuccess_ItisCodes() List mps = new ArrayList<>(); mps.add(new Milepost()); doReturn(mps).when(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); - String[] rsuRoutes = new String[] {"I 80"}; - doReturn(rsuRoutes).when(mockConfig).getRsuRoutes(); - doReturn(new String[] {"1234"}).when(mockDataFrameService) - .getItisCodesForDataFrameId(any()); + doReturn(new String[] { "1234" }).when(mockDataFrameService).getItisCodesForDataFrameId(any()); var validationResults = getValidationResults(); var errors = new ArrayList(); @@ -1245,6 +1227,7 @@ public void updateAndResubmitToOde_RsuUpdateTimSuccess_ItisCodes() verifyNoInteractions(mockPathNodeXYService, mockRegionService, mockSdwService); verify(mockMilepostService).getMilepostsByStartEndPointDirection(any()); + verify(mockMilepostService).getMilepostCache(any()); verify(mockMilepostReduction).applyMilepostReductionAlgorithm(any(), any()); verifyNoMoreInteractions(mockMilepostService, mockMilepostReduction, mockDataFrameService, mockRsuService, mockOdeService, mockActiveTimHoldingService); @@ -1407,4 +1390,4 @@ private ActiveTim getActiveTim() { tim.setActiveTimId(-1L); return tim; } -} \ No newline at end of file +} diff --git a/cv-data-service-library/src/test/java/com/trihydro/library/service/MilepostServiceTest.java b/cv-data-service-library/src/test/java/com/trihydro/library/service/MilepostServiceTest.java index a668e816e..aed55ab2a 100644 --- a/cv-data-service-library/src/test/java/com/trihydro/library/service/MilepostServiceTest.java +++ b/cv-data-service-library/src/test/java/com/trihydro/library/service/MilepostServiceTest.java @@ -19,7 +19,9 @@ import org.mockito.Mock; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; public class MilepostServiceTest extends BaseServiceTest { @@ -89,4 +91,65 @@ public void getMilepostsByPointWithBuffer() { Assertions.assertEquals(1, data.size()); Assertions.assertEquals(milepost, data.get(0)); } -} \ No newline at end of file + + @Test + public void getBufferForPath_Success() { + // prepare + String routeId = "routeId"; + double desiredDistanceInMiles = 10.0; + Milepost milepost1 = new Milepost(); + Milepost milepost2 = new Milepost(); + List pathMileposts = new ArrayList<>(); + pathMileposts.add(milepost1); + pathMileposts.add(milepost2); + Milepost bufferMilepost1 = new Milepost(); + Milepost bufferMilepost2 = new Milepost(); + List bufferMileposts = new ArrayList<>(); + bufferMileposts.add(bufferMilepost1); + bufferMileposts.add(bufferMilepost2); + when(mockRespMilepostList.getBody()).thenReturn(bufferMileposts); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity> entity = new HttpEntity<>(pathMileposts, headers); + String url = String.format("%s/cdot-upstream-path/get-buffer-for-path/%s/%s", baseUrl, routeId, desiredDistanceInMiles); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() { + }; + when(mockRestTemplate.exchange(url, HttpMethod.POST, entity, responseType)).thenReturn(mockRespMilepostList); + + // execute + List data = uut.getBufferForPath(routeId, desiredDistanceInMiles, pathMileposts); + + // verify + verify(mockRestTemplate).exchange(url, HttpMethod.POST, entity, responseType); + Assertions.assertEquals(2, data.size()); + Assertions.assertEquals(bufferMilepost1, data.get(0)); + Assertions.assertEquals(bufferMilepost2, data.get(1)); + } + + @Test + public void getBufferForPath_Failure_ResponseBodyNull() { + // prepare + String routeId = "routeId"; + double desiredDistanceInMiles = 10.0; + Milepost milepost1 = new Milepost(); + Milepost milepost2 = new Milepost(); + List pathMileposts = new ArrayList<>(); + pathMileposts.add(milepost1); + pathMileposts.add(milepost2); + when(mockRespMilepostList.getBody()).thenReturn(null); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity> entity = new HttpEntity<>(pathMileposts, headers); + String url = String.format("%s/cdot-upstream-path/get-buffer-for-path/%s/%s", baseUrl, routeId, desiredDistanceInMiles); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference>() { + }; + when(mockRestTemplate.exchange(url, HttpMethod.POST, entity, responseType)).thenReturn(mockRespMilepostList); + + // execute + List data = uut.getBufferForPath(routeId, desiredDistanceInMiles, pathMileposts); + + // verify + verify(mockRestTemplate).exchange(url, HttpMethod.POST, entity, responseType); + Assertions.assertNull(data); + } +} diff --git a/cv-data-service-library/src/test/java/com/trihydro/library/service/WydotTimServiceTest.java b/cv-data-service-library/src/test/java/com/trihydro/library/service/WydotTimServiceTest.java index e14436a2f..854bd9ff7 100644 --- a/cv-data-service-library/src/test/java/com/trihydro/library/service/WydotTimServiceTest.java +++ b/cv-data-service-library/src/test/java/com/trihydro/library/service/WydotTimServiceTest.java @@ -1,9 +1,7 @@ package com.trihydro.library.service; import static org.junit.Assert.assertNull; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; @@ -17,9 +15,6 @@ import java.io.IOException; import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -50,7 +45,6 @@ import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.ActiveTim; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.Coordinate; import com.trihydro.library.model.EmailProps; import com.trihydro.library.model.Milepost; @@ -127,18 +121,18 @@ private List getActiveTims(boolean isSat) { List activeTims = new ArrayList(); ActiveTim aTim = new ActiveTim(); ActiveTim aTim2 = new ActiveTim(); - aTim.setActiveTimId(-1l); - aTim2.setActiveTimId(-2l); + aTim.setActiveTimId(-1L); + aTim2.setActiveTimId(-2L); if (isSat) { aTim.setSatRecordId("C27CBB9F"); aTim2.setSatRecordId("86E03786"); } else { aTim.setStartPoint(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))); aTim.setEndPoint(new Coordinate(BigDecimal.valueOf(3), BigDecimal.valueOf(4))); - aTim.setTimId(-10l); + aTim.setTimId(-10L); aTim2.setStartPoint(new Coordinate(BigDecimal.valueOf(5), BigDecimal.valueOf(6))); aTim2.setEndPoint(new Coordinate(BigDecimal.valueOf(7), BigDecimal.valueOf(8))); - aTim2.setTimId(-20l); + aTim2.setTimId(-20L); } activeTims.add(aTim); activeTims.add(aTim2); @@ -146,9 +140,8 @@ private List getActiveTims(boolean isSat) { return activeTims; } - private OdeTravelerInformationMessage getMockOdeTravelerInformationMessage() throws IOException { - String timJson = - new String(Files.readAllBytes(Paths.get("src/test/resources/com/trihydro/library/service/mockOdeTravelerInformationMessage.json"))); + private OdeTravelerInformationMessage getMockOdeTravelerInformationMessage() { + String timJson = "{\"msgCnt\":\"1\",\"timeStamp\":\"2017-08-03T22:25:36.297Z\",\"urlB\":\"null\",\"packetID\":\"EC9C236B0000000000\",\"dataframes\":[{\"startDateTime\":\"2017-08-02T22:25:00.000Z\",\"durationTime\":1,\"doNotUse1\":\"0\",\"frameType\":\"advisory\",\"msgId\":{\"furtherInfoID\":\"0\"},\"priority\":\"0\",\"doNotUse2\":\"3\",\"regions\":[{\"name\":\"Testing TIM\",\"regulatorID\":\"0\",\"segmentID\":\"33\",\"anchorPosition\":{\"latitude\":\"41.2500807\",\"longitude\":\"-111.0093847\",\"elevation\":\"2020.6969900289998\"},\"laneWidth\":\"7\",\"directionality\":\"3\",\"closedPath\":\"false\",\"description\":\"path\",\"path\":{\"scale\":\"0\",\"type\":\"ll\",\"nodes\":[{\"nodeLong\":\"0.0030982\",\"nodeLat\":\"0.0014562\",\"delta\":\"node-LL3\"},{\"nodeLong\":\"-111.0093847\",\"nodeLat\":\"41.2500807\",\"delta\":\"node-LatLon\"}]},\"direction\":\"0000000000001010\"}],\"doNotUse4\":\"2\",\"doNotUse3\":\"3\",\"content\":\"Advisory\",\"items\":[\"125\",\"some text\",\"250\",\"'98765\"],\"url\":\"null\"}]}"; Gson gson = new Gson(); return gson.fromJson(timJson, OdeTravelerInformationMessage.class); } @@ -230,16 +223,16 @@ public void createTim_ReturnsNull_WhenBuildTimReturnsNull() { String timTypeStr = "A"; String startDateTime = "2023-01-01T00:00:00.000Z"; String endDateTime = "2023-01-01T01:00:00.000Z"; - ContentEnum content = ContentEnum.workZone; TravelerInfoType frameType = TravelerInfoType.advisory; List allMileposts = new ArrayList<>(); List reducedMileposts = new ArrayList<>(); Milepost anchor = new Milepost(); + String dotGnisId = "1B2843"; - when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any(), any())).thenReturn(null); + when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any())).thenReturn(null); // Act - WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, content, frameType, allMileposts, reducedMileposts, anchor); + WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, frameType, allMileposts, reducedMileposts, anchor, dotGnisId); // Assert assertNull(result); @@ -251,18 +244,18 @@ public void createTim_SetsStartDateTime_WhenProvided() { String timTypeStr = "A"; String startDateTime = "2023-01-01T00:00:00.000Z"; String endDateTime = "2023-01-01T01:00:00.000Z"; - ContentEnum content = ContentEnum.workZone; TravelerInfoType frameType = TravelerInfoType.advisory; List allMileposts = new ArrayList<>(); List reducedMileposts = new ArrayList<>(); Milepost anchor = new Milepost(); + String dotGnisId = "1B2843"; WydotTravelerInputData timToSend = getMockWydotTravelerInputDataWithDataFrame(); - when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any(), any())).thenReturn(timToSend); + when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any())).thenReturn(timToSend); // Act - WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, content, frameType, allMileposts, reducedMileposts, anchor); + WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, frameType, allMileposts, reducedMileposts, anchor, dotGnisId); // Assert assertEquals(startDateTime, result.getTim().getDataframes()[0].getStartDateTime()); @@ -274,19 +267,19 @@ public void createTim_SetsDurationTime_WhenEndDateTimeProvided() { String timTypeStr = "A"; String startDateTime = "2023-01-01T00:00:00.000Z"; String endDateTime = "2023-01-01T01:00:00.000Z"; - ContentEnum content = ContentEnum.workZone; TravelerInfoType frameType = TravelerInfoType.advisory; List allMileposts = new ArrayList<>(); List reducedMileposts = new ArrayList<>(); Milepost anchor = new Milepost(); + String dotGnisId = "1B2843"; WydotTravelerInputData timToSend = getMockWydotTravelerInputDataWithDataFrame(); - when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any(), any())).thenReturn(timToSend); + when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any())).thenReturn(timToSend); when(mockUtility.getMinutesDurationBetweenTwoDates(anyString(), anyString())).thenReturn(60); // Act - WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, content, frameType, allMileposts, reducedMileposts, anchor); + WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, frameType, allMileposts, reducedMileposts, anchor, dotGnisId); // Assert assertEquals(60, result.getTim().getDataframes()[0].getDurationTime()); @@ -298,46 +291,69 @@ public void createTim_SetsDurationTimeTo120_ForParkingTim() { String timTypeStr = "P"; String startDateTime = "2023-01-01T00:00:00.000Z"; String endDateTime = "2023-01-01T01:00:00.000Z"; - ContentEnum content = ContentEnum.workZone; TravelerInfoType frameType = TravelerInfoType.advisory; List allMileposts = new ArrayList<>(); List reducedMileposts = new ArrayList<>(); Milepost anchor = new Milepost(); + String dotGnisId = "1B2843"; WydotTravelerInputData timToSend = getMockWydotTravelerInputDataWithDataFrame(); - when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any(), any())).thenReturn(timToSend); + when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any())).thenReturn(timToSend); // Act - WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, content, frameType, allMileposts, reducedMileposts, anchor); + WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, frameType, allMileposts, reducedMileposts, anchor, dotGnisId); // Assert assertEquals(120, result.getTim().getDataframes()[0].getDurationTime()); } @Test - public void createTim_SetsRandomPacketId() { + public void createTim_SetsRandomPacketIdWithGnisIdPrefix() { // Arrange String timTypeStr = "A"; String startDateTime = "2023-01-01T00:00:00.000Z"; String endDateTime = "2023-01-01T01:00:00.000Z"; - ContentEnum content = ContentEnum.workZone; TravelerInfoType frameType = TravelerInfoType.advisory; List allMileposts = new ArrayList<>(); List reducedMileposts = new ArrayList<>(); Milepost anchor = new Milepost(); + String dotGnisId = "1B2843"; WydotTravelerInputData timToSend = getMockWydotTravelerInputDataWithDataFrame(); - when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any(), any())).thenReturn(timToSend); + when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any())).thenReturn(timToSend); // Act - WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, content, frameType, allMileposts, reducedMileposts, anchor); + WydotTravelerInputData result = uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, frameType, allMileposts, reducedMileposts, anchor, dotGnisId); // Assert assertNotNull(result.getTim().getPacketID()); assertEquals(18, result.getTim().getPacketID().length()); assertTrue(result.getTim().getPacketID().matches("[0-9A-F]+")); + assertTrue(result.getTim().getPacketID().startsWith("1B2843")); + } + + @Test + public void createTim_ThrowsExceptionPacketIdUnsetGNISId() { + // Arrange + String timTypeStr = "A"; + String startDateTime = "2023-01-01T00:00:00.000Z"; + String endDateTime = "2023-01-01T01:00:00.000Z"; + TravelerInfoType frameType = TravelerInfoType.advisory; + List allMileposts = new ArrayList<>(); + List reducedMileposts = new ArrayList<>(); + Milepost anchor = new Milepost(); + String dotGnisId = "000000"; + + WydotTravelerInputData timToSend = getMockWydotTravelerInputDataWithDataFrame(); + + when(mockCreateBaseTimUtil.buildTim(any(), any(), any(), any(), any(), any())).thenReturn(timToSend); + + // Act & Assert + assertThrows(IllegalStateException.class, () -> { + uut.createTim(new WydotTim(), timTypeStr, startDateTime, endDateTime, frameType, allMileposts, reducedMileposts, anchor, dotGnisId); + }); } @Test @@ -554,11 +570,11 @@ public void deleteTimsFromRsusAndSdx_Rsu() { List activeTims = getActiveTims(false); List timRsus = new ArrayList<>(); TimRsu timRsu = new TimRsu(); - timRsu.setRsuId(-10l); + timRsu.setRsuId(-10L); timRsu.setRsuIndex(-1); timRsus.add(timRsu); - when(mockTimRsuService.getTimRsusByTimId(-10l)).thenReturn(new ArrayList<>()); - when(mockTimRsuService.getTimRsusByTimId(-20l)).thenReturn(timRsus); + when(mockTimRsuService.getTimRsusByTimId(-10L)).thenReturn(new ArrayList<>()); + when(mockTimRsuService.getTimRsusByTimId(-20L)).thenReturn(timRsus); ArrayList allRsus = new ArrayList<>(); WydotRsu wydotRsu = new WydotRsu(); wydotRsu.setRsuId(-10); @@ -574,8 +590,8 @@ public void deleteTimsFromRsusAndSdx_Rsu() { var result = uut.deleteTimsFromRsusAndSdx(activeTims); // Assert - verify(mockActiveTimService).deleteActiveTim(-1l); - verify(mockActiveTimService).deleteActiveTim(-2l); + verify(mockActiveTimService).deleteActiveTim(-1L); + verify(mockActiveTimService).deleteActiveTim(-2L); Assertions.assertEquals(result.getSuccessfulRsuDeletions().size(), 2); } @@ -598,7 +614,7 @@ public void deleteTimsFromRsusAndSdx_Sdx() throws MailException, MessagingExcept // Assert verify(mockEmailHelper).SendEmail(mockEmailProps.getAlertAddresses(), subject, body); List delIds = new ArrayList(); - delIds.add(-2l); + delIds.add(-2L); verify(mockActiveTimService).deleteActiveTimsById(delIds); verify(mockTimRsuService, never()).getTimRsusByTimId(isA(Long.class)); Assertions.assertEquals(1, result.getSuccessfulSatelliteDeletions().size()); @@ -618,8 +634,8 @@ public void deleteTimsFromRsusAndSdx_SdxNullValueInMap() throws MailException, M // Assert List delIds = new ArrayList(); - delIds.add(-1l); - delIds.add(-2l); + delIds.add(-1L); + delIds.add(-2L); verify(mockActiveTimService).deleteActiveTimsById(delIds); } @@ -629,11 +645,11 @@ public void deleteTimsFromRsusAndSdx_Exceptions() { List activeTims = getActiveTims(false); List timRsus = new ArrayList<>(); TimRsu timRsu = new TimRsu(); - timRsu.setRsuId(-10l); + timRsu.setRsuId(-10L); timRsu.setRsuIndex(-1); timRsus.add(timRsu); - when(mockTimRsuService.getTimRsusByTimId(-10l)).thenReturn(new ArrayList<>()); - when(mockTimRsuService.getTimRsusByTimId(-20l)).thenReturn(timRsus); + when(mockTimRsuService.getTimRsusByTimId(-10L)).thenReturn(new ArrayList<>()); + when(mockTimRsuService.getTimRsusByTimId(-20L)).thenReturn(timRsus); ArrayList allRsus = new ArrayList<>(); WydotRsu wydotRsu = new WydotRsu(); wydotRsu.setRsuId(-10); @@ -649,8 +665,8 @@ public void deleteTimsFromRsusAndSdx_Exceptions() { var result = uut.deleteTimsFromRsusAndSdx(activeTims); // Assert - verify(mockActiveTimService).deleteActiveTim(-1l); - verify(mockActiveTimService).deleteActiveTim(-2l); + verify(mockActiveTimService).deleteActiveTim(-1L); + verify(mockActiveTimService).deleteActiveTim(-2L); List timRsuJson = new ArrayList(); Gson gson = new Gson(); for (TimRsu tr : timRsus) { @@ -952,6 +968,6 @@ public void setBufferItisCodes_unrecognizedAction() { Integer[] result = uut.setBufferItisCodes(action); // Assert - Assertions.assertEquals(null, result); + Assertions.assertNull(result); } } \ No newline at end of file diff --git a/cv-data-service-library/src/test/resources/application.properties b/cv-data-service-library/src/test/resources/application.properties index 1cb73ae12..1283129c1 100644 --- a/cv-data-service-library/src/test/resources/application.properties +++ b/cv-data-service-library/src/test/resources/application.properties @@ -11,4 +11,8 @@ config.dbPassword=password config.maximumPoolSize=7 config.connectionTimeout=300000 config.env=test -config.sdwRestUrl=http://localhost:12230 \ No newline at end of file +config.sdwRestUrl=http://localhost:12230 + +data-service-library.kafka.confluentKey=testKey +data-service-library.kafka.confluentSecret=testSecret +data-service-library.kafka.kafkaType=LOCAL \ No newline at end of file diff --git a/cv-data-service-library/src/test/resources/com/trihydro/library/service/mockOdeTravelerInformationMessage.json b/cv-data-service-library/src/test/resources/com/trihydro/library/service/mockOdeTravelerInformationMessage.json index 828c86c39..e350b63ef 100644 --- a/cv-data-service-library/src/test/resources/com/trihydro/library/service/mockOdeTravelerInformationMessage.json +++ b/cv-data-service-library/src/test/resources/com/trihydro/library/service/mockOdeTravelerInformationMessage.json @@ -10,16 +10,7 @@ "doNotUse1": "0", "frameType": "advisory", "msgId": { - "roadSignID": { - "position": { - "latitude": "41.678473", - "longitude": "-108.782775", - "elevation": "917.1432" - }, - "viewAngle": "1010101010101010", - "mutcdCode": "warning", - "crc": "0000" - } + "furtherInfoID": "0" }, "priority": "0", "doNotUse2": "3", diff --git a/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput.json b/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput.json index 169a60727..2f93bdc33 100644 --- a/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput.json +++ b/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput.json @@ -90,17 +90,7 @@ "roadSignage": "" }, "msgId": { - "roadSignID": { - "viewAngle": 1100000000000001, - "mutcdCode": { - "warning": "" - }, - "position": { - "elevation": 20, - "lat": 263055670, - "long": -801481500 - } - } + "furtherInfoID": "0" }, "startTime": 149760, "priority": 2, diff --git a/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_Geometry.json b/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_Geometry.json index cff628b73..c50d92da9 100644 --- a/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_Geometry.json +++ b/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_Geometry.json @@ -77,17 +77,7 @@ "roadSignage": "" }, "msgId": { - "roadSignID": { - "viewAngle": 1100000000000001, - "mutcdCode": { - "warning": "" - }, - "position": { - "elevation": 20, - "lat": 263055670, - "long": -801481500 - } - } + "furtherInfoID": "0" }, "startTime": 149760, "priority": 2, diff --git a/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_MultipleRegions.json b/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_MultipleRegions.json index 1549e6c85..b223fea56 100644 --- a/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_MultipleRegions.json +++ b/cv-data-service-library/src/test/resources/rxMsg_TIM_OdeOutput_MultipleRegions.json @@ -134,17 +134,7 @@ "roadSignage": "" }, "msgId": { - "roadSignID": { - "viewAngle": 1100000000000001, - "mutcdCode": { - "warning": "" - }, - "position": { - "elevation": 20, - "lat": 263055670, - "long": -801481500 - } - } + "furtherInfoID": "0" }, "startTime": 149760, "priority": 2, diff --git a/cv-data-service-library/src/test/resources/rxMsg_TIM_SpeedLimit.json b/cv-data-service-library/src/test/resources/rxMsg_TIM_SpeedLimit.json index 4692d3167..6814be0e4 100644 --- a/cv-data-service-library/src/test/resources/rxMsg_TIM_SpeedLimit.json +++ b/cv-data-service-library/src/test/resources/rxMsg_TIM_SpeedLimit.json @@ -90,17 +90,7 @@ "roadSignage": "" }, "msgId": { - "roadSignID": { - "viewAngle": 1100000000000001, - "mutcdCode": { - "warning": "" - }, - "position": { - "elevation": 20, - "lat": 263055670, - "long": -801481500 - } - } + "furtherInfoID": "0" }, "startTime": 149760, "priority": 2, diff --git a/cv-data-service-library/src/test/resources/sdxDecodeResponse.json b/cv-data-service-library/src/test/resources/sdxDecodeResponse.json index 0ee50ee8c..1102aa065 100644 --- a/cv-data-service-library/src/test/resources/sdxDecodeResponse.json +++ b/cv-data-service-library/src/test/resources/sdxDecodeResponse.json @@ -1,4 +1,4 @@ { "messageType": "MessageFrame", - "decodedMessage": "3113469004null0414344751-1101051425111111111111111120194690043200050westbound_I80_39.9_53.31_SAT-4035A5DF_RC_LYMI80EGRAD00414344751-11010514253270000000011111100000-1048300445417415787-1101068786414338729-1048297813417401082-1101173822414302517-1048296846417313218-1101278808414263469-1048334156417231472-1101362065414212124-1048363596417151273-1048348231417067803-1101430219414153700-1101515051414095801-1048292665416990008-1101609734414047121-1048303785416903264-1101704290413998478-1048330081416818875-1101798529413950074-1048362115416736381-1048394037416654255-1101901550413914121-1102014424413891332-1048426742416569080-1102126907413868840-1048459137416484285-1102235582413840132-1048492892416400669-1102332568413793094-1048526150416318091-1048559229416236049-1102434259413752451-1102543983413731407-1048592545416153296-1102655116413714865-1048625771416070802-1102767179413702216-1048658799415988821-1102881705413689256-1048694127415905527-1048732305415821992-1102996201413671479-1103105581413647716-1048769216415741004-1103216030413622307-1048806392415659600-1103325763413587617-1048843990415577334-11033794134135705070058955907null" + "decodedMessage": "3113469004null0020194690043200050westbound_I80_39.9_53.31_SAT-4035A5DF_RC_LYMI80EGRAD00414344751-11010514253270000000011111100000-1048300445417415787-1101068786414338729-1048297813417401082-1101173822414302517-1048296846417313218-1101278808414263469-1048334156417231472-1101362065414212124-1048363596417151273-1048348231417067803-1101430219414153700-1101515051414095801-1048292665416990008-1101609734414047121-1048303785416903264-1101704290413998478-1048330081416818875-1101798529413950074-1048362115416736381-1048394037416654255-1101901550413914121-1102014424413891332-1048426742416569080-1102126907413868840-1048459137416484285-1102235582413840132-1048492892416400669-1102332568413793094-1048526150416318091-1048559229416236049-1102434259413752451-1102543983413731407-1048592545416153296-1102655116413714865-1048625771416070802-1102767179413702216-1048658799415988821-1102881705413689256-1048694127415905527-1048732305415821992-1102996201413671479-1103105581413647716-1048769216415741004-1103216030413622307-1048806392415659600-1103325763413587617-1048843990415577334-11033794134135705070058955907null" } diff --git a/cv-data-service-library/src/test/resources/tim_construction.json b/cv-data-service-library/src/test/resources/tim_construction.json index 8385e897d..8594cc3fb 100644 --- a/cv-data-service-library/src/test/resources/tim_construction.json +++ b/cv-data-service-library/src/test/resources/tim_construction.json @@ -39,28 +39,7 @@ "doNotUse1": 0, "frameType": "advisory", "msgId": { - "roadSignID": { - "position": { "lat": 417732928, "long": -1071000312 }, - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - }, - "mutcdCode": "warning" - } + "furtherInfoID": "0" }, "durationTime": 32000, "startYear": 2021, diff --git a/cv-data-service-library/src/test/resources/tim_construction_MultipleRegions.json b/cv-data-service-library/src/test/resources/tim_construction_MultipleRegions.json index 2b0d145ab..5661c16de 100644 --- a/cv-data-service-library/src/test/resources/tim_construction_MultipleRegions.json +++ b/cv-data-service-library/src/test/resources/tim_construction_MultipleRegions.json @@ -39,28 +39,7 @@ "doNotUse1": 0, "frameType": "advisory", "msgId": { - "roadSignID": { - "position": { "lat": 417732928, "long": -1071000312 }, - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - }, - "mutcdCode": "warning" - } + "furtherInfoID": "0" }, "durationTime": 32000, "startYear": 2021, diff --git a/cv-data-service-library/src/test/resources/tim_parking.json b/cv-data-service-library/src/test/resources/tim_parking.json index 519b60e3b..e96e1cb20 100644 --- a/cv-data-service-library/src/test/resources/tim_parking.json +++ b/cv-data-service-library/src/test/resources/tim_parking.json @@ -39,28 +39,7 @@ "doNotUse1": 0, "frameType": "advisory", "msgId": { - "roadSignID": { - "position": { "lat": 417732928, "long": -1071000312 }, - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - }, - "mutcdCode": "warning" - } + "furtherInfoID": "0" }, "durationTime": 32000, "startYear": 2021, diff --git a/cv-data-service-library/src/test/resources/tim_parking_MultipleRegions.json b/cv-data-service-library/src/test/resources/tim_parking_MultipleRegions.json index 594adfcc4..34b291a81 100644 --- a/cv-data-service-library/src/test/resources/tim_parking_MultipleRegions.json +++ b/cv-data-service-library/src/test/resources/tim_parking_MultipleRegions.json @@ -142,28 +142,7 @@ "doNotUse4": 0, "startYear": 2021, "msgId": { - "roadSignID": { - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - }, - "mutcdCode": "warning", - "position": { "lat": 410985067, "long": -1051331761 } - } + "furtherInfoID": "0" }, "priority": 5, "content": { diff --git a/cv-data-service-library/src/test/resources/tim_vsl.json b/cv-data-service-library/src/test/resources/tim_vsl.json index fde8dd0cb..881717ad8 100644 --- a/cv-data-service-library/src/test/resources/tim_vsl.json +++ b/cv-data-service-library/src/test/resources/tim_vsl.json @@ -39,28 +39,7 @@ "doNotUse1": 0, "frameType": "advisory", "msgId": { - "roadSignID": { - "position": { "lat": 417732928, "long": -1071000312 }, - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - }, - "mutcdCode": "warning" - } + "furtherInfoID": "0" }, "durationTime": 32000, "startYear": 2021, diff --git a/cv-data-service-library/src/test/resources/tim_vsl_MultipleRegions.json b/cv-data-service-library/src/test/resources/tim_vsl_MultipleRegions.json index e8220debf..9fe41d220 100644 --- a/cv-data-service-library/src/test/resources/tim_vsl_MultipleRegions.json +++ b/cv-data-service-library/src/test/resources/tim_vsl_MultipleRegions.json @@ -126,28 +126,7 @@ "doNotUse4": 1, "startYear": 2021, "msgId": { - "roadSignID": { - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - }, - "mutcdCode": "regulatory", - "position": { "lat": 428605724, "long": -1063379489 } - } + "furtherInfoID": "0" }, "priority": 5, "content": { diff --git a/cv-data-tasks/src/main/java/com/trihydro/tasks/actions/CleanupActiveTims.java b/cv-data-tasks/src/main/java/com/trihydro/tasks/actions/CleanupActiveTims.java index c64d53ee5..8cb056f03 100644 --- a/cv-data-tasks/src/main/java/com/trihydro/tasks/actions/CleanupActiveTims.java +++ b/cv-data-tasks/src/main/java/com/trihydro/tasks/actions/CleanupActiveTims.java @@ -17,51 +17,57 @@ import org.springframework.http.MediaType; import org.springframework.stereotype.Component; +import com.trihydro.library.service.MilepostService; + @Component public class CleanupActiveTims implements Runnable { private DataTasksConfiguration configuration; private Utility utility; private ActiveTimService activeTimService; private RestTemplateProvider restTemplateProvider; + private MilepostService milepostService; @Autowired public void InjectDependencies(DataTasksConfiguration _configuration, Utility _utility, - ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider) { + ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider, MilepostService _milepostService) { configuration = _configuration; utility = _utility; activeTimService = _activeTimService; restTemplateProvider = _restTemplateProvider; + milepostService = _milepostService; } + @Override public void run() { utility.logWithDate("Running...", this.getClass()); try { - List activeTims = new ArrayList(); - List tmp = null; + List activeTims = new ArrayList<>(); + List tmp; // select active tims missing ITIS codes tmp = activeTimService.getActiveTimsMissingItisCodes(); - if (tmp.size() > 0) { + if (tmp.isEmpty()) { + } else { utility.logWithDate("Found " + tmp.size() + " Active TIMs missing ITIS Codes", this.getClass()); activeTims.addAll(tmp); } // add active tims that weren't sent to the SDX or any RSUs tmp = activeTimService.getActiveTimsNotSent(); - if (tmp.size() > 0) { + if (!tmp.isEmpty()) { utility.logWithDate("Found " + tmp.size() + " Active TIMs that weren't distributed", this.getClass()); activeTims.addAll(tmp); } - if (activeTims.size() == 0) { + if (!activeTims.isEmpty()) { utility.logWithDate("Found 0 Active TIMs", this.getClass()); } // delete from rsus and the SDX HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity entity = null; + HttpEntity entity; String activeTimJson; Gson gson = new Gson(); @@ -69,7 +75,7 @@ public void run() { for (ActiveTim activeTim : activeTims) { activeTimJson = gson.toJson(activeTim); - entity = new HttpEntity(activeTimJson, headers); + entity = new HttpEntity<>(activeTimJson, headers); utility.logWithDate( "CleanupActiveTims - Deleting ActiveTim: { activeTimId: " + activeTim.getActiveTimId() + " }", @@ -77,6 +83,10 @@ public void run() { restTemplateProvider.GetRestTemplate().exchange(configuration.getWrapperUrl() + "/delete-tim/", HttpMethod.DELETE, entity, String.class); } + + // clear the milepostService cache to ensure that the milepost data is up to date + utility.logWithDate("Deleting milepost cache", this.getClass()); + milepostService.clearMilepostCache(); } catch (Exception e) { e.printStackTrace(); // don't rethrow error, or the task won't be reran until the service is diff --git a/db-scripts/pgsql/setup/sql/1-create_all_tables.sql b/db-scripts/pgsql/setup/sql/1-create_all_tables.sql index b8c72654c..bd0b10b65 100644 --- a/db-scripts/pgsql/setup/sql/1-create_all_tables.sql +++ b/db-scripts/pgsql/setup/sql/1-create_all_tables.sql @@ -1,9 +1,10 @@ SET client_encoding TO 'UTF8'; - +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS postgis; -- not part of a dependency relationship -- -CREATE TABLE active_tim_holding ( +CREATE TABLE IF NOT EXISTS active_tim_holding ( active_tim_holding_id bigint NOT NULL, client_id varchar(255), direction varchar(50) NOT NULL, @@ -29,7 +30,7 @@ ALTER TABLE active_tim_holding ALTER COLUMN END_LONGITUDE SET NOT NULL; ALTER TABLE active_tim_holding ALTER COLUMN DIRECTION SET NOT NULL; -CREATE TABLE http_logging ( +CREATE TABLE IF NOT EXISTS http_logging ( http_logging_id bigint NOT NULL, request_time timestamp NOT NULL, rest_request varchar(2000) NOT NULL, @@ -41,7 +42,7 @@ ALTER TABLE http_logging ALTER COLUMN REQUEST_TIME SET NOT NULL; ALTER TABLE http_logging ALTER COLUMN REST_REQUEST SET NOT NULL; -CREATE TABLE milepost_test ( +CREATE TABLE IF NOT EXISTS milepost_test ( route varchar(255), milepost decimal(38,8), direction varchar(255), @@ -52,7 +53,7 @@ CREATE TABLE milepost_test ( ) ; -CREATE TABLE mileposts ( +CREATE TABLE IF NOT EXISTS mileposts ( common_name varchar(20), direction varchar(1), milepost decimal(38,8), @@ -63,7 +64,7 @@ CREATE TABLE mileposts ( ) ; -CREATE TABLE rw_buffer_action_lut ( +CREATE TABLE IF NOT EXISTS rw_buffer_action_lut ( description varchar(50), code varchar(20), rw_buffer_action_lut_id bigint NOT NULL @@ -71,7 +72,7 @@ CREATE TABLE rw_buffer_action_lut ( ALTER TABLE rw_buffer_action_lut ADD PRIMARY KEY (rw_buffer_action_lut_id); -CREATE TABLE tim_type ( +CREATE TABLE IF NOT EXISTS tim_type ( type varchar(10), description varchar(255), tim_type_id bigint NOT NULL @@ -79,7 +80,7 @@ CREATE TABLE tim_type ( ALTER TABLE tim_type ADD PRIMARY KEY (tim_type_id); -CREATE TABLE entity_type ( +CREATE TABLE IF NOT EXISTS entity_type ( entity_type_id bigint NOT NULL, name varchar(128) NOT NULL, description varchar(255) @@ -89,7 +90,7 @@ ALTER TABLE entity_type ALTER COLUMN ENTITY_TYPE_ID SET NOT NULL; ALTER TABLE entity_type ALTER COLUMN NAME SET NOT NULL; -CREATE TABLE status_type ( +CREATE TABLE IF NOT EXISTS status_type ( status_type_id bigint NOT NULL, name varchar(128) NOT NULL, description varchar(255) @@ -99,7 +100,7 @@ ALTER TABLE status_type ALTER COLUMN STATUS_TYPE_ID SET NOT NULL; ALTER TABLE status_type ALTER COLUMN NAME SET NOT NULL; -CREATE TABLE security_result_code_type ( +CREATE TABLE IF NOT EXISTS security_result_code_type ( security_result_code_type varchar(255) NOT NULL, security_result_code_type_id bigint NOT NULL ) ; @@ -107,7 +108,7 @@ ALTER TABLE security_result_code_type ADD PRIMARY KEY (security_result_code_type ALTER TABLE security_result_code_type ALTER COLUMN SECURITY_RESULT_CODE_TYPE SET NOT NULL; -CREATE TABLE category ( +CREATE TABLE IF NOT EXISTS category ( category_id bigint NOT NULL, category varchar(255) ) ; @@ -115,7 +116,7 @@ ALTER TABLE category ADD PRIMARY KEY (category_id); ALTER TABLE category ALTER COLUMN CATEGORY_ID SET NOT NULL; -CREATE TABLE node_xy ( +CREATE TABLE IF NOT EXISTS node_xy ( node_xy_id bigint NOT NULL, delta varchar(255), node_lat double precision, @@ -129,7 +130,7 @@ ALTER TABLE node_xy ADD PRIMARY KEY (node_xy_id); ALTER TABLE node_xy ALTER COLUMN NODE_XY_ID SET NOT NULL; -CREATE TABLE node_ll ( +CREATE TABLE IF NOT EXISTS node_ll ( node_ll_id bigint NOT NULL, delta varchar(255), node_lat double precision, @@ -143,7 +144,7 @@ ALTER TABLE node_ll ADD PRIMARY KEY (node_ll_id); ALTER TABLE node_ll ALTER COLUMN NODE_LL_ID SET NOT NULL; -CREATE TABLE computed_lane ( +CREATE TABLE IF NOT EXISTS computed_lane ( computed_lane_id bigint NOT NULL, lane_id bigint NOT NULL, offset_small_x bigint NOT NULL, @@ -163,18 +164,7 @@ ALTER TABLE computed_lane ALTER COLUMN OFFSET_SMALL_Y SET NOT NULL; ALTER TABLE computed_lane ALTER COLUMN OFFSET_LARGE_Y SET NOT NULL; -CREATE TABLE rsu_firmware ( - firmware_id varchar(128) NOT NULL, - firmware_file varchar(255) NOT NULL, - update_process varchar(255), - release_date timestamp(0) NOT NULL -) ; -ALTER TABLE rsu_firmware ADD PRIMARY KEY (firmware_id); -ALTER TABLE rsu_firmware ALTER COLUMN FIRMWARE_FILE SET NOT NULL; -ALTER TABLE rsu_firmware ALTER COLUMN RELEASE_DATE SET NOT NULL; - - -CREATE TABLE status_log ( +CREATE TABLE IF NOT EXISTS status_log ( log_id bigint NOT NULL, status_time timestamp NOT NULL, entity_id integer NOT NULL, @@ -193,7 +183,7 @@ ALTER TABLE status_log ADD CONSTRAINT entypetolog_fk FOREIGN KEY (entity_type_id ALTER TABLE status_log ADD CONSTRAINT sttypetolog_fk FOREIGN KEY (status_type_id) REFERENCES status_type(status_type_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE itis_code ( +CREATE TABLE IF NOT EXISTS itis_code ( itis_code_id bigint NOT NULL, description varchar(255) NOT NULL, category_id bigint NOT NULL, @@ -206,7 +196,7 @@ ALTER TABLE itis_code ALTER COLUMN CATEGORY_ID SET NOT NULL; ALTER TABLE itis_code ADD CONSTRAINT fk_category FOREIGN KEY (category_id) REFERENCES category(category_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE tim ( +CREATE TABLE IF NOT EXISTS tim ( msg_cnt varchar(255), url_b varchar(255), time_stamp timestamp, @@ -243,7 +233,7 @@ ALTER TABLE tim ADD PRIMARY KEY (tim_id); ALTER TABLE tim ADD CONSTRAINT fk_sec_result_code_type_tim FOREIGN KEY (security_result_code) REFERENCES security_result_code_type(security_result_code_type_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE shape_point ( +CREATE TABLE IF NOT EXISTS shape_point ( shape_point_id bigint NOT NULL, lane_width bigint, directionality bigint, @@ -258,7 +248,7 @@ ALTER TABLE shape_point ALTER COLUMN SHAPE_POINT_ID SET NOT NULL; ALTER TABLE shape_point ADD CONSTRAINT fk_computed_lane_shape_point FOREIGN KEY (computed_lane_id) REFERENCES computed_lane(computed_lane_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE path ( +CREATE TABLE IF NOT EXISTS path ( path_id bigint NOT NULL, scale bigint, type varchar(255), @@ -269,7 +259,7 @@ ALTER TABLE path ALTER COLUMN PATH_ID SET NOT NULL; ALTER TABLE path ADD CONSTRAINT fk_computed_lane_path FOREIGN KEY (computed_lane_id) REFERENCES computed_lane(computed_lane_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE data_list ( +CREATE TABLE IF NOT EXISTS data_list ( data_list_id bigint NOT NULL, node_xy_id bigint NOT NULL, path_endpoint_angle bigint NOT NULL, @@ -289,19 +279,7 @@ ALTER TABLE data_list ALTER COLUMN LANE_ANGLE SET NOT NULL; ALTER TABLE data_list ADD CONSTRAINT fk_node_xy_data_list FOREIGN KEY (node_xy_id) REFERENCES node_xy(node_xy_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE rsu ( - rsu_id bigint NOT NULL, - deviceid integer, - update_username varchar(255) DEFAULT 'ADMIN', - update_password varchar(128), - firmware_id varchar(128) -) ; -ALTER TABLE rsu ADD PRIMARY KEY (rsu_id); -ALTER TABLE rsu ALTER COLUMN RSU_ID SET NOT NULL; -ALTER TABLE rsu ADD CONSTRAINT fk_rsu2firmware FOREIGN KEY (firmware_id) REFERENCES rsu_firmware(firmware_id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE; - - -CREATE TABLE incident_action_lut ( +CREATE TABLE IF NOT EXISTS incident_action_lut ( description varchar(60), code varchar(10), itis_code_id bigint, @@ -311,7 +289,7 @@ ALTER TABLE incident_action_lut ADD PRIMARY KEY (incident_action_lut_id); ALTER TABLE incident_action_lut ADD CONSTRAINT fk_itis_code_incident_action FOREIGN KEY (itis_code_id) REFERENCES itis_code(itis_code_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE incident_effect_lut ( +CREATE TABLE IF NOT EXISTS incident_effect_lut ( description varchar(50), code varchar(20), itis_code_id bigint, @@ -321,7 +299,7 @@ ALTER TABLE incident_effect_lut ADD PRIMARY KEY (incident_effect_lut_id); ALTER TABLE incident_effect_lut ADD CONSTRAINT fk_itis_code_incident_effect FOREIGN KEY (itis_code_id) REFERENCES itis_code(itis_code_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE incident_problem_lut ( +CREATE TABLE IF NOT EXISTS incident_problem_lut ( description varchar(50), code varchar(20), itis_code_id bigint, @@ -331,7 +309,7 @@ ALTER TABLE incident_problem_lut ADD PRIMARY KEY (incident_problem_lut_id); ALTER TABLE incident_problem_lut ADD CONSTRAINT fk_itis_code_incident_problem FOREIGN KEY (itis_code_id) REFERENCES itis_code(itis_code_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE active_tim ( +CREATE TABLE IF NOT EXISTS active_tim ( tim_id bigint, milepost_start double precision, milepost_stop double precision, @@ -356,7 +334,7 @@ ALTER TABLE active_tim ADD PRIMARY KEY (active_tim_id); ALTER TABLE active_tim ADD CONSTRAINT fk_tim_active_tim FOREIGN KEY (tim_id) REFERENCES tim(tim_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE data_frame ( +CREATE TABLE IF NOT EXISTS data_frame ( data_frame_id bigint NOT NULL, tim_id bigint NOT NULL, ssp_tim_rights integer, @@ -385,7 +363,7 @@ ALTER TABLE data_frame ALTER COLUMN TIM_ID SET NOT NULL; ALTER TABLE data_frame ADD CONSTRAINT fk_tim_df FOREIGN KEY (tim_id) REFERENCES tim(tim_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE path_node_ll ( +CREATE TABLE IF NOT EXISTS path_node_ll ( path_node_ll_id bigint NOT NULL, path_id bigint NOT NULL, node_ll_id bigint NOT NULL @@ -399,7 +377,7 @@ ALTER TABLE path_node_ll ADD CONSTRAINT fk_path_node_ll_node_ll FOREIGN KEY (nod ALTER TABLE path_node_ll ADD CONSTRAINT fk_path_node_ll_path FOREIGN KEY (path_id) REFERENCES path(path_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE path_node_xy ( +CREATE TABLE IF NOT EXISTS path_node_xy ( path_node_xy_id bigint NOT NULL, path_id bigint NOT NULL, node_xy_id bigint NOT NULL @@ -413,7 +391,7 @@ ALTER TABLE path_node_xy ADD CONSTRAINT fk_node_xy_path FOREIGN KEY (node_xy_id) ALTER TABLE path_node_xy ADD CONSTRAINT fk_path_node_xy FOREIGN KEY (path_id) REFERENCES path(path_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE shape_point_node_xy ( +CREATE TABLE IF NOT EXISTS shape_point_node_xy ( shape_point_node_xy_id bigint NOT NULL, shape_point_id bigint NOT NULL, node_xy_id bigint NOT NULL @@ -427,7 +405,7 @@ ALTER TABLE shape_point_node_xy ADD CONSTRAINT fk_node_xy_shape_point FOREIGN KE ALTER TABLE shape_point_node_xy ADD CONSTRAINT fk_shape_point_node_xy FOREIGN KEY (shape_point_id) REFERENCES shape_point(shape_point_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE old_region ( +CREATE TABLE IF NOT EXISTS old_region ( old_region_id bigint NOT NULL, direction varchar(255) NOT NULL, extent bigint, @@ -452,24 +430,8 @@ ALTER TABLE old_region ALTER COLUMN CIRCLE_UNITS SET NOT NULL; ALTER TABLE old_region ADD CONSTRAINT fk_shape_point FOREIGN KEY (shape_point_id) REFERENCES shape_point(shape_point_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE tim_rsu ( - tim_rsu_id bigint NOT NULL, - rsu_id bigint NOT NULL, - tim_id bigint NOT NULL, - rsu_index bigint -) ; -ALTER TABLE tim_rsu ADD UNIQUE (rsu_id,tim_id,rsu_index); -ALTER TABLE tim_rsu ADD PRIMARY KEY (tim_rsu_id); -ALTER TABLE tim_rsu ALTER COLUMN TIM_RSU_ID SET NOT NULL; -ALTER TABLE tim_rsu ALTER COLUMN RSU_ID SET NOT NULL; -ALTER TABLE tim_rsu ALTER COLUMN TIM_ID SET NOT NULL; -ALTER TABLE tim_rsu ADD CONSTRAINT sys_c0021538 FOREIGN KEY (rsu_id) REFERENCES rsu(rsu_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; - -ALTER TABLE tim_rsu ADD CONSTRAINT sys_c0021539 FOREIGN KEY (tim_id) REFERENCES tim(tim_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; - - -- dependent level 3 (dependent on level 2 tables and possibly level 1/level 0 tables) -- -CREATE TABLE data_frame_itis_code ( +CREATE TABLE IF NOT EXISTS data_frame_itis_code ( data_frame_itis_code_id bigint NOT NULL, itis_code_id bigint, data_frame_id bigint NOT NULL, @@ -484,7 +446,7 @@ ALTER TABLE data_frame_itis_code ADD CONSTRAINT fk_data_frame_itis_code FOREIGN ALTER TABLE data_frame_itis_code ADD CONSTRAINT fk_itis_code FOREIGN KEY (itis_code_id) REFERENCES itis_code(itis_code_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE region ( +CREATE TABLE IF NOT EXISTS region ( region_id bigint NOT NULL, data_frame_id bigint NOT NULL, name varchar(255), @@ -522,7 +484,7 @@ ALTER TABLE region ADD CONSTRAINT fk_old_region FOREIGN KEY (old_region_id) REFE ALTER TABLE region ADD CONSTRAINT fk_path FOREIGN KEY (path_id) REFERENCES path(path_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; -CREATE TABLE region_list ( +CREATE TABLE IF NOT EXISTS region_list ( region_list_id bigint NOT NULL, old_region_id bigint NOT NULL, x_offset bigint NOT NULL, @@ -536,3 +498,223 @@ ALTER TABLE region_list ALTER COLUMN X_OFFSET SET NOT NULL; ALTER TABLE region_list ALTER COLUMN Y_OFFSET SET NOT NULL; ALTER TABLE region_list ALTER COLUMN Z_OFFSET SET NOT NULL; ALTER TABLE region_list ADD CONSTRAINT fk_old_region_region_list FOREIGN KEY (old_region_id) REFERENCES old_region(old_region_id) ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE; + +-- RSU-Specific Tables + +CREATE SEQUENCE manufacturers_manufacturer_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS manufacturers +( + manufacturer_id integer NOT NULL DEFAULT nextval('manufacturers_manufacturer_id_seq'::regclass), + name character varying(128) COLLATE pg_catalog.default NOT NULL, + CONSTRAINT manufacturers_pkey PRIMARY KEY (manufacturer_id), + CONSTRAINT manufacturers_name UNIQUE (name) +); + +CREATE SEQUENCE rsu_models_rsu_model_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS rsu_models +( + rsu_model_id integer NOT NULL DEFAULT nextval('rsu_models_rsu_model_id_seq'::regclass), + name character varying(128) COLLATE pg_catalog.default NOT NULL, + supported_radio character varying(128) COLLATE pg_catalog.default NOT NULL, + manufacturer integer NOT NULL, + CONSTRAINT rsu_models_pkey PRIMARY KEY (rsu_model_id), + CONSTRAINT rsu_models_name UNIQUE (name), + CONSTRAINT fk_manufacturer FOREIGN KEY (manufacturer) + REFERENCES manufacturers (manufacturer_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION +); + +CREATE SEQUENCE rsu_credentials_credential_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS rsu_credentials +( + credential_id integer NOT NULL DEFAULT nextval('rsu_credentials_credential_id_seq'::regclass), + username character varying(128) COLLATE pg_catalog.default NOT NULL, + password character varying(128) COLLATE pg_catalog.default NOT NULL, + nickname character varying(128) COLLATE pg_catalog.default NOT NULL, + CONSTRAINT rsu_credentials_pkey PRIMARY KEY (credential_id), + CONSTRAINT rsu_credentials_nickname UNIQUE (nickname) +); + +CREATE SEQUENCE snmp_credentials_snmp_credential_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS snmp_credentials +( + snmp_credential_id integer NOT NULL DEFAULT nextval('snmp_credentials_snmp_credential_id_seq'::regclass), + username character varying(128) COLLATE pg_catalog.default NOT NULL, + password character varying(128) COLLATE pg_catalog.default NOT NULL, + encrypt_password character varying(128) COLLATE pg_catalog.default, + nickname character varying(128) COLLATE pg_catalog.default NOT NULL, + CONSTRAINT snmp_credentials_pkey PRIMARY KEY (snmp_credential_id), + CONSTRAINT snmp_credentials_nickname UNIQUE (nickname) +); + +CREATE SEQUENCE snmp_protocols_snmp_protocol_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS snmp_protocols +( + snmp_protocol_id integer NOT NULL DEFAULT nextval('snmp_protocols_snmp_protocol_id_seq'::regclass), + protocol_code character varying(128) COLLATE pg_catalog.default NOT NULL, + nickname character varying(128) COLLATE pg_catalog.default NOT NULL, + CONSTRAINT snmp_protocols_pkey PRIMARY KEY (snmp_protocol_id), + CONSTRAINT snmp_protocols_nickname UNIQUE (nickname) +); + +CREATE SEQUENCE firmware_images_firmware_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS firmware_images +( + firmware_id integer NOT NULL DEFAULT nextval('firmware_images_firmware_id_seq'::regclass), + name character varying(128) COLLATE pg_catalog.default NOT NULL, + model integer NOT NULL, + install_package character varying(128) COLLATE pg_catalog.default NOT NULL, + version character varying(128) COLLATE pg_catalog.default NOT NULL, + CONSTRAINT firmware_images_pkey PRIMARY KEY (firmware_id), + CONSTRAINT firmware_images_name UNIQUE (name), + CONSTRAINT firmware_images_install_package UNIQUE (install_package), + CONSTRAINT firmware_images_version UNIQUE (version), + CONSTRAINT fk_model FOREIGN KEY (model) + REFERENCES rsu_models (rsu_model_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION +); + +CREATE SEQUENCE rsus_rsu_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS rsus +( + rsu_id integer NOT NULL DEFAULT nextval('rsus_rsu_id_seq'::regclass), + geography geography NOT NULL, + milepost double precision NOT NULL, + ipv4_address inet NOT NULL, + serial_number character varying(128) COLLATE pg_catalog.default NOT NULL, + iss_scms_id character varying(128) COLLATE pg_catalog.default NOT NULL, + primary_route character varying(128) COLLATE pg_catalog.default NOT NULL, + model integer NOT NULL, + credential_id integer NOT NULL, + snmp_credential_id integer NOT NULL, + snmp_protocol_id integer NOT NULL, + firmware_version integer, + target_firmware_version integer, + CONSTRAINT rsu_pkey PRIMARY KEY (rsu_id), + CONSTRAINT rsu_ipv4_address UNIQUE (ipv4_address), + CONSTRAINT rsu_milepost_primary_route UNIQUE (milepost, primary_route), + CONSTRAINT rsu_serial_number UNIQUE (serial_number), + CONSTRAINT rsu_iss_scms_id UNIQUE (iss_scms_id), + CONSTRAINT fk_model FOREIGN KEY (model) + REFERENCES rsu_models (rsu_model_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION, + CONSTRAINT fk_credential_id FOREIGN KEY (credential_id) + REFERENCES rsu_credentials (credential_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION, + CONSTRAINT fk_snmp_credential_id FOREIGN KEY (snmp_credential_id) + REFERENCES snmp_credentials (snmp_credential_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION, + CONSTRAINT fk_snmp_protocol_id FOREIGN KEY (snmp_protocol_id) + REFERENCES snmp_protocols (snmp_protocol_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION, + CONSTRAINT fk_firmware_version FOREIGN KEY (firmware_version) + REFERENCES firmware_images (firmware_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION, + CONSTRAINT fk_target_firmware_version FOREIGN KEY (target_firmware_version) + REFERENCES firmware_images (firmware_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION +); + +CREATE TABLE IF NOT EXISTS tim_rsu ( + tim_rsu_id bigint NOT NULL, + rsu_id bigint NOT NULL, + tim_id bigint NOT NULL, + rsu_index bigint +) ; +ALTER TABLE tim_rsu ADD UNIQUE (rsu_id,tim_id,rsu_index); +ALTER TABLE tim_rsu ADD PRIMARY KEY (tim_rsu_id); +ALTER TABLE tim_rsu ALTER COLUMN TIM_RSU_ID SET NOT NULL; +ALTER TABLE tim_rsu ALTER COLUMN RSU_ID SET NOT NULL; +ALTER TABLE tim_rsu ALTER COLUMN TIM_ID SET NOT NULL; +ALTER TABLE tim_rsu ADD CONSTRAINT sys_c0021538 FOREIGN KEY (rsu_id) REFERENCES rsus(rsu_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; + +ALTER TABLE tim_rsu ADD CONSTRAINT sys_c0021539 FOREIGN KEY (tim_id) REFERENCES tim(tim_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; + +CREATE SEQUENCE public.organizations_organization_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS public.organizations +( + organization_id integer NOT NULL DEFAULT nextval('organizations_organization_id_seq'::regclass), + name character varying(128) COLLATE pg_catalog.default NOT NULL, + email character varying(128) COLLATE pg_catalog.default, + CONSTRAINT organizations_pkey PRIMARY KEY (organization_id), + CONSTRAINT organizations_name UNIQUE (name) +); + +CREATE SEQUENCE rsu_organization_rsu_organization_id_seq + INCREMENT 1 + START 1 + MINVALUE 1 + MAXVALUE 2147483647 + CACHE 1; + +CREATE TABLE IF NOT EXISTS rsu_organization +( + rsu_organization_id integer NOT NULL DEFAULT nextval('rsu_organization_rsu_organization_id_seq'::regclass), + rsu_id integer NOT NULL, + organization_id integer NOT NULL, + CONSTRAINT rsu_organization_pkey PRIMARY KEY (rsu_organization_id), + CONSTRAINT fk_rsu_id FOREIGN KEY (rsu_id) + REFERENCES rsus (rsu_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION, + CONSTRAINT fk_organization_id FOREIGN KEY (organization_id) + REFERENCES organizations (organization_id) MATCH SIMPLE + ON UPDATE NO ACTION + ON DELETE NO ACTION +); \ No newline at end of file diff --git a/db-scripts/pgsql/setup/sql/4-create_all_triggers.sql b/db-scripts/pgsql/setup/sql/4-create_all_triggers.sql index cdf6466b7..64750cd7b 100644 --- a/db-scripts/pgsql/setup/sql/4-create_all_triggers.sql +++ b/db-scripts/pgsql/setup/sql/4-create_all_triggers.sql @@ -362,21 +362,6 @@ CREATE TRIGGER trg_region_list_id BEFORE INSERT ON region_list FOR EACH ROW EXECUTE PROCEDURE trigger_fct_trg_region_list_id(); -DROP TRIGGER IF EXISTS trg_rsu_id ON rsu CASCADE; -CREATE OR REPLACE FUNCTION trigger_fct_trg_rsu_id() RETURNS trigger AS $BODY$ -BEGIN -select nextval('rsu_id_seq') -into STRICT NEW.rsu_id -; -RETURN NEW; -end -$BODY$ - LANGUAGE 'plpgsql' SECURITY DEFINER; - -CREATE TRIGGER trg_rsu_id - BEFORE INSERT ON rsu FOR EACH ROW - EXECUTE PROCEDURE trigger_fct_trg_rsu_id(); - DROP TRIGGER IF EXISTS trg_shape_point_id ON shape_point CASCADE; CREATE OR REPLACE FUNCTION trigger_fct_trg_shape_point_id() RETURNS trigger AS $BODY$ BEGIN diff --git a/db-scripts/pgsql/static-data/sql/03-itis_code.sql b/db-scripts/pgsql/static-data/sql/03-itis_code.sql index 3b238de62..5d95c1eae 100644 --- a/db-scripts/pgsql/static-data/sql/03-itis_code.sql +++ b/db-scripts/pgsql/static-data/sql/03-itis_code.sql @@ -50,6 +50,7 @@ INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (3 INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (4,E'Hazardous material spill',2,550); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (5,E'Closed',2,770); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (6,E'Closed for the season',2,774); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (7,E'Closed to traffic',2,769); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (8,E'Avalanche control activities',2,1042); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (10,E'Herd of animals on roadway',2,1292); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (11,E'Landslide',2,1310); @@ -96,6 +97,7 @@ INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (4 -- BOWR ITIS CODES (5127, 2563, 2569, 7682, 2577, 8739 and 11589-11607) INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (26,E'Strong winds',2,5127); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (27,E'Gusty winds',2, 5131); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (428,E'Truck restriction',2,2563); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (429,E'No high profile vehicles',2,2569); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (430,E'Below',2,7682); @@ -121,5 +123,53 @@ INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (4 INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (450,E'65000',1,11606); INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (451,E'70000',1,11607); +-- Connecting the West ITIS Codes +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (500,E'May Exceed',2,7759); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (501,E'Dense Fog',2,5377); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (502,E'Slippery',2,5897); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (503,E'Ahead',2,13569); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (504,E'Right Lane',3,8196); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (505,E'Left Lane',3,8195); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (506,E'Center Lane',3,8197); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (507,E'Blocked Ahead',3,776); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (508,E'Closed Ahead',3,771); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (509,E'Right',3,13579); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (510,E'Left',3,13580); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (511,E'Lane',3,13588); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (512,E'Right Shoulder',3,8208); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (513,E'Left Shoulder',3,8209); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (514,E'Both Directions of Travel',3,13593); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (515,E'End',3,13583); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (516,E'Reduced',1,12302); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (517,E'Advice',2,7712); + +-- Small Number Values +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (530,E'0',1,12542); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (531,E'1',1,12543); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (532,E'2',1,12544); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (533,E'3',1,12545); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (534,E'4',1,12546); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (535,E'5',1,12547); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (536,E'6',1,12548); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (537,E'7',1,12549); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (538,E'8',1,12550); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (539,E'9',1,12551); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (540,E'10',1,12552); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (541,E'15',1,12557); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (542,E'20',1,12562); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (543,E'25',1,12567); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (544,E'30',1,12572); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (545,E'35',1,12577); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (546,E'40',1,12582); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (547,E'45',1,12587); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (548,E'50',1,12592); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (549,E'55',1,12597); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (550,E'60',1,12602); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (551,E'65',1,12607); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (552,E'70',1,12612); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (553,E'75',1,12617); +INSERT INTO itis_code (itis_code_id,description,category_id,itis_code) VALUES (554,E'80',1,12622); + + COMMIT; diff --git a/db-scripts/pgsql/teardown/sql/1-drop_all_tables.sql b/db-scripts/pgsql/teardown/sql/1-drop_all_tables.sql index d1a7f777f..37da92f81 100644 --- a/db-scripts/pgsql/teardown/sql/1-drop_all_tables.sql +++ b/db-scripts/pgsql/teardown/sql/1-drop_all_tables.sql @@ -13,14 +13,12 @@ drop table if exists category cascade; drop table if exists node_xy cascade; drop table if exists node_ll cascade; drop table if exists computed_lane cascade; -drop table if exists rsu_firmware cascade; drop table if exists status_log cascade; drop table if exists itis_code cascade; drop table if exists tim cascade; drop table if exists shape_point cascade; drop table if exists path cascade; drop table if exists data_list cascade; -drop table if exists rsu cascade; drop table if exists incident_action_lut cascade; drop table if exists incident_effect_lut cascade; drop table if exists incident_problem_lut cascade; diff --git a/developer-tools/geojson-from-ode-tim/sampledata.json b/developer-tools/geojson-from-ode-tim/sampledata.json index b8ec7a2fc..fab46f9c3 100644 --- a/developer-tools/geojson-from-ode-tim/sampledata.json +++ b/developer-tools/geojson-from-ode-tim/sampledata.json @@ -24,14 +24,7 @@ "doNotUse1": 0, "frameType": "advisory", "msgId": { - "roadSignID": { - "position": { - "latitude": 44.8062595, - "longitude": -107.3203401 - }, - "viewAngle": "1111111111111111", - "mutcdCode": "warning" - } + "furtherInfoID": "0" }, "startDateTime": "2024-10-02T11:00:50.814Z", "durationTime": 32000, diff --git a/docker-compose-cdot-deployment.yml b/docker-compose-cdot-deployment.yml new file mode 100644 index 000000000..733de75ce --- /dev/null +++ b/docker-compose-cdot-deployment.yml @@ -0,0 +1,221 @@ +services: + ode_wrapper: + build: ode-wrapper + restart: always + environment: + SERVER_PORT: ${WRAPPER_SERVER_PORT} + CONFIG_ODE_URL: ${WRAPPER_CONFIG_ODE_URL} + CONFIG_DB_URL: ${WRAPPER_CONFIG_DB_URL} + CONFIG_DB_USERNAME: ${WRAPPER_CONFIG_DB_USERNAME} + CONFIG_DB_PASSWORD: ${WRAPPER_CONFIG_DB_PASSWORD} + CONFIG_MAXIMUM_POOL_SIZE: ${WRAPPER_CONFIG_MAXIMUM_POOL_SIZE} + CONFIG_CONNECTION_TIMEOUT: ${WRAPPER_CONFIG_CONNECTION_TIMEOUT} + CONFIG_SDW_TTL: ${WRAPPER_CONFIG_SDW_TTL} + CONFIG_SDW_REST_URL: ${SDW_REST_URL} + CONFIG_SDW_API_KEY: ${SDW_API_KEY} + CONFIG_ALERT_ADDRESSES: ${WRAPPER_CONFIG_ALERT_ADDRESSES} + CONFIG_FROM_EMAIL: ${WRAPPER_CONFIG_FROM_EMAIL} + CONFIG_MAIL_HOST: ${MAIL_HOST} + CONFIG_MAIL_PORT: ${MAIL_PORT} + CONFIG_ENVIRONMENT_NAME: ${ENVIRONMENT_NAME} + CONFIG_DEFAULT_LANE_WIDTH: ${WRAPPER_CONFIG_DEFAULT_LANE_WIDTH} + CONFIG_CV_REST_SERVICE: ${WRAPPER_CONFIG_CV_REST_SERVICE} + CONFIG_HTTP_LOGGING_MAX_SIZE: ${WRAPPER_CONFIG_HTTP_LOGGING_MAX_SIZE} + CONFIG_RSU_ROUTES: ${WRAPPER_CONFIG_RSU_ROUTES} + CONFIG_POINT_INCIDENT_BUFFER_MILES: ${WRAPPER_CONFIG_POINT_INCIDENT_BUFFER_MILES} + ports: + - "7777:7777" + logging: + options: + max-size: "20m" + max-file: "3" + + cv-data-tasks: + build: cv-data-tasks + restart: always + environment: + CONFIG_ODE_URL: ${TASKS_CONFIG_ODE_URL} + CONFIG_CV_REST_SERVICE: ${TASKS_CONFIG_CV_REST_SERVICE} + CONFIG_RSU_DATA_SERVICE_URL: ${TASKS_CONFIG_RSU_DATA_SERVICE_URL} + CONFIG_WRAPPER_URL: ${TASKS_CONFIG_WRAPPER_URL} + CONFIG_MAIL_HOST: ${MAIL_HOST} + CONFIG_MAIL_PORT: ${MAIL_PORT} + CONFIG_ENVIRONMENT_NAME: ${ENVIRONMENT_NAME} + CONFIG_SDW_REST_URL: ${SDW_REST_URL} + CONFIG_SDW_API_KEY: ${SDW_API_KEY} + CONFIG_TMDD_URL: ${TASKS_CONFIG_TMDD_URL} + CONFIG_TMDD_USER: ${TASKS_CONFIG_TMDD_USER} + CONFIG_TMDD_PASSWORD: ${TASKS_CONFIG_TMDD_PASSWORD} + CONFIG_ALERT_ADDRESSES: ${TASKS_CONFIG_ALERT_ADDRESSES} + CONFIG_FROM_EMAIL: ${TASKS_CONFIG_FROM_EMAIL} + CONFIG_RUN_TMDD_VALIDATION: ${TASKS_CONFIG_RUN_TMDD_VALIDATION} + CONFIG_RUN_RSU_VALIDATION: ${TASKS_CONFIG_RUN_RSU_VALIDATION} + CONFIG_RSU_VALIDATION_DELAY_SECONDS: ${TASKS_CONFIG_RSU_VALIDATION_DELAY_SECONDS} + CONFIG_RSU_VAL_THREAD_POOL_SIZE: ${TASKS_CONFIG_RSU_VAL_THREAD_POOL_SIZE} + CONFIG_RSU_VAL_TIMEOUT_SECONDS: ${TASKS_CONFIG_RSU_VAL_TIMEOUT_SECONDS} + CONFIG_REMOVE_EXPIRED_PERIOD_MINUTES: ${TASKS_CONFIG_REMOVE_EXPIRED_PERIOD_MINUTES} + CONFIG_CLEANUP_PERIOD_MINUTES: ${TASKS_CONFIG_CLEANUP_PERIOD_MINUTES} + CONFIG_SDX_VALIDATION_PERIOD_MINUTES: ${TASKS_CONFIG_SDX_VALIDATION_PERIOD_MINUTES} + CONFIG_RSU_VALIDATION_PERIOD_MINUTES: ${TASKS_CONFIG_RSU_VALIDATION_PERIOD_MINUTES} + CONFIG_TMDD_VALIDATION_PERIOD_MINUTES: ${TASKS_CONFIG_TMDD_VALIDATION_PERIOD_MINUTES} + CONFIG_RETENTION_ENFORCEMENT_PERIOD_MINUTES: ${TASKS_CONFIG_RETENTION_ENFORCEMENT_PERIOD_MINUTES} + CONFIG_RETENTION_REMOVE_TIMS: ${TASKS_CONFIG_RETENTION_REMOVE_TIMS} + CONFIG_RETENTION_REMOVE_STATUS_LOGS: ${TASKS_CONFIG_RETENTION_REMOVE_STATUS_LOGS} + CONFIG_HSM_FUNCTIONALITY_MINUTES: ${TASKS_CONFIG_HSM_FUNCTIONALITY_MINUTES} + CONFIG_HSM_URL: ${TASKS_CONFIG_HSM_URL} + CONFIG_HSM_ERROR_EMAIL_FREQUENCY_MINUTES: ${TASKS_CONFIG_HSM_ERROR_EMAIL_FREQUENCY_MINUTES} + CONFIG_RUN_HSM_CHECK: ${TASKS_CONFIG_RUN_HSM_CHECK} + CONFIG_SDW_TTL: ${TASKS_CONFIG_SDW_TTL} + CONFIG_DEFAULT_LANE_WIDTH: ${TASKS_CONFIG_DEFAULT_LANE_WIDTH} + CONFIG_RSU_ROUTES: ${TASKS_CONFIG_RSU_ROUTES} + CONFIG_POINT_INCIDENT_BUFFER_MILES: ${TASKS_CONFIG_POINT_INCIDENT_BUFFER_MILES} + logging: + options: + max-size: "20m" + max-file: "3" + depends_on: + - ode_wrapper + - cv-data-controller + - rsu-data-controller + + tim-refresh: + build: tim-refresh + restart: always + environment: + CONFIG_ODE_URL: ${REFRESH_CONFIG_ODE_URL} + CONFIG_SDW_TTL: ${REFRESH_CONFIG_SDW_TTL} + CONFIG_CV_REST_SERVICE: ${REFRESH_CONFIG_CV_REST_SERVICE} + CONFIG_SDW_REST_URL: ${SDW_REST_URL} + CONFIG_SDW_API_KEY: ${SDW_API_KEY} + CONFIG_DEFAULT_LANE_WIDTH: ${REFRESH_CONFIG_DEFAULT_LANE_WIDTH} + CONFIG_RSU_ROUTES: ${REFRESH_CONFIG_RSU_ROUTES} + CONFIG_POINT_INCIDENT_BUFFER_MILES: ${REFRESH_CONFIG_POINT_INCIDENT_BUFFER_MILES} + CRON_EXPRESSION: ${REFRESH_CRON_EXPRESSION} + CONFIG_ALERT_ADDRESSES: ${REFRESH_CONFIG_ALERT_ADDRESSES} + CONFIG_FROM_EMAIL: ${REFRESH_CONFIG_FROM_EMAIL} + CONFIG_ENVIRONMENT_NAME: ${ENVIRONMENT_NAME} + CONFIG_MAIL_HOST: ${MAIL_HOST} + CONFIG_MAIL_PORT: ${MAIL_PORT} + logging: + options: + max-size: "20m" + max-file: "3" + + cv-data-controller: + build: cv-data-controller + restart: always + ports: + - "8888:8888" + environment: + SERVER_PORT: ${CONTROLLER_SERVER_PORT} + CONFIG_DB_URL: ${CONTROLLER_CONFIG_DB_URL} + CONFIG_DB_USERNAME: ${CONTROLLER_CONFIG_DB_USERNAME} + CONFIG_DB_PASSWORD: ${CONTROLLER_CONFIG_DB_PASSWORD} + CONFIG_MAXIMUM_POOL_SIZE: ${CONTROLLER_CONFIG_MAXIMUM_POOL_SIZE} + CONFIG_CONNECTION_TIMEOUT: ${CONTROLLER_CONFIG_CONNECTION_TIMEOUT} + CONFIG_ODE_URL: ${CONTROLLER_CONFIG_ODE_URL} + SPRING_DATA_NEO4J_URI: ${CONTROLLER_SPRING_DATA_NEO4J_URI} + CONFIG_ALERT_ADDRESSES: ${CONTROLLER_CONFIG_ALERT_ADDRESSES} + CONFIG_FROM_EMAIL: ${CONTROLLER_CONFIG_FROM_EMAIL} + CONFIG_ENVIRONMENT_NAME: ${ENVIRONMENT_NAME} + CONFIG_MAIL_HOST: ${MAIL_HOST} + CONFIG_MAIL_PORT: ${MAIL_PORT} + LOGGING_LEVEL_ROOT: ${CONTROLLER_LOGGING_LEVEL_ROOT} + logging: + options: + max-size: "20m" + max-file: "3" + + rsu-data-controller: + build: rsu-data-controller + restart: always + ports: + - "8898:8898" + environment: + SERVER_PORT: ${RSUCONTROLLER_SERVER_PORT} + CONFIG_SNMP_RETRIES: ${RSUCONTROLLER_CONFIG_SNMP_RETRIES} + CONFIG_SNMP_TIMEOUT_SECONDS: ${RSUCONTROLLER_CONFIG_SNMP_TIMEOUT_SECONDS} + CONFIG_SNMP_USER_NAME: ${RSUCONTROLLER_CONFIG_SNMP_USER_NAME} + CONFIG_SNMP_AUTH_PASSPHRASE: ${RSUCONTROLLER_CONFIG_SNMP_AUTH_PASSPHRASE} + CONFIG_SNMP_AUTH_PROTOCOL: ${RSUCONTROLLER_CONFIG_SNMP_AUTH_PROTOCOL} + CONFIG_SNMP_SECURITY_LEVEL: ${RSUCONTROLLER_CONFIG_SNMP_SECURITY_LEVEL} + DB_URL: ${RSUCONTROLLER_DB_URL} + DB_USERNAME: ${RSUCONTROLLER_DB_USERNAME} + DB_PASSWORD: ${RSUCONTROLLER_DB_PASSWORD} + MAXIMUM_POOL_SIZE: ${RSUCONTROLLER_MAXIMUM_POOL_SIZE} + CONNECTION_TIMEOUT: ${RSUCONTROLLER_CONNECTION_TIMEOUT} + logging: + options: + max-size: "20m" + max-file: "3" + + tim_logger: + build: ode-data-logger + restart: always + environment: + KAFKA_HOST_SERVER: ${LOGGER_KAFKA_HOST_SERVER} + DATA_SERVICE_LIBRARY_KAFKA_KAFKA_TYPE: ${KAFKA_TYPE} + DATA_SERVICE_LIBRARY_KAFKA_CONFLUENT_KEY: ${CONFLUENT_KEY} + DATA_SERVICE_LIBRARY_KAFKA_CONFLUENT_SECRET: ${CONFLUENT_SECRET} + ALERT_ADDRESSES: ${LOGGER_ALERT_ADDRESSES} + FROM_EMAIL: ${LOGGER_FROM_EMAIL} + ENVIRONMENT_NAME: ${ENVIRONMENT_NAME} + MAIL_HOST: ${MAIL_HOST} + MAIL_PORT: ${MAIL_PORT} + DEPOSIT_TOPIC: ${TIM_TOPIC} + DEPOSIT_GROUP: ${TIM_GROUP_ORACLE} + CV_REST_SERVICE: ${LOGGER_CV_REST_SERVICE} + PRODUCER_TOPIC: ${DBCONSUMER_DEPOSIT_TOPIC} + logging: + options: + max-size: "20m" + max-file: "3" + + logger-kafka-consumer: + build: logger-kafka-consumer + restart: always + environment: + DEPOSIT_GROUP: ${DBCONSUMER_DEPOSIT_GROUP} + DEPOSIT_TOPIC: ${DBCONSUMER_DEPOSIT_TOPIC} + KAFKA_HOST_SERVER: ${DBCONSUMER_KAFKA_HOST_SERVER} + DATA_SERVICE_LIBRARY_KAFKA_KAFKA_TYPE: ${KAFKA_TYPE} + DATA_SERVICE_LIBRARY_KAFKA_CONFLUENT_KEY: ${CONFLUENT_KEY} + DATA_SERVICE_LIBRARY_KAFKA_CONFLUENT_SECRET: ${CONFLUENT_SECRET} + MAX_POLL_INTERVAL_MS: ${DBCONSUMER_MAX_POLL_INTERVAL_MS} + MAX_POLL_RECORDS: ${DBCONSUMER_MAX_POLL_RECORDS} + DB_URL: ${DBCONSUMER_DB_URL} + DB_USERNAME: ${DBCONSUMER_DB_USERNAME} + DB_PASSWORD: ${DBCONSUMER_DB_PASSWORD} + MAXIMUM_POOL_SIZE: ${DBCONSUMER_MAXIMUM_POOL_SIZE} + CONNECTION_TIMEOUT: ${DBCONSUMER_CONNECTION_TIMEOUT} + ALERT_ADDRESSES: ${DBCONSUMER_ALERT_ADDRESSES} + FROM_EMAIL: ${DBCONSUMER_FROM_EMAIL} + ENVIRONMENT_NAME: ${ENVIRONMENT_NAME} + MAIL_HOST: ${MAIL_HOST} + MAIL_PORT: ${MAIL_PORT} + logging: + options: + max-size: "20m" + max-file: "3" + + cert-expiration: + build: cert-expiration + restart: always + environment: + KAFKA_HOST_SERVER: ${LOGGER_KAFKA_HOST_SERVER} + DATA_SERVICE_LIBRARY_KAFKA_KAFKA_TYPE: ${KAFKA_TYPE} + DATA_SERVICE_LIBRARY_KAFKA_CONFLUENT_KEY: ${CONFLUENT_KEY} + DATA_SERVICE_LIBRARY_KAFKA_CONFLUENT_SECRET: ${CONFLUENT_SECRET} + ALERT_ADDRESSES: ${LOGGER_ALERT_ADDRESSES} + FROM_EMAIL: ${LOGGER_FROM_EMAIL} + ENVIRONMENT_NAME: ${ENVIRONMENT_NAME} + MAIL_HOST: ${MAIL_HOST} + MAIL_PORT: ${MAIL_PORT} + DEPOSIT_TOPIC: ${EXP_TOPIC} + DEPOSIT_GROUP: ${EXP_GROUP} + CV_REST_SERVICE: ${LOGGER_CV_REST_SERVICE} + PRODUCER_TOPIC: ${DBCONSUMER_DEPOSIT_TOPIC} + logging: + options: + max-size: "20m" + max-file: "3" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f067bf275..e6ff704b5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,12 +6,10 @@ services: environment: SERVER_PORT: ${WRAPPER_SERVER_PORT} CONFIG_ODE_URL: ${WRAPPER_CONFIG_ODE_URL} - CONFIG_DB_URL: ${WRAPPER_CONFIG_DB_URL} - CONFIG_DB_USERNAME: ${WRAPPER_CONFIG_DB_USERNAME} - CONFIG_DB_PASSWORD: ${WRAPPER_CONFIG_DB_PASSWORD} CONFIG_MAXIMUM_POOL_SIZE: ${WRAPPER_CONFIG_MAXIMUM_POOL_SIZE} CONFIG_CONNECTION_TIMEOUT: ${WRAPPER_CONFIG_CONNECTION_TIMEOUT} CONFIG_ENV: ${WRAPPER_CONFIG_ENV} + CONFIG_DOT_GNIS_ID: ${WRAPPER_CONFIG_DOT_GNIS_ID} CONFIG_SDW_TTL: ${WRAPPER_CONFIG_SDW_TTL} CONFIG_SDW_REST_URL: ${SDW_REST_URL} CONFIG_SDW_API_KEY: ${SDW_API_KEY} @@ -161,6 +159,11 @@ services: CONFIG_SNMP_AUTH_PASSPHRASE: ${RSUCONTROLLER_CONFIG_SNMP_AUTH_PASSPHRASE} CONFIG_SNMP_AUTH_PROTOCOL: ${RSUCONTROLLER_CONFIG_SNMP_AUTH_PROTOCOL} CONFIG_SNMP_SECURITY_LEVEL: ${RSUCONTROLLER_CONFIG_SNMP_SECURITY_LEVEL} + DB_URL: ${RSUCONTROLLER_DB_URL} + DB_USERNAME: ${RSUCONTROLLER_DB_USERNAME} + DB_PASSWORD: ${RSUCONTROLLER_DB_PASSWORD} + MAXIMUM_POOL_SIZE: ${RSUCONTROLLER_MAXIMUM_POOL_SIZE} + CONNECTION_TIMEOUT: ${RSUCONTROLLER_CONNECTION_TIMEOUT} LOGGING_LEVEL_COM_TRIHYDRO: ${LOGGING_LEVEL_COM_TRIHYDRO} logging: options: diff --git a/local-deployment/docker-compose.yml b/local-deployment/docker-compose.yml index d33ed2200..30b02640c 100644 --- a/local-deployment/docker-compose.yml +++ b/local-deployment/docker-compose.yml @@ -202,9 +202,6 @@ services: environment: SERVER_PORT: 7777 CONFIG_ODE_URL: http://ode:8080 - CONFIG_DB_URL: jdbc:postgresql://${POSTGRES_DB_HOSTNAME}:5432/${POSTGRES_DB_NAME}?user=${POSTGRES_USER} - CONFIG_DB_USERNAME: ${POSTGRES_USER} - CONFIG_DB_PASSWORD: ${POSTGRES_PASSWORD} CONFIG_MAXIMUM_POOL_SIZE: 7 CONFIG_CONNECTION_TIMEOUT: 300000 CONFIG_ENV: local @@ -221,6 +218,7 @@ services: CONFIG_HTTP_LOGGING_MAX_SIZE: 2000 CONFIG_RSU_ROUTES: ${RSU_ROUTES} CONFIG_POINT_INCIDENT_BUFFER_MILES: 1 + CONFIG_DOT_GNIS_ID: ${DOT_GNIS_ID} LOGGING_LEVEL_COM_TRIHYDRO: ${LOGGING_LEVEL_COM_TRIHYDRO} ports: - "7777:7777" @@ -242,6 +240,11 @@ services: CONFIG_SNMP_AUTH_PASSPHRASE: testpassword CONFIG_SNMP_AUTH_PROTOCOL: SHA CONFIG_SNMP_SECURITY_LEVEL: authNoPriv + DB_URL: jdbc:postgresql://${POSTGRES_DB_HOSTNAME}:5432/${POSTGRES_DB_NAME}?user=${POSTGRES_USER} + DB_USERNAME: ${POSTGRES_USER} + DB_PASSWORD: ${POSTGRES_PASSWORD} + MAXIMUM_POOL_SIZE: 13 + CONNECTION_TIMEOUT: 300000 LOGGING_LEVEL_COM_TRIHYDRO: ${LOGGING_LEVEL_COM_TRIHYDRO} logging: options: diff --git a/local-deployment/kafka/kafka_init.sh b/local-deployment/kafka/kafka_init.sh index 9ed08f089..f9dbe553e 100644 --- a/local-deployment/kafka/kafka_init.sh +++ b/local-deployment/kafka/kafka_init.sh @@ -13,6 +13,7 @@ echo 'Creating kafka topics' /opt/bitnami/kafka/bin/kafka-topics.sh --create --if-not-exists --topic "topic.OdeBsmJson" --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 /opt/bitnami/kafka/bin/kafka-topics.sh --create --if-not-exists --topic "topic.FilteredOdeBsmJson" --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 /opt/bitnami/kafka/bin/kafka-topics.sh --create --if-not-exists --topic "topic.OdeTimJson" --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 +/opt/bitnami/kafka/bin/kafka-topics.sh --create --if-not-exists --topic "topic.OdeTimJsonTMCFiltered" --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 /opt/bitnami/kafka/bin/kafka-topics.sh --create --if-not-exists --topic "topic.OdeTimBroadcastJson" --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 /opt/bitnami/kafka/bin/kafka-topics.sh --create --if-not-exists --topic "topic.J2735TimBroadcastJson" --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 /opt/bitnami/kafka/bin/kafka-topics.sh --create --if-not-exists --topic "topic.OdeDriverAlertJson" --bootstrap-server kafka:9092 --replication-factor 1 --partitions 1 diff --git a/local-deployment/sample.env b/local-deployment/sample.env index 3d2c7497b..8fc7518f4 100644 --- a/local-deployment/sample.env +++ b/local-deployment/sample.env @@ -6,6 +6,7 @@ POSTGRES_DB_HOSTNAME=postgres POSTGRES_DB_NAME=postgres POSTGRES_USER=username POSTGRES_PASSWORD=password +DOT_GNIS_ID=1B2843 MONGO_USER=username MONGO_PASSWORD=password RSU_ROUTES="route1, route2" diff --git a/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimService.java b/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimService.java index c9f61034b..965f243d0 100644 --- a/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimService.java +++ b/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimService.java @@ -14,6 +14,9 @@ import java.util.Date; import java.util.TimeZone; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + import com.trihydro.library.helpers.SQLNullHandler; import com.trihydro.library.model.ActiveTim; import com.trihydro.library.model.Coordinate; @@ -234,10 +237,9 @@ public ActiveTim getActiveRsuTim(String clientId, String direction, String ipv4A query += " atim.START_LATITUDE, atim.START_LONGITUDE, atim.END_LATITUDE, atim.END_LONGITUDE"; query += " from active_tim atim"; query += " inner join tim_rsu on atim.tim_id = tim_rsu.tim_id"; - query += " inner join rsu on tim_rsu.rsu_id = rsu.rsu_id"; - query += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; + query += " inner join rsus on tim_rsu.rsu_id = rsus.rsu_id"; query += " where sat_record_id is null and ipv4_address = '" + ipv4Address + "' and client_id = '" - + clientId + "' and atim.direction = '" + direction + "'"; + + clientId + "' and atim.direction = '" + direction + "'"; try ( Connection connection = dbInteractions.getConnectionPool(); diff --git a/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/RsuService.java b/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/RsuService.java index 42637a0a2..ce59cd4d1 100644 --- a/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/RsuService.java +++ b/logger-kafka-consumer/src/main/java/com/trihydro/loggerkafkaconsumer/app/services/RsuService.java @@ -26,7 +26,9 @@ public ArrayList getRsus() { // select all RSUs from RSU table rs = statement.executeQuery( - "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid order by milepost asc"); + "select rsu_id, ST_X(ST_AsText(geography)) as longitude, " + + "ST_Y(ST_AsText(geography)) as latitude, ipv4_address, primary_route, " + + "milepost from rsus order by milepost asc"); while (rs.next()) { WydotRsu rsu = new WydotRsu(); diff --git a/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimServiceTest.java b/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimServiceTest.java index 8fb77ec80..b8c2873cb 100644 --- a/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimServiceTest.java +++ b/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/ActiveTimServiceTest.java @@ -216,8 +216,7 @@ public void getActiveRsuTim_SUCCESS() throws SQLException { query += " atim.START_LATITUDE, atim.START_LONGITUDE, atim.END_LATITUDE, atim.END_LONGITUDE"; query += " from active_tim atim"; query += " inner join tim_rsu on atim.tim_id = tim_rsu.tim_id"; - query += " inner join rsu on tim_rsu.rsu_id = rsu.rsu_id"; - query += " inner join rsu_view on rsu.deviceid = rsu_view.deviceid"; + query += " inner join rsus on tim_rsu.rsu_id = rsus.rsu_id"; query += " where sat_record_id is null"; query += " and ipv4_address = 'ipv4Address' and client_id = 'clientId'"; query += " and atim.direction = 'direction'"; diff --git a/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/RsuServiceTest.java b/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/RsuServiceTest.java index 08558c2af..2163cf0e8 100644 --- a/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/RsuServiceTest.java +++ b/logger-kafka-consumer/src/test/java/com/trihydro/loggerkafkaconsumer/app/services/RsuServiceTest.java @@ -1,15 +1,14 @@ package com.trihydro.loggerkafkaconsumer.app.services; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; - import java.sql.SQLException; import java.util.ArrayList; -import com.trihydro.library.model.WydotRsu; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +import com.trihydro.library.model.WydotRsu; public class RsuServiceTest extends TestBase { @@ -23,7 +22,8 @@ public void getRsus_SUCCESS() throws SQLException { // Assert Assertions.assertEquals(1, data.size()); verify(mockStatement).executeQuery( - "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid order by milepost asc"); + "select rsu_id, ST_X(ST_AsText(geography)) as longitude, ST_Y(ST_AsText(geography)) " + + "as latitude, ipv4_address, primary_route, milepost from rsus order by milepost asc"); verify(mockRs).getInt("RSU_ID"); verify(mockRs).getString("IPV4_ADDRESS"); verify(mockRs).getBigDecimal("LATITUDE"); @@ -45,7 +45,8 @@ public void getRsus_FAIL() throws SQLException { // Assert Assertions.assertEquals(0, data.size()); verify(mockStatement).executeQuery( - "select * from rsu inner join rsu_view on rsu.deviceid = rsu_view.deviceid order by milepost asc"); + "select rsu_id, ST_X(ST_AsText(geography)) as longitude, ST_Y(ST_AsText(geography)) " + + "as latitude, ipv4_address, primary_route, milepost from rsus order by milepost asc"); verify(mockStatement).close(); verify(mockRs).close(); verify(mockConnection).close(); diff --git a/logger-kafka-consumer/src/test/resources/TIM_odeTimStartDateTime.json b/logger-kafka-consumer/src/test/resources/TIM_odeTimStartDateTime.json index 4b66fec03..b8225015d 100644 --- a/logger-kafka-consumer/src/test/resources/TIM_odeTimStartDateTime.json +++ b/logger-kafka-consumer/src/test/resources/TIM_odeTimStartDateTime.json @@ -254,31 +254,7 @@ "doNotUse4": 0, "startYear": 2020, "msgId": { - "roadSignID": { - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - }, - "mutcdCode": "warning", - "position": { - "lat": 418082518, - "long": -1105341319 - } - } + "furtherInfoID": "0" }, "priority": 5, "content": { diff --git a/logger-kafka-consumer/src/test/resources/TIM_odeTim_Rsus.json b/logger-kafka-consumer/src/test/resources/TIM_odeTim_Rsus.json index 1c0e0c33b..562f5ec7d 100644 --- a/logger-kafka-consumer/src/test/resources/TIM_odeTim_Rsus.json +++ b/logger-kafka-consumer/src/test/resources/TIM_odeTim_Rsus.json @@ -60,31 +60,7 @@ "durationTime": 32000, "frameType": "advisory", "msgId": { - "roadSignID": { - "mutcdCode": "warning", - "position": { - "lat": 412696444, - "long": -1054796709 - }, - "viewAngle": { - "from000-0to022-5degrees": true, - "from022-5to045-0degrees": true, - "from045-0to067-5degrees": true, - "from067-5to090-0degrees": true, - "from090-0to112-5degrees": true, - "from112-5to135-0degrees": true, - "from135-0to157-5degrees": true, - "from157-5to180-0degrees": true, - "from180-0to202-5degrees": true, - "from202-5to225-0degrees": true, - "from225-0to247-5degrees": true, - "from247-5to270-0degrees": true, - "from270-0to292-5degrees": true, - "from292-5to315-0degrees": true, - "from315-0to337-5degrees": true, - "from337-5to360-0degrees": true - } - } + "furtherInfoID": "0" }, "priority": 5, "regions": [ diff --git a/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput.json b/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput.json index 169a60727..2f93bdc33 100644 --- a/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput.json +++ b/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput.json @@ -90,17 +90,7 @@ "roadSignage": "" }, "msgId": { - "roadSignID": { - "viewAngle": 1100000000000001, - "mutcdCode": { - "warning": "" - }, - "position": { - "elevation": 20, - "lat": 263055670, - "long": -801481500 - } - } + "furtherInfoID": "0" }, "startTime": 149760, "priority": 2, diff --git a/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput_NullMetadata.json b/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput_NullMetadata.json index 99c9e6fae..c51107342 100644 --- a/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput_NullMetadata.json +++ b/logger-kafka-consumer/src/test/resources/rxMsg_TIM_OdeOutput_NullMetadata.json @@ -62,17 +62,7 @@ "roadSignage": "" }, "msgId": { - "roadSignID": { - "viewAngle": 1100000000000001, - "mutcdCode": { - "warning": "" - }, - "position": { - "elevation": 20, - "lat": 263055670, - "long": -801481500 - } - } + "furtherInfoID": "0" }, "startTime": 149760, "priority": 2, diff --git a/ode-wrapper/README.md b/ode-wrapper/README.md index 43cd69116..c60368723 100644 --- a/ode-wrapper/README.md +++ b/ode-wrapper/README.md @@ -120,6 +120,7 @@ You may configure these values in `ode-wrapper/src/main/resources/application.pr | CONFIG_MAXIMUM_POOL_SIZE | WRAPPER_CONFIG_MAXIMUM_POOL_SIZE | config.maximumPoolSize | Number of threads in ThreadPool | 7 | | CONFIG_CONNECTION_TIMEOUT | WRAPPER_CONFIG_CONNECTION_TIMEOUT | config.connectionTimeout | Connection timeout in milliseconds | 10000 | | CONFIG_ENV | WRAPPER_CONFIG_ENV | config.env | Configuration environment | dev | +| CONFIG_DOT_GNIS_ID | WRAPPER_CONFIG_DOT_GNIS_ID | config.dotGnisId | GNIS ID of the DOT used for the packetID | CDOT: 1B2843, UDOT: 163775, WYDOT: 1B285F | | CONFIG_SDW_TTL | WRAPPER_CONFIG_SDW_TTL | config.sdwTtl | SDW time to live default | oneday | | CONFIG_SDW_REST_URL | SDW_REST_URL | config.sdwRestUrl | REST endpoint for SDX | https://sdx-endpoint.com | | CONFIG_SDW_API_KEY | SDW_API_KEY | config.sdwApiKey | API Key for accessing SDX | asdf | diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/config/BasicConfiguration.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/config/BasicConfiguration.java index 4b9177252..6295f430b 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/config/BasicConfiguration.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/config/BasicConfiguration.java @@ -26,6 +26,7 @@ public class BasicConfiguration implements SdwProps, RsuDataServiceProps, TmddPr private String odeUrl; private String sdwRestUrl; private String sdwApiKey; + private String dotGnisId; private String mailHost; private int mailPort; private String[] alertAddresses; @@ -60,6 +61,14 @@ public void setPointIncidentBufferMiles(Double pointIncidentBufferMiles) { this.pointIncidentBufferMiles = pointIncidentBufferMiles; } + public String getDotGnisId() { + return dotGnisId; + } + + public void setDotGnisId(String dotGnisId) { + this.dotGnisId = dotGnisId; + } + public String getFromEmail() { return fromEmail; } diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/UtilityController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/UtilityController.java index 26131ecba..035d9a1db 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/UtilityController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/UtilityController.java @@ -1,12 +1,12 @@ package com.trihydro.odewrapper.controller; -import com.trihydro.library.exceptionhandlers.IdenticalPointsExceptionHandler; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.trihydro.library.exceptionhandlers.IdenticalPointsExceptionHandler; import com.trihydro.library.helpers.MilepostReduction; import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; @@ -15,6 +15,7 @@ import com.trihydro.library.model.TimQuery; import com.trihydro.library.model.WydotRsu; import com.trihydro.library.service.ActiveTimService; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.OdeService; import com.trihydro.library.service.RestTemplateProvider; import com.trihydro.library.service.TimTypeService; @@ -58,9 +59,9 @@ class RsuClearSuccess { public UtilityController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, OdeService _odeService, RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, - Utility _utility, TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + Utility _utility, TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, - _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, identicalPointsExceptionHandler); + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); this.odeService = _odeService; } diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBaseController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBaseController.java index 506eb93ce..48a69ef5e 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBaseController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBaseController.java @@ -1,7 +1,6 @@ package com.trihydro.odewrapper.controller; import com.trihydro.library.exceptionhandlers.IdenticalPointsExceptionHandler; -import com.trihydro.library.model.TimUpdateModel; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; @@ -13,7 +12,6 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Objects; @@ -25,7 +23,6 @@ import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.ActiveTim; import com.trihydro.library.model.Buffer; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.Coordinate; import com.trihydro.library.model.Milepost; import com.trihydro.library.model.TimType; @@ -33,6 +30,7 @@ import com.trihydro.library.model.WydotTimRw; import com.trihydro.library.model.WydotTravelerInputData; import com.trihydro.library.service.ActiveTimService; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.RestTemplateProvider; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; @@ -66,17 +64,17 @@ public abstract class WydotTimBaseController { MilepostReduction milepostReduction; protected Utility utility; protected TimGenerationHelper timGenerationHelper; + protected MilepostService milepostService; private final IdenticalPointsExceptionHandler identicalPointsExceptionHandler; protected static Gson gson = new Gson(); private List timTypes; + protected final List bufferTimITISCodes; - public WydotTimBaseController(BasicConfiguration _basicConfiguration, - WydotTimService _wydotTimService, TimTypeService _timTypeService, - SetItisCodes _setItisCodes, ActiveTimService _activeTimService, - RestTemplateProvider _restTemplateProvider, - MilepostReduction _milepostReduction, Utility _utility, - TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + public WydotTimBaseController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, + TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, + RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { configuration = _basicConfiguration; wydotTimService = _wydotTimService; timTypeService = _timTypeService; @@ -86,6 +84,9 @@ public WydotTimBaseController(BasicConfiguration _basicConfiguration, milepostReduction = _milepostReduction; utility = _utility; timGenerationHelper = _timGenerationHelper; + milepostService = _milepostService; + // closed-ahead, blocked-ahead, and ahead ITIS codes + bufferTimITISCodes = List.of(771, 776, 13569); this.identicalPointsExceptionHandler = identicalPointsExceptionHandler; } @@ -113,7 +114,7 @@ protected String getIsoDateTimeString(ZonedDateTime date) { protected ControllerResult validateInputParking(WydotTimParking tim) { ControllerResult result = new ControllerResult(); - List resultMessages = new ArrayList(); + List resultMessages = new ArrayList<>(); // get route number if (tim.getDirection() != null) { @@ -158,7 +159,7 @@ protected ControllerResult validateInputParking(WydotTimParking tim) { public ControllerResult validateInputIncident(WydotTimIncident tim) { ControllerResult result = new ControllerResult(); - List resultMessages = new ArrayList(); + List resultMessages = new ArrayList<>(); // get route number if (tim.getDirection() != null) { @@ -185,16 +186,9 @@ public ControllerResult validateInputIncident(WydotTimIncident tim) { if (tim.getIncidentId() == null) { resultMessages.add("Null value for incidentId"); } - if (tim.getStartPoint() == null || !tim.getStartPoint().isValid()) { - resultMessages.add("Invalid startPoint"); - } - // endPoint may be null here, so check if not null that it is valid - if (tim.getEndPoint() != null && !tim.getEndPoint().isValid()) { - resultMessages.add("Invalid endPoint"); - } // set itis codes - List itisCodes = setItisCodes.setItisCodesIncident(tim); + List itisCodes = setItisCodes.setItisCodes(tim); if (itisCodes.isEmpty()) { resultMessages.add("No ITIS codes found"); } @@ -232,11 +226,15 @@ protected ControllerResult validateInputRw(WydotTimRw tim) { !tim.getDirection().equalsIgnoreCase("b")) { resultMessages.add("direction not supported"); } - if (tim.getStartPoint() == null || !tim.getStartPoint().isValid()) { - resultMessages.add("Invalid startPoint"); - } - if (tim.getEndPoint() == null || !tim.getEndPoint().isValid()) { - resultMessages.add("Invalid endPoint"); + + // if geometry isn't present, check for start/end points + if (!tim.isGeometryValid()) { + if (tim.getStartPoint() == null || !tim.getStartPoint().isValid()) { + resultMessages.add("Invalid startPoint"); + } + if (tim.getEndPoint() == null || !tim.getEndPoint().isValid()) { + resultMessages.add("Invalid endPoint"); + } } if (tim.getHighway() == null) { resultMessages.add("Null value for highway"); @@ -299,7 +297,7 @@ protected ControllerResult validateInputRw(WydotTimRw tim) { } // set itis codes - List itisCodes = setItisCodes.setItisCodesRw(tim); + List itisCodes = setItisCodes.setItisCodes(tim); if (itisCodes.isEmpty()) { resultMessages.add("No ITIS codes found"); } @@ -345,12 +343,17 @@ protected ControllerResult validateInputRc(WydotTimRc tim) { !tim.getDirection().equalsIgnoreCase("b")) { resultMessages.add("direction not supported"); } - if (tim.getStartPoint() == null || !tim.getStartPoint().isValid()) { - resultMessages.add("Invalid startPoint"); - } - if (tim.getEndPoint() == null || !tim.getEndPoint().isValid()) { - resultMessages.add("Invalid endPoint"); + + // if geometry isn't present check for start/end points + if (!tim.isGeometryValid()) { + if (tim.getStartPoint() == null || !tim.getStartPoint().isValid()) { + resultMessages.add("Invalid startPoint"); + } + if (tim.getEndPoint() == null || !tim.getEndPoint().isValid()) { + resultMessages.add("Invalid endPoint"); + } } + if (tim.getRoute() == null) { resultMessages.add("Null value for route"); } @@ -364,7 +367,7 @@ protected ControllerResult validateInputRc(WydotTimRc tim) { } // set itis codes - List itisCodes = setItisCodes.setItisCodesRc(tim); + List itisCodes = setItisCodes.setItisCodes(tim); if (itisCodes.isEmpty()) { resultMessages.add("No ITIS codes found"); } @@ -423,12 +426,6 @@ protected ControllerResult validateInputVsl(WydotTimVsl tim) { !tim.getDirection().equalsIgnoreCase("b")) { resultMessages.add("direction not supported"); } - if (tim.getStartPoint() == null || !tim.getStartPoint().isValid()) { - resultMessages.add("Invalid startPoint"); - } - if (tim.getEndPoint() == null || !tim.getEndPoint().isValid()) { - resultMessages.add("Invalid endPoint"); - } if (tim.getRoute() == null) { resultMessages.add("Null value for route"); } @@ -438,16 +435,25 @@ protected ControllerResult validateInputVsl(WydotTimVsl tim) { if (tim.getDeviceId() == null) { resultMessages.add("Null value for deviceId"); } else { - tim.setClientId(tim.getDeviceId()); + tim.setClientId(tim.getClientId()); } // set itis codes - List itisCodes = setItisCodes.setItisCodesVsl(tim); - if (itisCodes.isEmpty()) { - resultMessages.add("No ITIS codes found"); + + try { + List itisCodes; + itisCodes= setItisCodes.setItisCodesVsl(tim); + if (itisCodes.isEmpty()) { + resultMessages.add("No ITIS codes found"); + } + result.setItisCodes(itisCodes); + tim.setItisCodes(itisCodes); + if (itisCodes.isEmpty()) { + resultMessages.add("No ITIS codes found"); + } + } catch (Exception e) { + resultMessages.add("Could not determine speed for speed limit tim"); } - result.setItisCodes(itisCodes); - tim.setItisCodes(itisCodes); result.setResultMessages(resultMessages); return result; @@ -639,8 +645,7 @@ protected ControllerResult validateInputBowr(WydotTimBowr tim) { } public void processRequest(WydotTim wydotTim, TimType timType, String startDateTime, - String endDateTime, Integer pk, ContentEnum content, - TravelerInfoType frameType) { + String endDateTime, Integer pk, TravelerInfoType frameType) { if (wydotTim.getDirection().equalsIgnoreCase("b")) { var iTim = wydotTim.copy(); @@ -648,14 +653,11 @@ public void processRequest(WydotTim wydotTim, TimType timType, String startDateT iTim.setDirection("I"); dTim.setDirection("D"); // I - expireReduceCreateSendTims(iTim, timType, startDateTime, endDateTime, pk, content, - frameType); + expireReduceCreateSendTims(iTim, timType, startDateTime, endDateTime, pk, frameType); // D - expireReduceCreateSendTims(dTim, timType, startDateTime, endDateTime, pk, content, - frameType); + expireReduceCreateSendTims(dTim, timType, startDateTime, endDateTime, pk, frameType); } else { - expireReduceCreateSendTims(wydotTim, timType, startDateTime, endDateTime, pk, content, - frameType); + expireReduceCreateSendTims(wydotTim, timType, startDateTime, endDateTime, pk, frameType); } } @@ -684,13 +686,16 @@ public List getTimTypes() { protected void expireReduceCreateSendTims(WydotTim wydotTim, TimType timType, String startDateTime, String endDateTime, Integer pk, - ContentEnum content, TravelerInfoType frameType) { + TravelerInfoType frameType) { // Clear any existing TIMs with the same client id Long timTypeId = timType != null ? timType.getTimTypeId() : null; var existingTims = activeTimService.getActiveTimsByClientIdDirection(wydotTim.getClientId(), timTypeId, wydotTim.getDirection()); + // Use wydotTimService to get all mileposts for the TIM + List milepostsAll = wydotTimService.getAllMilepostsForTim(wydotTim); + // Expire existing tims List existingTimIds = new ArrayList<>(); for (ActiveTim existingTim : existingTims) { @@ -698,9 +703,6 @@ protected void expireReduceCreateSendTims(WydotTim wydotTim, TimType timType, } timGenerationHelper.expireTimAndResubmitToOde(existingTimIds); - // Get mileposts that will define the TIM's region - var milepostsAll = wydotTimService.getAllMilepostsForTim(wydotTim); - // Per J2735, NodeSetLL's must contain at least 2 nodes. ODE will fail to // PER-encode TIM if we supply less than 2. if (milepostsAll.size() < 2) { @@ -726,20 +728,20 @@ protected void expireReduceCreateSendTims(WydotTim wydotTim, TimType timType, var reducedMileposts = milepostReduction.applyMilepostReductionAlgorithm(milepostsAll, configuration.getPathDistanceLimit()); - createSendTims(wydotTim, timType, startDateTime, endDateTime, pk, content, frameType, + createSendTims(wydotTim, timType, startDateTime, endDateTime, pk, frameType, milepostsAll, reducedMileposts, anchor); } // creates a TIM and sends it to RSUs and Satellite protected void createSendTims(WydotTim wydotTim, TimType timType, String startDateTime, - String endDateTime, Integer pk, ContentEnum content, + String endDateTime, Integer pk, TravelerInfoType frameType, List allMileposts, List reducedMileposts, Milepost anchor) { // create TIM WydotTravelerInputData timToSend = wydotTimService.createTim(wydotTim, timType.getType(), startDateTime, endDateTime, - content, frameType, allMileposts, reducedMileposts, anchor); + frameType, allMileposts, reducedMileposts, anchor, configuration.getDotGnisId()); if (timToSend == null) { return; @@ -755,15 +757,15 @@ protected void createSendTims(WydotTim wydotTim, TimType timType, String startDa endPoint = new Coordinate(endMp.getLatitude(), endMp.getLongitude()); } - if (Arrays.asList(configuration.getRsuRoutes()).contains(wydotTim.getRoute())) { - // send TIM to RSUs - wydotTimService.sendTimToRsus(wydotTim, timToSend, regionNamePrev, timType, pk, - endDateTime, endPoint); - } + // send TIM to RSUs + wydotTimService.sendTimToRsus(wydotTim, timToSend, regionNamePrev, timType, pk, endDateTime, endPoint); + // send TIM to SDW // remove rsus from TIM timToSend.getRequest().setRsus(null); wydotTimService.sendTimToSDW(wydotTim, timToSend, regionNamePrev, timType, pk, endPoint, reducedMileposts); } + + } \ No newline at end of file diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBowrController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBowrController.java index c7ed16e7b..5f390a371 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBowrController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimBowrController.java @@ -8,9 +8,9 @@ import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.ActiveTim; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.WydotTim; import com.trihydro.library.service.ActiveTimService; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.RestTemplateProvider; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; @@ -44,9 +44,9 @@ public class WydotTimBowrController extends WydotTimBaseController { public WydotTimBowrController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, - TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, - _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, identicalPointsExceptionHandler); + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); } @RequestMapping(value = "/create-or-update-bowr-tim", method = RequestMethod.POST, headers = "Accept=application/json") @@ -62,7 +62,7 @@ public ResponseEntity createOrUpdateBowrTim(@RequestBody TimBowrList tim timResult = validateInputBowr(wydotTimBowr); - if (timResult.getResultMessages().size() > 0) { + if (!timResult.getResultMessages().isEmpty()) { results.add(timResult); errors.add(timResult); continue; @@ -76,7 +76,7 @@ public ResponseEntity createOrUpdateBowrTim(@RequestBody TimBowrList tim processRequestAsync(timsToSend); String responseMessage = gson.toJson(results); - if (errors.size() > 0) { + if (!errors.isEmpty()) { utility.logWithDate("Failed to send TIMs: " + gson.toJson(errors), this.getClass()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseMessage); } @@ -90,7 +90,7 @@ public ResponseEntity submitBowrClear(@PathVariable String clientId) { List existingTimIds = new ArrayList(); // validate client id - if (clientId == null || clientId.length() == 0) { + if (clientId == null || clientId.isEmpty()) { String responseMessage = "Null or empty value for client id"; return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseMessage); } @@ -99,7 +99,7 @@ public ResponseEntity submitBowrClear(@PathVariable String clientId) { var timType = getTimType(type); Long timTypeId = timType != null ? timType.getTimTypeId() : null; List existingActiveTims = activeTimService.getActiveTimsByClientIdDirection(clientId, timTypeId, null); - if (existingActiveTims.size() == 0) { + if (existingActiveTims.isEmpty()) { utility.logWithDate("No active TIMs found for client id: " + clientId, this.getClass()); String responseMessage = "No active TIMs found for client id: " + clientId; return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseMessage); @@ -111,9 +111,7 @@ public ResponseEntity submitBowrClear(@PathVariable String clientId) { } // expire existing tims - if (existingTimIds.size() > 0) { - timGenerationHelper.expireTimAndResubmitToOde(existingTimIds); - } + timGenerationHelper.expireTimAndResubmitToOde(existingTimIds); String responseMessage = "success"; return ResponseEntity.status(HttpStatus.OK).body(responseMessage); @@ -135,7 +133,7 @@ public void run() { // get end time String endTime = wydotTimBowr.getEndDateTime(); - processRequest(tim, getTimType(type), startTime, endTime, null, ContentEnum.advisory, + processRequest(tim, getTimType(type), startTime, endTime, null, TravelerInfoType.advisory); } } diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimCcController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimCcController.java index 9fc7ea454..53cca041c 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimCcController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimCcController.java @@ -10,9 +10,9 @@ import com.trihydro.library.helpers.MilepostReduction; import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.WydotTim; import com.trihydro.library.service.ActiveTimService; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.RestTemplateProvider; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; @@ -45,9 +45,9 @@ public class WydotTimCcController extends WydotTimBaseController { public WydotTimCcController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, - TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, - _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, identicalPointsExceptionHandler); + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); } @RequestMapping(value = "/cc-tim", method = RequestMethod.POST, headers = "Accept=application/json") @@ -59,7 +59,7 @@ public ResponseEntity createChainControlTim(@RequestBody TimRcList timRc utility.logWithDate(dateFormat.format(date) + " - CHAIN CONTROL TIM", this.getClass()); String post = gson.toJson(timRcList); - utility.logWithDate(post.toString(), this.getClass()); + utility.logWithDate(post, this.getClass()); List resultList = new ArrayList(); ControllerResult resultTim = null; @@ -75,7 +75,7 @@ public ResponseEntity createChainControlTim(@RequestBody TimRcList timRc resultTim = validateInputCc(wydotTim); - if (resultTim.getResultMessages().size() > 0) { + if (!resultTim.getResultMessages().isEmpty()) { resultList.add(resultTim); continue; } @@ -99,7 +99,7 @@ public void processRequestAsync(List wydotTims) { public void run() { var startTime = getStartTime(); for (WydotTim tim : wydotTims) { - processRequest(tim, getTimType(type), startTime, null, null, ContentEnum.advisory, + processRequest(tim, getTimType(type), startTime, null, null, TravelerInfoType.advisory); } } diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimIncidentController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimIncidentController.java index 6efd15d6b..b84cdf330 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimIncidentController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimIncidentController.java @@ -1,79 +1,75 @@ package com.trihydro.odewrapper.controller; import com.trihydro.library.exceptionhandlers.IdenticalPointsExceptionHandler; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import com.trihydro.library.helpers.MilepostReduction; import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.ActiveTim; -import com.trihydro.library.model.ContentEnum; -import com.trihydro.library.service.ActiveTimService; -import com.trihydro.library.service.RestTemplateProvider; -import com.trihydro.library.service.TimTypeService; -import com.trihydro.library.service.WydotTimService; +import com.trihydro.library.model.WydotTim; +import com.trihydro.library.service.*; import com.trihydro.odewrapper.config.BasicConfiguration; +import com.trihydro.odewrapper.factory.BufferTimFactory; import com.trihydro.odewrapper.helpers.SetItisCodes; import com.trihydro.odewrapper.model.ControllerResult; import com.trihydro.odewrapper.model.TimIncidentList; import com.trihydro.odewrapper.model.WydotTimIncident; - +import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import io.swagger.annotations.Api; +import org.springframework.web.bind.annotation.*; import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; + @CrossOrigin @RestController @Api(description = "Incidents") @Slf4j -public class WydotTimIncidentController extends WydotTimBaseController { - - private final String type = "I"; +public class WydotTimIncidentController extends WydotTimBaseController implements BufferTimFactory { + + private final String type = "I"; + List timsToSend = new ArrayList<>(); + + @Autowired + public WydotTimIncidentController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, + TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, + RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); + } - @Autowired - public WydotTimIncidentController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, TimTypeService _timTypeService, - SetItisCodes _setItisCodes, ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider, - MilepostReduction _milepostReduction, Utility _utility, TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { - super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, _restTemplateProvider, _milepostReduction, - _utility, _timGenerationHelper, identicalPointsExceptionHandler); - } + @RequestMapping(value = "/incident-tim", method = RequestMethod.POST, headers = "Accept=application/json") + public ResponseEntity createIncidentTim(@RequestBody TimIncidentList timIncidentList) { - @RequestMapping(value = "/incident-tim", method = RequestMethod.POST, headers = "Accept=application/json") - public ResponseEntity createIncidentTim(@RequestBody TimIncidentList timIncidentList) { - log.info("Create Incident TIM"); - String post = gson.toJson(timIncidentList); - log.info(post); + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + Date date = new Date(); - List timsToSend = new ArrayList<>(); + utility.logWithDate(dateFormat.format(date) + " - Create Incident TIM", this.getClass()); + String post = gson.toJson(timIncidentList); + utility.logWithDate(post, this.getClass()); - List resultList = new ArrayList<>(); - ControllerResult resultTim; + List resultList = new ArrayList<>(); + ControllerResult resultTim; // build TIM for (WydotTimIncident wydotTim : timIncidentList.getTimIncidentList()) { resultTim = validateInputIncident(wydotTim); - if (!resultTim.getResultMessages().isEmpty()) { - resultList.add(resultTim); - continue; - } - - // make tims - timsToSend.add(wydotTim); + if (wydotTim.getDirection().equalsIgnoreCase("i")) { + timsToSend.addAll(makeIncreasingTims(wydotTim, bufferTimITISCodes, milepostService)); + } + else { + timsToSend.addAll(makeDecreasingTims(wydotTim, bufferTimITISCodes, milepostService)); + } resultTim.getResultMessages().add("success"); resultList.add(resultTim); @@ -85,57 +81,68 @@ public ResponseEntity createIncidentTim(@RequestBody TimIncidentList tim return ResponseEntity.status(HttpStatus.OK).body(responseMessage); } - @RequestMapping(value = "/incident-tim", method = RequestMethod.PUT, headers = "Accept=application/json") - public ResponseEntity updateIncidentTim(@RequestBody TimIncidentList timIncidentList) { - log.info("Update Incident TIM"); - String post = gson.toJson(timIncidentList); - log.info(post); + @RequestMapping(value = "/incident-tim", method = RequestMethod.PUT, headers = "Accept=application/json") + public ResponseEntity updateIncidentTim(@RequestBody TimIncidentList timIncidentList) { - List resultList = new ArrayList<>(); - ControllerResult resultTim; - List timsToSend = new ArrayList<>(); + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + Date date = new Date(); - // delete TIMs - for (WydotTimIncident wydotTim : timIncidentList.getTimIncidentList()) { - resultTim = validateInputIncident(wydotTim); - if (!resultTim.getResultMessages().isEmpty()) { - resultList.add(resultTim); - continue; - } - // make tims - timsToSend.add(wydotTim); - resultTim.getResultMessages().add("success"); - resultList.add(resultTim); - } + utility.logWithDate(dateFormat.format(date) + " - Update Incident TIM", this.getClass()); + String post = gson.toJson(timIncidentList); + utility.logWithDate(post, this.getClass()); + + List resultList = new ArrayList<>(); + ControllerResult resultTim; + + // delete TIMs + for (WydotTimIncident wydotTim : timIncidentList.getTimIncidentList()) { + + resultTim = validateInputIncident(wydotTim); + + if (!resultTim.getResultMessages().isEmpty()) { + resultList.add(resultTim); + continue; + } + + // make tims + timsToSend.add(wydotTim); + + resultTim.getResultMessages().add("success"); + resultList.add(resultTim); + } + if (!timsToSend.isEmpty()) { + // make tims, expire existing ones, and send them + makeTimsAsync(timsToSend); + } - if (!timsToSend.isEmpty()) { - // make tims, expire existing ones, and send them - makeTimsAsync(timsToSend); + String responseMessage = gson.toJson(resultList); + return ResponseEntity.status(HttpStatus.OK).body(responseMessage); } - String responseMessage = gson.toJson(resultList); - return ResponseEntity.status(HttpStatus.OK).body(responseMessage); - } - public void makeTimsAsync(List wydotTims) { - new Thread(() -> { - var startTime = getStartTime(); - for (WydotTimIncident wydotTim : wydotTims) { - // set route - wydotTim.setRoute(wydotTim.getHighway()); - processRequest(wydotTim, getTimType(type), startTime, null, wydotTim.getPk(), ContentEnum.advisory, TravelerInfoType.advisory); - } - }).start(); - } + public void makeTimsAsync(List wydotTims) { + + new Thread(() -> { + var startTime = getStartTime(); + for (var wydotTim : wydotTims) { + var wydotTimIncident = (WydotTimIncident)wydotTim; + // set route + wydotTim.setRoute(wydotTimIncident.getRoute()); + processRequest(wydotTimIncident, getTimType(type), startTime, null, wydotTimIncident.getPk(), + TravelerInfoType.advisory); + } + }).start(); + } @RequestMapping(value = "/incident-tim/{incidentId}", method = RequestMethod.DELETE, headers = "Accept=application/json") public ResponseEntity deleteIncidentTim(@PathVariable String incidentId) { log.info("Delete Incident TIM"); - // expire and clear TIM - wydotTimService.clearTimsById("I", incidentId, null); - String responseMessage = "success"; - return ResponseEntity.status(HttpStatus.OK).body(responseMessage); - } + // expire and clear TIM + wydotTimService.clearTimsById("I", incidentId, null, true); + + String responseMessage = "success"; + return ResponseEntity.status(HttpStatus.OK).body(responseMessage); + } @RequestMapping(value = "/incident-tim", method = RequestMethod.GET, headers = "Accept=application/json") public Collection getIncidentTims() { diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimParkingController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimParkingController.java index b7b9ddc26..f8074df0e 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimParkingController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimParkingController.java @@ -12,8 +12,8 @@ import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.ActiveTim; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.service.ActiveTimService; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.RestTemplateProvider; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; @@ -47,9 +47,9 @@ public class WydotTimParkingController extends WydotTimBaseController { public WydotTimParkingController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, - TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, - _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, identicalPointsExceptionHandler); + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); } @RequestMapping(value = "/parking-tim", method = RequestMethod.POST, headers = "Accept=application/json") @@ -60,7 +60,7 @@ public ResponseEntity createParkingTim(@RequestBody TimParkingList timPa utility.logWithDate(dateFormat.format(date) + " - Create Parking TIM", this.getClass()); String post = gson.toJson(timParkingList); - utility.logWithDate(post.toString(), this.getClass()); + utility.logWithDate(post, this.getClass()); List resultList = new ArrayList(); ControllerResult resultTim = null; @@ -71,7 +71,7 @@ public ResponseEntity createParkingTim(@RequestBody TimParkingList timPa resultTim = validateInputParking(wydotTim); - if (resultTim.getResultMessages().size() > 0) { + if (!resultTim.getResultMessages().isEmpty()) { resultList.add(resultTim); continue; } @@ -140,7 +140,7 @@ public void processRequestAsync(List wydotTims) { public void run() { var startTime = getStartTime(); for (WydotTimParking wydotTim : wydotTims) { - processRequest(wydotTim, getTimType(type), startTime, null, null, ContentEnum.exitService, + processRequest(wydotTim, getTimType(type), startTime, null, null, TravelerInfoType.advisory); } } diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRcController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRcController.java index 86ad03ba8..85a98fcdc 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRcController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRcController.java @@ -4,6 +4,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; @@ -11,7 +12,6 @@ import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.ActiveTim; -import com.trihydro.library.model.ContentEnum; import com.trihydro.library.model.WydotTim; import com.trihydro.library.service.ActiveTimService; import com.trihydro.library.service.RestTemplateProvider; @@ -32,6 +32,8 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import com.trihydro.library.service.MilepostService; + import io.swagger.annotations.Api; import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; @@ -47,9 +49,9 @@ public class WydotTimRcController extends WydotTimBaseController { public WydotTimRcController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, - TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, - _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, identicalPointsExceptionHandler); + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); configuration = _basicConfiguration; } @@ -61,26 +63,34 @@ public ResponseEntity createUpdateRoadConditionsTim(@RequestBody TimRcLi utility.logWithDate(dateFormat.format(date) + " - Create Update RC TIM", this.getClass()); String post = gson.toJson(timRcList); - utility.logWithDate(post.toString(), this.getClass()); + utility.logWithDate(post, this.getClass()); - List resultList = new ArrayList(); - List errList = new ArrayList(); - ControllerResult resultTim = null; - List timsToSend = new ArrayList(); + List resultList = new ArrayList<>(); + List errList = new ArrayList<>(); + ControllerResult resultTim; + List timsToSend = new ArrayList<>(); // build TIM for (WydotTimRc wydotTim : timRcList.getTimRcList()) { resultTim = validateInputRc(wydotTim); - if (resultTim.getResultMessages().size() > 0) { + if (!resultTim.getResultMessages().isEmpty()) { resultList.add(resultTim); errList.add(resultTim); continue; } - // add TIM to list for processing later - timsToSend.add(wydotTim); + // Each ITIS string in the TIM corresponds to a single TIM to be sent to ODE + for (String itisCodeEntry : wydotTim.getItisCodes()) { + List itisCodes = Arrays.asList(itisCodeEntry.split(" ")); + WydotTimRc timToSend = wydotTim.copy(); + timToSend.setItisCodes(itisCodes); + var itisCodeAbb = SetItisCodes.getItisCodeAbbreviation(itisCodeEntry); + String clientIdWithItis = wydotTim.getClientId() + '-' + wydotTim.getDirection() + '-' + itisCodeAbb; + timToSend.setClientId(clientIdWithItis); + timsToSend.add(timToSend); + } resultTim.getResultMessages().add("success"); resultList.add(resultTim); @@ -89,7 +99,7 @@ public ResponseEntity createUpdateRoadConditionsTim(@RequestBody TimRcLi processRequestAsync(timsToSend); String responseMessage = gson.toJson(resultList); - if (errList.size() > 0) { + if (!errList.isEmpty()) { utility.logWithDate("Failed to send TIMs: " + gson.toJson(errList), this.getClass()); } return ResponseEntity.status(HttpStatus.OK).body(responseMessage); @@ -105,7 +115,7 @@ public ResponseEntity submitAllClearRoadConditionsTim(@RequestBody TimRc utility.logWithDate(dateFormat.format(date) + " - All Clear", this.getClass()); String post = gson.toJson(timRcList); - utility.logWithDate(post.toString(), this.getClass()); + utility.logWithDate(post, this.getClass()); List errList = new ArrayList(); ControllerResult resultTim = null; @@ -113,7 +123,7 @@ public ResponseEntity submitAllClearRoadConditionsTim(@RequestBody TimRc for (WydotTimRc wydotTim : timRcList.getTimRcList()) { resultTim = validateRcAc(wydotTim); - if (resultTim.getResultMessages().size() > 0) { + if (!resultTim.getResultMessages().isEmpty()) { resultList.add(resultTim); errList.add(resultTim); continue; @@ -144,23 +154,24 @@ public ResponseEntity submitAllClearRoadConditionsTim(@RequestBody TimRc } // Expire existing tims - if (existingTimIds.size() > 0) { + if (!existingTimIds.isEmpty()) { timGenerationHelper.expireTimAndResubmitToOde(existingTimIds); } String responseMessage = gson.toJson(resultList); + if (!errList.isEmpty()) { + utility.logWithDate("Failed to send TIMs: " + gson.toJson(errList), this.getClass()); + } return ResponseEntity.status(HttpStatus.OK).body(responseMessage); } public void processRequestAsync(List wydotTims) { // An Async task always executes in new thread - new Thread(new Runnable() { - public void run() { - var startTime = getStartTime(); - for (WydotTim tim : wydotTims) { - processRequest(tim, getTimType(type), startTime, null, null, ContentEnum.advisory, - TravelerInfoType.advisory); - } + new Thread(() -> { + var startTime = getStartTime(); + for (WydotTim tim : wydotTims) { + processRequest(tim, getTimType(type), startTime, null, null, + TravelerInfoType.advisory); } }).start(); } diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRwController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRwController.java index 7c014d700..29b92e882 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRwController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimRwController.java @@ -1,7 +1,7 @@ package com.trihydro.odewrapper.controller; import com.trihydro.library.exceptionhandlers.IdenticalPointsExceptionHandler; -import java.math.BigDecimal; + import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -10,24 +10,17 @@ import com.trihydro.library.helpers.MilepostReduction; import com.trihydro.library.helpers.TimGenerationHelper; import com.trihydro.library.helpers.Utility; -import com.trihydro.library.model.ActiveTim; -import com.trihydro.library.model.Buffer; -import com.trihydro.library.model.ContentEnum; -import com.trihydro.library.model.Coordinate; -import com.trihydro.library.model.TimRwList; -import com.trihydro.library.model.WydotTimRw; +import com.trihydro.library.model.*; import com.trihydro.library.service.ActiveTimService; import com.trihydro.library.service.RestTemplateProvider; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; import com.trihydro.odewrapper.config.BasicConfiguration; +import com.trihydro.odewrapper.factory.BufferTimFactory; import com.trihydro.odewrapper.helpers.SetItisCodes; import com.trihydro.odewrapper.model.ControllerResult; import org.apache.commons.lang3.StringUtils; -import org.gavaghan.geodesy.Ellipsoid; -import org.gavaghan.geodesy.GeodeticCalculator; -import org.gavaghan.geodesy.GlobalCoordinates; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -38,35 +31,37 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import com.trihydro.library.service.MilepostService; + import io.swagger.annotations.Api; import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; @CrossOrigin @RestController @Api(description = "Road Construction") -public class WydotTimRwController extends WydotTimBaseController { +public class WydotTimRwController extends WydotTimBaseController implements BufferTimFactory { private final String type = "RW"; - List timsToSend; + List timsToSend; @Autowired public WydotTimRwController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, - TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, - _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, identicalPointsExceptionHandler); + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); } @RequestMapping(value = "/rw-tim", method = RequestMethod.POST, headers = "Accept=application/json") public ResponseEntity createRoadContructionTim(@RequestBody TimRwList timRwList) { utility.logWithDate("Create/Update RW TIM", this.getClass()); String post = gson.toJson(timRwList); - utility.logWithDate(post.toString(), this.getClass()); + utility.logWithDate(post, this.getClass()); - List resultList = new ArrayList(); - ControllerResult resultTim = null; - timsToSend = new ArrayList(); + List resultList = new ArrayList<>(); + ControllerResult resultTim; + timsToSend = new ArrayList<>(); // build TIM for (WydotTimRw wydotTim : timRwList.getTimRwList()) { @@ -75,7 +70,7 @@ public ResponseEntity createRoadContructionTim(@RequestBody TimRwList ti resultTim = validateInputRw(wydotTim); // if there are invalidation messages skip to next TIM - if (resultTim.getResultMessages().size() > 0) { + if (!resultTim.getResultMessages().isEmpty()) { resultList.add(resultTim); continue; } @@ -86,18 +81,15 @@ public ResponseEntity createRoadContructionTim(@RequestBody TimRwList ti if (wydotTim.getBuffers() != null) wydotTim.getBuffers().sort(Comparator.comparingDouble(Buffer::getDistance)); - // if bi-directional if (wydotTim.getDirection().equalsIgnoreCase("b")) { - // make i TIMs - makeIncreasingTims(wydotTim); - // make d TIMs - makeDecreasingTims(wydotTim); + // if bi-directional, make both increasing and decreasing TIMs + timsToSend.addAll(makeIncreasingTims(wydotTim, bufferTimITISCodes, milepostService)); + timsToSend.addAll(makeDecreasingTims(wydotTim, bufferTimITISCodes, milepostService)); + } else if (wydotTim.getDirection().equalsIgnoreCase("i")) { + timsToSend.addAll(makeIncreasingTims(wydotTim, bufferTimITISCodes, milepostService)); + } else { + timsToSend.addAll(makeDecreasingTims(wydotTim, bufferTimITISCodes, milepostService)); } - // else make one direction TIMs - else if (wydotTim.getDirection().equalsIgnoreCase("i")) - makeIncreasingTims(wydotTim); - else - makeDecreasingTims(wydotTim); // compile result messages for user resultTim.getResultMessages().add("success"); @@ -110,164 +102,21 @@ else if (wydotTim.getDirection().equalsIgnoreCase("i")) return ResponseEntity.status(HttpStatus.OK).body(responseMessage); } - public void makeIncreasingTims(WydotTimRw wydotTim) { - - // i - add buffer for point TIMs - WydotTimRw timOneWay = wydotTim.copy(); - if (StringUtils.isBlank(timOneWay.getSchedStart())) { - String startTime = getStartTime(); - timOneWay.setSchedStart(startTime); - } - - timOneWay.setDirection("I"); - timsToSend.add(timOneWay); - - if (timOneWay.getBuffers() != null) - makeIncreasingBufferTim(timOneWay); - } - - public void makeDecreasingTims(WydotTimRw wydotTim) { - - // d - add buffer for point TIMs - + private WydotTimRw copyTimWithStartDate(WydotTimRw wydotTim) { WydotTimRw timOneWay = wydotTim.copy(); if (StringUtils.isBlank(timOneWay.getSchedStart())) { String startTime = getStartTime(); timOneWay.setSchedStart(startTime); } - - timOneWay.setDirection("D"); - timsToSend.add(timOneWay); - if (timOneWay.getBuffers() != null) - makeDecreasingBufferTim(timOneWay); - } - - private double getIBearingForRoute(String route) { - // TODO: this needs to call out to the DIRECTION_EXCEPTION view and compare - // mileage to determine direction - Integer numericRoute = Integer.parseInt(route.replaceAll("\\D+", "")); - if (numericRoute % 2 == 0) { - return 270; - } - return 180; - } - - private double getDBearingForRoute(String route) { - // TODO: this needs to call out to the DIRECTION_EXCEPTION view and compare - // mileage to determine direction - Integer numericRoute = Integer.parseInt(route.replaceAll("\\D+", "")); - if (numericRoute % 2 == 0) { - return 90; - } - return 0; - } - - public void makeIncreasingBufferTim(WydotTimRw wydotTim) { - - double bufferBefore = 0.000; - - Ellipsoid reference = Ellipsoid.WGS84; - GlobalCoordinates startCoordinates = new GlobalCoordinates(wydotTim.getStartPoint().getLatitude().doubleValue(), - wydotTim.getStartPoint().getLongitude().doubleValue()); - GlobalCoordinates nextCoordinates = null; - double bearing = getIBearingForRoute(wydotTim.getRoute()); - GeodeticCalculator calculator = new GeodeticCalculator(); - - for (int i = 0; i < wydotTim.getBuffers().size(); i++) { - // i - // starts at lower milepost minus the buffer distance - nextCoordinates = calculator.calculateEndingGlobalCoordinates(reference, startCoordinates, bearing, - wydotTim.getBuffers().get(i).getDistanceMeters()); - - // update start and stopping points - WydotTimRw wydotTimBuffer = wydotTim.copy(); - - wydotTimBuffer.setStartPoint(new Coordinate(BigDecimal.valueOf(nextCoordinates.getLatitude()), - BigDecimal.valueOf(nextCoordinates.getLongitude()))); - wydotTimBuffer.setEndPoint(new Coordinate(BigDecimal.valueOf(startCoordinates.getLatitude()), - BigDecimal.valueOf(startCoordinates.getLongitude()))); - wydotTimBuffer.setAction(wydotTim.getBuffers().get(i).getAction()); - wydotTimBuffer.setClientId(wydotTim.getClientId() + "%BUFF" + Integer.toString((int) bufferBefore)); - - // send buffer tim - wydotTimBuffer.setAdvisory(wydotTimService.setBufferItisCodes(wydotTimBuffer.getAction())); - if (wydotTimBuffer.getAdvisory() != null) { - List tempList = new ArrayList(wydotTimBuffer.getAdvisory().length); - for (Integer code : wydotTimBuffer.getAdvisory()) { - tempList.add(code.toString()); - } - wydotTimBuffer.setItisCodes(tempList); - } - timsToSend.add(wydotTimBuffer); - - // update running buffer distance - bufferBefore = wydotTim.getBuffers().get(i).getDistance(); - startCoordinates = nextCoordinates; - } - } - - public void makeDecreasingBufferTim(WydotTimRw wydotTim) { - - double bufferBefore = 0; - - Ellipsoid reference = Ellipsoid.WGS84; - GlobalCoordinates startCoordinates = new GlobalCoordinates(wydotTim.getEndPoint().getLatitude().doubleValue(), - wydotTim.getEndPoint().getLongitude().doubleValue()); - GlobalCoordinates nextCoordinates = null; - double bearing = getDBearingForRoute(wydotTim.getRoute()); - GeodeticCalculator calculator = new GeodeticCalculator(); - - for (int i = 0; i < wydotTim.getBuffers().size(); i++) { - // d - // starts at higher milepost plus buffer distance - nextCoordinates = calculator.calculateEndingGlobalCoordinates(reference, startCoordinates, bearing, - wydotTim.getBuffers().get(i).getDistanceMeters()); - - // update start and stopping mileposts - WydotTimRw wydotTimBuffer = wydotTim.copy(); - - wydotTimBuffer.setStartPoint(new Coordinate(BigDecimal.valueOf(startCoordinates.getLatitude()), - BigDecimal.valueOf(startCoordinates.getLongitude()))); - wydotTimBuffer.setEndPoint(new Coordinate(BigDecimal.valueOf(nextCoordinates.getLatitude()), - BigDecimal.valueOf(nextCoordinates.getLongitude()))); - wydotTimBuffer.setAction(wydotTim.getBuffers().get(i).getAction()); - wydotTimBuffer.setClientId(wydotTim.getClientId() + "%BUFF" + Integer.toString((int) bufferBefore)); - - // send buffer tim - wydotTimBuffer.setAdvisory(wydotTimService.setBufferItisCodes(wydotTimBuffer.getAction())); - List tempList = new ArrayList(wydotTimBuffer.getAdvisory().length); - for (Integer code : wydotTimBuffer.getAdvisory()) { - tempList.add(code.toString()); - } - wydotTimBuffer.setItisCodes(tempList); - timsToSend.add(wydotTimBuffer); - - // update running buffer distance - bufferBefore = wydotTim.getBuffers().get(i).getDistance(); - startCoordinates = nextCoordinates; - } + return timOneWay; } public void processRequestAsync() { // An Async task always executes in new thread - new Thread(new Runnable() { - public void run() { - for (WydotTimRw tim : timsToSend) { - // check for reduce speed, itis code 7443 - if (tim.getItisCodes() != null && tim.getItisCodes().size() == 3 - && tim.getItisCodes().get(0).equals("7443")) { - processRequest(tim, getTimType(type), tim.getSchedStart(), tim.getSchedEnd(), null, - ContentEnum.speedLimit, TravelerInfoType.advisory); - } else if (tim.getItisCodes() != null && tim.getItisCodes().get(0).equals("7186")) { - // prepare to stop - processRequest(tim, getTimType(type), tim.getSchedStart(), tim.getSchedEnd(), null, - ContentEnum.advisory, TravelerInfoType.advisory); - } else { - // the rest are content=workZone - processRequest(tim, getTimType(type), tim.getSchedStart(), tim.getSchedEnd(), null, - ContentEnum.workZone, TravelerInfoType.advisory); - } - } + new Thread(() -> { + for (var tim : timsToSend) { + WydotTimRw timRw = (WydotTimRw) tim; + processRequest(timRw, getTimType(type), timRw.getSchedStart(), timRw.getSchedEnd(), null, TravelerInfoType.advisory); } }).start(); @@ -314,4 +163,4 @@ public Collection getRoadConstructionTim() { return activeTims; } -} \ No newline at end of file +} diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimVslController.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimVslController.java index 987a8d78a..d25c11e22 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimVslController.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/controller/WydotTimVslController.java @@ -1,117 +1,125 @@ -package com.trihydro.odewrapper.controller; - -import com.trihydro.library.exceptionhandlers.IdenticalPointsExceptionHandler; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; - -import com.trihydro.library.helpers.MilepostReduction; -import com.trihydro.library.helpers.TimGenerationHelper; -import com.trihydro.library.helpers.Utility; -import com.trihydro.library.model.ActiveTim; -import com.trihydro.library.model.ContentEnum; -import com.trihydro.library.model.WydotTim; -import com.trihydro.library.service.ActiveTimService; -import com.trihydro.library.service.RestTemplateProvider; -import com.trihydro.library.service.TimTypeService; -import com.trihydro.library.service.WydotTimService; -import com.trihydro.odewrapper.config.BasicConfiguration; -import com.trihydro.odewrapper.helpers.SetItisCodes; -import com.trihydro.odewrapper.model.ControllerResult; -import com.trihydro.odewrapper.model.TimVslList; -import com.trihydro.odewrapper.model.WydotTimVsl; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import io.swagger.annotations.Api; -import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; - -@CrossOrigin -@RestController -@Api(description = "Variable Speed Limits") -public class WydotTimVslController extends WydotTimBaseController { - - private final String type = "VSL"; - - @Autowired - public WydotTimVslController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, - TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, - RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, - TimGenerationHelper _timGenerationHelper, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { - super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, - _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, identicalPointsExceptionHandler); - } - - @RequestMapping(value = "/vsl-tim", method = RequestMethod.POST, headers = "Accept=application/json") - public ResponseEntity createUpdateVslTim(@RequestBody TimVslList timVslList) { - - DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - Date date = new Date(); - - utility.logWithDate(dateFormat.format(date) + " - Create/Update VSL TIM", this.getClass()); - String post = gson.toJson(timVslList); - utility.logWithDate(post.toString(), this.getClass()); - - List resultList = new ArrayList(); - ControllerResult resultTim = null; - List timsToSend = new ArrayList(); - - // build TIM - for (WydotTimVsl wydotTim : timVslList.getTimVslList()) { - resultTim = validateInputVsl(wydotTim); - - if (resultTim.getResultMessages().size() > 0) { - resultList.add(resultTim); - continue; - } - - // add TIM to list for processing later - timsToSend.add(wydotTim); - - resultTim.getResultMessages().add("success"); - resultList.add(resultTim); - } - - processRequestAsync(timsToSend); - String responseMessage = gson.toJson(resultList); - return ResponseEntity.status(HttpStatus.OK).body(responseMessage); - } - - public void processRequestAsync(List wydotTims) { - // An Async task always executes in new thread - new Thread(new Runnable() { - public void run() { - var startTime = getStartTime(); - for (WydotTim tim : wydotTims) { - processRequest(tim, getTimType(type), startTime, null, null, ContentEnum.speedLimit, - TravelerInfoType.roadSignage); - } - } - }).start(); - } - - @RequestMapping(value = "/vsl-tim", method = RequestMethod.GET, headers = "Accept=application/json") - public Collection getVslTims() { - - // get active TIMs - List activeTims = wydotTimService.selectTimsByType(type); - - // add ITIS codes to TIMs - for (ActiveTim activeTim : activeTims) { - activeTimService.addItisCodesToActiveTim(activeTim); - } - - return activeTims; - } - -} +package com.trihydro.odewrapper.controller; + +import com.trihydro.library.exceptionhandlers.IdenticalPointsExceptionHandler; +import com.trihydro.library.helpers.MilepostReduction; +import com.trihydro.library.helpers.TimGenerationHelper; +import com.trihydro.library.helpers.Utility; +import com.trihydro.library.model.ActiveTim; +import com.trihydro.library.model.WydotTim; +import com.trihydro.library.service.*; +import com.trihydro.odewrapper.config.BasicConfiguration; +import com.trihydro.odewrapper.factory.BufferTimFactory; +import com.trihydro.odewrapper.helpers.SetItisCodes; +import com.trihydro.odewrapper.model.ControllerResult; +import com.trihydro.odewrapper.model.TimVslList; +import com.trihydro.odewrapper.model.WydotTimVsl; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import us.dot.its.jpo.ode.plugin.j2735.timstorage.FrameType.TravelerInfoType; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +@CrossOrigin +@RestController +@Api(description = "Variable Speed Limits") +public class WydotTimVslController extends WydotTimBaseController implements BufferTimFactory { + + private final String type = "VSL"; + List timsToSend = new ArrayList<>(); + + @Autowired + public WydotTimVslController(BasicConfiguration _basicConfiguration, WydotTimService _wydotTimService, + TimTypeService _timTypeService, SetItisCodes _setItisCodes, ActiveTimService _activeTimService, + RestTemplateProvider _restTemplateProvider, MilepostReduction _milepostReduction, Utility _utility, + TimGenerationHelper _timGenerationHelper, MilepostService _milepostService, IdenticalPointsExceptionHandler identicalPointsExceptionHandler) { + super(_basicConfiguration, _wydotTimService, _timTypeService, _setItisCodes, _activeTimService, + _restTemplateProvider, _milepostReduction, _utility, _timGenerationHelper, _milepostService, identicalPointsExceptionHandler); + } + + @RequestMapping(value = "/vsl-tim", method = RequestMethod.POST, headers = "Accept=application/json") + public ResponseEntity createUpdateVslTim(@RequestBody TimVslList timVslList) { + + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + Date date = new Date(); + + utility.logWithDate(dateFormat.format(date) + " - Create/Update VSL TIM", this.getClass()); + String post = gson.toJson(timVslList); + utility.logWithDate(post, this.getClass()); + + List resultList = new ArrayList<>(); + ControllerResult resultTim; + + // build TIM + for (WydotTimVsl wydotTim : timVslList.getTimVslList()) { + resultTim = validateInputVsl(wydotTim); + + if (!resultTim.getResultMessages().isEmpty()) { + resultList.add(resultTim); + continue; + } + + if (wydotTim.getDirection().equalsIgnoreCase("i")) { + timsToSend.addAll(makeIncreasingTims(wydotTim, bufferTimITISCodes, milepostService)); + } + else { + timsToSend.addAll(makeDecreasingTims(wydotTim, bufferTimITISCodes, milepostService)); + } + + resultTim.getResultMessages().add("success"); + resultList.add(resultTim); + } + + processRequestAsync(timsToSend); + String responseMessage = gson.toJson(resultList); + return ResponseEntity.status(HttpStatus.OK).body(responseMessage); + } + + public void processRequestAsync(List wydotTims) { + // An Async task always executes in new thread + new Thread(() -> { + var startTime = getStartTime(); + for (WydotTim tim : wydotTims) { + processRequest(tim, getTimType(type), startTime, null, null, + TravelerInfoType.roadSignage); + } + }).start(); + } + + @RequestMapping(value = "/vsl-tim/{vslTimId}", method = RequestMethod.DELETE, headers = "Accept=application/json") + public ResponseEntity deleteVslTim(@PathVariable String vslTimId) { + + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + Date date = new Date(); + + utility.logWithDate(dateFormat.format(date) + " - Delete VSL TIM", this.getClass()); + + // expire and clear TIM + wydotTimService.clearTimsById("VSL", vslTimId, null, true); + + String responseMessage = "success"; + return ResponseEntity.status(HttpStatus.OK).body(responseMessage); + } + + @RequestMapping(value = "/vsl-tim", method = RequestMethod.GET, headers = "Accept=application/json") + public Collection getVslTims() { + + // get active TIMs + List activeTims = wydotTimService.selectTimsByType(type); + + // add ITIS codes to TIMs + for (ActiveTim activeTim : activeTims) { + activeTimService.addItisCodesToActiveTim(activeTim); + } + + return activeTims; + } + +} diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/factory/BufferTimFactory.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/factory/BufferTimFactory.java new file mode 100644 index 000000000..e974dd04e --- /dev/null +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/factory/BufferTimFactory.java @@ -0,0 +1,79 @@ +package com.trihydro.odewrapper.factory; + +import com.trihydro.library.model.Coordinate; +import com.trihydro.library.model.Milepost; +import com.trihydro.library.model.WydotTim; +import com.trihydro.library.service.MilepostService; +import com.trihydro.odewrapper.helpers.SetItisCodes; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public interface BufferTimFactory { + default List makeIncreasingTims(WydotTim wydotTim, List bufferTimITISCodes, MilepostService milepostService) { + return makeOneWayTims("I", wydotTim, bufferTimITISCodes, milepostService); + } + + default List milepostToGeometry(List mileposts) { + var timGeometry = new ArrayList(); + for (Milepost milepost : mileposts) { + timGeometry.add(new Coordinate(milepost.getLatitude(), milepost.getLongitude())); + } + return timGeometry; + } + + default List makeDecreasingTims(WydotTim wydotTim, List bufferTimITISCodes, MilepostService milepostService) { + return makeOneWayTims("d", wydotTim, bufferTimITISCodes, milepostService); + } + + private List makeOneWayTims(String direction, WydotTim wydotTim, List bufferTimITISCodes, MilepostService milepostService) { + var timOneWay = wydotTim.copy(); + timOneWay.setDirection(direction); + + var timsFromItisCodes = buildTimsFromItisCodes(timOneWay, bufferTimITISCodes, false); + var timsToSend = new ArrayList<>(timsFromItisCodes); + + var bufferTims = makeBufferTims(wydotTim, bufferTimITISCodes, milepostService); + timsToSend.addAll(bufferTims); + return timsToSend; + } + + default List makeBufferTims(WydotTim wydotTim, List bufferTimITISCodes, MilepostService milepostService) { + if(wydotTim.getRoute() != null) { + // If the route of the TIM is supported, create buffer based on mileposts associated with that route + List bufferMps = milepostService.getBufferForPath(wydotTim.getRoute().replace('-', '_'), 1.0, wydotTim.toMileposts()); + wydotTim.setGeometry(milepostToGeometry(bufferMps)); + wydotTim.setClientId(wydotTim.getClientId() + "%BUFF"); + } + + return buildTimsFromItisCodes(wydotTim, bufferTimITISCodes,true); + } + + default List buildTimsFromItisCodes(WydotTim tim, List bufferTimITISCodes, boolean isBuffer) { + var timsToSend = new ArrayList(); + for (String itisCodeEntry : tim.getItisCodes()) { + // CTW Update requires that individual TIMs are created for each ITIS ordering + List itisCodes = Arrays.asList(itisCodeEntry.split(" ")); + + // only generate appropriate TIMs for geometry list (buffer, workZone) + String lastItisCode = itisCodes.get(itisCodes.size() - 1); + boolean isBufferTim = bufferTimITISCodes.contains(Integer.valueOf(lastItisCode)); + if (isBuffer && !isBufferTim) { + continue; + } else if (!isBuffer && isBufferTim) { + continue; + } + + WydotTim timToSend = tim.copy(); + timToSend.setItisCodes(itisCodes); + var itisCodeAbb = SetItisCodes.getItisCodeAbbreviation(itisCodeEntry); + String clientIdWithItis = tim.getClientId() + '-' + tim.getDirection() + '-' + itisCodeAbb; + timToSend.setClientId(clientIdWithItis); + timsToSend.add(timToSend); + } + + return timsToSend; + } + +} diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/helpers/SetItisCodes.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/helpers/SetItisCodes.java index 062daa1a3..2b8723db8 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/helpers/SetItisCodes.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/helpers/SetItisCodes.java @@ -1,7 +1,9 @@ package com.trihydro.odewrapper.helpers; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Optional; import com.trihydro.library.model.CustomItisEnum; import com.trihydro.library.model.IncidentChoice; @@ -10,7 +12,6 @@ import com.trihydro.library.service.IncidentChoicesService; import com.trihydro.library.service.ItisCodeService; import com.trihydro.odewrapper.model.WydotTimBowr; -import com.trihydro.odewrapper.model.WydotTimIncident; import com.trihydro.odewrapper.model.WydotTimParking; import com.trihydro.odewrapper.model.WydotTimRc; import com.trihydro.odewrapper.model.WydotTimVsl; @@ -22,344 +23,274 @@ @Component @Slf4j public class SetItisCodes { - private final IncidentChoicesService incidentChoicesService; - private final ItisCodeService itisCodeService; - - private List incidentProblems; - private List incidentEffects; - private List incidentActions; - - private List itisCodes; - - @Autowired - public SetItisCodes(ItisCodeService _itisCodeService, IncidentChoicesService _incidentChoicesService) { - itisCodeService = _itisCodeService; - incidentChoicesService = _incidentChoicesService; - } - - public List getItisCodes() { - if (itisCodes != null) { - return itisCodes; - } else { - itisCodes = itisCodeService.selectAll(); - return itisCodes; - } - } + private final IncidentChoicesService incidentChoicesService; + private final ItisCodeService itisCodeService; + + private List incidentProblems; + private List incidentEffects; + private List incidentActions; - public List setItisCodesFromAdvisoryArray(WydotTimRc wydotTim) { + private List itisCodes; - // check to see if code exists + private final String ADVISORY_ITIS_CODE = "7712"; + private final String REDUCED_ITIS_CODE = "12302"; + private final String AHEAD_ITIS_CODE = "13569"; - List items = new ArrayList<>(); - for (Integer item : wydotTim.getAdvisory()) { + private static final int SMALL_ITIS_CODE_MIN = 12544; - getItisCodes().stream().filter(x -> x.getItisCode().equals(item)).findFirst().ifPresent(code -> items.add(item.toString())); + @Autowired + public SetItisCodes(ItisCodeService _itisCodeService, IncidentChoicesService _incidentChoicesService) { + itisCodeService = _itisCodeService; + incidentChoicesService = _incidentChoicesService; + } + public List getAllItisCodesFromDatabase() { + if (itisCodes != null) { + return itisCodes; + } else { + itisCodes = itisCodeService.selectAll(); + return itisCodes; + } } - return items; - } - public List setItisCodesRc(WydotTimRc wydotTim) { + public List setItisCodesFromAdvisoryArray(WydotTimRc wydotTim) { + + // check to see if code exists + List items = new ArrayList<>(); + for (Integer item : wydotTim.getAdvisory()) { - List items = new ArrayList<>(); + getAllItisCodesFromDatabase().stream().filter(x -> x.getItisCode().equals(item)).findFirst().ifPresent(code -> items.add(item.toString())); - if (wydotTim.getAdvisory() == null) { - return items; + } + return items; } - ItisCode code; - - for (Integer item : wydotTim.getAdvisory()) { - - var alphaItis = getCustomAlphabetic(item); - if (alphaItis != null) { - items.add(alphaItis); - continue; - } - // map "closed" itis code - if (item == 769) { - code = getItisCodes().stream().filter(x -> x.getItisCode().equals(770)).findFirst().orElse(null); - } else { - code = getItisCodes().stream().filter(x -> x.getItisCode().equals(item)).findFirst().orElse(null); - } - - if (code != null) { - items.add(code.getItisCode().toString()); - } + public String getCustomAlphabetic(Integer itisCode) { + String text = null; + var en = CustomItisEnum.valueOf(itisCode); + if (en != null) { + text = en.getStringValue(); + } + return text; } - return items; - } + public List setItisCodesParking(WydotTimParking wydotTim) { - public String getCustomAlphabetic(Integer itisCode) { - String text = null; - var en = CustomItisEnum.valueOf(itisCode); - if (en != null) { - text = en.getStringValue(); - } - return text; - } + // check to see if code exists + List items = new ArrayList<>(); - public List setItisCodesVsl(WydotTimVsl wydotTim) { + ItisCode code = getAllItisCodesFromDatabase().stream().filter(x -> x.getItisCode().equals(wydotTim.getAvailability())).findFirst().orElse(null); - List items = new ArrayList<>(); + log.info("Availablity : {}", wydotTim.getAvailability()); + log.info("Exit : {}", wydotTim.getExit()); - // speed limit itis code - getItisCodes().stream().filter(x -> x.getDescription().equals("speed limit")).findFirst() - .ifPresent(speedLimit -> items.add(speedLimit.getItisCode().toString())); + if (code != null) { + items.add(wydotTim.getAvailability().toString()); + } - // number e.g 50, convert to ITIS code - int speed = wydotTim.getSpeed() + 12544; - items.add(Integer.toString(speed)); + // for parking TIM, content=exitService, and includes additional itis codes + // depending on if rest area or exit number + if (wydotTim.getExit() != null) { + // if exit, the exit number should be a text value. + // This has some strange implications as seen here + // https://github.com/usdot-jpo-ode/jpo-ode/blob/540b79f1697f4d6464e8c4b8491666ec9cf08d8d/jpo-ode-plugins/src/main/java/us/dot/its/jpo/ode/plugin/j2735/builders/TravelerMessageFromHumanToAsnConverter.java#L337 + // the ODE translates a text value only if we start with a single quote to + // denote this. No ending quote is used + items.add("11794");// Exit Number + if (wydotTim.getExit().equalsIgnoreCase("turnout") || wydotTim.getExit().equalsIgnoreCase("parking")) { + items.add("'" + (int) Math.round(wydotTim.getMileMarker())); + } else { + items.add("'" + wydotTim.getExit()); + } + } else { + items.add("7986");// Rest Area + log.info("rest area"); + } - // mph itis code - getItisCodes().stream().filter(x -> x.getDescription().equals("mph")).findFirst().ifPresent(mph -> items.add(mph.getItisCode().toString())); + return items; + } - return items; - } + public List getIncidentProblems() { + if (incidentProblems != null) { + return incidentProblems; + } else { + incidentProblems = incidentChoicesService.selectAllIncidentProblems(); + return incidentProblems; + } + } - public List setItisCodesParking(WydotTimParking wydotTim) { + public List getIncidentEffects() { + if (incidentEffects != null) { + return incidentEffects; + } else { + incidentEffects = incidentChoicesService.selectAllIncidentEffects(); + return incidentEffects; + } + } - // check to see if code exists - List items = new ArrayList<>(); + public List getIncidentActions() { + if (incidentActions != null) { + return incidentActions; + } else { + incidentActions = incidentChoicesService.selectAllIncidentActions(); + return incidentActions; + } + } - ItisCode code = getItisCodes().stream().filter(x -> x.getItisCode().equals(wydotTim.getAvailability())).findFirst().orElse(null); + public List setItisCodes(WydotTim wydotTim) { - log.info("Availablity : {}", wydotTim.getAvailability()); - log.info("Exit : {}", wydotTim.getExit()); + List items = new ArrayList<>(); - if (code != null) { - items.add(wydotTim.getAvailability().toString()); - } + if (wydotTim.getItisCodes() == null) { + return items; + } - // for parking TIM, content=exitService, and includes additional itis codes - // depending on if rest area or exit number - if (wydotTim.getExit() != null) { - // if exit, the exit number should be a text value. - // This has some strange implications as seen here - // https://github.com/usdot-jpo-ode/jpo-ode/blob/540b79f1697f4d6464e8c4b8491666ec9cf08d8d/jpo-ode-plugins/src/main/java/us/dot/its/jpo/ode/plugin/j2735/builders/TravelerMessageFromHumanToAsnConverter.java#L337 - // the ODE translates a text value only if we start with a single quote to - // denote this. No ending quote is used - items.add("11794");// Exit Number - if (wydotTim.getExit().equalsIgnoreCase("turnout") || wydotTim.getExit().equalsIgnoreCase("parking")) { - items.add("'" + (int) Math.round(wydotTim.getMileMarker())); - } else { - items.add("'" + wydotTim.getExit()); - } - } else { - items.add("7986");// Rest Area - log.info("rest area"); - } + ItisCode code; - return items; - } + for (String item : wydotTim.getItisCodes()) { - public List setItisCodesIncident(WydotTimIncident wydotTim) { - List items = new ArrayList<>(); + if (item.contains(" ")) { + // if the item contains a space it is a sequence of ITIS codes + items.add(item); + continue; + } + Integer itisCode = Integer.valueOf(item); - // action - IncidentChoice incidentAction = getIncidentActions().stream().filter(x -> x.getCode().equals(wydotTim.getAction())).findFirst().orElse(null); + var alphaItis = getCustomAlphabetic(itisCode); + if (alphaItis != null) { + items.add(alphaItis); + continue; + } - // if action is not null and action itis code exists - if (incidentAction != null && incidentAction.getItisCodeId() != null) { - getItisCodes().stream().filter(x -> x.getItisCodeId().equals(incidentAction.getItisCodeId())).findFirst() - .ifPresent(actionItisCode -> items.add(actionItisCode.getItisCode().toString())); - } + code = getAllItisCodesFromDatabase().stream().filter(x -> x.getItisCode().equals(itisCode)).findFirst().orElse(null); - // effect - IncidentChoice incidentEffect = getIncidentEffects().stream().filter(x -> x.getCode().equals(wydotTim.getEffect())).findFirst().orElse(null); + if (code != null) + items.add(code.getItisCode().toString()); + } - // if effect is not null and effect itis code exists - if (incidentEffect != null && incidentEffect.getItisCodeId() != null) { - getItisCodes().stream().filter(x -> x.getItisCodeId().equals(incidentEffect.getItisCodeId())).findFirst() - .ifPresent(effectItisCode -> items.add(effectItisCode.getItisCode().toString())); + return items; } - if (wydotTim.getProblem() != null && !wydotTim.getProblem().equals("other")) { - // Retrieve the matching incident problem based on the provided code - IncidentChoice incidentProblem = - getIncidentProblems().stream().filter(problem -> problem.getCode().equals(wydotTim.getProblem())).findFirst().orElse(null); - - // Add the ITIS code if the incident problem exists and has a valid ITIS code ID - if (incidentProblem != null) { - Integer itisCodeId = incidentProblem.getItisCodeId(); - if (itisCodeId != null) { - getItisCodes().stream().filter(code -> code.getItisCodeId().equals(itisCodeId)).findFirst() - .ifPresent(problemItisCode -> items.add(problemItisCode.getItisCode().toString())); + /** + * Creates a properly ordered list of ITIS codes based on the TIM. + * + * @param wydotTim TIM to base the ITIS codes on + * @return Properly ordered list of ITIS codes to assign back to the TIM + */ + public List setItisCodesVsl(WydotTimVsl wydotTim) { + + List items = new ArrayList(); + if (wydotTim.getSpeed() == null) { + throw new IllegalArgumentException("Cannot determine Speed limit. Speed cannot be null."); } - } - } else { - items.addAll(handleOtherIncidentProblem(wydotTim)); - } - // If no incident problem is provided, default to "Incident" (ITIS code 531) - if (items.isEmpty()) { - items.add("531"); // 531 is "Incident" - } + List allItisCodes = getAllItisCodesFromDatabase(); - return items; - } + // add advisory code first if advisory speed limit + wydotTim.getItisCodes().stream().filter(x -> x.contains(ADVISORY_ITIS_CODE)).findFirst() + .ifPresent(items::add); - private List handleOtherIncidentProblem(WydotTimIncident wydotTim) { - List items = new ArrayList<>(); - if (wydotTim.getProblemOtherText() == null) { - log.warn("problemOtherText is null for 'other' incident problem"); - return items; - } - String problemOtherText = wydotTim.getProblemOtherText(); + // speed limit itis code + allItisCodes.stream().filter(x -> x.getDescription().equals("speed limit")).findFirst().ifPresent(mph -> items.add(mph.getItisCode().toString())); - if (!problemOtherText.contains("GVW")) { - log.error("Unsupported problemOtherText: {}", problemOtherText); - return items; - } + // add reduced code next if reduced speed + wydotTim.getItisCodes().stream().filter(x -> x.contains(REDUCED_ITIS_CODE)).findFirst() + .ifPresent(items::add); - // Extract the weight limit from the problemOtherText - String weightLimitInPounds = getWeightLimitFromProblemOtherText(problemOtherText); - if (weightLimitInPounds == null) { - log.warn("Weight limit not found in problemOtherText: {}", problemOtherText); - return items; - } + // J2540 small number ITIS codes start at 12,544 and increment by 1 to represent each number up to 255. + // To covert speed to an ITIS code, adding 12,544 is enough. + items.add(Integer.toString(wydotTim.getSpeed() + SMALL_ITIS_CODE_MIN)); - String weightLimitInItisCode = null; - try { - // Convert weight limit to ITIS code - weightLimitInItisCode = translateWeightToItisCode(Integer.parseInt(weightLimitInPounds)); - } catch (WeightNotSupportedException e) { - log.warn("Weight limit not supported: {}", weightLimitInPounds); - return items; - } + // mph itis code + allItisCodes.stream().filter(x -> x.getDescription().equals("mph")).findFirst().ifPresent(mph -> items.add(mph.getItisCode().toString())); - items.add("2563"); // Truck restriction - items.add("2577"); // Gross-Weight-Limit - items.add(weightLimitInItisCode); // Weight limit in ITIS code - items.add("8739"); // Pounds - - return items; - } - - /** - * Given a problemOtherText string of the format "Weight limit of 60,000 GVW is in effect", - * return the weight limit (60000) in pounds as a string. - */ - private String getWeightLimitFromProblemOtherText(String problemOtherText) { - problemOtherText = problemOtherText.replaceAll(",", ""); - String[] parts = problemOtherText.split(" "); - for (String part : parts) { - if (part.matches("\\d{1,5}")) { // Match a number with 1 to 5 digits - return part; - } - } - return null; // Return null if no weight limit found - } - - public List getIncidentProblems() { - if (incidentProblems != null) { - return incidentProblems; - } else { - incidentProblems = incidentChoicesService.selectAllIncidentProblems(); - return incidentProblems; - } - } - - public List getIncidentEffects() { - if (incidentEffects != null) { - return incidentEffects; - } else { - incidentEffects = incidentChoicesService.selectAllIncidentEffects(); - return incidentEffects; + // add ahead code next if tim includes ahead code last + wydotTim.getItisCodes().stream().filter(x -> x.contains(AHEAD_ITIS_CODE)).findFirst() + .ifPresent(items::add); + + return items; } - } - - public List getIncidentActions() { - if (incidentActions != null) { - return incidentActions; - } else { - incidentActions = incidentChoicesService.selectAllIncidentActions(); - return incidentActions; + + public List setItisCodesBowr(WydotTimBowr tim) throws WeightNotSupportedException { + List itisCodes = new ArrayList<>(); + + int weightInPounds = tim.getData(); + + itisCodes.add("5127"); // Strong winds + itisCodes.add("2563"); // Truck restriction + itisCodes.add("2569"); // No high profile vehicles + itisCodes.add("7682"); // Below + itisCodes.add("2577"); // Gross-Weight-Limit + itisCodes.add(translateWeightToItisCode(weightInPounds)); // Weight, translated from pounds to ITIS code + itisCodes.add("8739"); // Pounds + + return itisCodes; } - } - - public List setItisCodesRw(WydotTim wydotTim) { - - List items = new ArrayList(); - - items.add("1025"); - - return items; - } - - public List setItisCodesBowr(WydotTimBowr tim) throws WeightNotSupportedException { - List itisCodes = new ArrayList<>(); - - int weightInPounds = tim.getData(); - - itisCodes.add("5127"); // Strong winds - itisCodes.add("2563"); // Truck restriction - itisCodes.add("2569"); // No high profile vehicles - itisCodes.add("7682"); // Below - itisCodes.add("2577"); // Gross-Weight-Limit - itisCodes.add(translateWeightToItisCode(weightInPounds)); // Weight, translated from pounds to ITIS code - itisCodes.add("8739"); // Pounds - - return itisCodes; - } - - /** - * This method translates the weight in pounds to its corresponding ITIS code. - * These are large number ITIS codes and do not abide by the standard translations used for other numbers such as mph. - * Supported weights are 20000 to 30000 in increments of 1000 and 30000 to 70000 in increments of 5000 - * - * @throws WeightNotSupportedException if the weight is not supported - */ - private String translateWeightToItisCode(int weightInPounds) throws WeightNotSupportedException { - switch (weightInPounds) { - case 20000: - return "11589"; - case 21000: - return "11590"; - case 22000: - return "11591"; - case 23000: - return "11592"; - case 24000: - return "11593"; - case 25000: - return "11594"; - case 26000: - return "11595"; - case 27000: - return "11596"; - case 28000: - return "11597"; - case 29000: - return "11598"; - case 30000: - return "11599"; - case 35000: - return "11600"; - case 40000: - return "11601"; - case 45000: - return "11602"; - case 50000: - return "11603"; - case 55000: - return "11604"; - case 60000: - return "11605"; - case 65000: - return "11606"; - case 70000: - return "11607"; - default: - throw new WeightNotSupportedException("Weight " + weightInPounds + " is not supported"); + + public static String getItisCodeAbbreviation(String itisCodes) { + List words = Arrays.asList(itisCodes.split(" ")); + if (words.size() < 3) { + return itisCodes.replace(" ", "-"); + } + + return words.stream().map(word -> word.substring(0, 1)).reduce("", String::concat); } - } - public static class WeightNotSupportedException extends Exception { - public WeightNotSupportedException(String message) { - super(message); + /** + * This method translates the weight in pounds to its corresponding ITIS code. + * These are large number ITIS codes and do not abide by the standard translations used for other numbers such as mph. + * Supported weights are 20000 to 30000 in increments of 1000 and 30000 to 70000 in increments of 5000 + * @throws WeightNotSupportedException + */ + private String translateWeightToItisCode(int weightInPounds) throws WeightNotSupportedException { + switch(weightInPounds) { + case 20000: + return "11589"; + case 21000: + return "11590"; + case 22000: + return "11591"; + case 23000: + return "11592"; + case 24000: + return "11593"; + case 25000: + return "11594"; + case 26000: + return "11595"; + case 27000: + return "11596"; + case 28000: + return "11597"; + case 29000: + return "11598"; + case 30000: + return "11599"; + case 35000: + return "11600"; + case 40000: + return "11601"; + case 45000: + return "11602"; + case 50000: + return "11603"; + case 55000: + return "11604"; + case 60000: + return "11605"; + case 65000: + return "11606"; + case 70000: + return "11607"; + default: + throw new WeightNotSupportedException("Weight " + weightInPounds + " is not supported"); + } + } + + public class WeightNotSupportedException extends Exception { + public WeightNotSupportedException(String message) { + super(message); + } } - } } \ No newline at end of file diff --git a/ode-wrapper/src/main/java/com/trihydro/odewrapper/model/WydotTimVsl.java b/ode-wrapper/src/main/java/com/trihydro/odewrapper/model/WydotTimVsl.java index 76af8a4fa..525b98d37 100644 --- a/ode-wrapper/src/main/java/com/trihydro/odewrapper/model/WydotTimVsl.java +++ b/ode-wrapper/src/main/java/com/trihydro/odewrapper/model/WydotTimVsl.java @@ -1,9 +1,11 @@ package com.trihydro.odewrapper.model; import com.trihydro.library.model.WydotTim; +import io.swagger.annotations.ApiModelProperty; public class WydotTimVsl extends WydotTim { + @ApiModelProperty(required = true) private Integer speed; private String deviceId; diff --git a/ode-wrapper/src/main/resources/application-dev.properties b/ode-wrapper/src/main/resources/application-dev.properties index efb8a6b36..ac3f25848 100644 --- a/ode-wrapper/src/main/resources/application-dev.properties +++ b/ode-wrapper/src/main/resources/application-dev.properties @@ -13,6 +13,7 @@ config.sdwApiKey= config.alertAddresses=user@example.com,user2@example.com config.fromEmail=support@example.com config.environmentName=DEV +config.dotGnisId=${WRAPPER_CONFIG_DOT_GNIS_ID:000000} config.mailHost=localhost config.mailPort=25 config.defaultLaneWidth=50 diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/CopyConstructorTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/CopyConstructorTest.java index d85bb1731..ab0386c36 100644 --- a/ode-wrapper/src/test/java/com/trihydro/odewrapper/CopyConstructorTest.java +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/CopyConstructorTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertFalse; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Arrays; import com.google.gson.Gson; @@ -50,6 +51,8 @@ private void setBaseClassProps(WydotTim o) { o.setRoute("firstRoute"); o.setItisCodes(Arrays.asList("1", "2")); o.setClientId("firstClientId"); + o.setGeometry(new ArrayList()); + o.setBearing(0); } @Test diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimIncidentControllerTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimIncidentControllerTest.java index 26c4d07eb..5742d76e0 100644 --- a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimIncidentControllerTest.java +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimIncidentControllerTest.java @@ -2,8 +2,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.Collection; @@ -13,6 +12,7 @@ import com.trihydro.library.helpers.Utility; import com.trihydro.library.model.ActiveTim; import com.trihydro.library.model.ItisCode; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; import com.trihydro.odewrapper.config.BasicConfiguration; @@ -45,6 +45,8 @@ public class WydotTimIncidentControllerTest { SetItisCodes setItisCodes; @Mock Utility utility; + @Mock + MilepostService milepostService; @InjectMocks @Spy @@ -54,6 +56,8 @@ public class WydotTimIncidentControllerTest { @BeforeEach public void setup() throws Exception { + milepostService = mock(MilepostService.class); + List itisCodes = new ArrayList<>(); ItisCode ic = new ItisCode(); ic.setCategoryId(-1); @@ -63,8 +67,8 @@ public void setup() throws Exception { itisCodes.add(ic); List itisCodesIncident = new ArrayList<>(); itisCodesIncident.add("531"); - lenient().doReturn(itisCodesIncident).when(setItisCodes).setItisCodesIncident(any()); - lenient().doReturn(itisCodes).when(setItisCodes).getItisCodes(); + lenient().doReturn(itisCodesIncident).when(setItisCodes).setItisCodes(any()); + lenient().doReturn(itisCodes).when(setItisCodes).getAllItisCodesFromDatabase(); lenient().doNothing().when(uut).makeTimsAsync(any()); lenient().doReturn(true).when(uut).routeSupported(isA(String.class)); @@ -92,7 +96,7 @@ public void testCreateIncidentTim_bothDirections_success() throws Exception { } @Test - public void testCreateIncidentTim_bothDirections_NoMileposts() throws Exception { + public void testCreateIncidentTim_bothDirections_RouteNotSupported() throws Exception { // Arrange String incidentJson = "{\"timIncidentList\": [{ \"startPoint\": {\"latitude\": 41.161446, \"longitude\": -104.653162},\"endPoint\": {\"latitude\": 41.170465, \"longitude\": -104.085578}, \"impact\":\"L\", \"problem\": \"fire\", \"effect\": \"test\",\"action\": \"test\", \"pk\": 3622, \"highway\": \"I-25\", \"incidentId\":\"IN49251\", \"direction\": \"b\", \"ts\": \"2018-04-16T19:30:05.000Z\"}]}"; @@ -133,6 +137,7 @@ public void testCreateIncidentTim_bothDirections_NoItisCodes() throws Exception @Test public void testCreateIncidentTim_oneDirection_success() throws Exception { + //Arrange String incidentJson = "{\"timIncidentList\": [{ \"startPoint\": {\"latitude\": 41.161446, \"longitude\": -104.653162},\"endPoint\": {\"latitude\": 41.170465, \"longitude\": -104.085578}, \"impact\":\"L\", \"problem\": \"fire\", \"effect\": \"test\",\"action\": \"test\", \"pk\": 3622, \"highway\": \"I-80\", \"incidentId\":\"OD49251\", \"direction\": \"i\", \"ts\":\"2018-04-16T19:30:05.000Z\" }]}"; TimIncidentList til = gson.fromJson(incidentJson, TimIncidentList.class); @@ -150,8 +155,9 @@ public void testCreateIncidentTim_oneDirection_success() throws Exception { } @Test - public void testCreateIncidentTim_oneDirection_NoMileposts() throws Exception { + public void testCreateIncidentTim_oneDirection_RouteNotSupported() throws Exception { + // Arrange String incidentJson = "{\"timIncidentList\": [{ \"startPoint\": {\"latitude\": 41.161446, \"longitude\": -104.653162},\"endPoint\": {\"latitude\": 41.170465, \"longitude\": -104.085578}, \"impact\":\"L\", \"problem\": \"fire\", \"effect\": \"test\",\"action\": \"test\", \"pk\": 3622, \"highway\": \"I-25\", \"incidentId\":\"IN49251\", \"direction\": \"i\", \"ts\":\"2018-04-16T19:30:05.000Z\" }]}"; TimIncidentList til = gson.fromJson(incidentJson, TimIncidentList.class); doReturn(false).when(uut).routeSupported("I-25"); @@ -171,6 +177,7 @@ public void testCreateIncidentTim_oneDirection_NoMileposts() throws Exception { @Test public void testCreateIncidentTim_oneDirection_NoItisCodes() throws Exception { + // Arrange String incidentJson = "{\"timIncidentList\": [{ \"startPoint\": {\"latitude\": 41.161446, \"longitude\": -104.653162},\"endPoint\": {\"latitude\": 41.170465, \"longitude\": -104.085578}, \"impact\":\"L\", \"problem\": \"test\", \"effect\": \"test\",\"action\": \"test\", \"pk\": 3622, \"highway\": \"I-80\", \"incidentId\":\"IN49251\", \"direction\": \"i\", \"ts\":\"2018-04-16T19:30:05.000Z\" }]}"; TimIncidentList til = gson.fromJson(incidentJson, TimIncidentList.class); diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimParkingControllerTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimParkingControllerTest.java index 80b7930b9..c00a1a487 100644 --- a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimParkingControllerTest.java +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimParkingControllerTest.java @@ -69,7 +69,7 @@ public void setup() throws Exception { List itisCodesIncident = new ArrayList<>(); itisCodesIncident.add("531"); lenient().doReturn(itisCodesIncident).when(setItisCodes).setItisCodesParking(any()); - lenient().doReturn(itisCodes).when(setItisCodes).getItisCodes(); + lenient().doReturn(itisCodes).when(setItisCodes).getAllItisCodesFromDatabase(); lenient().doNothing().when(uut).processRequestAsync(any()); lenient().doReturn(true).when(uut).routeSupported(isA(String.class)); diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRcControllerTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRcControllerTest.java index bd914b6e0..485711a9f 100644 --- a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRcControllerTest.java +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRcControllerTest.java @@ -4,7 +4,6 @@ import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -73,8 +72,8 @@ public void setup() throws Exception { itisCodes.add(ic); List itisCodesIncident = new ArrayList<>(); itisCodesIncident.add("531"); - lenient().doReturn(itisCodesIncident).when(setItisCodes).setItisCodesRc(any()); - lenient().doReturn(itisCodes).when(setItisCodes).getItisCodes(); + lenient().doReturn(itisCodesIncident).when(setItisCodes).setItisCodes(any()); + lenient().doReturn(itisCodes).when(setItisCodes).getAllItisCodesFromDatabase(); lenient().doReturn(true).when(uut).routeSupported(isA(String.class)); } @@ -148,7 +147,7 @@ public void testCreateRcTim_bothDirections_NoItisCodes() throws Exception { // Arrange String rcJson = "{\"timRcList\": [{ \"route\": \"I80\", \"startPoint\": {\"latitude\": 41.161446, \"longitude\": -104.653162},\"endPoint\": {\"latitude\": 41.170465, \"longitude\": -104.085578},\"roadCode\": \"LARI80WQDHLD\", \"direction\":\"b\",\"advisory\": [11]} ]}"; TimRcList timRcList = gson.fromJson(rcJson, TimRcList.class); - lenient().doReturn(new ArrayList<>()).when(setItisCodes).setItisCodesRc(any()); + lenient().doReturn(new ArrayList<>()).when(setItisCodes).setItisCodes(any()); // Act ResponseEntity data = uut.createUpdateRoadConditionsTim(timRcList); diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRwControllerTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRwControllerTest.java index 7c933ca79..809504631 100644 --- a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRwControllerTest.java +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimRwControllerTest.java @@ -2,9 +2,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.Collection; @@ -16,6 +14,7 @@ import com.trihydro.library.model.ActiveTim; import com.trihydro.library.model.ItisCode; import com.trihydro.library.model.TimRwList; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; import com.trihydro.odewrapper.config.BasicConfiguration; @@ -49,6 +48,8 @@ public class WydotTimRwControllerTest { SetItisCodes setItisCodes; @Mock Utility utility; + @Mock + private MilepostService milepostService; @InjectMocks @Spy @@ -58,6 +59,8 @@ public class WydotTimRwControllerTest { @BeforeEach public void setup() throws Exception { + milepostService = mock(MilepostService.class); + List itisCodes = new ArrayList<>(); ItisCode ic = new ItisCode(); ic.setCategoryId(-1); @@ -67,8 +70,8 @@ public void setup() throws Exception { itisCodes.add(ic); List itisCodesIncident = new ArrayList<>(); itisCodesIncident.add("531"); - lenient().doReturn(itisCodesIncident).when(setItisCodes).setItisCodesRw(any()); - lenient().doReturn(itisCodes).when(setItisCodes).getItisCodes(); + lenient().doReturn(itisCodesIncident).when(setItisCodes).setItisCodes(any()); + lenient().doReturn(itisCodes).when(setItisCodes).getAllItisCodesFromDatabase(); lenient().doReturn(true).when(uut).routeSupported(isA(String.class)); @@ -117,7 +120,7 @@ public void testCreateRwTim_bothDirections_NoMileposts() throws Exception { @Test public void testCreateRwTim_bothDirections_NoItisCodes() throws Exception { - + // Arrange String rwJson = "{ \"timRwList\": [ {\"startPoint\": {\"latitude\": 41.161446, \"longitude\": -104.653162},\"endPoint\": {\"latitude\": 41.170465, \"longitude\": -104.085578},\"highway\": \"I-80\",\"pk\": \"15917\",\"id\": \"15917\",\"projectKey\": 19185,\"direction\":\"d\",\"surface\": \"P\",\"schedStart\": \"2018-04-16\"}]}"; TimRwList timRwList = gson.fromJson(rwJson, TimRwList.class); diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimVslControllerTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimVslControllerTest.java index 7f63d35f5..f639e14fd 100644 --- a/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimVslControllerTest.java +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/WydotTimVslControllerTest.java @@ -2,8 +2,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.*; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -14,6 +14,7 @@ import com.trihydro.library.model.ActiveTim; import com.trihydro.library.model.ItisCode; import com.trihydro.library.service.ActiveTimService; +import com.trihydro.library.service.MilepostService; import com.trihydro.library.service.TimTypeService; import com.trihydro.library.service.WydotTimService; import com.trihydro.odewrapper.config.BasicConfiguration; @@ -50,6 +51,8 @@ public class WydotTimVslControllerTest { ActiveTimService mockActiveTimService; @Mock Utility utility; + @Mock + MilepostService milepostService; @InjectMocks @Spy @@ -66,13 +69,15 @@ public void setup() throws Exception { ic.setItisCode(-2); ic.setItisCodeId(-3); itisCodes.add(ic); - List itisCodesIncident = new ArrayList<>(); - itisCodesIncident.add("531"); - lenient().doReturn(itisCodesIncident).when(mockSetItisCodes).setItisCodesVsl(any()); - lenient().doReturn(itisCodes).when(mockSetItisCodes).getItisCodes(); + List itisCodesVsl = new ArrayList<>(); + itisCodesVsl.add("531"); + lenient().doReturn(itisCodesVsl).when(mockSetItisCodes).setItisCodesVsl(any()); + lenient().doReturn(itisCodes).when(mockSetItisCodes).getAllItisCodesFromDatabase(); + + milepostService = mock(MilepostService.class); - lenient().doNothing().when(uut).processRequestAsync(any()); lenient().doReturn(true).when(uut).routeSupported(isA(String.class)); + lenient().doNothing().when(uut).processRequestAsync(any()); } @Test diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/factory/BufferTimFactoryTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/factory/BufferTimFactoryTest.java new file mode 100644 index 000000000..9924f3a68 --- /dev/null +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/factory/BufferTimFactoryTest.java @@ -0,0 +1,213 @@ +package com.trihydro.odewrapper.factory; + +import com.trihydro.library.model.Coordinate; +import com.trihydro.library.model.ItisCode; +import com.trihydro.library.model.Milepost; +import com.trihydro.library.model.WydotTim; +import com.trihydro.library.service.MilepostService; +import com.trihydro.odewrapper.helpers.SetItisCodes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class BufferTimFactoryTest implements BufferTimFactory { + @Mock + private MilepostService milepostService; + @Mock + private SetItisCodes setItisCodes; + private WydotTim wydotTim; + + @BeforeEach + void setUp() { + milepostService = mock(MilepostService.class); + + wydotTim = new WydotTim(); + wydotTim.setStartPoint(new Coordinate()); + wydotTim.setEndPoint(new Coordinate(BigDecimal.valueOf(1), BigDecimal.valueOf(2))); + var wydotTimItisCodes = new ArrayList(); + wydotTimItisCodes.add("1309"); + wydotTim.setItisCodes(wydotTimItisCodes); + wydotTim.setClientId("testclientid"); + wydotTim.setRoute("I-80"); + wydotTim.setDirection("I"); + + List itisCodes = new ArrayList<>(); + ItisCode ic = new ItisCode(); + ic.setCategoryId(-1); + ic.setDescription("description"); + ic.setItisCode(-2); + ic.setItisCodeId(-3); + itisCodes.add(ic); + + lenient().doReturn(wydotTimItisCodes).when(setItisCodes).setItisCodes(any()); + lenient().doReturn(itisCodes).when(setItisCodes).getAllItisCodesFromDatabase(); + } + + private List getMileposts() { + List mileposts = new ArrayList<>(); + + var mp = new Milepost(); + mp = new Milepost(); + mp.setLatitude(BigDecimal.valueOf(200)); + mp.setLongitude(BigDecimal.valueOf(300)); + mileposts.add(mp); + + + mp = new Milepost(); + mp.setLatitude(BigDecimal.valueOf(300)); + mp.setLongitude(BigDecimal.valueOf(300)); + mileposts.add(mp); + + mp = new Milepost(); + mp.setLatitude(BigDecimal.valueOf(400)); + mp.setLongitude(BigDecimal.valueOf(400)); + mileposts.add(mp); + + mp = new Milepost(); + mp.setLatitude(BigDecimal.valueOf(500)); + mp.setLongitude(BigDecimal.valueOf(500)); + mileposts.add(mp); + return mileposts; + } + + @Test + void testMilepostToGeometry() { + // Arrange + List mileposts = getMileposts(); + + // Act + List geometry = milepostToGeometry(mileposts); + + // Assert + assertEquals(4, geometry.size()); + assertEquals(BigDecimal.valueOf(200), geometry.get(0).getLatitude()); + assertEquals(BigDecimal.valueOf(300), geometry.get(0).getLongitude()); + } + + @Test + void testBuildTimsFromItisCodes_withoutBufferCode() { + // Arrange + List bufferCodes = List.of(7364); + + // Act + List tims = buildTimsFromItisCodes(wydotTim, bufferCodes, false); + + // Assert + assertEquals(1, tims.size()); + assertEquals("testclientid-I-1309", tims.get(0).getClientId()); + } + + @Test + void testBuildTimsFromItisCodes_withBufferCode() { + // Arrange + var wydotTimItisCodes = new ArrayList(); + wydotTimItisCodes.add("1309 7364"); + wydotTim.setItisCodes(wydotTimItisCodes); + List bufferCodes = List.of(7364); + + // Act + List tims = buildTimsFromItisCodes(wydotTim, bufferCodes, true); + + // Assert + assertEquals(1, tims.size()); + assertEquals("testclientid-I-1309-7364", tims.get(0).getClientId()); + } + + + @Test + void testBuildTimsFromItisCodes_excludesBufferCodeWhenNotisBufferAndBufferTim() { + // Arrange + var wydotTimItisCodes = new ArrayList(); + wydotTimItisCodes.add("1309 7364"); + wydotTim.setItisCodes(wydotTimItisCodes); + List bufferCodes = List.of(7364); // different from last code 7342 + + // Act + List tims = buildTimsFromItisCodes(wydotTim, bufferCodes, false); + + // Assert + assertTrue(tims.isEmpty()); + } + + @Test + void testBuildTimsFromItisCodes_excludesBufferCodeWhenisBufferAndNotBufferTim() { + // Arrange + List bufferCodes = List.of(7364); // different from last code 7342 + + // Act + List tims = buildTimsFromItisCodes(wydotTim, bufferCodes, true); + + // Assert + assertTrue(tims.isEmpty()); + } + + @Test + void testMakeIncreasingTims_callsMakeOneWayWithI() { + // Arrange + List bufferCodes = List.of(7364); // unrelated + + // Act + List result = makeIncreasingTims(wydotTim, bufferCodes, milepostService); + + // Assert + for (WydotTim tim : result) { + assertEquals("I", tim.getDirection()); + } + } + + @Test + void testMakeDecreasingTims_callsMakeOneWayWithD() { + // Arrange + when(milepostService.getBufferForPath(any(), eq(1.0), any())) + .thenReturn(getMileposts()); + List bufferCodes = List.of(7364); // unrelated + + // Act + List result = makeDecreasingTims(wydotTim, bufferCodes, milepostService); + + // Assert + for (WydotTim tim : result) { + assertEquals("d", tim.getDirection()); + } + } + + @Test + void testMakeBufferTims_createsBufferTimsWithUpdatedClientIdAndGeometry() { + // Arrange + when(milepostService.getBufferForPath(any(), eq(1.0), any())) + .thenReturn(getMileposts()); + // Set a buffer ITIS code that matches the end of an ITIS entry + List bufferCodes = List.of(7364); + wydotTim.setItisCodes(List.of("1309 7364")); // Ends in 7364 -> matches buffer code + + // Act + List result = makeBufferTims(wydotTim, bufferCodes, milepostService); + + // Assert + assertEquals(1, result.size()); + WydotTim tim = result.get(0); + + // Assert that clientId has been updated with "%BUFF" + assertTrue(tim.getClientId().contains("%BUFF")); + + // Assert geometry was set correctly + assertNotNull(wydotTim.getGeometry()); + assertEquals(4, wydotTim.getGeometry().size()); + assertEquals(BigDecimal.valueOf(200), wydotTim.getGeometry().get(0).getLatitude()); + assertEquals(BigDecimal.valueOf(300), wydotTim.getGeometry().get(0).getLongitude()); + + // Assert direction and ITIS code structure + assertEquals("I", tim.getDirection()); + assertEquals(List.of("1309", "7364"), tim.getItisCodes()); + } +} diff --git a/ode-wrapper/src/test/java/com/trihydro/odewrapper/helpers/SetItisCodesTest.java b/ode-wrapper/src/test/java/com/trihydro/odewrapper/helpers/SetItisCodesTest.java index abbafcb6a..bff111c35 100644 --- a/ode-wrapper/src/test/java/com/trihydro/odewrapper/helpers/SetItisCodesTest.java +++ b/ode-wrapper/src/test/java/com/trihydro/odewrapper/helpers/SetItisCodesTest.java @@ -1,10 +1,7 @@ package com.trihydro.odewrapper.helpers; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; -import com.trihydro.library.model.IncidentChoice; -import com.trihydro.odewrapper.model.WydotTimIncident; import java.util.ArrayList; import java.util.List; @@ -16,6 +13,7 @@ import com.trihydro.odewrapper.model.WydotTimBowr; import com.trihydro.odewrapper.model.WydotTimRc; +import com.trihydro.odewrapper.model.WydotTimVsl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,256 +24,206 @@ @ExtendWith(MockitoExtension.class) public class SetItisCodesTest { - @Mock - ItisCodeService mockItisCodeService; - @Mock - IncidentChoicesService mockIncidentChoicesService; - - @InjectMocks - SetItisCodes uut; - - public void setup() { - List itisCodes = new ArrayList<>(); - ItisCode code = new ItisCode(); - code.setItisCode(268);// speed limit - itisCodes.add(code); - - code = new ItisCode(); - code.setItisCode(770);// closed - itisCodes.add(code); - - code = new ItisCode(); - code.setItisCode(1309);// rockfall - itisCodes.add(code); - - code = new ItisCode(); - code.setItisCode(3084);// wildfire - itisCodes.add(code); - - code = new ItisCode(); - code.setItisCode(4868); // snow - itisCodes.add(code); - - code = new ItisCode(); - code.setItisCode(770); // closed - itisCodes.add(code); - - doReturn(itisCodes).when(mockItisCodeService).selectAll(); - } - - @Test - public void setItisCodesRc_numeric() { - // Arrange - setup(); - WydotTimRc tim = new WydotTimRc(); - Integer[] itisCodes = new Integer[2]; - itisCodes[0] = 4868; - itisCodes[1] = 1309; - tim.setAdvisory(itisCodes); - // Act - var result = uut.setItisCodesRc(tim); - - // Assert - Assertions.assertEquals(2, result.size()); - } - - @Test - public void setItisCodesRc_nonExistent() { - // Arrange - setup(); - WydotTimRc tim = new WydotTimRc(); - Integer[] itisCodes = new Integer[2]; - itisCodes[0] = 0; - itisCodes[1] = 13; - tim.setAdvisory(itisCodes); - // Act - var result = uut.setItisCodesRc(tim); - - // Assert - Assertions.assertEquals(0, result.size()); - } - - @Test - public void setItisCodesRc_translated() { - // Arrange - setup(); - WydotTimRc tim = new WydotTimRc(); - Integer[] itisCodes = new Integer[2]; - itisCodes[0] = 4868; - itisCodes[1] = 769; - tim.setAdvisory(itisCodes); - // Act - var result = uut.setItisCodesRc(tim); - - // Assert - Assertions.assertEquals(2, result.size()); - Assertions.assertTrue(result.contains("770")); - } - - @Test - public void setItisCodesRc_alphabetic() { - // Arrange - setup(); - WydotTimRc tim = new WydotTimRc(); - Integer[] itisCodes = new Integer[2]; - itisCodes[0] = 4868; - itisCodes[1] = CustomItisEnum.blowOver.getValue(); - tim.setAdvisory(itisCodes); - // Act - var result = uut.setItisCodesRc(tim); - - // Assert - Assertions.assertEquals(2, result.size()); - Assertions.assertTrue(result.contains("Extreme blow over risk")); - } - - @Test - public void setItisCodesBowr_SUCCESS() throws WeightNotSupportedException { - // Arrange - // calling setup() not necessary here - int weightInPounds = 20000; - String weightAsItisCode = "11589"; - WydotTimBowr tim = new WydotTimBowr(); - tim.setData(weightInPounds); - List expectedResult = List.of("5127", "2563", "2569", "7682", "2577", weightAsItisCode, "8739"); - - // Act - List result = uut.setItisCodesBowr(tim); - - // Assert - Assertions.assertEquals(expectedResult, result); - } - - @Test - public void setItisCodesBowr_FAILURE() { - // Arrange - // calling setup() not necessary here - int weightInPounds = 23456; - WydotTimBowr tim = new WydotTimBowr(); - tim.setData(weightInPounds); - - // Act & Assert - Assertions.assertThrows(WeightNotSupportedException.class, () -> uut.setItisCodesBowr(tim)); - } - - @Test - public void testSetItisCodesIncident_ReturnsDefaultIncidentCode() { - // Arrange - WydotTimIncident mockIncident = new WydotTimIncident(); // Mock incident object - List expectedCodes = List.of("531"); // Expected default incident code - - // Act - List result = uut.setItisCodesIncident(mockIncident); - - // Assert - Assertions.assertNotNull(result, "Resulting list should not be null."); - Assertions.assertEquals(expectedCodes, result, "Default incident code should be returned."); - } - - @Test - public void testSetItisCodesIncident_WithExistingProblemItisCode_ShouldReturnExistingItisCode() { - // Arrange - WydotTimIncident incident = new WydotTimIncident(); - incident.setProblem("268"); - List expectedItisCodes = List.of("268"); - - IncidentChoice mockIncidentChoice = new IncidentChoice(); - mockIncidentChoice.setCode("268"); - mockIncidentChoice.setItisCodeId(1); - mockIncidentChoice.setDescription("Speed Limit"); - when(mockIncidentChoicesService.selectAllIncidentProblems()).thenReturn(List.of(mockIncidentChoice)); - - ItisCode mockItisCode = new ItisCode(); - mockItisCode.setItisCode(268); - mockItisCode.setItisCodeId(1); - when(mockItisCodeService.selectAll()).thenReturn(List.of(mockItisCode)); - - // Act - List actualItisCodes = uut.setItisCodesIncident(incident); - - // Assert - Assertions.assertNotNull(actualItisCodes, "Resulting list should not be null."); - Assertions.assertEquals(expectedItisCodes, actualItisCodes, "The ITIS code for the incident problem should be returned."); - } - - @Test - public void testSetItisCodesIncident_OtherProblemGVW_ShouldReturnGVWItisCodes() { - // Arrange - WydotTimIncident incident = new WydotTimIncident(); - incident.setProblem("other"); - incident.setProblemOtherText("Weight limit of 60,000 GVW is in effect"); - List expectedItisCodes = List.of("2563", "2577", "11605", "8739"); - - // Act - List actualItisCodes = uut.setItisCodesIncident(incident); - - // Assert - Assertions.assertNotNull(actualItisCodes, "Resulting list should not be null."); - Assertions.assertEquals(expectedItisCodes, actualItisCodes, "The ITIS codes for a Gross Vehicle Weight restriction (60000 pounds) should be returned."); - } - - @Test - public void testSetItisCodesIncident_OtherProblemNoGVW_ShouldReturnDefaultIncidentCode() { - // Arrange - WydotTimIncident incident = new WydotTimIncident(); - incident.setProblem("other"); - incident.setProblemOtherText("Some other problem"); - List expectedItisCodes = List.of("531"); - - // Act - List actualItisCodes = uut.setItisCodesIncident(incident); - - // Assert - Assertions.assertNotNull(actualItisCodes, "Resulting list should not be null."); - Assertions.assertEquals(expectedItisCodes, actualItisCodes, "The default incident code should be returned."); - } - - @Test - public void testSetItisCodesIncident_OtherProblemNull_ShouldReturnDefaultIncidentCode() { - // Arrange - WydotTimIncident incident = new WydotTimIncident(); - incident.setProblem("other"); - incident.setProblemOtherText(null); - List expectedItisCodes = List.of("531"); - - // Act - List actualItisCodes = uut.setItisCodesIncident(incident); - - // Assert - Assertions.assertNotNull(actualItisCodes, "Resulting list should not be null."); - Assertions.assertEquals(expectedItisCodes, actualItisCodes, "The default incident code should be returned."); - } - - @Test - public void testSetItisCodesIncident_WeightNotFoundInProblemOtherText_ShouldReturnDefaultIncidentCode() { - // Arrange - WydotTimIncident incident = new WydotTimIncident(); - incident.setProblem("other"); - incident.setProblemOtherText("Some GVW weight restriction"); - List expectedItisCodes = List.of("531"); - - // Act - List actualItisCodes = uut.setItisCodesIncident(incident); - - // Assert - Assertions.assertNotNull(actualItisCodes, "Resulting list should not be null."); - Assertions.assertEquals(expectedItisCodes, actualItisCodes, "The default incident code should be returned."); - } - - @Test - public void testSetItisCodesIncident_WeightNotSupported_ShouldReturnDefaultIncidentCode() { - // Arrange - WydotTimIncident incident = new WydotTimIncident(); - incident.setProblem("other"); - incident.setProblemOtherText("Weight limit of 1,000,000 GVW is in effect"); - List expectedItisCodes = List.of("531"); - - // Act - List actualItisCodes = uut.setItisCodesIncident(incident); - - // Assert - Assertions.assertNotNull(actualItisCodes, "Resulting list should not be null."); - Assertions.assertEquals(expectedItisCodes, actualItisCodes, "The default incident code should be returned."); - } - + @Mock + ItisCodeService mockItisCodeService; + @Mock + IncidentChoicesService mockIncidentChoicesService; + + @InjectMocks + SetItisCodes uut; + + public void setupItisCodeDefinitions() { + List itisCodes = new ArrayList<>(); + ItisCode code = new ItisCode(); + code.setItisCode(268); + code.setDescription("speed limit"); + itisCodes.add(code); + + code = new ItisCode(); + code.setItisCode(770); + code.setDescription("closed"); + itisCodes.add(code); + + code = new ItisCode(); + code.setItisCode(1309); + code.setDescription("rockfall"); + itisCodes.add(code); + + code = new ItisCode(); + code.setItisCode(3084); + code.setDescription("wildfire"); + itisCodes.add(code); + + code = new ItisCode(); + code.setItisCode(4868); + code.setDescription("snow"); + itisCodes.add(code); + + code = new ItisCode(); + code.setItisCode(770); + code.setDescription("closed"); + itisCodes.add(code); + + code = new ItisCode(); + code.setItisCode(8720); + code.setDescription("mph"); + itisCodes.add(code); + + doReturn(itisCodes).when(mockItisCodeService).selectAll(); + } + + @Test + public void setItisCodesRc_numeric() { + // Arrange + setupItisCodeDefinitions(); + WydotTimRc tim = new WydotTimRc(); + ArrayList itisCodes = new ArrayList<>(); + itisCodes.add("4868"); + itisCodes.add("1309"); + tim.setItisCodes(itisCodes); + // Act + var result = uut.setItisCodes(tim); + + // Assert + Assertions.assertEquals(2, result.size()); + } + + @Test + public void setItisCodesRc_nonExistent() { + // Arrange + setupItisCodeDefinitions(); + WydotTimRc tim = new WydotTimRc(); + ArrayList itisCodes = new ArrayList<>(); + itisCodes.add("0"); + itisCodes.add("13"); + tim.setItisCodes(itisCodes); + // Act + var result = uut.setItisCodes(tim); + + // Assert + Assertions.assertEquals(0, result.size()); + } + + @Test + public void setItisCodesRc_translated() { + // Arrange + setupItisCodeDefinitions(); + WydotTimRc tim = new WydotTimRc(); + ArrayList itisCodes = new ArrayList<>(); + itisCodes.add("4868"); + itisCodes.add("770"); + tim.setItisCodes(itisCodes); + // Act + var result = uut.setItisCodes(tim); + + // Assert + Assertions.assertEquals(2, result.size()); + Assertions.assertTrue(result.contains("770")); + } + + @Test + public void setItisCodesRc_alphabetic() { + // Arrange + setupItisCodeDefinitions(); + WydotTimRc tim = new WydotTimRc(); + ArrayList itisCodes = new ArrayList<>(); + itisCodes.add("4868"); + itisCodes.add(String.valueOf(CustomItisEnum.blowOver.getValue())); + tim.setItisCodes(itisCodes); + // Act + var result = uut.setItisCodes(tim); + + // Assert + Assertions.assertEquals(2, result.size()); + Assertions.assertTrue(result.contains("Extreme blow over risk")); + } + + @Test + public void setItisCodesBowr_SUCCESS() throws WeightNotSupportedException { + // Arrange + // calling setup() not necessary here + int weightInPounds = 20000; + String weightAsItisCode = "11589"; + WydotTimBowr tim = new WydotTimBowr(); + tim.setData(weightInPounds); + List expectedResult = List.of("5127", "2563", "2569", "7682", "2577", weightAsItisCode, "8739"); + + // Act + List result = uut.setItisCodesBowr(tim); + + // Assert + Assertions.assertEquals(expectedResult, result); + } + + @Test + public void setItisCodesBowr_FAILURE() { + // Arrange + // calling setup() not necessary here + int weightInPounds = 23456; + WydotTimBowr tim = new WydotTimBowr(); + tim.setData(weightInPounds); + + // Act & Assert + Assertions.assertThrows(WeightNotSupportedException.class, () -> uut.setItisCodesBowr(tim)); + } + + @Test + public void setItisCodesVsl_Success() { + // Arrange + setupItisCodeDefinitions(); + int speedMph = 50; + WydotTimVsl tim = new WydotTimVsl(); + tim.setSpeed(speedMph); + tim.setItisCodes(List.of("268", "8720", "12594")); + List expectedResult = List.of("268", "12594", "8720"); + + // Act + var result = uut.setItisCodesVsl(tim); + + // Assert + Assertions.assertEquals(expectedResult, result); + } + + @Test + public void setItisCodesVsl_Failure() { + // Arrange + WydotTimVsl tim = new WydotTimVsl(); + + // Act and Assert + Assertions.assertThrows(IllegalArgumentException.class, () -> uut.setItisCodesVsl(tim)); + } + + @Test + public void setItisCodes_reducedAhead_Success() { + // Arrange + setupItisCodeDefinitions(); + int speedMph = 50; + WydotTimVsl tim = new WydotTimVsl(); + tim.setSpeed(speedMph); + tim.setItisCodes(List.of("13569", "268", "12594", "8720", "12302")); + List expectedResult = List.of("268", "12302", "12594", "8720", "13569"); + + // Act + var result = uut.setItisCodesVsl(tim); + + // Assert + Assertions.assertEquals(expectedResult, result); + } + + @Test + public void setItisCodesVsl_advisorySpeedLimit_Success() { + // Arrange + setupItisCodeDefinitions(); + int speedMph = 50; + WydotTimVsl tim = new WydotTimVsl(); + tim.setSpeed(speedMph); + tim.setItisCodes(List.of("268", "7712", "12594", "8720")); + List expectedResult = List.of("7712", "268", "12594", "8720"); + + // Act + var result = uut.setItisCodesVsl(tim); + + // Assert + Assertions.assertEquals(expectedResult, result); + } } \ No newline at end of file diff --git a/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/Application.java b/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/Application.java index 1f09d1159..c51193ac7 100644 --- a/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/Application.java +++ b/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/Application.java @@ -4,10 +4,18 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Import; +import com.trihydro.library.helpers.DbInteractions; +import com.trihydro.library.helpers.EmailHelper; +import com.trihydro.library.helpers.JavaMailSenderImplProvider; +import com.trihydro.library.helpers.SQLNullHandler; +import com.trihydro.rsudatacontroller.config.BasicConfiguration; + @SpringBootApplication -@Import({ Utility.class }) +@Import({ Utility.class, DbInteractions.class, SQLNullHandler.class, EmailHelper.class, JavaMailSenderImplProvider.class, }) +@EnableConfigurationProperties(BasicConfiguration.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); diff --git a/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/config/BasicConfiguration.java b/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/config/BasicConfiguration.java index 1e4395f91..c4f78749f 100644 --- a/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/config/BasicConfiguration.java +++ b/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/config/BasicConfiguration.java @@ -1,18 +1,30 @@ package com.trihydro.rsudatacontroller.config; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; -@Component -@ConfigurationProperties("config") -public class BasicConfiguration { +import com.trihydro.library.model.DbInteractionsProps; +import com.trihydro.library.model.EmailProps; + +@ConfigurationProperties +public class BasicConfiguration implements DbInteractionsProps, EmailProps { private int snmpRetries; private int snmpTimeoutSeconds; - private String snmpUserName; - private String snmpAuthPassphrase; private String snmpAuthProtocol; private String snmpSecurityLevel; + private String dbUrl; + private String dbUsername; + private String dbPassword; + + private int maximumPoolSize; + private int connectionTimeout; + + private String[] alertAddresses; + private String fromEmail; + private String environmentName; + private String mailHost; + private int mailPort; + public int getSnmpRetries() { return snmpRetries; } @@ -29,22 +41,6 @@ public void setSnmpTimeoutSeconds(int snmpTimeoutSeconds) { this.snmpTimeoutSeconds = snmpTimeoutSeconds; } - public String getSnmpUserName() { - return snmpUserName; - } - - public void setSnmpUserName(String snmpUserName) { - this.snmpUserName = snmpUserName; - } - - public String getSnmpAuthPassphrase() { - return snmpAuthPassphrase; - } - - public void setSnmpAuthPassphrase(String snmpAuthPassphrase) { - this.snmpAuthPassphrase = snmpAuthPassphrase; - } - public String getSnmpAuthProtocol() { return snmpAuthProtocol; } @@ -60,4 +56,84 @@ public String getSnmpSecurityLevel() { public void setSnmpSecurityLevel(String snmpSecurityLevel) { this.snmpSecurityLevel = snmpSecurityLevel; } + + public String getDbUrl() { + return dbUrl; + } + + public void setDbUrl(String dbUrl) { + this.dbUrl = dbUrl; + } + + public String getDbUsername() { + return dbUsername; + } + + public void setDbUsername(String dbUsername) { + this.dbUsername = dbUsername; + } + + public String getDbPassword() { + return dbPassword; + } + + public void setDbPassword(String dbPassword) { + this.dbPassword = dbPassword; + } + + public int getMaximumPoolSize() { + return maximumPoolSize; + } + + public void setMaximumPoolSize(int maximumPoolSize) { + this.maximumPoolSize = maximumPoolSize; + } + + public int getConnectionTimeout() { + return connectionTimeout; + } + + public void setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public String[] getAlertAddresses() { + return alertAddresses; + } + + public void setAlertAddresses(String[] alertAddresses) { + this.alertAddresses = alertAddresses; + } + + public String getFromEmail() { + return fromEmail; + } + + public void setFromEmail(String fromEmail) { + this.fromEmail = fromEmail; + } + + public String getEnvironmentName() { + return environmentName; + } + + public void setEnvironmentName(String environmentName) { + this.environmentName = environmentName; + } + + public String getMailHost() { + return mailHost; + } + + public void setMailHost(String mailHost) { + this.mailHost = mailHost; + } + + public int getMailPort() { + return mailPort; + } + + public void setMailPort(int mailPort) { + this.mailPort = mailPort; + } } \ No newline at end of file diff --git a/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/service/RsuService.java b/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/service/RsuService.java index 1866b4fbf..ddcc9d1f0 100644 --- a/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/service/RsuService.java +++ b/rsu-data-controller/src/main/java/com/trihydro/rsudatacontroller/service/RsuService.java @@ -3,6 +3,9 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -10,6 +13,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.trihydro.library.helpers.DbInteractions; import com.trihydro.library.helpers.Utility; import com.trihydro.rsudatacontroller.config.BasicConfiguration; import com.trihydro.rsudatacontroller.model.RsuTim; @@ -18,20 +22,26 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import us.dot.its.jpo.ode.plugin.RoadSideUnit.RSU; +import us.dot.its.jpo.ode.plugin.SnmpProtocol; + @Component public class RsuService { - private static final String oid_rsuSRMDeliveryStart = "1.0.15628.4.1.4.1.7"; + private static final String OID_FOUR_DOT_ONE_SRM_DELIVERY_START = "1.0.15628.4.1.4.1.7"; + private static final String OID_NTCIP_1218_DELIVERY_START = "1.3.6.1.4.1.1206.4.2.18.3.2.1.5"; private static final DateTimeFormatter rsuDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private ProcessFactory processFactory; private BasicConfiguration config; private Utility utility; + protected DbInteractions dbInteractions; @Autowired - public void InjectDependencies(ProcessFactory processFactory, BasicConfiguration config, Utility utility) { + public void InjectDependencies(ProcessFactory processFactory, BasicConfiguration config, DbInteractions dbInteractions, Utility utility) { this.processFactory = processFactory; this.config = config; this.utility = utility; + this.dbInteractions = dbInteractions; } /** @@ -42,10 +52,21 @@ public void InjectDependencies(ProcessFactory processFactory, BasicConfiguration * @throws Exception if unable to invoke command to perform SNMP communication */ public List getAllDeliveryStartTimes(String rsuIpv4Address) throws Exception { - Process p = processFactory.buildAndStartProcess("snmpwalk", "-v", "3", "-r", + Process p; + + RSU rsu = getRSU(rsuIpv4Address); + + if (rsu.getSnmpProtocol() == SnmpProtocol.FOURDOT1) { + p = processFactory.buildAndStartProcess("snmpwalk", "-v", "3", "-r", Integer.toString(config.getSnmpRetries()), "-t", Integer.toString(config.getSnmpTimeoutSeconds()), "-u", - config.getSnmpUserName(), "-l", config.getSnmpSecurityLevel(), "-a", config.getSnmpAuthProtocol(), "-A", - config.getSnmpAuthPassphrase(), rsuIpv4Address, oid_rsuSRMDeliveryStart); + rsu.getRsuUsername(), "-l", config.getSnmpSecurityLevel(), "-a", config.getSnmpAuthProtocol(), "-A", + rsu.getRsuPassword(), rsuIpv4Address, OID_FOUR_DOT_ONE_SRM_DELIVERY_START); + } else { + p = processFactory.buildAndStartProcess("snmpwalk", "-v", "3", "-r", + Integer.toString(config.getSnmpRetries()), "-t", Integer.toString(config.getSnmpTimeoutSeconds()), "-u", + rsu.getRsuUsername(), "-l", config.getSnmpSecurityLevel(), "-a", config.getSnmpAuthProtocol(), "-A", + rsu.getRsuPassword(), rsuIpv4Address, OID_NTCIP_1218_DELIVERY_START); + } String snmpWalkOutput = getProcessOutput(p); @@ -67,7 +88,7 @@ public List getAllDeliveryStartTimes(String rsuIpv4Address) throws Excep if (im.find() && hm.find()) { RsuTim tim = new RsuTim(); - tim.setIndex(Integer.parseInt(im.group(1))); + tim.setIndex(Integer.valueOf(im.group(1))); tim.setDeliveryStartTime(hexStringToDateTime(hm.group(1))); tims.add(tim); @@ -106,4 +127,27 @@ private String hexStringToDateTime(String hexString) { LocalDateTime date = LocalDateTime.of(year, month, day, hour, minute, 0); return date.format(rsuDateTimeFormatter); } + + protected RSU getRSU(String rsuIpv4Address) throws Exception { + // select RSU username, password, and firmware type + String SELECT_RSU_CREDENTIALS = "SELECT rc.username, rc.password, sp.nickname " + + "FROM rsus " + + "JOIN rsu_credentials AS rc ON rsus.snmp_credential_id = rc.credential_id " + + "JOIN snmp_protocols AS sp ON rsus.snmp_protocol_id = sp.snmp_protocol_id " + + "WHERE rsus.ipv4_address = ?"; + try (Connection connection = dbInteractions.getConnectionPool(); + PreparedStatement statement = connection.prepareStatement(SELECT_RSU_CREDENTIALS)) { + statement.setString(1, rsuIpv4Address); // Setting parameter to prevent injection. + try (ResultSet rs = statement.executeQuery()) { + if (!rs.next()) { + utility.logWithDate("Unable to find RSU in database (RSU: " + rsuIpv4Address + ")"); + return null; + } + String rsuUsername = rs.getString("username"); + String rsuPassword = rs.getString("password"); + SnmpProtocol snmpProtocol = rs.getString("nickname").equals("NTCIP 1218") ? SnmpProtocol.NTCIP1218 : SnmpProtocol.FOURDOT1; + return new RSU(rsuIpv4Address, rsuUsername, rsuPassword, config.getSnmpRetries(), config.getSnmpTimeoutSeconds(), snmpProtocol); + } + } + } } \ No newline at end of file diff --git a/rsu-data-controller/src/main/resources/application-dev.properties b/rsu-data-controller/src/main/resources/application-dev.properties index 68ed2d799..ca0c72b59 100644 --- a/rsu-data-controller/src/main/resources/application-dev.properties +++ b/rsu-data-controller/src/main/resources/application-dev.properties @@ -4,4 +4,11 @@ config.snmpTimeoutSeconds=5 config.snmpUserName=username config.snmpAuthPassphrase=password config.snmpAuthProtocol=SHA -config.snmpSecurityLevel=authNoPriv \ No newline at end of file +config.snmpSecurityLevel=authNoPriv + +dbUrl=jdbc:postgresql://localhost:5432/dbname?user=username +dbUsername=username +dbPassword=password + +maximumPoolSize=13 +connectionTimeout=300000 \ No newline at end of file diff --git a/rsu-data-controller/src/test/java/com/trihydro/rsudatacontroller/service/RsuServiceTest.java b/rsu-data-controller/src/test/java/com/trihydro/rsudatacontroller/service/RsuServiceTest.java index 7b6456c19..bd3428f93 100644 --- a/rsu-data-controller/src/test/java/com/trihydro/rsudatacontroller/service/RsuServiceTest.java +++ b/rsu-data-controller/src/test/java/com/trihydro/rsudatacontroller/service/RsuServiceTest.java @@ -4,21 +4,29 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.util.List; +import com.trihydro.library.helpers.DbInteractions; import com.trihydro.library.helpers.Utility; import com.trihydro.rsudatacontroller.config.BasicConfiguration; import com.trihydro.rsudatacontroller.model.RsuTim; import com.trihydro.rsudatacontroller.process.ProcessFactory; +import us.dot.its.jpo.ode.plugin.RoadSideUnit.RSU; +import us.dot.its.jpo.ode.plugin.SnmpProtocol; + import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -26,6 +34,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; + @ExtendWith(MockitoExtension.class) public class RsuServiceTest { @Mock @@ -47,12 +56,9 @@ public class RsuServiceTest { @InjectMocks RsuService uut; - @BeforeEach public void initMocks() { when(mockConfig.getSnmpRetries()).thenReturn(0); when(mockConfig.getSnmpTimeoutSeconds()).thenReturn(10); - when(mockConfig.getSnmpUserName()).thenReturn("username"); - when(mockConfig.getSnmpAuthPassphrase()).thenReturn("passphrase"); when(mockConfig.getSnmpAuthProtocol()).thenReturn("protocol"); when(mockConfig.getSnmpSecurityLevel()).thenReturn("level"); } @@ -65,12 +71,15 @@ private void setupProcess() { public void getAllDeliveryStartTimes_success() throws Exception { // Arrange setupProcess(); + initMocks(); InputStream output = getInputStream("iso.0.15628.4.1.4.1.7.2 = Hex-STRING: 07 E4 03 14 11 3B", "iso.0.15628.4.1.4.1.7.3 = Hex-STRING: 07 E4 03 14 13 1E"); doReturn(output).when(mockProcess).getInputStream(); + RsuService spyUut = spy(uut); + doReturn(new RSU("0.0.0.0", "username", "password", 3, 10, SnmpProtocol.FOURDOT1)).when(spyUut).getRSU(any()); // Act - List results = uut.getAllDeliveryStartTimes("0.0.0.0"); + List results = spyUut.getAllDeliveryStartTimes("0.0.0.0"); // Assert Assertions.assertEquals(2, results.size()); @@ -80,7 +89,7 @@ public void getAllDeliveryStartTimes_success() throws Exception { Assertions.assertEquals("2020-03-20 19:30:00", results.get(1).getDeliveryStartTime()); Assertions.assertEquals( - "snmpwalk -v 3 -r 0 -t 10 -u username -l level -a protocol -A passphrase 0.0.0.0 1.0.15628.4.1.4.1.7", + "snmpwalk -v 3 -r 0 -t 10 -u username -l level -a protocol -A password 0.0.0.0 1.0.15628.4.1.4.1.7", String.join(" ", factoryArgs.getAllValues())); } @@ -88,11 +97,14 @@ public void getAllDeliveryStartTimes_success() throws Exception { public void getAllDeliveryStartTimes_single() throws Exception { // Arrange setupProcess(); + initMocks(); InputStream output = getInputStream("iso.0.15628.4.1.4.1.7.2 = Hex-STRING: 07 E4 03 14 11 3B "); doReturn(output).when(mockProcess).getInputStream(); + RsuService spyUut = spy(uut); + doReturn(new RSU("0.0.0.0", "username", "password", 3, 10, SnmpProtocol.FOURDOT1)).when(spyUut).getRSU(any()); // Act - List results = uut.getAllDeliveryStartTimes("0.0.0.0"); + List results = spyUut.getAllDeliveryStartTimes("0.0.0.0"); // Assert Assertions.assertEquals(1, results.size()); @@ -100,7 +112,7 @@ public void getAllDeliveryStartTimes_single() throws Exception { Assertions.assertEquals("2020-03-20 17:59:00", results.get(0).getDeliveryStartTime()); Assertions.assertEquals( - "snmpwalk -v 3 -r 0 -t 10 -u username -l level -a protocol -A passphrase 0.0.0.0 1.0.15628.4.1.4.1.7", + "snmpwalk -v 3 -r 0 -t 10 -u username -l level -a protocol -A password 0.0.0.0 1.0.15628.4.1.4.1.7", String.join(" ", factoryArgs.getAllValues())); } @@ -108,17 +120,20 @@ public void getAllDeliveryStartTimes_single() throws Exception { public void getAllDeliveryStartTimes_none() throws Exception { // Arrange setupProcess(); + initMocks(); InputStream output = getInputStream(""); doReturn(output).when(mockProcess).getInputStream(); + RsuService spyUut = spy(uut); + doReturn(new RSU("0.0.0.0", "username", "password", 3, 10, SnmpProtocol.FOURDOT1)).when(spyUut).getRSU(any()); // Act - List results = uut.getAllDeliveryStartTimes("0.0.0.0"); + List results = spyUut.getAllDeliveryStartTimes("0.0.0.0"); // Assert Assertions.assertEquals(0, results.size()); Assertions.assertEquals( - "snmpwalk -v 3 -r 0 -t 10 -u username -l level -a protocol -A passphrase 0.0.0.0 1.0.15628.4.1.4.1.7", + "snmpwalk -v 3 -r 0 -t 10 -u username -l level -a protocol -A password 0.0.0.0 1.0.15628.4.1.4.1.7", String.join(" ", factoryArgs.getAllValues())); } @@ -126,11 +141,14 @@ public void getAllDeliveryStartTimes_none() throws Exception { public void getAllDeliveryStartTimes_snmpTimeout() throws Exception { // Arrange setupProcess(); + initMocks(); InputStream output = getInputStream("snmpwalk: Timeout"); doReturn(output).when(mockProcess).getInputStream(); + RsuService spyUut = spy(uut); + doReturn(new RSU("0.0.0.0", "username", "password", 3, 10, SnmpProtocol.FOURDOT1)).when(spyUut).getRSU(any()); // Act - List results = uut.getAllDeliveryStartTimes("0.0.0.0"); + List results = spyUut.getAllDeliveryStartTimes("0.0.0.0"); // Assert Assertions.assertNull(results); @@ -142,21 +160,96 @@ public void getAllDeliveryStartTimes_throwsRuntimeException() throws Exception { // Arrange doThrow(new RuntimeException("unable to find snmpwalk command")).when(mockProcessFactory) .buildAndStartProcess(any()); + RsuService spyUut = spy(uut); + doReturn(new RSU("0.0.0.0", "username", "password", 3, 10, SnmpProtocol.FOURDOT1)).when(spyUut).getRSU(any()); // Act - Assertions.assertThrows(RuntimeException.class, () -> uut.getAllDeliveryStartTimes("0.0.0.0")); + Assertions.assertThrows(RuntimeException.class, () -> spyUut.getAllDeliveryStartTimes("0.0.0.0")); } @Test public void getAllDeliveryStartTimes_throwsIOException() throws Exception { // Arrange setupProcess(); + initMocks(); doThrow(new IOException("error occurred reading input stream")).when(mockInputStream).read(any(), anyInt(), anyInt()); doReturn(mockInputStream).when(mockProcess).getInputStream(); + RsuService spyUut = spy(uut); + doReturn(new RSU("0.0.0.0", "username", "password", 3, 10, SnmpProtocol.FOURDOT1)).when(spyUut).getRSU(any()); + + // Act + Assertions.assertThrows(IOException.class, () -> spyUut.getAllDeliveryStartTimes("0.0.0.0")); + } + + @Test + public void getRSU_Success() throws Exception { + // Arrange + String rsuIpv4Address = "192.168.1.1"; + String username = "testUser"; + String password = "testPass"; + String nickname = "NTCIP 1218"; + SnmpProtocol snmpProtocol = SnmpProtocol.NTCIP1218; + + Connection mockConnection = mock(Connection.class); + PreparedStatement mockStatement = mock(PreparedStatement.class); + ResultSet mockResultSet = mock(ResultSet.class); + RsuService spyUut = spy(uut); + DbInteractions mockDbInteractions = mock(DbInteractions.class); + + when(mockDbInteractions.getConnectionPool()).thenReturn(mockConnection); + when(mockConnection.prepareStatement(any())).thenReturn(mockStatement); + when(mockStatement.executeQuery()).thenReturn(mockResultSet); + when(mockResultSet.next()).thenReturn(true).thenReturn(false); + when(mockResultSet.getString("username")).thenReturn(username); + when(mockResultSet.getString("password")).thenReturn(password); + when(mockResultSet.getString("nickname")).thenReturn(nickname); + + spyUut.dbInteractions = mockDbInteractions; // Act - Assertions.assertThrows(IOException.class, () -> uut.getAllDeliveryStartTimes("0.0.0.0")); + RSU result = spyUut.getRSU(rsuIpv4Address); + + // Assert + Assertions.assertNotNull(result); + Assertions.assertEquals(rsuIpv4Address, result.getRsuTarget()); + Assertions.assertEquals(username, result.getRsuUsername()); + Assertions.assertEquals(password, result.getRsuPassword()); + Assertions.assertEquals(snmpProtocol, result.getSnmpProtocol()); + + verify(mockConnection).close(); + verify(mockStatement).close(); + verify(mockResultSet).close(); + } + + @Test + public void getRSU_NoResult() throws Exception { + // Arrange + String rsuIpv4Address = "192.168.1.1"; + + Connection mockConnection = mock(Connection.class); + PreparedStatement mockStatement = mock(PreparedStatement.class); + ResultSet mockResultSet = mock(ResultSet.class); + DbInteractions mockDbInteractions = mock(DbInteractions.class); + + RsuService spyUut = spy(uut); + + when(mockDbInteractions.getConnectionPool()).thenReturn(mockConnection); + when(mockConnection.prepareStatement(any())).thenReturn(mockStatement); + when(mockStatement.executeQuery()).thenReturn(mockResultSet); + when(mockResultSet.next()).thenReturn(false); + + spyUut.dbInteractions = mockDbInteractions; + + // Act + RSU result = spyUut.getRSU(rsuIpv4Address); + + // Assert + Assertions.assertNull(result); + + verify(mockConnection).close(); + verify(mockStatement).close(); + verify(mockResultSet).close(); } private InputStream getInputStream(String... lines) { diff --git a/sample.env b/sample.env index 610c7b264..25e1207f9 100644 --- a/sample.env +++ b/sample.env @@ -17,6 +17,13 @@ ENVIRONMENT_NAME=DEV SDW_REST_URL= SDW_API_KEY= ######################### +# Kafka Properties +KAFKA_TYPE=local +# These values are only required if KAFKA_TYPE is set to 'confluent' +# More information on setting up Confluent Cloud can be found here: https://www.confluent.io/confluent-cloud/ +CONFLUENT_KEY= +CONFLUENT_SECRET= +######################### # Logger Properties BSM_TOPIC=topic.OdeBsmJson BSM_GROUP_MONGO=group_bsm_mongo_logger @@ -51,6 +58,7 @@ CONTROLLER_SERVER_SSL_KEY_STORE=classpath:keystore.jks CONTROLLER_SERVER_SSL_KEY_STORE_PASSWORD= CONTROLLER_SERVER_SSL_KEY_STORE_TYPE=JKS CONTROLLER_SERVER_SSL_KEY_ALIAS=key-alias +CONTROLLER_LOGGING_LEVEL_ROOT=INFO # Data Logger LOGGER_KAFKA_HOST_SERVER=ode-url @@ -75,12 +83,10 @@ MONGO_FROM_EMAIL=support@example.com # ODE Wrapper WRAPPER_SERVER_PORT=7777 WRAPPER_CONFIG_ODE_URL=http://ode-url:8080 -WRAPPER_CONFIG_DB_URL=jdbc:postgresql://localhost:5432/dbname?user=username -WRAPPER_CONFIG_DB_USERNAME=username -WRAPPER_CONFIG_DB_PASSWORD= WRAPPER_CONFIG_MAXIMUM_POOL_SIZE=7 WRAPPER_CONFIG_CONNECTION_TIMEOUT=300000 WRAPPER_CONFIG_ENV=dev +WRAPPER_CONFIG_DOT_GNIS_ID= WRAPPER_CONFIG_SDW_TTL=oneday WRAPPER_CONFIG_ALERT_ADDRESSES=user@example.com,user2@example.com WRAPPER_CONFIG_FROM_EMAIL=support@example.com @@ -131,13 +137,16 @@ RSUCONTROLLER_CONFIG_SNMP_USER_NAME=username RSUCONTROLLER_CONFIG_SNMP_AUTH_PASSPHRASE= RSUCONTROLLER_CONFIG_SNMP_AUTH_PROTOCOL=SHA RSUCONTROLLER_CONFIG_SNMP_SECURITY_LEVEL=authNoPriv +RSUCONTROLLER_DB_URL=jdbc:postgresql://localhost:5432/dbname?user=username +RSUCONTROLLER_DB_USERNAME=username +RSUCONTROLLER_DB_PASSWORD= +RSUCONTROLLER_MAXIMUM_POOL_SIZE=13 +RSUCONTROLLER_CONNECTION_TIMEOUT=300000 # Data Tasks TASKS_CONFIG_ODE_URL=http://ode-url:8080 TASKS_CONFIG_CV_REST_SERVICE=https://ode-url:8888 TASKS_CONFIG_WRAPPER_URL=https://ode-url:7777 -TASKS_CONFIG_CV_REST_SERVICE_DEV=https://ode-url:8888 -# TASKS_CONFIG_CV_REST_SERVICE_PROD=https://ode.wyoroad.info:8888 TASKS_CONFIG_RSU_DATA_SERVICE_URL=http://ode-url:8898 # TASKS_CONFIG_TMDD_URL=https://tmdd-url # TASKS_CONFIG_TMDD_USER=support@example.com