Skip to content
Snippets Groups Projects
Commit cf30b031 authored by Théo PIRKL's avatar Théo PIRKL
Browse files

Merge branch 'devel' into 'master'

*poof* final version

See merge request !21
parents 2d5f1624 616a9c24
Branches
No related tags found
1 merge request!21*poof* final version
Showing
with 1550 additions and 5 deletions
......@@ -3,3 +3,8 @@
*.jar
target/
**/*.DS_Store
*.project
**.vscode/
*.classpath
**.settings
*.iml
\ No newline at end of file
# Travail Pratique 4
Un travail de Alexis Durgnat, Michael El Kharroubi, Quentin Leblanc et Théo Pirkl
## Description
Ce travail pratique consiste à proposer une application de réseau social permettant de savoir qui prend
quel transport public. Certaines intégrations y seront ajoutées.
......@@ -9,12 +8,31 @@ quel transport public. Certaines intégrations y seront ajoutées.
Voici un mockup de l'application :
![alt text](app.png)
## Compilation
L'application peut être compilée avec
```
mvn compile exec:java
```
Les tests sont exécutés avec
```
mvn test
```
## Utilisation
Lors du lancement de l'application, un champs demande le nom d'utilisateur. Après avoir entré celui-ci, l'application principale s'ouvre.
Il est possible de chercher une correspondance grâce à la barre supérieure. La première combobox est le départ, la seconde la destinations.
Après avoir sélectionné le point de départ et d'arriver, un clic sur "Itinéraires" permet d'afficher les prochaines correspondances disponibles.
La barre latérale droite contient les notifications et messages des utilisateurs connectés. Il est possible d'envoyer un message à tout le monde
grâce au champ textuel en dessous.
## Technique
Nous implémentons :
* L'API OpenData Transport [(disponible ici)](https://transport.opendata.ch)
* L'API Prévisions-Météo.ch [(disponible ici)](https://www.prevision-meteo.ch/uploads/pdf/recuperation-donnees-meteo.pdf)
* Une interface graphique avec JavaFX, liée à un WebEngine
* D'autres trucs (?)
* Une interface graphique avec JavaFX
* Un chat :cat:
* Quelques surprises... :wink:
## Intégration
Merci de suivre au possible le système suivant :
......
......@@ -12,7 +12,87 @@
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<!-- JUnit -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<!-- Java FX -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
<!-- Rabbit MQ -->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.5.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>ch.hepia.Main</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<excludes>
<exclude>some test to exclude</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package ch.hepia;
import ch.hepia.config.AppConfig;
import ch.hepia.config.AppContext;
import ch.hepia.mq.MessageManager;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
/**
* Starts up the app.
*/
public class Main extends Application {
private static AppContext appContext;
/**
* Main starter
* @param args The passed arguments
*/
public static void main(String[] args) throws Exception {
MessageManager m = new MessageManager(
AppConfig.RABBITMQ_HOSTNAME, AppConfig.RABBITMQ_USERNAME, AppConfig.RABBITMQ_PASSWORD,
AppConfig.RABBITMQ_EXCHANGE
);
appContext = new AppContext(m);
launch(args);
}
/**
* Starts up the JavaFX app.
* @param stage The stage to start
* @throws IOException When goofed up with JavaFX
*/
@Override
public void start(Stage stage) throws IOException {
Parent root = FXMLLoader.load(Main.class.getResource("/fxml/ConnectionWindow.fxml"));
Scene scene = new Scene(root, AppConfig.APP_WIDTH, AppConfig.APP_HEIGHT);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
stage.setTitle(AppConfig.APP_NAME);
stage.setOnCloseRequest(t -> {
Platform.exit();
try {
appContext.getMessageManager().close();
} catch (Exception e){
System.exit(1);
}
System.exit(0);
});
}
/**
* Gets the app context of the app
* @return the app context of the app
*/
public static AppContext getContext(){
return appContext;
}
}
package ch.hepia.api;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HTTPUtils {
/**
* Fetch datas with an http GET request on the form of a string given the url path
* @param path
* @return content
* @throws IOException
*/
public static String getContent(String path) throws IOException {
URL url = new URL(path);
HttpURLConnection http = (HttpURLConnection) url.openConnection();
http.setRequestMethod("GET");
http.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(http.getInputStream()));
String line;
StringBuilder content = new StringBuilder();
while((line = reader.readLine()) != null){
content.append(line);
}
reader.close();
http.disconnect();
return content.toString();
}
}
package ch.hepia.api.transport;
import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.Serializable;
public class Connection implements Serializable {
private static final long serialVersionUID = 0xAEF55565673L;
private Stop from;
private Stop to;
private Time duration;
private Service service;
private List<String> products;
private int capacity1st;
private int capacity2nd;
private List<Section> sections;
/**
* Empty Connection
*/
public final static class EmptyConnection extends Connection{
private static final long serialVersionUID = 0xAEF55565672L;
/**
* Constructor of EmptyConnection All values are default ones An Empty
* Connection go from Geneva to Geneva
*
* @throws ParseException
*/
public EmptyConnection() throws ParseException {
super(new Stop.StopBuilder(new JSONObject()).build(),
new Stop.StopBuilder(new JSONObject()).build(),
new Time(new SimpleDateFormat("dd:kk:mm:ss").parse("00:00:00:00").getTime()),
new Service.ServiceBuilder(new JSONObject()).build(), new ArrayList<>(), 0, 0, new ArrayList<>());
}
}
/**
* Constructor of Connection Object
*
* @param from stop object
* @param to stop object
* @param duration time of the connection
* @param service how regular is the connection
* @param products list the products you have to purchase for this connection
* @param capacity1st number of seats in 1st class
* @param capacity2nd number of seats in 2nd class
* @param sections Where the connection will go through
*/
private Connection(Stop from, Stop to, Time duration, Service service, List<String> products, int capacity1st,
int capacity2nd, List<Section> sections) {
this.from = from;
this.to = to;
this.duration = duration;
this.service = service;
this.products = new ArrayList<>(products);
this.capacity1st = capacity1st;
this.capacity2nd = capacity2nd;
this.sections = new ArrayList<>(sections);
}
public Section getInCommonSection(Connection connection) throws ParseException {
for (Section section : this.sections) {
if (connection.sections.contains(section)) {
return section;
}
}
return Section.empty();
}
/**
* Get all the sections of the connection
*
* @return A list of Section objects
*/
public List<Section> getSections() {
return new ArrayList<>(sections);
}
public Stop getFrom() {
return this.from;
}
public Stop getTo() {
return this.to;
}
/**
* Builder of Connection object
*/
public final static class ConnectionBuilder {
private JSONObject datas;
/**
* Constructor of the class ConnectionBuilder Stock Datas from a JSON object
* given
*
* @param datas contains datas to construct a Connection object
*/
public ConnectionBuilder(JSONObject datas) {
this.datas = datas;
}
/**
* Build a Connection object from the datas obtained
*
* @return a new Connection object
* @throws ParseException
*/
public Connection build() throws ParseException {
// if the datas retrieved contain nothing, we have to prevent errors
if (datas.isEmpty()) {
return new EmptyConnection();
}
JSONObject fromJSON = datas.isNull("from") ? new JSONObject() : datas.getJSONObject("from");
Stop.StopBuilder from = new Stop.StopBuilder(fromJSON);
JSONObject toJSON = datas.isNull("to") ? new JSONObject() : datas.getJSONObject("to");
Stop.StopBuilder to = new Stop.StopBuilder(toJSON);
DateFormat formatter = new SimpleDateFormat("dd:kk:mm:ss");
String date = datas.isNull("duration") ? "00:00:00:00" : datas.getString("duration").replace('d', ':');
Time duration = new Time(formatter.parse(date).getTime());
JSONObject serviceJSON = datas.isNull("service") ? new JSONObject() : new JSONObject(datas.get("service"));
Service.ServiceBuilder service = new Service.ServiceBuilder(serviceJSON);
JSONArray productsJSON = datas.isNull("from") ? new JSONArray() : datas.getJSONArray("products");
List<String> products = new ArrayList<>();
productsJSON.forEach(k -> products.add(k.toString()));
int capacity1st = datas.isNull("capacity1st") ? 0 : datas.getInt("capacity1st");
int capacity2nd = datas.isNull("capacity2nd") ? 0 : datas.getInt("capacity2nd");
JSONArray sectionsJSON = datas.isNull("from") ? new JSONArray() : datas.getJSONArray("sections");
List<Section> sections = new ArrayList<>();
sectionsJSON.forEach(o -> {
JSONObject k = (JSONObject) o;
Section.SectionBuilder section = new Section.SectionBuilder(k);
try {
sections.add(section.build());
} catch (ParseException e) {
e.printStackTrace();
}
});
return new Connection(from.build(), to.build(), duration, service.build(), products, capacity1st,
capacity2nd, sections);
}
}
}
package ch.hepia.api.transport;
import org.json.JSONObject;
import java.io.Serializable;
public class Coordinates implements Serializable {
private static final long serialVersionUID = 0xFFF34565673L;
private String type;
private double x;
private double y;
/**
* Default coordinates containing default values (Geneva is the default value)
* WGS84 is the default type value
*/
private final static class DefaultCoordinates extends Coordinates{
private static final long serialVersionUID = 0xFFF34565670L;
/**
* Constructor of DefaultCoordinates, located in Geneva
*/
private DefaultCoordinates(){
super("WGS84", 46.210237, 6.142422);
}
}
/**
* Constructor of the class Coordinates
* A coordinates is represented by a type of place and a point (x, y)
* @param type type of place we are a these coordinates
* @param x coordinate in x
* @param y coordinate in y
*/
private Coordinates(String type, double x, double y){
this.type = type;
this.x = x;
this.y = y;
}
@Override
public String toString(){
StringBuilder string = new StringBuilder();
return string.append("Coordonnées du type ").append(type).append(" au point (").append(x).append(", ").append(y).append(")").toString();
}
/**
* Get the x coordinate of the place (x, y)
* @return x
*/
public double getX(){
return x;
}
/**
* Get the y coordinate of the place (x, y)
* @return y
*/
public double getY(){
return y;
}
@Override
public boolean equals(Object o){
if (this == o) {
return true;
}
if (o == null || o.getClass() != this.getClass()) {
return false;
}
Coordinates c = (Coordinates) o;
return c.type.equals(this.type) &&
Math.abs(c.x - this.x) < Math.pow(10, -6) &&
Math.abs(c.y - this.y) < Math.pow(10, -6);
}
/**
* Builder of Coordinates object
*/
public final static class CoordinatesBuilder{
private JSONObject datas;
private String type;
/**
* Constructor of the class CoordinatesBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Coordinates object
*/
public CoordinatesBuilder(JSONObject datas, String type){
this.datas = datas;
this.type = type;
}
/**
* Build a Coordinates object from the datas obtained
* @return a new Coordinates object
*/
public Coordinates build(){
if(datas.isEmpty()){
return new DefaultCoordinates();
}
String type = datas.getString("type");
double x = datas.isNull("x") ? 0 : datas.getDouble("x");
double y = datas.isNull("y") ? 0 : datas.getDouble("y");
return new Coordinates(type, x, y);
}
}
}
package ch.hepia.api.transport;
import org.json.JSONArray;
import org.json.JSONObject;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.io.Serializable;
public class Journey implements Serializable {
private static final long serialVersionUID = 0xCBF34565673L;
private String name;
private String category;
private int categoryCode;
private String number;
private String operator;
private String to;
private List<Stop> passList;
private int capacity1st;
private int capacity2nd;
/**
* Empty Journey
*/
public final static class EmptyJourney extends Journey{
private static final long serialVersionUID = 0xCBF34565670L;
/**
* Constructor of EmptyJourney
* No Information and no Stops in the Journey
* @throws ParseException
*/
private EmptyJourney() throws ParseException {
super("", "", 0, "", "", "",
new ArrayList<>(), 0, 0);
}
}
/**
* Constructor of the Journey Object
* @param name
* @param category what transport category the journey is
* @param categoryCode
* @param number
* @param operator which company operates the journey
* @param to destination of the journey
* @param passList Where the journey will pass through
* @param capacity1st number of seats inst class
* @param capacity2nd number of seats in nd class
*/
private Journey(String name, String category, int categoryCode, String number, String operator, String to, List<Stop> passList, int capacity1st, int capacity2nd){
this.name = name;
this.category = category;
this.categoryCode = categoryCode;
this.number = number;
this.operator = operator;
this.to = to;
this.passList = new ArrayList<>(passList);
this.capacity1st = capacity1st;
this.capacity2nd = capacity2nd;
}
/**
* Get the name of the journey
* @return name
*/
public String getName(){
return name;
}
/**
* Get the Category of the transport of the Journey
* @return category
*/
public String getCategory(){
return category;
}
/**
* Get the categoryCode affiliated with the Journey
* @return categoryCode
*/
public int getCategoryCode(){
return categoryCode;
}
/**
* Get where the Journey is headed to
* @return to
*/
public String getTo(){
return to;
}
/**
* Get the transport number
* @return number
*/
public String getNumber(){
return number;
}
/**
* Get all the Stops where the journey will pass through
* @return passList
*/
public List<Stop> getPassList(){
return new ArrayList<>(passList);
}
@Override
public boolean equals(Object o){
if (this == o) {
return true;
}
if (o == null || o.getClass() != this.getClass()) {
return false;
}
Journey j = (Journey) o;
return j.number.equals(this.number) && j.name.equals(this.name);
}
/**
* Builder of Journey object
*/
public final static class JourneyBuilder{
private JSONObject datas;
/**
* Constructor of the class JourneyBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Journey object
*/
public JourneyBuilder(JSONObject datas){
this.datas = datas;
}
/**
* Build a new Journey object from the datas obtained
* @return a new Journey Object
* @throws ParseException
*/
public Journey build() throws ParseException {
if(datas.isEmpty()){
return new EmptyJourney();
}
String name = datas.isNull("name") ? "" : datas.getString("name");
String category = datas.isNull("category") ? "" : datas.getString("category");
int categoryCode = datas.isNull("categoryCode") ? 0 : datas.getInt("categoryCode");
String number = datas.isNull("number") ? "" : datas.getString("number");
String operator = datas.isNull("operator") ? "" : datas.getString("operator");
String to = datas.isNull("to") ? "" : datas.getString("to");
JSONArray passListJSON = datas.isNull("from") ? new JSONArray() : datas.getJSONArray("passList");
List<Stop> passList = new ArrayList<>();
passListJSON.forEach( o -> {
JSONObject k = (JSONObject) o;
Stop.StopBuilder stop = new Stop.StopBuilder(k);
try {
passList.add(stop.build());
} catch (ParseException e) {
e.printStackTrace();
}
});
int capacity1st = datas.isNull("capacity1st") ? 0 : datas.getInt("capacity1st");
int capacity2nd = datas.isNull("capacity2nd") ? 0 : datas.getInt("capacity2nd");
return new Journey(name, category, categoryCode, number, operator, to, passList, capacity1st, capacity2nd);
}
}
}
package ch.hepia.api.transport;
import ch.hepia.api.HTTPUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class LinkAPI {
private String baseURL = "http://transport.opendata.ch/v1/";
/**
* Get the stations containing the string query in their names
* This return a List of Station type Location Objects
* @param query
* @return a Lis<Location>
* @throws IOException
*/
public List<Location> getStations(String query) throws IOException {
String path = baseURL + "locations?query=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
String content = HTTPUtils.getContent(path);
JSONArray stations = new JSONObject(content).getJSONArray("stations");
List<Location> stationsList = new ArrayList<>();
stations.forEach(o -> {
JSONObject k = (JSONObject) o;
Location l = new Location.LocationBuilder(k, "station").build();
stationsList.add(l);
});
return stationsList;
}
/**
* Get all the connections from an end point to another
* Return a List of Connection Objects
* @param from The origin
* @param to The destination
* @return a List<Connection>
* @throws IOException
*/
public List<Connection> getConnections(String from, String to) throws IOException {
String path = baseURL + "connections?from=" +
URLEncoder.encode(from, StandardCharsets.UTF_8) + "&to=" +
URLEncoder.encode(to, StandardCharsets.UTF_8);
String content = HTTPUtils.getContent(path);
JSONArray connections = new JSONObject(content).getJSONArray("connections");
List<Connection> connectionsList = new ArrayList<>();
connections.forEach(o->{
JSONObject k = (JSONObject) o;
try {
Connection c = new Connection.ConnectionBuilder(k).build();
connectionsList.add(c);
} catch(Exception e){
e.printStackTrace();
}
});
return connectionsList;
}
/**
* Get the Stationboard of the station given
* The StationBoard is a List of Journey Objects
* The limit is the maximum number of stations the Stationboard should fetch
* @param station The station to get
* @param limit The limit of transportations
* @return a List<Journey>
* @throws IOException
*/
public List<Journey> getStationBoard(String station, int limit) throws IOException {
String path = baseURL + "stationboard?station=" + URLEncoder.encode(station, StandardCharsets.UTF_8);
if(limit != 0){
path += "&limit=" + limit;
}
String content = HTTPUtils.getContent(path);
JSONArray journeys = new JSONObject(content).getJSONArray("stationboard");
List<Journey> journeysList = new ArrayList<>();
journeys.forEach(o->{
JSONObject k = (JSONObject) o;
try {
Journey j = new Journey.JourneyBuilder(k).build();
journeysList.add(j);
} catch(Exception e){
e.printStackTrace();
}
});
return journeysList;
}
}
package ch.hepia.api.transport;
import org.json.JSONObject;
import java.io.Serializable;
public class Location implements Serializable {
private static final long serialVersionUID = 0xAEF84565673L;
private int id;
private Type type;
private String name;
private double score;
private Coordinates where;
private double distance;
/**
* Default Location
*/
private final static class DefaultLocation extends Location{
private static final long serialVersionUID = 0xAEF84565670L;
/**
* Constructor of DefaultLocation, centered in Geneva
* Type is REFINE, because it's a default choice
*/
private DefaultLocation(){
//here building new empty coordinates will return a default coordinates corresponding to Geneva
super(8501008, Type.REFINE, "Genève", 0, new Coordinates.CoordinatesBuilder(new JSONObject(), "refine").build(), 0);
}
}
/**
* Constructor of the class Location
* @param id unique to the Location
* @param type type of place the Location is
* @param name
* @param score accuracy of the result (may not be used)
* @param where Localisation of the Location
* @param distance distance to the Location if there has been Coordinates (may not be used)
*/
private Location(int id, Type type, String name, double score, Coordinates where, double distance){
this.id = id;
this.type = type;
this.name = name;
this.score = score;
this.where = where;
this.distance = distance;
}
/**
* Get the coordinates of the Location
* @return where
*/
public Coordinates getCoordinates(){
return where;
}
/**
* Get the name of the location
* @return what
*/
public String getName(){
return name;
}
@Override
public boolean equals(Object o){
if (this == o) {
return true;
}
if (o == null || o.getClass() != this.getClass()) {
return false;
}
Location l = (Location) o;
return l.type.equals(this.type) &&
l.id == this.id &&
l.name.equals(this.name) &&
l.where.equals(this.where);
}
/**
* Builder of Location objects
*/
public final static class LocationBuilder{
private JSONObject datas;
private String type;
/**
* Constructor of the class LocationBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Locatiop object
*/
public LocationBuilder(JSONObject datas, String type){
this.datas = datas;
this.type = type;
}
/**
* Build a Location object with the datas obtained
* @return a new Location object
*/
public Location build(){
if(datas.isEmpty()){
return new DefaultLocation();
}
int id = datas.isNull("id") ? 0 : datas.getInt("id");
Type type = Type.valueOf(this.type.toUpperCase());
String name = datas.isNull("name") ? "" : datas.getString("name");
double score = datas.isNull("score") ? 0 : datas.getDouble("score");
JSONObject coordinatesJSON = datas.isNull("coordinate") ? new JSONObject() : datas.getJSONObject("coordinate");
Coordinates.CoordinatesBuilder coordinates = new Coordinates.CoordinatesBuilder(coordinatesJSON, this.type);
double distance = datas.isNull("distance") ? 0 : datas.getDouble("distance");
return new Location(id, type, name, score, coordinates.build(), distance);
}
}
}
package ch.hepia.api.transport;
import org.json.JSONObject;
import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.io.Serializable;
public class Prognosis implements Serializable {
private static final long serialVersionUID = 0xAE034565673L;
private int plateform;
private Time departure;
private Time arrival;
private int capacity1st;
private int capacity2nd;
/**
* Empty Prognosis
*/
private final static class EmptyPrognosis extends Prognosis{
private static final long serialVersionUID = 0xAE034565670L;
/**
* Constructor of EmptyPrognosis
* No departure and no Arrival Time
* No information on the capacity of 1st and 2nd class nor on the plateform
* @throws ParseException
*/
private EmptyPrognosis() throws ParseException {
super(0,
new Time(new SimpleDateFormat("dd:kk:mm:ss").parse("00:00:00:00").getTime()),
new Time(new SimpleDateFormat("dd:kk:mm:ss").parse("00:00:00:00").getTime()),
0, 0);
}
}
/**
* Constructor of the Prognosis class
* A Prognosis contains information on the status of a Stop Object
* @param plateform plateform where the transport should arrive and leave
* @param departure time of departure
* @param arrival time of arrival
* @param capacity1st number of seats in 1st class
* @param capacity2nd number of seats in 2nd class
*/
private Prognosis(int plateform, Time departure, Time arrival, int capacity1st, int capacity2nd){
this.plateform = plateform;
this.departure = departure;
this.arrival = arrival;
this.capacity1st = capacity1st;
this.capacity2nd = capacity2nd;
}
/**
* Builder of Prognosis Objects
*/
public final static class PrognosisBuilder{
private JSONObject datas;
/**
* Constructor of the class PrognosisBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Prognosis object
*/
public PrognosisBuilder(JSONObject datas){
this.datas = datas;
}
/**
* Build a Prognosis object from the datas obtained
* @return a new Prognosis object
* @throws ParseException
*/
public Prognosis build() throws ParseException {
if(datas.isEmpty()){
return new EmptyPrognosis();
}
int plateform = datas.isNull("plateform") ? 0 : datas.getInt("plateform");
DateFormat formatter = new SimpleDateFormat("dd:kk:mm:ss");
String depatureString = datas.isNull("departure") ? "00:00:00:00" : datas.getString("departure").replace('d',':');
Time departure = new Time(formatter.parse(depatureString).getTime());
String arrivalString = datas.isNull("arrival") ? "00:00:00:00" : datas.getString("arrival").replace('d', ':');
Time arrival = new Time(formatter.parse(arrivalString).getTime());
int capacity1st = datas.isNull("capacity1st") ? 0 : datas.getInt("capacity1st");
int capacity2nd = datas.isNull("capacity2nd") ? 0 : datas.getInt("capacity2nd");
return new Prognosis(plateform, departure, arrival, capacity1st, capacity2nd);
}
}
}
package ch.hepia.api.transport;
import org.json.JSONObject;
import java.text.ParseException;
import java.io.Serializable;
public class Section implements Serializable {
private static final long serialVersionUID = 0xAEF37565673L;
private Journey journey;
private double walktime;
private Stop departure;
private Stop arrival;
/**
* Empty Section
*/
private final static class EmptySection extends Section{
private static final long serialVersionUID = 0xAEF37565670L;
/**
* Constructor of EmptySection
* An empty Section is a Journey From Geneva to Geneva
* @throws ParseException
*/
private EmptySection() throws ParseException {
super(new Journey.JourneyBuilder(new JSONObject()).build(), 0,
new Stop.StopBuilder(new JSONObject()).build(),
new Stop.StopBuilder(new JSONObject()).build());
}
}
/**
* Constructor of the class Section
* @param journey what Journey this section is part of
* @param walkTime time to get to the Section by walk
* @param departure where the Section will depart from
* @param arrival where the Section will arrive to
*/
private Section(Journey journey, double walkTime, Stop departure, Stop arrival){
this.journey = journey;
this.walktime = walkTime;
this.departure = departure;
this.arrival = arrival;
}
public static Section empty() throws ParseException{
return new EmptySection();
}
@Override
public boolean equals(Object o){
if (this == o) {
return true;
}
if (o == null || o.getClass() != this.getClass()) {
return false;
}
Section s = (Section) o;
return s.journey.equals(this.journey);
}
/**
* Get the journey this Section is part of
* @return journey
*/
public Journey getJourney(){
return journey;
}
/**
* Get the Stop where the Section will depart from
* @return departure
*/
public Stop getDeparture(){
return departure;
}
/**
* get the Stop where the Section is headed to
* @return arrival
*/
public Stop getArrival(){
return arrival;
}
/**
* Builder of Section objects
*/
public final static class SectionBuilder{
private JSONObject datas;
/**
* Constructor of the class SectionBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Section object
*/
public SectionBuilder(JSONObject datas){
this.datas = datas;
}
/**
* Build a Section object from the datas obtained
* @return a new Section object
* @throws ParseException
*/
public Section build() throws ParseException {
if(datas.isEmpty()){
return new EmptySection();
}
JSONObject journeyJSON = datas.isNull("journey") ? new JSONObject() : datas.getJSONObject("journey");
Journey.JourneyBuilder journey = new Journey.JourneyBuilder(journeyJSON);
double walktime = datas.isNull("walktime") ? 0 : datas.getDouble("walktime");
JSONObject departureJSON = datas.isNull("departure") ? new JSONObject() : datas.getJSONObject("departure");
Stop.StopBuilder departure = new Stop.StopBuilder(departureJSON);
JSONObject arrivalJSON = datas.isNull("arrival") ? new JSONObject() : datas.getJSONObject("arrival");
Stop.StopBuilder arrival = new Stop.StopBuilder(arrivalJSON);
return new Section(journey.build(), walktime, departure.build(), arrival.build());
}
}
}
package ch.hepia.api.transport;
import org.json.JSONObject;
import java.io.Serializable;
public class Service implements Serializable {
private static final long serialVersionUID = 0xACF34565673L;
private String regular;
private String irregular;
/**
* Empty Service
*/
private final static class EmptyService extends Service{
private static final long serialVersionUID = 0xACF34565670L;
/**
* Constructor of EmptyService
* No informations given
*/
private EmptyService(){
super("", "");
}
}
/**
* Constructor of Service class
* @param regular is the service regular ?
* @param irregular is the service disturbed ?
*/
private Service(String regular, String irregular){
this.regular = regular;
this.irregular = irregular;
}
/**
* Builder of Service objects
*/
public final static class ServiceBuilder{
private JSONObject datas;
/**
* Constructor of the class ServiceBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Service object
*/
public ServiceBuilder(JSONObject datas){
this.datas = datas;
}
/**
* Build a Service object from the datas obtained
* @return a new Service object
*/
public Service build(){
if(datas.isEmpty()){
return new EmptyService();
}
String regular = datas.isNull("regular") ? "" : datas.getString("regular");
String irregular = datas.isNull("irregular") ? "" : datas.getString("irregular");
return new Service(regular, irregular);
}
}
}
package ch.hepia.api.transport;
import org.json.JSONObject;
import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.io.Serializable;
public class Stop implements Serializable {
private static final long serialVersionUID = 0xABF34565673L;
private Location station;
private Time arrival;
private Time departure;
private int delay;
private int plateform;
private Prognosis prognosis;
/**
* Default Stop in Geneva
*/
private final static class DefaultStop extends Stop{
private static final long serialVersionUID = 0xABF34565670L;
/**
* Constructor of DefaultStop
* DefaultStop is located in Geneva
* No Time of departure nor Arrival, no Prognosis, no plateform and no delay
* @throws ParseException
*/
private DefaultStop() throws ParseException {
super(new Location.LocationBuilder(new JSONObject(), "refine").build(),
new Time(new SimpleDateFormat("dd:kk:mm:ss").parse("00:00:00:00").getTime()),
new Time(new SimpleDateFormat("dd:kk:mm:ss").parse("00:00:00:00").getTime()),
0, 0,
new Prognosis.PrognosisBuilder(new JSONObject()).build());
}
}
/**
* Constructor of the Stop class
* @param station Location where the Stop is
* @param arrival time of arrival at this Stop
* @param departure time of departure from this Stop
* @param delay duration time of unpredictated delay
* @param plateform where the Stop will arrive to and depart from
* @param prognosis complementary informations (See also {@link Prognosis})
*/
private Stop(Location station, Time arrival, Time departure, int delay, int plateform, Prognosis prognosis){
this.station = station;
this.arrival = arrival;
this.departure = departure;
this.delay = delay;
this.plateform = plateform;
this.prognosis = prognosis;
}
/**
* Get the Location of the Stop
* @return station
*/
public Location getLocation(){
return station;
}
/**
* Get the departure time of the transport from the Stop
* @return departure
*/
public Time getDepartureTime(){
return departure;
}
/**
* Get the Arrival time of the transport to the Stop
* @return arrival
*/
public Time getArrivalTime(){
return arrival;
}
@Override
public boolean equals(Object o){
if (this == o) {
return true;
}
if (o == null || o.getClass() != this.getClass()) {
return false;
}
Stop s = (Stop) o;
return s.arrival.equals(this.arrival) &&
s.departure.equals(this.departure) &&
s.plateform == this.plateform &&
s.station.equals(this.station) &&
s.delay == this.delay;
}
/**
* Builder of Stop objects
*/
public final static class StopBuilder{
private JSONObject datas;
/**
* Constructor of the class StopBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Stop object
*/
public StopBuilder(JSONObject datas){
this.datas = datas;
}
/**
* Build a Stop object from the datas obtained
* @return a new Stop object
* @throws ParseException
*/
public Stop build() throws ParseException {
if(datas.isEmpty()){
return new DefaultStop();
}
//getting the first key to know the type of the Location
String[] keys = new String[10];
datas.keySet().toArray(keys);
String type = keys[4];
JSONObject locationJSON = datas.isNull("location") ? new JSONObject() : datas.getJSONObject("location");
Location.LocationBuilder location = new Location.LocationBuilder(locationJSON, type);
DateFormat formatter = new SimpleDateFormat("kk:mm:ss");
String arrivalString = datas.isNull("arrival") ? "00:00:00" : datas.getString("arrival").substring(11, datas.getString("arrival").indexOf("+"));
Time arrival = new Time(formatter.parse(arrivalString).getTime());
String depatureString = datas.isNull("departure") ? "00:00:00" : datas.getString("departure").substring(11, datas.getString("departure").indexOf("+"));
Time departure = new Time(formatter.parse(depatureString).getTime());
int delay = datas.isNull("delay") ? 0 : datas.getInt("delay");
int plateform = datas.isNull("plateform") ? 0 : datas.getInt("plateform");
JSONObject prognosisJSON = datas.isNull("prognosis") ? new JSONObject() : new JSONObject(datas.get("prognosis"));
Prognosis.PrognosisBuilder prognosis = new Prognosis.PrognosisBuilder(prognosisJSON);
return new Stop(location.build(), arrival, departure, delay, plateform, prognosis.build());
}
}
}
package ch.hepia.api.transport;
public enum Type {
STATION, POI, ADDRESS, REFINE
}
package ch.hepia.api.weather;
import java.io.IOException;
public class CantFetchWeatherException extends IOException {
private static final long serialVersionUID = 0xDBF34565673L;
}
package ch.hepia.api.weather;
import java.io.IOException;
public class CantReadWeatherException extends IOException {
private static final long serialVersionUID = 0xEBF34565673L;
}
package ch.hepia.api.weather;
import ch.hepia.config.AppConfig;
import org.json.JSONObject;
public class Meteo {
private double temperature;
private String conditions;
/**
* Constructor of Meteo class to obtain basic information on the weather
* @param temperature La température actuelle
* @param conditions
*/
private Meteo(double temperature, String conditions){
this.temperature = temperature;
this.conditions = conditions;
}
/**
* Get the temperature of the Meteo Object
* @return temperature
*/
public double getTemperature(){ return temperature; }
/**
* Get the weather conditions of the Meteo Object
* @return conditions
*/
public String getConditions(){ return conditions; }
/**
* Converts a meteo condition into one of our icons
* @return The path to our icon
* @apiNote Aussi appellé le switch des enfers.
* @apiNote Retourne sunny si ne trouve rien (politique du verre à moitié plein)
*/
public String getConditionsIcon(){
switch (this.conditions) {
case "Stratus":
case "Nuit nuageuse":
case "Fortement nuageux":
case "Développement nuageux":
case "Nuit avec développement nuageux":
return AppConfig.WEATHER_ICON_CLOUDY;
case "Ciel voilé":
case "Nuit légèrement voilée":
case "Faibles passages nuageux":
case "Brouillard":
case "Stratus se dissipant":
case "Nuit claire et stratus":
case "Faiblement nuageux":
return AppConfig.WEATHER_ICON_FOGGY;
case "Averses de pluie faible":
case "Nuit avec averses":
case "Averses de pluie modérée":
case "Averses de pluie forte":
case "Couvert avec averses":
case "Pluie faible":
case "Pluie forte":
case "Pluie modérée":
return AppConfig.WEATHER_ICON_RAINY;
case "Averses de neige faible":
case "Nuit avec averses de neige faible":
case "Neige faible":
case "Neige modérée":
case "Neige forte":
case "Pluie et neige mêlée faible":
case "Pluie et neige mêlée modérée":
case "Pluie et neige mêlée forte":
return AppConfig.WEATHER_ICON_SNOWY;
case "Faiblement orageux":
case "Nuit faiblement orageuse":
case "Orage modéré":
case "Fortement orageux":
return AppConfig.WEATHER_ICON_STORMY;
case "Ensoleillé":
case "Nuit claire":
case "Nuit bien dégagée":
case "Eclaircies":
default:
return AppConfig.WEATHER_ICON_SUNNY;
}
}
/**
* Builder of Meteo Object
*/
public static class MeteoBuilder{
private JSONObject datas;
/**
* Constructor of the class MeteoBuilder
* Stock Datas from a JSON object given
* @param datas contains datas to construct a Meteo object
*/
public MeteoBuilder(JSONObject datas){
this.datas = datas;
}
/**
* Build a Meteo object from the datas obtained
* @return a new Meteo object
* @throws CantReadWeatherException
*/
public Meteo build() throws CantReadWeatherException {
double temperature = datas.isNull("tmp") ? -2000 : datas.getDouble("tmp");
String conditions = datas.getString("condition");
if(temperature != -2000 && conditions != null){
return new Meteo(temperature, conditions);
}
throw new CantReadWeatherException();
}
}
}
package ch.hepia.api.weather;
import ch.hepia.api.HTTPUtils;
import ch.hepia.api.transport.Coordinates;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class WeatherAPI {
private String baseURL = "https://www.prevision-meteo.ch/services/json/";
/**
* Processes the data received by the API
* @param path The URL to process
* @return The processed data
* @throws IOException When the processed data cannot be processed.
*/
private Meteo processData(String path) throws IOException {
String content = HTTPUtils.getContent(path);
JSONObject informations = new JSONObject(content);
if(informations.isNull("errors")) {
return new Meteo.MeteoBuilder(informations.getJSONObject("current_condition")).build();
}
throw new CantFetchWeatherException();
}
/**
* Get the informations on the weather in the location searched
* @param city where we want to display the weather from
* @return a Meteo Object
* @throws IOException
*/
public Meteo getWeatherFrom(String city) throws IOException {
String path = baseURL + URLEncoder.encode(city, StandardCharsets.UTF_8);
return processData(path);
}
/**
* Get the informations on the weather in the location searched
* @param coordinates where we want to display the weather from
* @return a Meteo Object
* @throws IOException
*/
public Meteo getWeatherFrom(Coordinates coordinates) throws IOException {
String path = baseURL + "lat="+coordinates.getX()+"lng="+coordinates.getY();
return processData(path);
}
}
package ch.hepia.config;
import javafx.scene.paint.Color;
import java.util.List;
/**
* The variables of the app
*/
public final class AppConfig {
public static final String APP_NAME = "TransportWave";
public static final Integer APP_WIDTH = 1000;
public static final Integer APP_HEIGHT = 565;
public static final Integer APP_MAIN_VIEW_WIDTH = 622;
public static final String RABBITMQ_HOSTNAME = "redgrave.science";
public static final String RABBITMQ_USERNAME = "frog";
public static final String RABBITMQ_PASSWORD = "poney1234";
public static final String RABBITMQ_EXCHANGE = "broadcaster";
public static final Integer RABBITMQ_PORT = 5672; // The MQ uses the default port, so this value is not used.
public static final String WEATHER_DESTINATION = "Météo à destination";
public static final String ERROR_API_WEATHER = "Impossible de contacter les services météo.";
public static final String ERROR_API_UNREACHABLE = "Impossible de contacter les services de transport Suisses.";
public static final String ERROR_API_MQ = "Une erreur s'est produite lors de la publication de cet évènement.";
public static final String DEFAULT_JOURNEY_TEXT = "Vous n'avez prévu aucun voyage pour le moment.";
public static final String COMMON_ITINERARY_TEXT = "Vous allez croiser %s à %s ! Pensez à vous saluer !";
public static List<String> CHAT_COMMANDS = List.of(
"help",
"block",
"unblock",
"blacklist"
);
/**
* Resources
*/
public static final String CHAT_TRAIN_ICON = "/img/train.png";
public static final String CHAT_TRAIN_ICON_SELF = "/img/train_self.png";
public static final String CHAT_MESSAGE_ICON = "/img/bubble.png";
public static final String CHAT_MESSAGE_ICON_SELF = "/img/bubble_self.png";
public static final String HELP_MESSAGE_ICON = "/img/help.png";
public static final String WEATHER_ICON_CLOUDY = "/img/cloudy.png";
public static final String WEATHER_ICON_FOGGY = "/img/foggy.png";
public static final String WEATHER_ICON_RAINY = "/img/rainy.png";
public static final String WEATHER_ICON_SNOWY = "/img/snowy.png";
public static final String WEATHER_ICON_STORMY = "/img/stormy.png";
public static final String WEATHER_ICON_SUNNY = "/img/sunny.png";
public static final String JOURNEY_ICON_COMMON_ITINERARY = "/img/friends.png";
public static final String EASTER_EGG_23DBM = "/img/javafx_res1";
public static final String EASTER_EGG_CAFE = "/img/javafx_res2";
public static final String EASTER_EGG_EFFET_DE_BORD = "/img/javafx_res3";
public static final String EASTER_EGG_SCRUM = "/img/javafx_res4";
/**
* Style
*/
public static final Color COLOR_BLUE_10_OPACITY = Color.color(0.207, 0.694, 0.933, 0.1);
public static final Color COLOR_BLUE_50_OPACITY = Color.color(0.207, 0.694, 0.933, 0.5);
public static final Color COLOR_BLUE_100_OPACITY = Color.color(0.207, 0.694, 0.933);
public static final Color COLOR_GREEN_20_OPACITY = Color.color(1.0, 0.9, 0.5, 0.2);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment