Java tutorial
/* * Copyright (C) 2011 Nipuna Gunathilake. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.usf.cutr.gtfsrtvalidator.api.resource; import com.google.transit.realtime.GtfsRealtime; import edu.usf.cutr.gtfsrtvalidator.api.model.*; import edu.usf.cutr.gtfsrtvalidator.api.model.combined.CombinedIterationMessageModel; import edu.usf.cutr.gtfsrtvalidator.api.model.combined.CombinedMessageOccurrenceModel; import edu.usf.cutr.gtfsrtvalidator.background.BackgroundTask; import edu.usf.cutr.gtfsrtvalidator.db.GTFSDB; import edu.usf.cutr.gtfsrtvalidator.helper.TimeStampHelper; import org.hibernate.Session; import org.slf4j.LoggerFactory; import javax.ws.rs.*; import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Path("/gtfs-rt-feed") public class GtfsRtFeed { private static final org.slf4j.Logger _log = LoggerFactory.getLogger(GtfsRtFeed.class); private static final int INVALID_FEED = 0; private static final int VALID_FEED = 1; public static String agencyTimezone; public Response generateError(String errorMessage) { return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON) .entity(new ErrorMessageModel(errorMessage)).build(); } //Add new gtfs-rt feed to monitored list @POST @Produces(MediaType.APPLICATION_JSON) public Response postGtfsRtFeed(GtfsRtFeedModel feedInfo) { //feedInfo.setGtfsId(1); feedInfo.setStartTime(TimeStampHelper.getCurrentTimestamp()); //Validate URL for GTFS feed and the GTFS ID. if (feedInfo.getGtfsUrl() == null) { return generateError("GTFS-RT URL is required"); } else if (feedInfo.getGtfsFeedModel().getFeedId() == 0) { return generateError("GTFS Feed id is required"); } //Check if URL is valid try { URL feedUrl = new URL(feedInfo.getGtfsUrl()); HttpURLConnection connection = (HttpURLConnection) feedUrl.openConnection(); connection.setRequestMethod("GET"); connection.connect(); boolean connectionSuccessful = connection.getResponseCode() / 100 == 2; if (!connectionSuccessful) { return generateError("URL returns code: " + connection.getResponseCode()); } } catch (Exception ex) { return generateError("Invalid URL"); } //Checks if the GTFS-RT feed returns valid protobuf if (checkFeedType(feedInfo.getGtfsUrl()) == INVALID_FEED) { return generateError("The GTFS-RT URL given is not a valid feed"); } Session session = GTFSDB.InitSessionBeginTrans(); GtfsRtFeedModel storedFeedInfo = (GtfsRtFeedModel) session .createQuery(" FROM GtfsRtFeedModel WHERE " + "gtfsUrl= '" + feedInfo.getGtfsUrl() + "' AND gtfsFeedModel.feedId = " + feedInfo.getGtfsFeedModel().getFeedId()) .uniqueResult(); GTFSDB.commitAndCloseSession(session); if (storedFeedInfo == null) { //If null, create the gtfs-rt feed in the DB and return the feed session = GTFSDB.InitSessionBeginTrans(); session.save(feedInfo); GTFSDB.commitAndCloseSession(session); } else return Response.ok(storedFeedInfo).build(); return Response.ok(feedInfo).build(); } //GET feed to retrive all RT-feeds @GET @Produces(MediaType.APPLICATION_JSON) public Response getRtFeeds() { List<GtfsRtFeedModel> gtfsFeeds = new ArrayList<>(); try { Session session = GTFSDB.InitSessionBeginTrans(); gtfsFeeds = session.createQuery(" FROM GtfsRtFeedModel").list(); GTFSDB.commitAndCloseSession(session); } catch (Exception e) { e.printStackTrace(); } GenericEntity<List<GtfsRtFeedModel>> feedList = new GenericEntity<List<GtfsRtFeedModel>>(gtfsFeeds) { }; return Response.ok(feedList).build(); } private static HashMap<String, ScheduledExecutorService> runningTasks = new HashMap<>(); @PUT @Path("/{id}/{updateInterval}/monitor") public Response getID(@PathParam("id") int id, @PathParam("updateInterval") int updateInterval) { //Get RtFeedModel from id Session session = GTFSDB.InitSessionBeginTrans(); GtfsRtFeedModel gtfsRtFeed = (GtfsRtFeedModel) session .createQuery(" FROM GtfsRtFeedModel " + "WHERE rtFeedID = " + id).uniqueResult(); GTFSDB.commitAndCloseSession(session); //Extract the Url and gtfsId to start the background process startBackgroundTask(gtfsRtFeed, updateInterval); return Response.ok(gtfsRtFeed, MediaType.APPLICATION_JSON).build(); } //GET {id} return information about the feed with {id} @GET @Path("/{id : \\d+}/summary/pagination/{currentPage: \\d+}/{rowsPerPage: \\d+}") @Produces(MediaType.APPLICATION_JSON) public Response getRtFeedSummaryDetails(@PathParam("id") int id, @PathParam("currentPage") int currentPage, @PathParam("rowsPerPage") int rowsPerPage) { List<ViewErrorSummaryModel> feedSummary; int fromRow = (currentPage - 1) * rowsPerPage; Session session = GTFSDB.InitSessionBeginTrans(); feedSummary = session.createNamedQuery("ErrorSummaryByrtfeedID", ViewErrorSummaryModel.class) .setParameter(0, id).setParameter(1, id).setFirstResult(fromRow).setMaxResults(rowsPerPage).list(); GTFSDB.commitAndCloseSession(session); for (ViewErrorSummaryModel viewErrorSummaryModel : feedSummary) { int index = feedSummary.indexOf(viewErrorSummaryModel); String formattedTimestamp = getDateFormat(viewErrorSummaryModel.getLastTime(), id); viewErrorSummaryModel.setFormattedTimestamp(formattedTimestamp); viewErrorSummaryModel.setTimeZone(agencyTimezone); } GenericEntity<List<ViewErrorSummaryModel>> feedList = new GenericEntity<List<ViewErrorSummaryModel>>( feedSummary) { }; return Response.ok(feedList).build(); } // Return Log information about the feed with {id} @GET @Path("/{id : \\d+}/log/{toggledData: .*}/pagination/{currentPage: \\d+}/{rowsPerPage: \\d+}") @Produces(MediaType.APPLICATION_JSON) public Response getRtFeedLogDetails(@PathParam("id") int id, @PathParam("toggledData") String hideErrors, @PathParam("currentPage") int currentPage, @PathParam("rowsPerPage") int rowsPerPage) { List<ViewErrorLogModel> feedLog; String[] removeIds = hideErrors.split(","); // Getting the value of fromRow from the rowsPerPage and currentPage values. int fromRow = (currentPage - 1) * rowsPerPage; Session session = GTFSDB.InitSessionBeginTrans(); feedLog = session.createNamedQuery("ErrorLogByrtfeedID", ViewErrorLogModel.class).setParameter(0, id) .setParameter(1, id).setParameterList("errorIds", removeIds).setFirstResult(fromRow) .setMaxResults(rowsPerPage).list(); GTFSDB.commitAndCloseSession(session); for (ViewErrorLogModel viewErrorLogModel : feedLog) { String formattedTimestamp = getDateFormat(viewErrorLogModel.getOccurrence(), id); viewErrorLogModel.setFormattedTimestamp(formattedTimestamp); viewErrorLogModel.setTimeZone(agencyTimezone); } GenericEntity<List<ViewErrorLogModel>> feedList = new GenericEntity<List<ViewErrorLogModel>>(feedLog) { }; return Response.ok(feedList).build(); } // Returns number of iterations a feed has gone through @GET @Path("/{id : \\d+}/feedIterations") @Produces(MediaType.APPLICATION_JSON) public Response getFeedIterationsCount(@PathParam("id") int id) { ViewFeedIterationsCount iterationsCount; Session session = GTFSDB.InitSessionBeginTrans(); iterationsCount = (ViewFeedIterationsCount) session .createNamedQuery("feedIterationsCount", ViewFeedIterationsCount.class).setParameter(0, id) .uniqueResult(); GTFSDB.commitAndCloseSession(session); return Response.ok(iterationsCount).build(); } // Returns feed message for a requested iteration @GET @Path("/{iterationId : \\d+}/feedMessage") @Produces(MediaType.APPLICATION_JSON) public String getFeedMessage(@PathParam("iterationId") int iterationId) { ViewFeedMessageModel feedMessageModel; Session session = GTFSDB.InitSessionBeginTrans(); feedMessageModel = session.createNamedQuery("feedMessageByIterationId", ViewFeedMessageModel.class) .setParameter(0, iterationId).uniqueResult(); GTFSDB.commitAndCloseSession(session); feedMessageModel.setJsonFeedMessage(feedMessageModel.getByteFeedMessage()); return feedMessageModel.getJsonFeedMessage(); } // Returns total number of feed unique responses @GET @Path("/{id : \\d+}/uniqueResponses") @Produces(MediaType.APPLICATION_JSON) public Response getFeedUniqueResponses(@PathParam("id") int id) { ViewFeedUniqueResponseCount uniqueResponseCount; Session session = GTFSDB.InitSessionBeginTrans(); uniqueResponseCount = (ViewFeedUniqueResponseCount) session .createNamedQuery("feedUniqueResponseCount", ViewFeedUniqueResponseCount.class).setParameter(0, id) .uniqueResult(); GTFSDB.commitAndCloseSession(session); return Response.ok(uniqueResponseCount).build(); } // Returns total number of Gtfs-Rt feed errors @GET @Path("/{id : \\d+}/errorCount") @Produces(MediaType.APPLICATION_JSON) public Response getFeedErrorCount(@PathParam("id") int id) { List<ViewGtfsRtFeedErrorCountModel> viewGtfsRtFeedErrorCountModel; Session session = GTFSDB.InitSessionBeginTrans(); viewGtfsRtFeedErrorCountModel = session .createNamedQuery("feedErrorCount", ViewGtfsRtFeedErrorCountModel.class).setParameter(0, id).list(); GTFSDB.commitAndCloseSession(session); GenericEntity<List<ViewGtfsRtFeedErrorCountModel>> errorList = new GenericEntity<List<ViewGtfsRtFeedErrorCountModel>>( viewGtfsRtFeedErrorCountModel) { }; return Response.ok(errorList).build(); } @GET @Path("/{id}/{iteration}") @Produces(MediaType.APPLICATION_JSON) public Response getMessageDetails(@PathParam("id") int id, @PathParam("iteration") int iterationId) { CombinedIterationMessageModel messageList = new CombinedIterationMessageModel(); Session session = GTFSDB.InitSessionBeginTrans(); GtfsRtFeedIterationModel iterationModel = (GtfsRtFeedIterationModel) session .createQuery(" FROM GtfsRtFeedIterationModel WHERE IterationId = " + iterationId).uniqueResult(); GtfsRtFeedIterationString iterationString = new GtfsRtFeedIterationString(iterationModel); messageList.setGtfsFeedIterationModel(iterationString); List<CombinedMessageOccurrenceModel> combinedMessageOccurrenceModelList = new ArrayList<>(); //Get a message list List<MessageLogModel> messageLogModels = session .createQuery(" FROM MessageLogModel WHERE IterationId = " + iterationId).list(); //For each message get the occurrences for (MessageLogModel messageLog : messageLogModels) { List<OccurrenceModel> occurrenceModels = session .createQuery("FROM OccurrenceModel WHERE messageId = " + messageLog.getMessageId()).list(); //Add both to the returned list CombinedMessageOccurrenceModel messageOccurrence = new CombinedMessageOccurrenceModel(); messageOccurrence.setMessageLogModel(messageLog); messageOccurrence.setOccurrenceModels(occurrenceModels); combinedMessageOccurrenceModelList.add(messageOccurrence); } messageList.setMessageOccurrenceList(combinedMessageOccurrenceModelList); GTFSDB.commitAndCloseSession(session); return Response.ok(messageList).build(); } //TODO: DELETE {id} remove feed with {id} private int checkFeedType(String FeedURL) { GtfsRealtime.FeedMessage feed; try { URI FeedURI = new URI(FeedURL); URL url = FeedURI.toURL(); feed = GtfsRealtime.FeedMessage.parseFrom(url.openStream()); } catch (URISyntaxException | IllegalArgumentException | IOException e) { return INVALID_FEED; } if (feed.hasHeader()) { _log.info(String.format("%s is a valid GTFS-realtime feed", FeedURL)); return VALID_FEED; } return INVALID_FEED; } public synchronized static ScheduledExecutorService startBackgroundTask(GtfsRtFeedModel gtfsRtFeed, int updateInterval) { String rtFeedUrl = gtfsRtFeed.getGtfsUrl(); if (!runningTasks.containsKey(rtFeedUrl)) { ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.scheduleAtFixedRate(new BackgroundTask(gtfsRtFeed), 0, updateInterval, TimeUnit.SECONDS); runningTasks.put(rtFeedUrl, scheduler); return scheduler; } else { return runningTasks.get(rtFeedUrl); } } public String getDateFormat(long lastTime, int gtfsRtId) { Session session = GTFSDB.InitSessionBeginTrans(); GtfsRtFeedModel gtfsRtFeed = (GtfsRtFeedModel) session .createQuery(" FROM GtfsRtFeedModel " + "WHERE rtFeedID = " + gtfsRtId).uniqueResult(); GtfsFeedModel gtfsFeed = (GtfsFeedModel) session .createQuery("FROM GtfsFeedModel " + "WHERE feedID = " + gtfsRtFeed.getGtfsFeedModel().getFeedId()) .uniqueResult(); GTFSDB.commitAndCloseSession(session); agencyTimezone = gtfsFeed.getAgency(); DateFormat todaytimeFormat = new SimpleDateFormat("hh:mm:ss a"); DateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a"); DateFormat todayDateFormat = new SimpleDateFormat("yyyy-MM-dd"); TimeZone timeZone = TimeZone.getTimeZone(agencyTimezone); todaytimeFormat.setTimeZone(timeZone); dateTimeFormat.setTimeZone(timeZone); todayDateFormat.setTimeZone(timeZone); String formattedTime; String currentDate = todayDateFormat.format(new Date().getTime()); long fromStartOfDay = 0; try { fromStartOfDay = TimeUnit.MILLISECONDS.toSeconds(todayDateFormat.parse(currentDate).getTime()); // converting to seconds } catch (ParseException e) { e.printStackTrace(); } if (lastTime < fromStartOfDay) { formattedTime = dateTimeFormat.format(TimeUnit.SECONDS.toMillis(lastTime)); // converting to millisec } else { formattedTime = todaytimeFormat.format(TimeUnit.SECONDS.toMillis(lastTime)); } return formattedTime; } }