Welcome to the Clinic service! This service handles requests for:
- Registering clinics
- Deleting clinics
- Adding dentist to clinic
- Removing dentist from clinic
- Retrieving a specific clinic
- Retrieving all clinics
- Retrieving clinics within radius
- Retrieving N closest clinics
To run this service you need to follow the steps described below:
First you need to Clone the repo in to a folder in your computer, if you dont know how to do it check this guide.
If you do not have Java installed on your computer you can download both brew and Java with these commands:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install Java
brew install maven
Due to the usage of Google Maps API, a key is needed to run the service:
-
Open Google Cloud Console website and create a project
-
Click “Create credentials” → API Key”
-
Click “Show key” and "Copy"
-
Done! You now have a valid API key that will be used in the section below
In order to build and run the Clinic service you need to type these commands in your terminal:
- Navigate to the root project directory
cd Clinic-Service/src/main/java/com/group20/dentanoid /BackendMapAPI
- Install node modules
npm install
- Configure environment variables
Create a .env
file
GOOGLE_MAPS_API_KEY={key here}
- Navigate to
Clinic-Service
folder and compile the project into a binary (including deps)
mvn clean compile assembly:single
- Run the compiled JAR file
java -jar target/Clinic-Service-1.0-SNAPSHOT-jar-with-dependencies.jar
Congratulations! You are now running the Clinic service.
A comprehensive folder structure that accounts for generalizations and abstractions is necessary for scalability and maintainability. The relations of the folders were designed with the motive to facilitate extensions of the code in the future and to accommodate room for unpredictable changes whereas the self-contained environment adheres to the single responsibility principle.
Below, the microservice will be presented with respect to its three main folders:
First, a table that illustrates and discusses in-depth how changes are accommodated in TopicManagement
folder is presented. This table also touches on imperative concepts that are similar in its peer folder DataManagement
. Afterwards, a multitude of trees with nodes brings more light on the existing similarities to highlight a general pattern of sub-folders that is strictly followed as a result of obtaining maintainable code. Lastly, BackendMapAPI’s
involvement in the microservice and and how its behaviour deviates from its two peer folders is briefly discussed.
Adding new features would imply that the developer strictly follows the laid out folder structure to keep things organized.
- Black nodes --> Already existing folders
- Red nodes --> Example extensions of folders
- Documents --> Example extensions of scripts
The takeaway from the tree above is that TopicManagement
and DatabaseManagement/Schemas
must adhere to the following mathematical cardinalities to preserve code maintainability:
- Subfolder A: Contains nTopicArtifact folders (Clinic, Map and Appointment in the tree)
- Subfolder B: Contains nArtifactSubType folders (Dental, Health, Nearby and Multiplicity in the tree)
This diagram provides further details on what was adressed in the children nodes of TopicManagement
in the tree above:
- Green --> Already existing classes
- Yellow --> Demonstrations of further extensions of abstract classes that weren't mentioned in the tree above
- Red --> The red nodes in the tree above
Purpose: Provide high-level overview of the code flow - Not all details (classes / folders) are included
NOTE: Only the most significant classes and methods to the codeflow are included in the diagrams
The colors in the 2 diagrams below represent the following operational levels:
- Red = Microservice
- Orange = Segment of service
- Yellow = Artifact
- Green = Artifact subtypes → Where the requested operation occurs and generates a response
Keywords of the mqtt topic defines the codeflow trajectory which has its end in the green area
The picture above expressed in .java
classes rather than folders looks like this:
This folder's structure and behaviour is vastly different from its two peer folders TopicManagement
and Datamanagement
, but plays a crucial role in the system. This folder is a self-contained nodejs runtime environment that acts as a childprocess executed when registering a clinic.
In essence, its responsibilities are the following:
- Read
clinic.json
content (containsclinic_name
andposition
) - Perform a query using the attributes to find the desired real-world clinic
- Fetch the clinic's data (ratings, photoURL, address) and return to
TopicManagement
folder viaclinic.json
NOTE: In the picture below the three folders are portrayed as independent services, which isn't the case. This is a high-level overview that conveys TopicManagement
's central role in the service as a whole and how it interacts with its peer folders. Nevertheless, it's important to distinguish between its issued requests. As stated above, clinic.json
establishes a way of communicating to BackendMapAPI
. However, DatabaseManagement
's involvement in the entirety of the service is observed in the form of an aggregation to TopicManagement
, since its methods are called from its peer folder's classes.
As imagined, there are cases where a real-world clinic either isn't registered in Google API's database or when the inputted attributes don't link to any dental clinic. Ultimately, this creates two scenarios:
-
Scenario 1 - Real clinic: Clinic was found and fetched data is displayed on infowindow
-
Scenario 2 - Fictitious clinic: Clinic was not found and only employees are displayed on the infowindow
Scenario 1 - Real clinic:
Scenario 2 - Fictitious clinic:
When wanting to register a real-world clinic, two things must be inputted correctly:
- clinic_name: The string must be identical to what Google Maps API is operating with
- position: The global coordinates of the clinic must be inputted in a
,
separated string. Although the code accounts for margin of error and doesn't expect a pinpoint exact coordinate, it does require an approximate accuracy to find the desired clinic
Follow the procedure detailed below:
-
Open Google Maps
-
Search for desired clinic (clinic_name)
-
Zoom in on the red marker
-
Right click on it to retrieve its coordinates (position)
-
Input the two attributes in
Dentist Client
component
(picture here)
Recommendation: Select clinics with more than 20 ratings/reviews to ensure that it’s an official establishment registered in Google API’s database If you did any mistake in these steps, the code will not find the existing clinic and return a ‘fictitious’ one without ratings and pictures
NOTE: Google Places API
does not support all clinics that Google Maps does. The API has 100 million places in its database, which is a lot, but it doesn't cover all worldwide dental clinic establishments.
If the clinic isn't found: In some cases the string in which Places API
expects is tricky. Even though the clinic is registered, this may be the cause you are experiencing issues. If that's the case, contact one of the developers. Each developer that has access to modify the code can uncomment the code-block in childprocess-api.sh
so that its shell-window doesn't disappear after its execution is accomplished. In the window, the clinic_name
strings of the clinics with similar coordinates are printed. These strings are the ones that the API checks for, and the output looks like this:
The feature of fetching data from real-world clinics can be extended as an additional layer of security to the system. By disallowing Scenario 2 - Fictitious clinic
so that only established dental-clinic-coorporations stored in Google APIs database can be registered, scammers or clinics with bad user experience are rejected by the system. Clinics that aren't well-known (which tend to struggle with customer satisfaction) will most likely not be found by Google API. In this way, the system can leverage upon trustworthiness as a factor toward success. In addition, if the developers wish to make the system public and build a reputation of providing value beyond the users' expectations, they can define a star-rating threshold at which dental clinics are accepted to register themselves. Usally, high ratings indicate happy customers that boost the reputation and influence of the providing enterprise.
The system is capable of retrieving clinics regardless of global coordinates and send them back as a reponse to Patient Client
where they are displayed. Two modes support this feature:
- Radius: Returns the clinics that are within a specified circular radius from a position. The position is usually set to the user's current global coordinates, but it can also represent the searched position if
Search mode
is activated inPatient Client
. The upper limit of clinics that can be returned is X, where X is the number of existing clinics in the database. If no clinics are found within the radius an empty array is returned. Hence, the unpredictable number of clinics returned (A) is constrained accordingly:
0 <= A <= X
- Fixed: Returns the N closest clinics to a position. N is a positive integer defined by the user's request. The upper limit is unbounded, meaning that it depends on the datatype that is used in the code. As for now,
Integer
is used, but it can easily be changed tolong
ordouble
that store a greater range numerical values. In cases where the number of existing clinics in the database (n) is less than N, a response containing n clinics is issued. Note thatn >= 0
always holds true. As a result, the return statement is numerically bounded as follows:
n <= A <= N
Below, a surface-level overview of the more interesting solution Fixed
is provided:
In order to implement this feature, two steps needs to be done:
1. Calculate distance between user's position and a clinic
2. Store clinics that satisfy the criteria in a datastructure
Calculating the distance between two global points can be done in countless different ways. The question is what approach is best suited for this project. The developers had two ideas in mind: Euclidiean Distance and Haversine Formula.
In the end, the developers picked Haversine Formula by virtue of its inclusion of the radius of a sphere. Setting the radius variable to that of the Earth's, a comparison between distances worldwide is made possible.
In the process of calculating the distances, the clinics are stored in a map with their distances as the key, and the entire clinic-document as a value. A priority queue with a max heap is used with a max-length of N. Adding elements when the queue had N elements would induce a poll()
that deletes the element with the biggest key-value.
This service will not get updated in the future, due to project being considered as closed when GU course DIT356 is finished.
This service is a part of DIT356 distributed systems course, and is created by Group 20. Check here for more information about the entire project.
WIP DUE TO SERVICE STILL BEING DEVELOPED
In this service the following people have contributed:
- Mohamad Khalil
- Lucas Holter
- Cornelia Olofsson Larsson
- James Klouda
- Jonatan Boman
- Joel Mattson
The service may recieve updates until 9th January 2024, and none after.