Implement YAML config, start SQLite implementation
A config.yml file has been added, to allow configuring server settings. It will be expanded with new settings in the future. Also, SQLite support has been added, with a "database.sqlite" file. A basic table with user/pass/userid columns has been added for testing purposes.
This commit is contained in:
parent
4ab01c3787
commit
ce172c3dc4
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
.idea/
|
||||
target/
|
||||
run/
|
||||
*.ignore
|
||||
|
19
pom.xml
19
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>net.mindoverflow.webmarker</groupId>
|
||||
<artifactId>WebMarker</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>0.0.1-alpha</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
@ -16,12 +16,27 @@
|
||||
<version>1.13.1</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ro.pippo</groupId>
|
||||
<artifactId>pippo-controller</artifactId>
|
||||
<version>1.13.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>2.0.0-alpha1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.32.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.21</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -1,13 +1,39 @@
|
||||
package net.mindoverflow.webmarker;
|
||||
|
||||
import net.mindoverflow.webmarker.server.WebApplication;
|
||||
import net.mindoverflow.webmarker.runnables.StatsRunnable;
|
||||
import net.mindoverflow.webmarker.utils.Cached;
|
||||
import net.mindoverflow.webmarker.utils.sql.SQLiteManager;
|
||||
import net.mindoverflow.webmarker.webserver.WebApplication;
|
||||
import net.mindoverflow.webmarker.utils.config.ConfigEntries;
|
||||
import net.mindoverflow.webmarker.utils.config.ConfigManager;
|
||||
import net.mindoverflow.webmarker.utils.messaging.Messenger;
|
||||
import ro.pippo.core.Pippo;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class WebMarker {
|
||||
|
||||
private static final Messenger msg = new Messenger();
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
ConfigManager.checkFiles();
|
||||
ConfigManager.loadFiles();
|
||||
Cached.sqlManager = new SQLiteManager();
|
||||
Cached.sqlManager.initialize();
|
||||
|
||||
msg.info("Loading Pippo framework...");
|
||||
final Pippo pippo = new Pippo(new WebApplication());
|
||||
pippo.start();
|
||||
msg.info("Loaded Pippo framework.");
|
||||
|
||||
msg.info("Starting webserver...");
|
||||
int port = (int) ConfigEntries.WEBSERVER_PORT.getValue();
|
||||
pippo.start(port);
|
||||
msg.info("Started webserver.");
|
||||
|
||||
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
|
||||
exec.scheduleAtFixedRate(new StatsRunnable(), 0, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package net.mindoverflow.webmarker.runnables;
|
||||
|
||||
import net.mindoverflow.webmarker.utils.messaging.Messenger;
|
||||
|
||||
public class StatsRunnable implements Runnable {
|
||||
|
||||
Messenger msg = new Messenger();
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
double usedRam = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000000.0;
|
||||
msg.info("Used RAM: " + usedRam + "MB");
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package net.mindoverflow.webmarker.utils;
|
||||
|
||||
import net.mindoverflow.webmarker.utils.sql.SQLiteManager;
|
||||
|
||||
public class Cached {
|
||||
|
||||
public static SQLiteManager sqlManager;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.mindoverflow.webmarker.utils.config;
|
||||
|
||||
public enum ConfigEntries
|
||||
{
|
||||
WEBSERVER_PORT("port", 7344);
|
||||
|
||||
private final String path;
|
||||
private Object value;
|
||||
|
||||
ConfigEntries(String path, Object value)
|
||||
{
|
||||
this.path = path;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package net.mindoverflow.webmarker.utils.config;
|
||||
|
||||
import net.mindoverflow.webmarker.utils.messaging.MessageLevel;
|
||||
import net.mindoverflow.webmarker.utils.messaging.Messenger;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ConfigManager
|
||||
{
|
||||
|
||||
private static final Messenger msg = new Messenger();
|
||||
|
||||
public static void checkFiles()
|
||||
{
|
||||
msg.send(MessageLevel.INFO, "Checking configuration files: ");
|
||||
|
||||
File configFile = FileType.CONFIG_YAML.file;
|
||||
|
||||
if(!configFile.exists())
|
||||
{
|
||||
try {
|
||||
InputStream stream = ConfigManager.class.getResourceAsStream("/" + configFile.getName());
|
||||
Files.copy(stream, Paths.get(configFile.getAbsolutePath()));
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
msg.sendLine(MessageLevel.NONE, "FATAL");
|
||||
e.printStackTrace();
|
||||
msg.critical("Error creating missing file!");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
msg.sendLine(MessageLevel.NONE, "OK");
|
||||
}
|
||||
|
||||
public static void loadFiles()
|
||||
{
|
||||
msg.send(MessageLevel.INFO, "Loading configuration files: ");
|
||||
|
||||
try {
|
||||
InputStream stream = new FileInputStream(FileType.CONFIG_YAML.file);
|
||||
Yaml yaml = new Yaml();
|
||||
FileType.CONFIG_YAML.yaml = yaml.load(stream);
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
msg.critical("Error loading config file!");
|
||||
}
|
||||
|
||||
for(ConfigEntries entry : ConfigEntries.values())
|
||||
{
|
||||
String path = entry.getPath();
|
||||
Object value = FileType.CONFIG_YAML.yaml.get(path);
|
||||
entry.setValue(value);
|
||||
}
|
||||
|
||||
msg.sendLine(MessageLevel.NONE, "OK");
|
||||
|
||||
for(ConfigEntries entry : ConfigEntries.values())
|
||||
{ msg.info(entry.name() + ": " + entry.getValue()); }
|
||||
}
|
||||
|
||||
public static String getJarAbsolutePath()
|
||||
{
|
||||
|
||||
Path currentPath = Paths.get("");
|
||||
return currentPath.toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
public enum FileType
|
||||
{
|
||||
DATABASE_FILE(new File(getJarAbsolutePath() + File.separator + "database.sqlite"), null),
|
||||
CONFIG_YAML(new File(getJarAbsolutePath() + File.separator + "config.yml"), new HashMap<>());
|
||||
|
||||
public File file;
|
||||
public HashMap<String, Object> yaml;
|
||||
FileType(File givenFile, HashMap<String, Object> yamlConfig)
|
||||
{
|
||||
file = givenFile;
|
||||
yaml = yamlConfig;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.mindoverflow.webmarker.utils.messaging;
|
||||
|
||||
public enum MessageLevel {
|
||||
|
||||
INFO("[INFO] "),
|
||||
WARNING("[WARNING] "),
|
||||
CRITICAL("[CRITICAL] "),
|
||||
NONE("");
|
||||
|
||||
private String prefix;
|
||||
|
||||
MessageLevel(String prefix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public String getPrefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package net.mindoverflow.webmarker.utils.messaging;
|
||||
|
||||
public class Messenger {
|
||||
|
||||
public void info(String message)
|
||||
{ sendLine(MessageLevel.INFO, message); }
|
||||
|
||||
public void warn(String message)
|
||||
{ sendLine(MessageLevel.WARNING, message); }
|
||||
|
||||
public void critical(String message)
|
||||
{ sendLine(MessageLevel.CRITICAL, message); }
|
||||
|
||||
public void sendLine(MessageLevel level, String message)
|
||||
{ System.out.println(level.getPrefix() + message); }
|
||||
|
||||
public void send(MessageLevel level, String message)
|
||||
{ System.out.print(level.getPrefix() + message); }
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.mindoverflow.webmarker.utils.sql;
|
||||
|
||||
import net.mindoverflow.webmarker.utils.sql.primitives.SQLColumn;
|
||||
import net.mindoverflow.webmarker.utils.sql.primitives.SQLDataType;
|
||||
|
||||
public enum FDatabaseColumn
|
||||
{
|
||||
|
||||
ALL(new SQLColumn("*"), null),
|
||||
USERNAME(new SQLColumn("username"), SQLDataType.VARCHAR_128),
|
||||
PASSWORD(new SQLColumn("password"), SQLDataType.VARCHAR_128),
|
||||
USERID(new SQLColumn("userid"), SQLDataType.VARCHAR_128),
|
||||
|
||||
|
||||
|
||||
;
|
||||
|
||||
private final SQLColumn column;
|
||||
private final SQLDataType type;
|
||||
|
||||
FDatabaseColumn(SQLColumn column, SQLDataType type)
|
||||
{
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public SQLColumn getColumn()
|
||||
{ return column; }
|
||||
|
||||
public SQLDataType getDataType()
|
||||
{ return type; }
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package net.mindoverflow.webmarker.utils.sql;
|
||||
|
||||
|
||||
import net.mindoverflow.webmarker.utils.sql.primitives.SQLTable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public enum FDatabaseTable
|
||||
{
|
||||
USERS(new SQLTable("users", // table name
|
||||
new ArrayList<>(){{ // columns
|
||||
add(FDatabaseColumn.USERID);
|
||||
add(FDatabaseColumn.USERNAME);
|
||||
add(FDatabaseColumn.PASSWORD);
|
||||
}})),
|
||||
|
||||
;
|
||||
|
||||
private final SQLTable table;
|
||||
|
||||
FDatabaseTable(SQLTable table)
|
||||
{ this.table = table; }
|
||||
|
||||
public SQLTable getTable()
|
||||
{ return table; }
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package net.mindoverflow.webmarker.utils.sql;
|
||||
|
||||
import net.mindoverflow.webmarker.utils.config.ConfigManager;
|
||||
import net.mindoverflow.webmarker.utils.messaging.MessageLevel;
|
||||
import net.mindoverflow.webmarker.utils.messaging.Messenger;
|
||||
import net.mindoverflow.webmarker.utils.sql.primitives.SQLDataType;
|
||||
import net.mindoverflow.webmarker.utils.sql.primitives.SQLTable;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.List;
|
||||
|
||||
public class SQLiteManager {
|
||||
|
||||
private final Messenger msg = new Messenger();
|
||||
private Connection connection;
|
||||
|
||||
public void initialize()
|
||||
{
|
||||
msg.send(MessageLevel.INFO, "Connecting to SQLite database: ");
|
||||
|
||||
String url = "jdbc:sqlite:" + ConfigManager.FileType.DATABASE_FILE.file.getAbsolutePath();
|
||||
try {
|
||||
connection = DriverManager.getConnection(url);
|
||||
if(connection != null && !connection.isClosed())
|
||||
{
|
||||
msg.sendLine(MessageLevel.NONE, "OK");
|
||||
doInitialSetup();
|
||||
}
|
||||
|
||||
} catch (SQLException throwables) {
|
||||
msg.sendLine(MessageLevel.NONE, "FATAL");
|
||||
throwables.printStackTrace();
|
||||
msg.critical("Error connecting to SQLite database!");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void doInitialSetup()
|
||||
{
|
||||
for(FDatabaseTable currentTable : FDatabaseTable.values())
|
||||
{
|
||||
if(!tableExists(currentTable))
|
||||
{
|
||||
msg.info("Creating SQLite table `" + currentTable.getTable().getTableSQLName() + "`");
|
||||
createTable(currentTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tableExists(FDatabaseTable tableEnum)
|
||||
{
|
||||
String name = tableEnum.getTable().getTableSQLName();
|
||||
|
||||
try
|
||||
{
|
||||
DatabaseMetaData meta = connection.getMetaData();
|
||||
ResultSet result = meta.getTables(null, null, name, null);
|
||||
while(result.next())
|
||||
{
|
||||
String tableName = result.getString("TABLE_NAME");
|
||||
if(tableName != null && tableName.equals(name.toLowerCase())) return true;
|
||||
}
|
||||
|
||||
} catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
msg.critical("Error checking SQLite table " + name + "!");
|
||||
System.exit(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createTable(FDatabaseTable tableEnum)
|
||||
{
|
||||
SQLTable table = tableEnum.getTable();
|
||||
List<FDatabaseColumn> columns = table.getColumns();
|
||||
List<SQLDataType> dataTypes = table.getDataTypes();
|
||||
|
||||
StringBuilder query = new StringBuilder("CREATE TABLE IF NOT EXISTS ").append(table.getTableSQLName()).append(" (");
|
||||
|
||||
int pos = 0;
|
||||
for(FDatabaseColumn column : columns)
|
||||
{
|
||||
query.append(column.getColumn().getColumnSQLName()).append(" ").append(dataTypes.get(pos).getSQLName());
|
||||
pos++;
|
||||
|
||||
if(pos < columns.size()) // we don't want to append a colon to the last entry
|
||||
{ query.append(", "); }
|
||||
}
|
||||
query.append(");");
|
||||
executeUpdate(query.toString());
|
||||
}
|
||||
|
||||
private void executeUpdate(String query)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(connection == null || connection.isClosed())
|
||||
{
|
||||
msg.critical("Lost connection to SQLite database!");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
Statement statement = connection.createStatement();
|
||||
statement.executeUpdate(query);
|
||||
} catch (SQLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
msg.critical("Error executing SQLite update!");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package net.mindoverflow.webmarker.utils.sql.primitives;
|
||||
|
||||
public class SQLColumn {
|
||||
|
||||
private final String columnName;
|
||||
|
||||
public SQLColumn(String name)
|
||||
{ columnName = name; }
|
||||
|
||||
public String getColumnSQLName()
|
||||
{ return columnName; }
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package net.mindoverflow.webmarker.utils.sql.primitives;
|
||||
|
||||
public enum SQLDataType
|
||||
{
|
||||
INTEGER("INTEGER NOT NULL"),
|
||||
VARCHAR_128("VARCHAR(128)"),
|
||||
TEXT("TEXT"),
|
||||
DATETIME("DATETIME"),
|
||||
|
||||
;
|
||||
|
||||
private String sqlName;
|
||||
SQLDataType(String sqlName)
|
||||
{ this.sqlName = sqlName; }
|
||||
|
||||
public String getSQLName()
|
||||
{ return this.sqlName; }
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.mindoverflow.webmarker.utils.sql.primitives;
|
||||
|
||||
import net.mindoverflow.webmarker.utils.sql.FDatabaseColumn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SQLTable
|
||||
{
|
||||
private final String tableName;
|
||||
private final List<FDatabaseColumn> columns;
|
||||
private final List<SQLDataType> columnTypes = new ArrayList<>();
|
||||
|
||||
public SQLTable(String tableName, List<FDatabaseColumn> columns)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
this.columns = columns;
|
||||
|
||||
for(FDatabaseColumn column : columns)
|
||||
{ columnTypes.add(column.getDataType()); }
|
||||
}
|
||||
|
||||
public String getTableSQLName()
|
||||
{ return tableName; }
|
||||
|
||||
public List<FDatabaseColumn> getColumns()
|
||||
{ return columns; }
|
||||
|
||||
public List<SQLDataType> getDataTypes()
|
||||
{ return columnTypes; }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.mindoverflow.webmarker.server;
|
||||
package net.mindoverflow.webmarker.webserver;
|
||||
|
||||
import net.mindoverflow.webmarker.utils.URLMap;
|
||||
import ro.pippo.controller.ControllerApplication;
|
||||
@ -46,6 +46,13 @@ public class WebApplication extends ControllerApplication {
|
||||
|
||||
});
|
||||
|
||||
POST("/post", routeContext -> {
|
||||
int userId = routeContext.getParameter("id").toInt();
|
||||
String url = routeContext.getParameter("url").toString();
|
||||
|
||||
routeContext.send("AAAAAAAAAAAAA " + url);
|
||||
});
|
||||
|
||||
ANY("/.*", new TrailingSlashHandler(false)); // remove trailing slash
|
||||
}
|
||||
}
|
1
src/main/resources/config.yml
Normal file
1
src/main/resources/config.yml
Normal file
@ -0,0 +1 @@
|
||||
port: 7344
|
Loading…
Reference in New Issue
Block a user