Skip to content

Commit 59f7ca2

Browse files
Merge pull request #1 from tobiasbriones/dev
Finish development prior to v0.1.0 release
2 parents d848b7a + 4b24d38 commit 59f7ca2

File tree

102 files changed

+1052
-414
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1052
-414
lines changed

README.md

Lines changed: 297 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,313 @@
11
# Course Project at UNAH-MM545: Distributed Text File System
22

3-
Implementation of a server/client application in Java RMI and JavaFX to manage concurrent connections for managing a file system that accepts operations on users text files.
3+
[![GitHub Repository](https://raw.githubusercontent.com/tobiasbriones/general-images/main/example-projects/badges/ep-gh-repo-badge.svg)](https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system)
4+
5+
[![Project GitHub License](https://img.shields.io/github/license/tobiasbriones/cp-unah-mm545-distributed-text-file-system.svg?style=flat-square)](https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system/blob/main/LICENSE)
6+
7+
Implementation of a server/client application in Java RMI and JavaFX to manage concurrent
8+
connections for managing a file system that accepts operations on users' text files.
9+
10+
The original course project required a much simpler implementation, and the main objective was to
11+
apply DevOps skills. Needless to say, as I often do, I have added a huge amount of extra value to
12+
this project to make it worth it. My objectives are to keep working on some new features after the
13+
first release and build good DevOps documentation. Additionally, it's a good chance to show good use
14+
cases of the main underlying technologies: Java and JavaFX.
415

516
## Required technologies
617

718
- Java RMI or Python Pyro only.
819
- Anything that works for the client.
920
- Linux containers.
1021

22+
## Getting started
23+
24+
This system can be deployed in several ways. According to the course topics, you should use linux
25+
containers for the server applications. For this server, there are two applications that run the
26+
distributed system:
27+
28+
- **RMI Registry:** Receives the request from clients to connect to the remote object from the file
29+
server.
30+
31+
32+
- **RMI File System Server:** Manages the actual file system and physical files in storage. The
33+
clients access the remote object of this application through the RMI Registry, so the registry may
34+
be deployed separately from the server storing the actual files.
35+
36+
On the other side, for the client application you should run three or more of them to show the real
37+
time functionality.
38+
39+
One way to deploy all the system is as a standalone fashion. This way you need tons of RAM to run
40+
many VMs, JVMs, Linux Containers and other open applications as depicted by the following diagram:
41+
42+
![All-In-One Deployment](./docs/img/deployment.svg)
43+
44+
In that case, I would even suggest trying to use GraalVM to avoid that crazy amount of JVMs. That is
45+
something I haven't tested yet and the project at this stage is quite unstable. GraalVM also doesn't
46+
play well with the latest non-LTS Java versions and just properly deploying JavaFX is a bit of a
47+
mess by itself these days mostly if you use the latest versions of tools prior waiting for issue
48+
fixes. So let's keep that game for later with Java 17 LTS since I am also using `JDK 16` +
49+
`--enable-preview` as a good mathematician to take advantage of the new data oriented and FP
50+
features for the *model* (or domain) layer.
51+
52+
### Requirements
53+
54+
#### AIO deploy
55+
56+
For the "All-In-One" deployment model the requirements are as follows:
57+
58+
**Minimum requirements**
59+
60+
- Intel® Core™ i3-6100 / Intel® Core™ i5-2400
61+
- 8 GB of system memory
62+
- 35 GB of available storage
63+
64+
**Recommended requirements**
65+
66+
- Intel® Core™ i5-4590 / Intel® Core™ i7-2600
67+
- 12 GB of system memory
68+
- 50 GB of available SSD storage
69+
- Nvidia GT-730 / 256 MB of dedicated VRAM
70+
71+
Additionally, a broadband internet connection is required to install all the tools.
72+
73+
Some of these requirements are for the Ubuntu VM installation and accelerated graphics boots to make
74+
the VM run smoother.
75+
76+
#### Cloud deploy
77+
78+
For a cloud deployment the requirements are simple:
79+
80+
- An Ubuntu VM with at least 1 vCPU, 2 GB RAM, 8 GB storage.
81+
- A desktop computer to run the JavaFX clients.
82+
83+
It doesn't hurt to pick a better one. An Azure B2s / B2ms size is plenty enough for testing.
84+
85+
**Important:** If you plan to set up a cloud deployment over a WAN or the Internet then you must
86+
have a good background in networking since this is a really tough/impossible endeavor. I have
87+
tried for many days to achieve this goal but it is not feasible to fulfill. I don't plan on doing so,
88+
because the underlying technology is archaic (RMI) and I'm a Software Engineer and not a DevOps.
89+
The problem is likely due to the system using callbacks and the client has to be a server too to
90+
export its object, then firewall and inbound rules have to be configured for each client machine,
91+
the IPs and ports are another mess and a machine might just be able to run only one client at a
92+
time. Then, just make an "AIO"-fashioned deploy where all of the machines run on the same LAN if
93+
you don't have a larger infraestructure running on the same LAN.
94+
More on this:
95+
96+
- [How to send a message from Server to Client using Java RMI?](https://stackoverflow.com/questions/29284276/how-to-send-a-message-from-server-to-client-using-java-rmi)
97+
- [Can I invoke a client´s method from a server with RMI](https://stackoverflow.com/questions/21665300/can-i-invoke-a-client%C2%B4s-method-from-a-server-with-rmi)
98+
- [Java rmi over the internet](https://stackoverflow.com/questions/16268391/java-rmi-over-the-internet)
99+
100+
### Deployment
101+
102+
For this version of the software, you need to do some manual configs regarding IP addresses or
103+
hostnames. This is because the RMI technology requires knowing not only the server hostname where
104+
the JVM is running but also the client's hostname to answer back to it. If the hostname property
105+
isn't set on the client app then the server won't be able to respond to that client, or it might
106+
take a huge amount of time to respond. Fortunately, everything is set up already, and the config
107+
process just requires a bit of work.
108+
109+
#### Server applications
110+
111+
On server machine (assumed to be Ubuntu 20.x x64), install LXC, configure LXD and create two
112+
containers: `registry` and `fs`; for the registry server and the file-system server respectively. I
113+
don't recommend using snap along with LXC since I had a trouble which made me uninstall it later.
114+
Then install a proxy device into the registry container to map the VM RMI port to the registry
115+
container port:
116+
117+
`sudo apt update`
118+
119+
`sudo apt upgrade`
120+
121+
`sudo apt install lxd`
122+
123+
Choose the latest version of LXD (4.x+) and run `lxc list` to check it appears an empty list of
124+
containers, and the installation was successful. Run `sudo lxd init` and choose all the defaults to
125+
finish the lxd set up. Now install an Ubuntu image (in this case 20.04) and create the two
126+
containers required:
127+
128+
`lxc launch ubuntu:20.04 registry`
129+
130+
`lxc launch ubuntu:20.04 fs`
131+
132+
Then check with `lxc list` that you have created two new linux containers.
133+
134+
##### Common set up
135+
136+
Next, run the following commands on both containers `registry` and `fs` to install common tools that
137+
are suggested to deploy the applications:
138+
139+
`lxc exec { container } -- bash`
140+
141+
`sudo apt update`
142+
143+
`sudo apt upgrade`
144+
145+
`sudo apt install zip`
146+
147+
`sudo apt install unzip`
148+
149+
Install SDKMAN:
150+
151+
`curl -s "https://get.sdkman.io" | bash`
152+
153+
`source "$HOME/.sdkman/bin/sdkman-init.sh"`
154+
155+
Check SDKMAN installation: `sdk version`. Now install Gradle and Java. The current non-LTS version
156+
of Java I used is JDK16 with enable-preview, I suggest installing JDK17+ (which is not GA yet at the
157+
time of this release) for the current release v0.1.0:
158+
159+
`sdk list java` (choose the latest 17.0.x, 17+ version)
160+
161+
`sdk install java 17.0.{ x }-open`
162+
163+
`sdk install gradle`
164+
165+
Clone the project repository into a directory of choice:
166+
167+
`git clone https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system.git`
168+
169+
Now the common configuration has finished for both containers.
170+
171+
##### Registry container
172+
173+
Install the proxy device into the registry container to accept communication to the outside:
174+
175+
`lxc config device add registry rmi-port proxy listen=tcp:0.0.0.0:1099 connect=tcp:127.0.0.1:1099`
176+
177+
Prior to continuing, you'd like to take note of both container's IP addresses, check it out
178+
with `lxc list`.
179+
180+
Enter into the registry container and run the server as a registry application assuming you are into
181+
the project root directory:
182+
183+
`lxc exec registry -- bash`
184+
185+
`cd server`
186+
187+
`gradle run --args="{ registry-ip-address } reg"`
188+
189+
Thus, the server should be running as an RMI registry server and listening to incoming clients.
190+
191+
##### FileSystem container
192+
193+
Enter into the fs container and run the server as a file-system server:
194+
195+
`lxc exec fs -- bash`
196+
197+
`cd server`
198+
199+
`gradle run --args="{ fs-ip-address } fs { registry-ip-address }"`
200+
201+
Thus, the server should be running as an RMI file-system server. So, the remote object of this
202+
server has been bound to the registry server so that the registry server knows that clients want to
203+
access *that* remote object located at *this* container.
204+
205+
##### Troubleshooting
206+
207+
- Don't forget to configure the inbound/outbound security groups to allow traffic pass by your VM.
208+
209+
- Since I haven't added the dynamic IP config via the `NetworkInterface` Java API, and they have to
210+
be passed manually by JVM args, don't forget that IP addresses change when restarting the network.
211+
I was playing with that API though JShell, and I think it will work well when I implement it.
212+
213+
- [Storage issues](./docs/troubleshooting/storage/storage.md): Container out of space, "no space left on device" when running an app.
214+
215+
#### Desktop client
216+
217+
Finally, to deploy the client into a desktop machine: clone the repository, install SDKMAN, Gradle
218+
and a version of JDK with FX mods (Zulu FX or Liberica). If you use IntelliJ IDEA then it can be
219+
faster to run from the Gradle window. You will need the familiar commands if you are in Linux or
220+
Mac, for Windows the installations may be harder that's why I recommend using IntelliJ IDEA if you'
221+
re using Windows. The following commands work for an Ubuntu desktop:
222+
223+
`sudo apt update`
224+
225+
`sudo apt upgrade`
226+
227+
`sudo apt install zip`
228+
229+
`sudo apt install unzip`
230+
231+
`curl -s "https://get.sdkman.io" | bash`
232+
233+
`source "$HOME/.sdkman/bin/sdkman-init.sh"`
234+
235+
`sdk install gradle`
236+
237+
Install a JDK version of your choice (JDK17+) but make sure it contains the `fx` modules:
238+
239+
`sdk list java | grep fx`
240+
241+
`sdk install java 17.0.{ x }.fx-zulu`
242+
243+
Now edit the source file:
244+
245+
`cd client`
246+
247+
`sudo nano src/main/java/com/github/tobiasbriones/cp/rmifilesystem/client/FileSystemServices.java`
248+
249+
Then set the `HOST` constant of that file to the public IP address or hostname of your VM.
250+
251+
Finally, run the application and pass the IP address of your current desktop machine where the
252+
client will run:
253+
254+
`gradle run --args="{ client-ip-address }"`
255+
256+
##### Troubleshooting
257+
258+
- If you get a weird error when running the app,
259+
like [Error initializing QuantumRenderer: no suitable pipeline found](https://stackoverflow.com/questions/68204320/javafx-installation-issues-error-initializing-quantumrenderer)
260+
make sure to had installed an updated JDK version containing the JavaFX mods like Azul FX or
261+
BellSoft Liberica and run the application with that JDK.
262+
263+
##### Suggested reading
264+
265+
In [this article](./docs/troubleshooting/binary-incompatibility/binary-incompatibility.md), I talk about an experience I had with the famous binary compatibility.
266+
267+
##### Issues
268+
269+
One of the main issue of `v0.1.0` is the local FS update regarding deleting files. When a user
270+
deletes a file form the system, it's physically deleted from the user machine but not physically
271+
deleted from the other client machines. This feature will be implemented in a further project
272+
version. Significant performance optimizations will be scheduled for later releases too.
273+
274+
### Bibliography
275+
276+
- Linux Containers. (2021). Linuxcontainers.Org. https://linuxcontainers.org/
277+
278+
- Home - SDKMAN! the Software Development Kit Manager. (2021). Sdkman.Io. https://sdkman.io/
279+
280+
- Xenitellis, S. (2021, February 8). How to use the LXD Proxy Device to map ports between the host
281+
and the containers.
282+
Blog.Simos.Info. https://blog.simos.info/how-to-use-the-lxd-proxy-device-to-map-ports-between-the-host-and-the-containers/
283+
284+
## Screenshots
285+
286+
**LXC and Registry Container**
287+
![Registry](./docs/img/lxc-list-and-registry-screenshot.png)
288+
289+
**LXC and FS container**
290+
![FS](./docs/img/lxc-list-and-fs-screenshot.png)
291+
292+
**Client running and FS Server files**
293+
![Client](./docs/img/client-and-fs-files-screenshot.png)
294+
295+
**Demo Animation**
296+
![Demo Animation](./docs/img/demo.gif)
297+
298+
## Contact
299+
300+
This project: [Docs](https://tobiasbriones.github.io/cp-unah-mm545-distributed-text-file-system),
301+
[Repository](https://github.com/tobiasbriones/cp-unah-mm545-distributed-text-file-system)
302+
303+
Tobias Briones: [GitHub](https://github.com/tobiasbriones)
304+
11305
## About
12306

13307
**Course Project at UNAH-MM545: Distributed Text File System**
14308

15-
Implementation of a server/client application in Java RMI and JavaFX to manage concurrent connections for managing a file system that accepts operations on users text files.
309+
Implementation of a server/client application in Java RMI and JavaFX to manage concurrent
310+
connections for managing a file system that accepts operations on users' text files.
16311

17312
Copyright © 2021 Tobias Briones. All rights reserved.
18313

client/build.gradle.kts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ plugins {
1818
id("application")
1919
}
2020

21-
group = "io.github.tobiasbriones.cp"
22-
version = "1.0-SNAPSHOT"
21+
version = "0.1.0"
2322

2423
application {
25-
mainModule.set("io.github.tobiasbriones.cp.rmifilesystem.client")
26-
mainClass.set("io.github.tobiasbriones.cp.rmifilesystem.client.Launcher")
24+
mainModule.set("com.github.tobiasbriones.cp.rmifilesystem.client")
25+
mainClass.set("com.github.tobiasbriones.cp.rmifilesystem.client.Launcher")
2726
}
2827

2928
repositories {

client/src/main/java/io/github/tobiasbriones/cp/rmifilesystem/client/App.java renamed to client/src/main/java/com/github/tobiasbriones/cp/rmifilesystem/client/App.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@
1111
* https://opensource.org/licenses/BSD-3-Clause.
1212
*/
1313

14-
package io.github.tobiasbriones.cp.rmifilesystem.client;
15-
16-
import io.github.tobiasbriones.cp.rmifilesystem.client.info.Info;
17-
import io.github.tobiasbriones.cp.rmifilesystem.model.io.file.text.TextFileRepository;
18-
import io.github.tobiasbriones.cp.rmifilesystem.mvp.Initializable;
19-
import io.github.tobiasbriones.cp.rmifilesystem.mvp.MvpPresenter;
20-
import io.github.tobiasbriones.cp.rmifilesystem.mvp.MvpView;
21-
import io.github.tobiasbriones.cp.rmifilesystem.client.content.Content;
22-
import io.github.tobiasbriones.cp.rmifilesystem.client.header.Header;
23-
import io.github.tobiasbriones.cp.rmifilesystem.client.menu.AppMenu;
24-
import io.github.tobiasbriones.cp.rmifilesystem.model.FileSystemService;
14+
package com.github.tobiasbriones.cp.rmifilesystem.client;
15+
16+
import com.github.tobiasbriones.cp.rmifilesystem.client.content.Content;
17+
import com.github.tobiasbriones.cp.rmifilesystem.client.header.Header;
18+
import com.github.tobiasbriones.cp.rmifilesystem.client.info.Info;
19+
import com.github.tobiasbriones.cp.rmifilesystem.client.menu.AppMenu;
20+
import com.github.tobiasbriones.cp.rmifilesystem.model.io.file.text.TextFileRepository;
21+
import com.github.tobiasbriones.cp.rmifilesystem.mvp.Initializable;
22+
import com.github.tobiasbriones.cp.rmifilesystem.mvp.MvpPresenter;
23+
import com.github.tobiasbriones.cp.rmifilesystem.mvp.MvpView;
24+
import com.github.tobiasbriones.cp.rmifilesystem.model.FileSystemService;
2525
import javafx.application.Platform;
2626
import javafx.scene.Node;
2727
import javafx.scene.Parent;

client/src/main/java/io/github/tobiasbriones/cp/rmifilesystem/client/AppLocalFiles.java renamed to client/src/main/java/com/github/tobiasbriones/cp/rmifilesystem/client/AppLocalFiles.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
* https://opensource.org/licenses/BSD-3-Clause.
1212
*/
1313

14-
package io.github.tobiasbriones.cp.rmifilesystem.client;
14+
package com.github.tobiasbriones.cp.rmifilesystem.client;
1515

16-
import io.github.tobiasbriones.cp.rmifilesystem.impl.io.file.text.AppLocalTextFileRepository;
17-
import io.github.tobiasbriones.cp.rmifilesystem.impl.io.file.text.CommonPaths;
18-
import io.github.tobiasbriones.cp.rmifilesystem.model.io.Directory;
19-
import io.github.tobiasbriones.cp.rmifilesystem.model.io.File;
20-
import io.github.tobiasbriones.cp.rmifilesystem.model.io.file.text.TextFileRepository;
21-
import io.github.tobiasbriones.cp.rmifilesystem.model.io.node.DirectoryNode;
22-
import io.github.tobiasbriones.cp.rmifilesystem.model.io.node.FileSystem;
16+
import com.github.tobiasbriones.cp.rmifilesystem.impl.io.file.text.AppLocalTextFileRepository;
17+
import com.github.tobiasbriones.cp.rmifilesystem.impl.io.file.text.CommonPaths;
18+
import com.github.tobiasbriones.cp.rmifilesystem.model.io.Directory;
19+
import com.github.tobiasbriones.cp.rmifilesystem.model.io.File;
20+
import com.github.tobiasbriones.cp.rmifilesystem.model.io.file.text.TextFileRepository;
21+
import com.github.tobiasbriones.cp.rmifilesystem.model.io.node.DirectoryNode;
22+
import com.github.tobiasbriones.cp.rmifilesystem.model.io.node.FileSystem;
2323

2424
import java.io.*;
2525
import java.nio.file.Files;
@@ -29,7 +29,7 @@
2929
import java.util.Map;
3030
import java.util.Set;
3131

32-
import static io.github.tobiasbriones.cp.rmifilesystem.model.io.node.FileSystem.*;
32+
import static com.github.tobiasbriones.cp.rmifilesystem.model.io.node.FileSystem.*;
3333

3434
/**
3535
* @author Tobias Briones

0 commit comments

Comments
 (0)