org.onebusaway.nyc.vehicle_tracking.webapp.controllers.VehicleLocationSimulationController.java Source code

Java tutorial

Introduction

Here is the source code for org.onebusaway.nyc.vehicle_tracking.webapp.controllers.VehicleLocationSimulationController.java

Source

/**
 * Copyright (c) 2011 Metropolitan Transportation Authority
 *
 * 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 org.onebusaway.nyc.vehicle_tracking.webapp.controllers;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.onebusaway.gtfs.csv.CsvEntityWriterFactory;
import org.onebusaway.gtfs.csv.EntityHandler;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.nyc.vehicle_tracking.model.NycTestLocationRecord;
import org.onebusaway.nyc.vehicle_tracking.services.VehicleLocationDetails;
import org.onebusaway.nyc.vehicle_tracking.services.VehicleLocationSimulationService;
import org.onebusaway.nyc.vehicle_tracking.services.VehicleLocationSimulationSummary;
import org.onebusaway.transit_data.model.ListBean;
import org.onebusaway.transit_data.model.RouteBean;
import org.onebusaway.transit_data.model.blocks.BlockBean;
import org.onebusaway.transit_data.model.blocks.BlockStatusBean;
import org.onebusaway.transit_data.model.blocks.BlockTripBean;
import org.onebusaway.transit_data.model.trips.TripBean;
import org.onebusaway.transit_data_federation.services.AgencyAndIdLibrary;
import org.onebusaway.transit_data_federation.services.AgencyService;
import org.onebusaway.transit_data_federation.services.beans.BlockBeanService;
import org.onebusaway.transit_data_federation.services.beans.BlockStatusBeanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class VehicleLocationSimulationController {

    private static final Pattern CALENDAR_OFFSET_PATTERN = Pattern.compile("^(-{0,1}\\d+)(\\w+)$");

    private static final String CALENDAR_OFFSET_KEY = VehicleLocationSimulationController.class + ".calendarOffset";

    private VehicleLocationSimulationService _vehicleLocationSimulationService;

    private AgencyService _agencyService;

    private BlockBeanService _blockBeanService;

    private BlockStatusBeanService _blockStatusBeanService;

    @Autowired
    public void setVehicleLocationSimulationService(VehicleLocationSimulationService service) {
        _vehicleLocationSimulationService = service;
    }

    @Autowired
    public void setBlockBeanService(BlockBeanService blockBeanService) {
        _blockBeanService = blockBeanService;
    }

    @Autowired
    public void setAgencyService(AgencyService agencyService) {
        _agencyService = agencyService;
    }

    @Autowired
    public void setBlockStatusBeanService(BlockStatusBeanService blockStatusBeanService) {
        _blockStatusBeanService = blockStatusBeanService;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    @RequestMapping(value = "/vehicle-location-simulation.do", method = RequestMethod.GET)
    public ModelAndView index() {
        List<VehicleLocationSimulationSummary> simulations = _vehicleLocationSimulationService.getSimulations();
        return new ModelAndView("vehicle-location-simulation.jspx", "simulations", simulations);
    }

    @RequestMapping(value = "/vehicle-location-simulation!set-calendar-offset.do", method = RequestMethod.GET)
    public ModelAndView setCalendarOffser(HttpSession session,
            @RequestParam(required = false) String calendarOffset) {
        if (calendarOffset != null)
            session.setAttribute(CALENDAR_OFFSET_KEY, calendarOffset);
        else
            session.removeAttribute(CALENDAR_OFFSET_KEY);
        return new ModelAndView("redirect:/vehicle-location-simulation.do");
    }

    @RequestMapping(value = "/vehicle-location-simulation!upload-trace.do", method = RequestMethod.POST)
    public ModelAndView uploadTrace(@RequestParam("file") MultipartFile file,
            @RequestParam(value = "realtime", required = false, defaultValue = "false") boolean realtime,
            @RequestParam(value = "pauseOnStart", required = false, defaultValue = "false") boolean pauseOnStart,
            @RequestParam(value = "shiftStartTime", required = false, defaultValue = "false") boolean shiftStartTime,
            @RequestParam(value = "minimumRecordInterval", required = false, defaultValue = "0") int minimumRecordInterval,
            @RequestParam(value = "traceType", required = true) String traceType,
            @RequestParam(required = false, defaultValue = "false") boolean bypassInference,
            @RequestParam(required = false, defaultValue = "false") boolean fillActualProperties,
            @RequestParam(value = "loop", required = false, defaultValue = "false") boolean loop,
            @RequestParam(required = false, defaultValue = "false") boolean returnId) throws IOException {

        int taskId = -1;

        if (!file.isEmpty()) {

            String name = file.getOriginalFilename();
            InputStream in = file.getInputStream();

            if (name.endsWith(".gz"))
                in = new GZIPInputStream(in);

            taskId = _vehicleLocationSimulationService.simulateLocationsFromTrace(traceType, in, realtime,
                    pauseOnStart, shiftStartTime, minimumRecordInterval, bypassInference, fillActualProperties,
                    loop);
        }

        if (returnId) {
            return new ModelAndView("vehicle-location-simulation-taskId.jspx", "taskId", taskId);
        } else {
            return new ModelAndView("redirect:/vehicle-location-simulation.do");
        }
    }

    @RequestMapping(value = "/vehicle-location-simulation!toggle.do", method = RequestMethod.GET)
    public ModelAndView toggle(@RequestParam() int taskId) {
        _vehicleLocationSimulationService.toggleSimulation(taskId);
        return new ModelAndView("redirect:/vehicle-location-simulation.do");
    }

    @RequestMapping(value = "/vehicle-location-simulation!step.do", method = RequestMethod.GET)
    public ModelAndView step(@RequestParam() int taskId) {
        _vehicleLocationSimulationService.stepSimulation(taskId);
        return new ModelAndView("redirect:/vehicle-location-simulation.do");
    }

    @RequestMapping(value = "/vehicle-location-simulation!restart.do", method = RequestMethod.GET)
    public ModelAndView restart(@RequestParam() int taskId) {
        _vehicleLocationSimulationService.restartSimulation(taskId);
        return new ModelAndView("redirect:/vehicle-location-simulation.do");
    }

    @RequestMapping(value = "/vehicle-location-simulation!step-to.do", method = RequestMethod.GET)
    public ModelAndView stepTo(@RequestParam() int taskId, @RequestParam() int recordIndex) {
        _vehicleLocationSimulationService.stepSimulation(taskId, recordIndex);
        return new ModelAndView("redirect:/vehicle-location-simulation.do");
    }

    @RequestMapping(value = "/vehicle-location-simulation!cancel.do", method = RequestMethod.GET)
    public ModelAndView cancel(@RequestParam() int taskId) {
        _vehicleLocationSimulationService.cancelSimulation(taskId);
        return new ModelAndView("redirect:/vehicle-location-simulation.do");
    }

    @RequestMapping(value = "/vehicle-location-simulation!cancelAll.do", method = RequestMethod.GET)
    public ModelAndView cancelAll() {
        _vehicleLocationSimulationService.cancelAllSimulations();
        return new ModelAndView("redirect:/vehicle-location-simulation.do");
    }

    @RequestMapping(value = "/vehicle-location-simulation!task-summary.do", method = RequestMethod.GET)
    public ModelAndView taskData(@RequestParam() int taskId) {

        VehicleLocationSimulationSummary summary = _vehicleLocationSimulationService.getSimulation(taskId);
        return new ModelAndView("json", "summary", summary);
    }

    @RequestMapping(value = "/vehicle-location-simulation!task-details.do", method = RequestMethod.GET)
    public ModelAndView taskDetails(@RequestParam() int taskId,
            @RequestParam(required = false, defaultValue = "0") int historyOffset,
            @RequestParam(required = false, defaultValue = "false") boolean showSampledParticles) {

        VehicleLocationDetails details = _vehicleLocationSimulationService.getSimulationDetails(taskId,
                historyOffset);
        Map<String, Object> m = new HashMap<String, Object>();
        m.put("details", details);
        m.put("historyOffset", historyOffset);
        m.put("showSampledParticles", showSampledParticles);
        return new ModelAndView("vehicle-location-simulation-task-details.jspx", m);
    }

    @RequestMapping(value = "/vehicle-location-simulation!particle-details.do", method = RequestMethod.GET)
    public ModelAndView particleDetails(@RequestParam() int taskId, @RequestParam() int particleId) {

        VehicleLocationDetails details = _vehicleLocationSimulationService.getParticleDetails(taskId, particleId);
        return new ModelAndView("vehicle-location-simulation-task-details.jspx", "details", details);
    }

    @RequestMapping(value = "/vehicle-location-simulation!task-simulation-records.do", method = RequestMethod.GET)
    public void taskRecords(@RequestParam() int taskId, HttpServletResponse response) throws IOException {

        List<NycTestLocationRecord> records = _vehicleLocationSimulationService.getSimulationRecords(taskId);
        writeRecordsToOutput(response, records);
    }

    @RequestMapping(value = "/vehicle-location-simulation!task-result-records.do", method = RequestMethod.GET)
    public void taskParticles(@RequestParam() int taskId, HttpServletResponse response) throws IOException {

        List<NycTestLocationRecord> records = _vehicleLocationSimulationService.getResultRecords(taskId);
        writeRecordsToOutput(response, records);
    }

    @RequestMapping(value = "/vehicle-location-simulation!active-blocks.do", method = RequestMethod.GET)
    public ModelAndView activeBlocks(HttpSession session, @RequestParam(required = false) Date time) {

        List<BlockStatusBean> blocks = new ArrayList<BlockStatusBean>();

        time = getTime(session, time);

        for (String agencyId : _agencyService.getAllAgencyIds()) {
            ListBean<BlockStatusBean> beans = _blockStatusBeanService.getBlocksForAgency(agencyId, time.getTime());
            blocks.addAll(beans.getList());
        }

        Collections.sort(blocks, new BlockStatusBeanComparator());

        Map<String, Object> m = new HashMap<String, Object>();
        m.put("blocks", blocks);
        m.put("time", time);

        return new ModelAndView("vehicle-location-simulation-active-blocks.jspx", m);
    }

    @RequestMapping(value = "/vehicle-location-simulation!block.do", method = RequestMethod.GET)
    public ModelAndView block(@RequestParam String blockId, @RequestParam long serviceDate) {

        AgencyAndId id = AgencyAndIdLibrary.convertFromString(blockId);
        BlockBean block = _blockBeanService.getBlockForId(id);

        List<VehicleLocationSimulationSummary> simulations = _vehicleLocationSimulationService
                .getSimulationsForBlockInstance(id, serviceDate);

        Map<String, Object> model = new HashMap<String, Object>();
        model.put("block", block);
        model.put("serviceDate", serviceDate);
        model.put("simulations", simulations);
        return new ModelAndView("vehicle-location-simulation-block.jspx", model);
    }

    @RequestMapping(value = "/vehicle-location-simulation!block-add-simulation.do", method = RequestMethod.POST)
    public ModelAndView addBlockSimulation(HttpSession session, @RequestParam String blockId,
            @RequestParam long serviceDate,
            @RequestParam(required = false, defaultValue = "false") boolean bypassInference,
            @RequestParam(required = false, defaultValue = "false") boolean fillActualProperties,
            @RequestParam String properties) throws IOException {

        Date time = getTime(session, null);

        Properties props = new Properties();
        props.load(new StringReader(properties));

        AgencyAndId id = AgencyAndIdLibrary.convertFromString(blockId);

        _vehicleLocationSimulationService.addSimulationForBlockInstance(id, serviceDate, time.getTime(),
                bypassInference, fillActualProperties, props);

        Map<String, Object> model = new HashMap<String, Object>();
        model.put("blockId", blockId);
        model.put("serviceDate", serviceDate);
        return new ModelAndView("redirect:/vehicle-location-simulation!block.do", model);
    }

    /****
     * Private Methods
     ****/

    private void writeRecordsToOutput(HttpServletResponse response, List<NycTestLocationRecord> records)
            throws IOException {

        CsvEntityWriterFactory factory = new CsvEntityWriterFactory();
        OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream());

        EntityHandler handler = factory.createWriter(NycTestLocationRecord.class, writer);

        if (records == null)
            records = Collections.emptyList();

        for (NycTestLocationRecord record : records)
            handler.handleEntity(record);

        writer.close();
    }

    private Date getTime(HttpSession session, Date time) {

        if (time == null)
            time = new Date();

        String calendarOffset = (String) session.getAttribute(CALENDAR_OFFSET_KEY);

        if (calendarOffset != null) {

            Matcher m = CALENDAR_OFFSET_PATTERN.matcher(calendarOffset);
            if (m.matches()) {

                int amount = Integer.parseInt(m.group(1));
                String type = m.group(2);

                Calendar c = Calendar.getInstance();
                c.setTime(time);

                if (type.equals("M"))
                    c.add(Calendar.MONTH, amount);
                else if (type.equals("w"))
                    c.add(Calendar.WEEK_OF_YEAR, amount);
                else if (type.equals("d"))
                    c.add(Calendar.DAY_OF_YEAR, amount);
                else if (type.equals("h"))
                    c.add(Calendar.HOUR, amount);
                time = c.getTime();
            }
        }

        return time;
    }

    private static class BlockStatusBeanComparator implements Comparator<BlockStatusBean> {

        @Override
        public int compare(BlockStatusBean o1, BlockStatusBean o2) {

            String r1 = getRouteShortName(o1);
            String r2 = getRouteShortName(o2);

            int rc = r1.compareTo(r2);
            if (rc != 0)
                return rc;

            String headsign1 = getTripHeadsign(o1);
            String headsign2 = getTripHeadsign(o2);

            rc = headsign1.compareTo(headsign2);
            if (rc != 0)
                return rc;

            double d1 = o1.computeBestDistanceAlongBlock();
            double d2 = o2.computeBestDistanceAlongBlock();

            return Double.compare(d1, d2);
        }

        private String getRouteShortName(BlockStatusBean bean) {
            BlockTripBean activeTrip = bean.getActiveTrip();
            TripBean trip = activeTrip.getTrip();
            if (trip.getRouteShortName() != null)
                return trip.getRouteShortName();
            RouteBean route = trip.getRoute();
            return route.getShortName();
        }

        private String getTripHeadsign(BlockStatusBean bean) {
            BlockTripBean activeTrip = bean.getActiveTrip();
            TripBean trip = activeTrip.getTrip();
            if (trip.getTripHeadsign() != null)
                return trip.getTripHeadsign();
            RouteBean route = trip.getRoute();
            return route.getLongName();
        }
    }
}