-
-
Notifications
You must be signed in to change notification settings - Fork 189
Project Architecture
This page attempts to help new developers start contributing to Plan.
It does not go over the build tool & commands for building as those are detailed in Project Setup.
Page version: 5.0 build 263 Commit
- Java
- Modules & Dependencies between modules
- Dagger & Dependency injection
- Structure outline of
common-module - About Platform APIs
- Web dev
- Technology stack
- Template-like html
- Static Resources
| Module | Role |
|---|---|
api |
Contains code for public API interface classes |
extensions |
Contains built-in extensions that use DataExtension API (in public API) |
common |
Main package for everything |
bukkit, bungee, sponge, velocity
|
Platform specific modules |
plugin |
Creates a single jar out of the modules |
Most of the time work is done in common module as platforms are abstracted away.
api -> extensions -> common -> bukkit, bungee, sponge, velocity -> plugin
From the build order, the dependencies between the modules should be apparent.
Dagger (https://dagger.dev/) is used extensively around the project. It was used as a remedy to reduce static usage. (See decisions here Refactor plugin to use static getters and Dependency Injection: Dagger)
@Singleton annotations are used to tell Dagger that only a single instance should exist per initialized Component (So that each PlanSystem only has one DatabaseSystem instead of returning a new one every time the database is needed.)
@Inject annotations are used in Constructors to tell Dagger to resolve the dependencies for constructing a new instance of this class.
Note that the Inject constructors allow Injecting an instance of the class the constructor is in to another object:
public class Foo {
@Inject
public Foo() {}
}
public class Bar {
@Inject
public Bar(Foo foo) {}
}
This is the main mechanism used for instantiating different system level objects, more about those below.
The process begins in a platform specific module by creating a new Dagger Component that resolves all dependencies for PlanSystem.
- When the plugin is enabled by the platform it is running on
PlanSystem#enableis called, which will lead to all subsystems getting started in a specific order. - When the platform is shutting down and the plugin is disabled
PlanSystem#disableis called, which stops all extra threads and closes resources the plugin is using. - When the plugin is reloaded with
plan reloadcommand by user, first the plugin is disabled and then enabled. A new Dagger component is created in the process, soPlanSysteminstance is new each time the process enables.
Packages were restructured during 5.0 update and some classes might still be in odd locations (
TaskSystemfor example).
Below are packages that are in package common/src/java/com.djrapitops.plan
| Package | Role |
|---|---|
api |
Plan API v4. Deprecated. |
capability |
Capability Service implementation (APIv5) |
commands |
Implementation for commands (plan, planbungee/planvelocity) |
data |
Contains deprecated APIv4 data classes. |
delivery |
Output related packages |
delivery.domain |
Data objects related to delivering web content & doing analysis |
delivery.export |
Export System and its utilities, for exporting html and json files |
delivery.formatting |
Formatting utilities (some use settings) |
delivery.rendering |
Utilities for writing html and json |
delivery.webserver |
WebServer implementation & Request resolving |
exceptions |
Exceptions used around the plugin |
extension |
Implementation for DataExtension API (APIv5) |
gathering |
Input related packages |
gathering.afk |
AFK Tracking |
gathering.cache |
Caches for gathered data like Sessions |
gathering.domain |
Data objects related to gathered data |
gathering.importing |
Import system |
gathering.listeners |
Basis for event listeners (mostly platform based) |
gathering.timed |
Timed tasks related to data gathering |
identification |
Identification of current server and UUID utilities |
modules |
Dagger related dependency resolution classes |
processing |
Extra execution service for async processing |
query |
Implementation for Query API (APIv5) |
settings |
Everything that user can configure (Config, Locale, Theme) |
storage |
Database & resource (file/jar) management |
| `storage.database.queries | SQL queries for the database |
storage.database.transactions |
Transactions for the database |
utilities |
Bunch of random utilities |
version |
System that checks for new version |
Different server platforms offer more or less the same sort of functionality, but with a different API. This is why in Plan some of it is abstracted away with Abstract Plugin Framework.
This includes Commands and Task scheduling.
Most likely you will not need to know more than that RunnableFactory (for creating Tasks) can be Injected like all other Plan classes, and that Plan, PlanSponge, PlanBungee & PlanVelocity implement similar interface from APF.
Platform modules include only the implementation for the specific platform so code from Bukkit is not available in sponge module and so on.
In the platform modules you can find implementations for Listeners and some tasks that require platform specific function calls.
Note that proxy implementations (Bungee, Velocity) have different gathering behaviors and deliver different pages - this is done with the listeners and the different execution paths are done in the common module by using ServerInfo#isProxy method.
All web files can be found from /src/main/resources/assets/plan/web.
Plan uses the following stack to deliver the web content:
- .html files inside the jar, that have
${placeholder}replacement support - Java Sun HTTPServer webserver and custom HTTP 1.1 request resolution
- Google GSON for serving data as JSON.
- XMLHTTPRequest for loading the JSON
- jQuery for placing the data on the pages
Web in general is moving away from using jQuery as the Javascript ecosystem has matured to a point where its functionality can be found in every browser. The decision to use it was made based on it being used by Bootstrap and jQuery data-tables.
The html has some ${placeholder} placed inside it, which is how 4.x.x versions delivered the data to the users.
New uses are discouraged if there is a different way to deliver the same information to the client.
The placeholder replacement should be done in the delivery.rendering.pages package.
The html can be customized by the users, which is made possible by specific methods in PlanFiles that find the files.
Most of the javascript libraries used in the plugin are in /src/main/resources/assets/plan/web/vendor. Exceptions include jQuery and Font Awesome.
When introducing new resources into the .html files the resource paths should be added to the appropriate Exporter in delivery.export so that the files are available for all users.
If you have any questions you can open an issue or join the discord server.
