top of page
  • Writer's pictureAlibek Jakupov

Bicycle searching app with JAVA EE

Updated: Nov 19, 2021


Concept


The given project is aimed to allow user to localize themselves on the map, see the list of all the stations chosen by previously defined criteria, calculate the distance or the route from his location to the chosen station, see station details like name, full address, bonus, is the station closed/open etc. For logged users there should be a possibility to add the station to the Favorites list (given the system already provides sign in/sign features).



Justifying choice of language, frameworks and IDE

The system is composed of client and server side.


Data visualization and geolocation is provided on the client side by the means of google developer tools, javascript and html (with embedded jsp tags). With the help of jsp user data, list of stations may be obtained on the page.


Server side is responsible for obtaining data from data base, interpreting it, gathering data from open source API provided by Velib RESTful service and parsing xml obtained from Velib. MVC architecture is realized with the help of JSP (view), Java Beans (model) and java servlets (Controller). Data persistence is provided with the help of Hibernate framework (creating, replacing, updating and deleting with the help of HQL and xml mapping of database entities). To use Velib RESTful service the RESTful client is created on the server side. To parse XML the system uses standard API for XML SAX.



Development


Database structure is provided below


Velib_User is an entity describing a system user. All the attributes are standard for such kind of systems allowing user identification except longitude and latitude which are provided to find specific user’s position. Velib_Station is an entity describing Station (all the attributes corresponds exactly to those ones provided at this site except update Date which is a Date object obtained from SearchController.java and corresponds to the date of last update).

Favorites is an entity describing user’s favorite stations, which is composed of user IDs with corresponding station Ids. To get user’s favorites the SQL request (not HQL) is as follows: select * from station where station.STATION_ID in (select favorites.num_station from FAVORITES where FAVORITES.NUM_CLIENT = 3); (i.e. obtaining all the favorite stations of a user with an id equal to 3). Separate table was created to provide 3rd level of normalization (in other words, to avoid transitive dependencies).


Crucial system features are provided in the following flowcharts:


Sign in


Looking for stations


Showing station details


Adding a station to the favorite list


User may enter the system without being logged.

The first page he sees is welcome.jsp


There user may specify the search mode (District or Department) and specify the name of a region. The system then redirects user to the result page, which is showstations.jsp


Each time user request a SearchController the systems looks for all the stations available on the Velib site and updates the database using REST client.



Document stationsList = xmlParser.loadXMLSTring(service.
 path("service").path("carto").accept(MediaType.TEXT_PLAIN).
 get(String.class));
 
 NodeList nodeList = stationsList.getElementsByTagName("marker");
 
 for (int i = 0; i < nodeList.getLength(); i++) {
 for (int j =0; j < nodeList.item(i).getAttributes().getLength(); 
                        j++) {
 String parameter = nodeList.item(i).getAttributes().
 item(j).getNodeName();
 String value = nodeList.item(i).getAttributes().item(j).
 getNodeValue();
 
 if (parameter.equals("address")) {
                        address = value.trim().toLowerCase();
                    } else if (parameter.equals("bonus")) {
                        stBonus = Integer.parseInt(value);
                    } else if (parameter.equals("fullAddress")) {
                        fullAddress = value.trim().toLowerCase();
                    } else if (parameter.equals("lat")) {
                        lattitude = Double.parseDouble(value);
                    } else if (parameter.equals("lng")) {
                        longitude = Double.parseDouble(value);
                    } else if (parameter.equals("name")) {
                        stName = value.trim().toLowerCase();
                    } else if (parameter.equals("number")) {
                        stationId = Integer.parseInt(value);
                    } else if (parameter.equals("open")) {
                        stOpen = Integer.parseInt(value);
                    }
 
 if (!(stationId<0 || stName.equals(null))) {
 Station station = new Station(stationId, stName, 
                                address, fullAddress, longitude, lattitude,
                                stOpen, stBonus, updateDate);
 System.out.println("Saving station data");
 stationDAO.saveOrUpdate(station);
 System.out.println("Success");


In our case the system parser not a XML file but a single string containing all the XML code. To make it possible we have created loadXMLString function with the help of SAX:

public Document loadXMLSTring(String xml) throws

       ParserConfigurationException, SAXException, IOException {

 Document document = null;

 

 DocumentBuilderFactory factory =

 DocumentBuilderFactory.newInstance();

 DocumentBuilder parser = factory.newDocumentBuilder();

 InputSource inputSource = new InputSource(new StringReader(xml));

 

             document = parser.parse(inputSource);

 return document;

The result is DOM object which is further treated to obtain parameter names (the parameter names become entity attributes).


If a user double clicks on the station marker the system traces a route between his position and the station


To sum up, the systems requests Velib RESTful API, parsers XML data, updates database, obtains from the latest database version the list of all stations and creates a new list that satisfies user’s parameters. To find specific stations we just use contains() function provided by java.util.List (thus, stationsList.address.contains(“src”)). Searchby parameter is only needed to specify if we look for our string in a full address or in a short one.


To trace a route we just use javascript function provided by googlemaps API:


 google.maps.event.addListener(marker, 'dblclick',

                      (function(marker, i) {

 return function() {

 

 var request = {

                                      origin      : pos,

                                      destination : "<%=clientResult.get(i).getFullAddress()%>",

                                      travelMode  : google.maps.DirectionsTravelMode.DRIVING // Mode de conduite

                                  }

 var directionsService = new google.maps.DirectionsService(); // Service de calcul d'itinéraire

 directionsService.route(request, function(response, status){ // Envoie de la requête pour calculer le parcours

 if(status == google.maps.DirectionsStatus.OK){

 direction.setDirections(response); // Trace l'itinéraire sur la carte et les différentes Ã©tapes du parcours

                                      }

                                  });

                             }
                         })(marker, i));



To let the system know which station the user has chosen we pass as request parameter the station’s name which is unique and may considered as a primary key.


Thus on our page we do:

var showDetails = "<a href = \"ShowDetailsController?stationId=<%=clientResult.get(i).getStationId()%>\"> Show Details </a>";

And on the server side we obtain station id:


String stationID = request.getParameter("stationId");

The user has to be logged in to add the station to his favorites. To verify if the user is logged in or not we have created a VelibUser been of a session scope

<jsp:useBean id="velibUser" scope="session" class="model.VelibUser" />

and each we verify whether the bean variable is empty or not

<%

if (velibUser.getNom()==null) {

       out.print("You have to <a href=\"signup.jsp\">Login here</a> to add the station to your favorite");

}else {

       out.print("<a href = \"AddToFavoriteController\">Add to my Favorites</a>");

}

%>

Once the user is logged in we are able to add the station to our favorites and see all the favorite stations. Naturally, all the database operation are implemented with the help of Hibernate and using Data Access Object design pattern.


Finally, it is possible to mention that during the development instead of using Test Driven Development approach because of time constraints we have applied Test Oriented Development approach which is less proper but allows creating working and tested product within a short period of time. To do this, we have created a test package where we have put all the necessary tests.

N.B. To deploy and run application: see readme.txt provided in the source folder.


 

All the code is available on github

51 views0 comments
bottom of page