Java tutorial
/******************************************************************************* * Copyright 2012-2013 Trento RISE * * 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 eu.trentorise.smartcampus.mobility.service; import java.io.InputStream; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import javax.annotation.PostConstruct; import javax.annotation.Resource; import org.codehaus.jackson.map.DeserializationConfig.Feature; import org.codehaus.jackson.map.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import eu.trentorise.smartcampus.mobility.controller.extensions.PlanningPolicy; import eu.trentorise.smartcampus.mobility.controller.extensions.PlanningRequest; import eu.trentorise.smartcampus.mobility.controller.extensions.compilable.CompilablePolicy; import eu.trentorise.smartcampus.mobility.controller.extensions.compilable.CompilablePolicyData; import eu.trentorise.smartcampus.mobility.storage.DomainStorage; import eu.trentorise.smartcampus.mobility.util.HTTPConnector; import eu.trentorise.smartcampus.network.JsonUtils; import it.sayservice.platform.smartplanner.data.message.Itinerary; import it.sayservice.platform.smartplanner.data.message.SimpleLeg; import it.sayservice.platform.smartplanner.data.message.TType; import it.sayservice.platform.smartplanner.data.message.Transport; import it.sayservice.platform.smartplanner.data.message.alerts.Alert; import it.sayservice.platform.smartplanner.data.message.alerts.AlertAccident; import it.sayservice.platform.smartplanner.data.message.alerts.AlertDelay; import it.sayservice.platform.smartplanner.data.message.alerts.AlertParking; import it.sayservice.platform.smartplanner.data.message.alerts.AlertRoad; import it.sayservice.platform.smartplanner.data.message.alerts.AlertStrike; import it.sayservice.platform.smartplanner.data.message.journey.RecurrentJourney; import it.sayservice.platform.smartplanner.data.message.journey.RecurrentJourneyParameters; import it.sayservice.platform.smartplanner.data.message.journey.SingleJourney; import it.sayservice.platform.smartplanner.data.message.otpbeans.BikeStation; import it.sayservice.platform.smartplanner.data.message.otpbeans.GeolocalizedStopRequest; import it.sayservice.platform.smartplanner.data.message.otpbeans.Stop; /** * @author raman * */ @Component public class SmartPlannerService implements SmartPlannerHelper { private static final String STATION_NOT_PRESENT_IN_REPOSITORY = "station not present in repository"; @Autowired @Value("${smartplanner.router}") private String smartplannerRouter; private static final String DUMMY = "Nessuna"; private static final String DEFAULT = "default"; private String SMARTPLANNER; private String OTP; private static final String PLAN = "plan"; private static final String RECURRENT = "recurrentJourney"; @Autowired @Value("${otp.url}") private String otpURL; private static ObjectMapper mapper = new ObjectMapper(); static { mapper.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); } @Resource(name = "basicPoliciesMap") private Map<String, PlanningPolicy> policiesMap; @Autowired private ExecutorService executorService; @Autowired private DomainStorage storage; private static final Logger logger = LoggerFactory.getLogger(SmartPlannerService.class); @PostConstruct public void init() { SMARTPLANNER = "/smart-planner/" + smartplannerRouter + "/rest/"; OTP = "/smart-planner/" + smartplannerRouter + "/rest/"; } @Override public Map<String, PlanningPolicy> getPolicies(Boolean draft) { Map<String, PlanningPolicy> result = Maps.newHashMap(); //newHashMap(policiesMap); result.putAll(getStoredPolicies(draft)); return result; } private Map<String, PlanningPolicy> getStoredPolicies(Boolean draft) { Map<String, PlanningPolicy> result = Maps.newTreeMap(); Criteria criteria = new Criteria(); if (draft != null) { criteria.and("draft").is(draft); } List<CompilablePolicyData> compilable = storage.searchDomainObjects(criteria, CompilablePolicyData.class); for (CompilablePolicyData policy : compilable) { result.put(policy.getPolicyId(), new CompilablePolicy(policy)); } return result; } private PlanningPolicy getPlanningPolicy(String policyId, Boolean draft) { PlanningPolicy policy = policiesMap.get(policyId); if (policy == null) { Map<String, PlanningPolicy> stored = getStoredPolicies(draft); policy = stored.get(policyId); if (policy == null) { return policiesMap.get(DUMMY); } } return policy; } private String performGET(String request, String query) throws Exception { return HTTPConnector.doGet(otpURL + request, query, MediaType.APPLICATION_JSON_VALUE, null, "UTF-8"); } private String performPOST(String request, String body) throws Exception { return HTTPConnector.doPost(otpURL + request, body, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE); } @Override public String stopTimetable(String agencyId, String routeId, String stopId) throws Exception { return performGET(OTP + "gettimetable/" + agencyId + "/" + routeId + "/" + stopId, null); } @Override public String stopTimetable(String agencyId, String stopId, Integer maxResults) throws Exception { return performGET(OTP + "getlimitedtimetable/" + agencyId + "/" + stopId + "/" + maxResults, null); } @Override public String transitTimes(String agencyId, String routeId, Long from, Long to) throws Exception { return performGET(OTP + "getTransitTimes/" + agencyId + "/" + URLEncoder.encode(routeId, "utf8") + "/" + from + "/" + to, null); } @Override public String extendedTransitTimes(String agencyId, String routeId, Long from, Long to) throws Exception { return performGET(OTP + "getTransitTimes/" + agencyId + "/" + URLEncoder.encode(routeId, "utf8") + "/" + from + "/" + to + "/extended", null); } @Override public String delays(String agencyId, String routeId, Long from, Long to) throws Exception { return performGET(OTP + "getTransitDelays/" + agencyId + "/" + URLEncoder.encode(routeId, "utf8") + "/" + from + "/" + to, null); } @Override public RecurrentJourney planRecurrent(RecurrentJourneyParameters parameters) throws Exception { List<String> reqs = buildRecurrentJourneyPlannerRequest(parameters); List<SimpleLeg> legs = new ArrayList<SimpleLeg>(); for (String req : reqs) { String plan = performGET(SMARTPLANNER + RECURRENT, req); List<?> sl = mapper.readValue(plan, List.class); for (Object o : sl) { legs.add(mapper.convertValue(o, SimpleLeg.class)); } } RecurrentJourney journey = new RecurrentJourney(); journey.setParameters(parameters); journey.setLegs(legs); journey.setMonitorLegs(buildMonitorMap(legs)); return journey; } private List<String> buildRecurrentJourneyPlannerRequest(RecurrentJourneyParameters request) { List<String> reqs = new ArrayList<String>(); for (TType type : request.getTransportTypes()) { String rec = request.getRecurrence().toString().replaceAll("[\\[\\] ]", ""); String req = String.format( "recurrence=%s&from=%s&to=%s&time=%s&interval=%s&transportType=%s&routeType=%s&fromDate=%s&toDate=%s&numOfItn=%s", rec, request.getFrom().toLatLon(), request.getTo().toLatLon(), request.getTime(), request.getInterval(), type, request.getRouteType(), request.getFromDate(), request.getToDate(), request.getResultsNumber()); reqs.add(req); } return reqs; } private Map<String, Boolean> buildMonitorMap(List<SimpleLeg> legs) { Map<String, Boolean> result = new TreeMap<String, Boolean>(); for (SimpleLeg leg : legs) { Transport transport = leg.getTransport(); if (transport.getType() != TType.BUS && transport.getType() != TType.TRAIN) { continue; } String id = transport.getAgencyId() + "_" + transport.getRouteId(); if (!result.containsKey(id)) { result.put(id, true); } } return result; } @Override public RecurrentJourney replanRecurrent(RecurrentJourneyParameters parameters, RecurrentJourney oldJourney) throws Exception { List<String> reqs = buildRecurrentJourneyPlannerRequest(parameters); List<SimpleLeg> legs = new ArrayList<SimpleLeg>(); for (String req : reqs) { String plan = performGET(SMARTPLANNER + RECURRENT, req); List<?> sl = mapper.readValue(plan, List.class); for (Object o : sl) { legs.add((SimpleLeg) mapper.convertValue(o, SimpleLeg.class)); } } RecurrentJourney journey = new RecurrentJourney(); journey.setParameters(parameters); journey.setLegs(legs); journey.setMonitorLegs(buildMonitorMap(legs, oldJourney.getMonitorLegs())); return journey; } private Map<String, Boolean> buildMonitorMap(List<SimpleLeg> legs, Map<String, Boolean> old) { Map<String, Boolean> result = new TreeMap<String, Boolean>(); for (SimpleLeg leg : legs) { Transport transport = leg.getTransport(); if (transport.getType() != TType.BUS && transport.getType() != TType.TRAIN) { continue; } String id = transport.getAgencyId() + "_" + transport.getRouteId(); if (!result.containsKey(id)) { if (old.containsKey(id)) { result.put(id, old.get(id)); } else { result.put(id, true); } } } return result; } @Override public String parkingsByAgency(String agencyId) throws Exception { return performGET(SMARTPLANNER + "getParkingsByAgency?agencyId=" + agencyId, null); } @Override public String bikeStations() throws Exception { return performGET(SMARTPLANNER + "getBikeStations", null); } @Override public String bikeSharingByAgency(String agencyId) throws Exception { return performGET(SMARTPLANNER + "getBikeSharingByAgency?agencyId=" + agencyId, null); } @Override public void addBikeSharingStations(List<BikeStation> stations) throws Exception { String body = mapper.writeValueAsString(stations); performPOST(SMARTPLANNER + "data/bikesharing", body); } @Override public String roadInfoByAgency(String agencyId, Long from, Long to) throws Exception { return performGET(SMARTPLANNER + "getAR?agencyId=" + agencyId + "&from=" + from + "&to=" + to, null); } @Override public String routes(String agencyId) throws Exception { return performGET(OTP + "getroutes/" + agencyId, null); } @Override public String stops(String agencyId, String routeId) throws Exception { return performGET(OTP + "getstops/" + agencyId + "/" + routeId, null); } @Override public String stops(String agencyId, String routeId, double latitude, double longitude, double radius) throws Exception { return performGET( OTP + "getstops/" + agencyId + "/" + routeId + "/" + latitude + "/" + longitude + "/" + radius, null); } @Override public List<Stop> stops(String agencyId, double lat, double lng, double radius, Integer page, Integer count) throws Exception { GeolocalizedStopRequest gsr = new GeolocalizedStopRequest(); gsr.setAgencyId(agencyId); gsr.setCoordinates(new double[] { lat, lng }); gsr.setRadius(radius); gsr.setPageSize(count == null ? 100 : count); gsr.setPageNumber(page == null ? 0 : page); ObjectMapper mapper = new ObjectMapper(); String content = mapper.writeValueAsString(gsr); String res = performPOST(OTP + "getGeolocalizedStops", content); return JsonUtils.toObjectList(res, Stop.class); } @Override public synchronized List<Itinerary> planSingleJourney(SingleJourney journeyRequest, String policyId) throws Exception { // TODO: final only? draft? PlanningPolicy planningPolicy = getPlanningPolicy(policyId, null); List<PlanningRequest> planRequests = planningPolicy.generatePlanRequests(journeyRequest); List<PlanningRequest> successfulPlanRequests = Lists.newArrayList(); int iteration = 0; do { List<Future<PlanningRequest>> results = Lists.newArrayList(); for (PlanningRequest pr : planRequests) { CallablePlanningRequest callableReq = new CallablePlanningRequest(); callableReq.setRequest(pr); Future<PlanningRequest> future = executorService.submit(callableReq); results.add(future); } for (Future<PlanningRequest> plan : results) { PlanningRequest pr = plan.get(); List<?> its = mapper.readValue(pr.getPlan(), List.class); for (Object it : its) { Itinerary itinerary = mapper.convertValue(it, Itinerary.class); pr.getItinerary().add(itinerary); itinerary.setPromoted(pr.isPromoted()); } } List<PlanningRequest> evaluated = planningPolicy.evaluatePlanResults(planRequests); successfulPlanRequests.addAll(evaluated); iteration++; for (PlanningRequest pr : planRequests) { pr.setIteration(iteration); } } while (!planRequests.isEmpty() && iteration < 2); List<Itinerary> itineraries = planningPolicy.extractItinerariesFromPlanResults(journeyRequest, successfulPlanRequests); List<Itinerary> sortedItineraries = planningPolicy.filterAndSortItineraries(journeyRequest, itineraries); return sortedItineraries; } private class CallablePlanningRequest implements Callable<PlanningRequest> { private PlanningRequest request; public void setRequest(PlanningRequest req) { this.request = req; } @Override public PlanningRequest call() throws Exception { try { String plan = performGET(SMARTPLANNER + PLAN, request.getRequest()); request.setPlan(plan); } catch (Exception e) { e.printStackTrace(); request.setPlan(null); } return request; } } @Override public void sendAlert(Alert alert) throws Exception { String req = mapper.writeValueAsString(alert); String param = null; if (alert instanceof AlertDelay) { param = "updateAD"; } else if (alert instanceof AlertAccident) { param = "updateAE"; } else if (alert instanceof AlertStrike) { param = "updateAS"; } else if (alert instanceof AlertParking) { param = "updateAP"; } else if (alert instanceof AlertRoad) { param = "updateAR"; } else { throw new IllegalArgumentException("Unknown alert type " + alert.getClass().getName()); } String result = HTTPConnector.doPost(otpURL + SMARTPLANNER + param, req, MediaType.TEXT_HTML_VALUE, MediaType.APPLICATION_JSON_VALUE); logger.info(result); processAlerResult(alert, result); } private void processAlerResult(Alert alert, String result) { if (result == null) { } else if (result.contains(STATION_NOT_PRESENT_IN_REPOSITORY)) { AlertParking ap = (AlertParking) alert; if (ap.getPlace() != null && ap.getPlace().getAgencyId() != null) { if (ap.getPlace().getAgencyId().contains("BIKE_SHARING")) { BikeStation bs = new BikeStation(ap.getPlace(), "BIKE-RENTAL", 0, 0, ap.getNoOfvehicles(), ap.getPlacesAvailable()); } } System.err.println(ap.getId() + " / " + ap.getDescription()); } } @Override public InputStream routesDB(String appId) throws Exception { return HTTPConnector.doStreamGet(otpURL + OTP + "routesDB/" + appId, null, "application/zip", null); } @Override public InputStream extendedRoutesDB(String appId) throws Exception { return HTTPConnector.doStreamGet(otpURL + OTP + "routesDB/" + appId + "/extended", null, "application/zip", null); } @Override public String getVersions() throws Exception { return performGET(OTP + "versions", null); } @Override public String getTaxiStations(double latitude, double longitude, double radius) throws Exception { String response = null; double defaultRadius = 500; if (latitude > -1 && longitude > -1) { if (radius > -1) { defaultRadius = radius; } response = performGET(SMARTPLANNER + "taxisNearPoint?lat=" + latitude + "&lon=" + longitude + "&radius=" + defaultRadius, null); } return response; } @Override public String getAllTaxiStations() throws Exception { String response = null; response = performGET(SMARTPLANNER + "taxis", null); return response; } @Override public String getTaxiAgencyContacts() throws Exception { String response = null; response = performGET(SMARTPLANNER + "taxi/contacts/", null); return response; } @Override public String getAgencyTaxiStations(String agencyId) throws Exception { String response = null; response = performGET(SMARTPLANNER + "taxis/" + agencyId, null); return response; } @Override public String getTaxiAgencyContacts(String agencyId) throws Exception { String response = null; response = performGET(SMARTPLANNER + "taxi/contacts/" + agencyId, null); return response; } @Override public InputStream gtfs(String agencyId) throws Exception { return HTTPConnector.doStreamGet(otpURL + SMARTPLANNER + "gtfs/" + agencyId, null, "application/zip", null); } }