Issues (327)

main/java/fr/quatrevieux/araknemu/Araknemu.java (2 issues)

1
/*
2
 * This file is part of Araknemu.
3
 *
4
 * Araknemu is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * Araknemu is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with Araknemu.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2020 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu;
21
22
import fr.quatrevieux.araknemu.core.BootException;
23
import fr.quatrevieux.araknemu.core.Service;
24
import fr.quatrevieux.araknemu.core.config.Configuration;
25
import fr.quatrevieux.araknemu.core.config.ConfigurationLoader;
26
import fr.quatrevieux.araknemu.core.dbal.DatabaseConfiguration;
27
import fr.quatrevieux.araknemu.core.dbal.DatabaseHandler;
28
import fr.quatrevieux.araknemu.core.dbal.DefaultDatabaseHandler;
29
import fr.quatrevieux.araknemu.core.di.Container;
30
import fr.quatrevieux.araknemu.core.di.ItemPoolContainer;
31
import fr.quatrevieux.araknemu.data.living.repository.implementation.sql.SqlLivingRepositoriesModule;
32
import fr.quatrevieux.araknemu.data.world.repository.implementation.sql.SqlWorldRepositoriesModule;
33
import fr.quatrevieux.araknemu.game.GameModule;
34
import fr.quatrevieux.araknemu.game.GameService;
35
import fr.quatrevieux.araknemu.game.admin.AdminModule;
36
import fr.quatrevieux.araknemu.game.connector.LocalModule;
37
import fr.quatrevieux.araknemu.realm.RealmModule;
38
import fr.quatrevieux.araknemu.realm.RealmService;
39
import org.apache.logging.log4j.LogManager;
40
import org.apache.logging.log4j.Logger;
41
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
42
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
43
import org.checkerframework.checker.nullness.qual.Nullable;
44
45
import java.sql.SQLException;
46
import java.time.Instant;
47
import java.util.ArrayList;
48
import java.util.List;
49
50
/**
51
 * Startup class
52
 */
53
public class Araknemu {
54
    /**
55
     * Get the current version of the server (retrieved from pom.xml)
56
     */
57 1
    public static final @Nullable String VERSION = Araknemu.class.getPackage() != null ? Araknemu.class.getPackage().getImplementationVersion() : null;
58
    public static final String NAME = "Araknemu";
59
    public static final String YEAR = "2017-2021";
60
    public static final String AUTHOR = "Vincent Quatrevieux";
61
62 1
    private final Logger logger = LogManager.getLogger(getClass());
63
64
    private final Configuration configuration;
65
    private final DatabaseHandler database;
66 1
    private final List<Service> services = new ArrayList<>();
67 1
    private boolean started = false;
68
    private @MonotonicNonNull Instant startDate;
69
70 1
    public Araknemu(Configuration configuration, DatabaseHandler database) {
71 1
        this.configuration = configuration;
72 1
        this.database = database;
73 1
    }
74
75
    /**
76
     * Boot all services
77
     */
78
    @EnsuresNonNull("startDate")
79
    public void boot() throws BootException {
80 1
        System.out.println(NAME + " Copyright (c) " + YEAR + " " + AUTHOR);
81 1
        System.out.println("This program comes with ABSOLUTELY NO WARRANTY.");
82 1
        System.out.println("This is free software, and you are welcome to redistribute it under certain conditions.");
83
84 1
        logger.info("Starting {} v{}", NAME, VERSION != null ? VERSION : "DEV");
85 1
        logger.info("Booting services");
86
87 1
        for (Service service : services) {
88
            service.boot();
89
        }
90
91 1
        logger.info("Running garbage collector");
92 1
        System.gc();
0 ignored issues
show
Comprehensibility introduced by
The garbage collector should not be called manually, unless doing things like benchmarking. The JVM knows when to initiate garbage collection.
Loading history...
93
94 1
        started = true;
95 1
        startDate = Instant.now();
96 1
        logger.info("Araknemu started");
97 1
    }
98
99
    /**
100
     * Stop all services
101
     */
102
    public void shutdown() {
103 1
        if (!started) {
104 1
            return;
105
        }
106
107 1
        logger.info("Shutdown requested...");
108 1
        started = false;
109
110 1
        for (Service service : services) {
111 1
            service.shutdown();
112 1
        }
113
114 1
        services.clear();
115 1
        database.stop();
116 1
        System.gc();
0 ignored issues
show
Comprehensibility introduced by
The garbage collector should not be called manually, unless doing things like benchmarking. The JVM knows when to initiate garbage collection.
Loading history...
117
118 1
        logger.info("Araknemu successfully stopped");
119 1
    }
120
121
    /**
122
     * Add a new service
123
     */
124
    public void add(Service service) {
125 1
        services.add(service);
126 1
    }
127
128
    /**
129
     * Get the application configuration
130
     */
131
    public Configuration configuration() {
132 1
        return configuration;
133
    }
134
135
    /**
136
     * Get the database handler
137
     */
138
    public DatabaseHandler database() {
139 1
        return database;
140
    }
141
142
    /**
143
     * Check if the server is started
144
     */
145
    public boolean started() {
146 1
        return started;
147
    }
148
149
    /**
150
     * Get the server start date
151
     */
152
    public Instant startDate() {
153 1
        if (startDate == null) {
154
            throw new IllegalStateException("Server not started");
155
        }
156
157 1
        return startDate;
158
    }
159
160
    /**
161
     * Application entry point
162
     */
163
    public static void main(String[] args) throws Exception {
164
        final ConfigurationLoader configurationLoader = new ConfigurationLoader();
165
166
        if (args.length > 0) {
167
            configurationLoader.configFileName(args[0]);
168
        }
169
170
        final Configuration configuration = configurationLoader.load();
171
172
        final Araknemu app = new Araknemu(
173
            configuration,
174
            new DefaultDatabaseHandler(
175
                configuration.module(DatabaseConfiguration.MODULE),
176
                LogManager.getLogger(DatabaseHandler.class)
177
            )
178
        );
179
180
        final Container realmContainer = makeRealmContainer(app);
181
        final Container gameContainer  = makeGameContainer(app, realmContainer);
182
183
        app.add(realmContainer.get(RealmService.class));
184
        app.add(gameContainer.get(GameService.class));
185
186
        app.boot();
187
188
        Runtime.getRuntime().addShutdownHook(new Thread(app::shutdown));
189
    }
190
191
    private static Container makeRealmContainer(Araknemu app) throws SQLException {
192
        final Container container = new ItemPoolContainer();
193
194
        container.register(new SqlLivingRepositoriesModule(
195
            app.database().get("realm")
196
        ));
197
        container.register(new RealmModule(app));
198
199
        return container;
200
    }
201
202
    private static Container makeGameContainer(Araknemu app, Container realmContainer) throws SQLException {
203
        final Container container = new ItemPoolContainer();
204
205
        container.register(new SqlLivingRepositoriesModule(
206
            app.database().get("game")
207
        ));
208
        container.register(new SqlWorldRepositoriesModule(
209
            app.database().get("game")
210
        ));
211
        container.register(new GameModule(app));
212
        container.register(new AdminModule(app));
213
        container.register(new LocalModule(realmContainer));
214
215
        return container;
216
    }
217
}
218