mirror of
https://github.com/ProjectSWGCore/pswgcommon.git
synced 2026-01-17 00:04:25 -05:00
Removed deprecated RelationalDatabase and related code, as there are now 0 usages of it
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of PSWGCommon. *
|
||||
* *
|
||||
* --------------------------------------------------------------------------------*
|
||||
* *
|
||||
* PSWGCommon is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* PSWGCommon is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with PSWGCommon. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.data.info;
|
||||
|
||||
public class PostgresqlDatabase extends RelationalDatabase {
|
||||
|
||||
public PostgresqlDatabase(String host, String db, String user, String pass) {
|
||||
super("org.postgresql.Driver", "postgresql", host, db, user, pass, "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of PSWGCommon. *
|
||||
* *
|
||||
* --------------------------------------------------------------------------------*
|
||||
* *
|
||||
* PSWGCommon is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* PSWGCommon is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with PSWGCommon. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.data.info;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
|
||||
public abstract class RelationalDatabase implements Closeable {
|
||||
|
||||
private DatabaseMetaData metaData;
|
||||
private Connection connection;
|
||||
private boolean online;
|
||||
|
||||
protected RelationalDatabase(String jdbcClass, String url) {
|
||||
try {
|
||||
Class.forName(jdbcClass);
|
||||
initialize(url);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(e);
|
||||
online = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected RelationalDatabase(String jdbcClass, String url, String user, String pass) {
|
||||
try {
|
||||
Class.forName(jdbcClass);
|
||||
initialize(url, user, pass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(e);
|
||||
online = false;
|
||||
}
|
||||
}
|
||||
|
||||
public RelationalDatabase(String jdbcClass, String url, String user, String pass, String params) {
|
||||
try {
|
||||
Class.forName(jdbcClass);
|
||||
if (params != null && params.length() > 0)
|
||||
url += "?" + params;
|
||||
initialize(url, user, pass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(e);
|
||||
online = false;
|
||||
}
|
||||
}
|
||||
|
||||
public RelationalDatabase(String jdbcClass, String type, String host, String db, String user, String pass, String params) {
|
||||
try {
|
||||
Class.forName(jdbcClass);
|
||||
String url = "jdbc:" + type + "://" + host + "/" + db;
|
||||
if (params != null && params.length() > 0)
|
||||
url += "?" + params;
|
||||
initialize(url, user, pass);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(e);
|
||||
online = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize(String url) {
|
||||
try {
|
||||
connection = DriverManager.getConnection(url);
|
||||
metaData = connection.getMetaData();
|
||||
online = true;
|
||||
} catch (SQLException e) {
|
||||
Log.e("Failed to initialize relational database! %s - %s", e.getClass().getSimpleName(), e.getMessage());
|
||||
online = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize(String url, String user, String pass) {
|
||||
try {
|
||||
connection = DriverManager.getConnection(url, user, pass);
|
||||
metaData = connection.getMetaData();
|
||||
online = true;
|
||||
} catch (SQLException e) {
|
||||
Log.e("Failed to initialize relational database! %s - %s", e.getClass().getSimpleName(), e.getMessage());
|
||||
online = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
connection.close();
|
||||
online = false;
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
if (connection == null)
|
||||
return false;
|
||||
try {
|
||||
return online && !connection.isClosed();
|
||||
} catch (SQLException e) {
|
||||
return online;
|
||||
}
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement(String sql) {
|
||||
if (connection == null) {
|
||||
Log.e("Cannot prepare statement! Connection is null");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return connection.prepareStatement(sql);
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ResultSet executeQuery(String query) {
|
||||
if (connection == null)
|
||||
return null;
|
||||
Statement s = null;
|
||||
try {
|
||||
s = connection.createStatement();
|
||||
s.execute(query);
|
||||
try {
|
||||
s.closeOnCompletion();
|
||||
} catch (SQLFeatureNotSupportedException e) {
|
||||
// It was worth a shot
|
||||
}
|
||||
return s.getResultSet();
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
if (s != null) {
|
||||
try { s.close(); } catch (SQLException ex) { }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int updateQuery(String query) {
|
||||
if (connection == null)
|
||||
return 0;
|
||||
try {
|
||||
try (Statement s = connection.createStatement()) {
|
||||
return s.executeUpdate(query);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTable(String name) {
|
||||
if (metaData == null)
|
||||
return false;
|
||||
try {
|
||||
return metaData.getTables(null, null, name, null).next();
|
||||
} catch (SQLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,450 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of PSWGCommon. *
|
||||
* *
|
||||
* --------------------------------------------------------------------------------*
|
||||
* *
|
||||
* PSWGCommon is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* PSWGCommon is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with PSWGCommon. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.data.info;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
|
||||
/**
|
||||
* @deprecated use SdbLoader instead in Holocore.
|
||||
*/
|
||||
@Deprecated
|
||||
public class RelationalServerData extends RelationalDatabase {
|
||||
|
||||
private static final Charset ASCII = Charset.forName("ASCII");
|
||||
|
||||
private static final String META_TABLE = "__server_table_metadata__";
|
||||
private final PreparedStatement getTableMetadata;
|
||||
private final PreparedStatement updateTableMetadata;
|
||||
private final PreparedStatement insertTableMetadata;
|
||||
|
||||
public RelationalServerData(String file) {
|
||||
super("org.sqlite.JDBC", "jdbc:sqlite:" + file);
|
||||
/*
|
||||
* GREATLY speeds up INSERT speeds. This makes it so SQLite will not
|
||||
* wait until the previous write finishes before starting to write the
|
||||
* next INSERT. All imports will only take milliseconds. A caveat of
|
||||
* this is that if the power ever cuts or the application is force
|
||||
* killed it may result in database corruption.
|
||||
*/
|
||||
updateQuery("PRAGMA synchronous=OFF");
|
||||
updateQuery("CREATE TABLE IF NOT EXISTS "+META_TABLE+" (table_name TEXT, last_imported INTEGER)");
|
||||
getTableMetadata = prepareStatement("SELECT * FROM "+META_TABLE+" WHERE table_name=?");
|
||||
updateTableMetadata = prepareStatement("UPDATE "+META_TABLE+" SET last_imported=? WHERE table_name=?");
|
||||
insertTableMetadata = prepareStatement("INSERT INTO "+META_TABLE+" (table_name, last_imported) VALUES (?, ?)");
|
||||
}
|
||||
|
||||
public boolean linkTableWithSdb(String table, String filepath) {
|
||||
File sdb = new File(filepath);
|
||||
if (!sdb.isFile())
|
||||
return false;
|
||||
if (testLastModified(table, sdb) || testMasterSdbModified(table, sdb)) {
|
||||
updateQuery("DROP TABLE IF EXISTS " + table);
|
||||
importFromSdb(table, sdb);
|
||||
updateLastImported(table, System.currentTimeMillis());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testLastModified(String table, File sdb) {
|
||||
return sdb.lastModified() > getLastImported(table);
|
||||
}
|
||||
|
||||
private boolean testMasterSdbModified(String table, File sdb) {
|
||||
if (!sdb.getName().endsWith(".msdb"))
|
||||
return false;
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(sdb), ASCII))) {
|
||||
reader.readLine();
|
||||
reader.readLine();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (testLastModified(table, new File(sdb.getParent(), line.substring(0, line.indexOf('\t')))))
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a record with the specified information into the database
|
||||
* @param table the table to insert into
|
||||
* @param columns the columns to insert into
|
||||
* @param params the parameters to insert
|
||||
* @return TRUE on success, FALSE on failure
|
||||
* @throws SQLException upon error
|
||||
*/
|
||||
public boolean insert(String table, String [] columns, Object ... params) throws SQLException {
|
||||
StringBuilder columnStr = new StringBuilder("");
|
||||
StringBuilder valuesStr = new StringBuilder("");
|
||||
if (columns == null)
|
||||
columns = getColumnsForTable(table);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
columnStr.append(columns[i]);
|
||||
valuesStr.append('?');
|
||||
if (i+1 < columns.length) {
|
||||
columnStr.append(',');
|
||||
valuesStr.append(',');
|
||||
}
|
||||
}
|
||||
final String sql = String.format("INSERT INTO %s (%s) VALUES (%s)", table, columnStr, valuesStr);
|
||||
try (PreparedStatement statement = prepareStatement(sql)) {
|
||||
if (statement == null || params.length < getSqlParameterCount(sql))
|
||||
return false;
|
||||
assignParameters(statement, params);
|
||||
return statement.executeUpdate() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects from the specified table with the supplied where clause, given
|
||||
* the supplied parameters
|
||||
* @param tables the tables to query, separated by commas
|
||||
* @param columns the columns to select, null to select all
|
||||
* @param where the where clause
|
||||
* @param params the parameters to put into the ?s in the where clause
|
||||
* @return the result set
|
||||
* @throws SQLException upon error
|
||||
*/
|
||||
public ResultSet selectFromTable(String tables, String [] columns, String where, Object ... params) throws SQLException {
|
||||
final String sql = createSelectQuery(tables, columns, where, params);
|
||||
PreparedStatement statement = prepareStatement(sql);
|
||||
if (statement == null || params.length < getSqlParameterCount(sql))
|
||||
return null;
|
||||
assignParameters(statement, params);
|
||||
return statement.executeQuery();
|
||||
}
|
||||
|
||||
private void assignParameters(PreparedStatement statement, Object ... params) throws SQLException {
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (params[i] instanceof Integer || params[i] instanceof Long)
|
||||
statement.setLong(i+1, ((Number) params[i]).longValue());
|
||||
else if (params[i] instanceof Float || params[i] instanceof Double)
|
||||
statement.setDouble(i+1, ((Number) params[i]).doubleValue());
|
||||
else if (params[i] instanceof String)
|
||||
statement.setString(i+1, (String) params[i]);
|
||||
else if (params[i] != null)
|
||||
throw new IllegalArgumentException("Unknown object type: " + params[i].getClass().getSimpleName());
|
||||
else
|
||||
throw new NullPointerException("Parameters cannot have null elements!");
|
||||
}
|
||||
}
|
||||
|
||||
private int getSqlParameterCount(String sql) {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < sql.length(); i++) {
|
||||
if (sql.charAt(i) == '?')
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private String createSelectQuery(String tables, String [] columns, String where, Object ... params) {
|
||||
String columnStr = "*";
|
||||
if (columns == null && tables.contains(",")) {
|
||||
StringBuilder bldr = new StringBuilder("");
|
||||
for (String table : tables.split(",")) {
|
||||
bldr.append(table.trim());
|
||||
bldr.append(".*, ");
|
||||
}
|
||||
columnStr = bldr.substring(0, columnStr.length()-2);
|
||||
} else if (columns != null) {
|
||||
StringBuilder bldr = new StringBuilder("");
|
||||
for (String column : columns) {
|
||||
bldr.append(column);
|
||||
bldr.append(", ");
|
||||
}
|
||||
columnStr = bldr.substring(0, bldr.length()-2);
|
||||
}
|
||||
return "SELECT " + columnStr + " FROM " + tables + " WHERE " + where;
|
||||
}
|
||||
|
||||
private String [] getColumnsForTable(String table) throws SQLException {
|
||||
List<String> columns = new ArrayList<>();
|
||||
try (ResultSet set = executeQuery("PRAGMA table_info('"+table+"')")) {
|
||||
int colInd = set.findColumn("name");
|
||||
while (set.next()) {
|
||||
columns.add(set.getString(colInd));
|
||||
}
|
||||
}
|
||||
return columns.toArray(new String[columns.size()]);
|
||||
}
|
||||
|
||||
private long getLastImported(String table) {
|
||||
synchronized (getTableMetadata) {
|
||||
ResultSet set = null;
|
||||
try {
|
||||
getTableMetadata.setString(1, table);
|
||||
set = getTableMetadata.executeQuery();
|
||||
if (set.next())
|
||||
return set.getLong("last_imported");
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
} finally {
|
||||
if (set != null) {
|
||||
try {
|
||||
set.close();
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLastImported(String table, long lastImported) {
|
||||
synchronized (updateTableMetadata) {
|
||||
try {
|
||||
updateTableMetadata.setLong(1, lastImported);
|
||||
updateTableMetadata.setString(2, table);
|
||||
if (updateTableMetadata.executeUpdate() > 0)
|
||||
return;
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
synchronized (insertTableMetadata) {
|
||||
try {
|
||||
insertTableMetadata.setString(1, table);
|
||||
insertTableMetadata.setLong(2, lastImported);
|
||||
insertTableMetadata.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean importFromSdb(String table, File sdb) {
|
||||
try (TableReader reader = new TableReader(table, sdb)) {
|
||||
Log.i("Importing sdb... '" + sdb + "'");
|
||||
if (sdb.getName().endsWith(".msdb"))
|
||||
reader.readMaster();
|
||||
else
|
||||
reader.readNormal();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.e(e);
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e("Invalid file format. Aborting read of %s! Message: %s", sdb, e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private class TableReader implements Closeable {
|
||||
|
||||
private final String table;
|
||||
private final File file;
|
||||
private String [] columnNames;
|
||||
private String [] columnTypes;
|
||||
private PreparedStatement insert;
|
||||
|
||||
public TableReader(String table, File file) {
|
||||
this.table = table;
|
||||
this.file = file;
|
||||
this.columnNames = null;
|
||||
this.columnTypes = null;
|
||||
this.insert = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (insert != null) {
|
||||
try {
|
||||
insert.close();
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readNormal() throws IOException, SQLException {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), ASCII))) {
|
||||
readNormalRemainder(reader, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void readMaster() throws SQLException, IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), ASCII))) {
|
||||
int lineNum = 1;
|
||||
readLine(reader.readLine(), lineNum++);
|
||||
readLine(reader.readLine(), lineNum++);
|
||||
readMasterRemainder(reader, lineNum);
|
||||
}
|
||||
}
|
||||
|
||||
private void readSlave() throws IOException, SQLException {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), ASCII))) {
|
||||
int lineNum = 3;
|
||||
reader.readLine();
|
||||
reader.readLine(); // Skip column names and types
|
||||
readNormalRemainder(reader, lineNum);
|
||||
}
|
||||
}
|
||||
|
||||
private void readMasterRemainder(BufferedReader reader, int lineNum) throws IOException, SQLException {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String [] parts = line.split("\t");
|
||||
if (parts.length != 2) {
|
||||
Log.e("Invalid line [%d]: %s", lineNum, line);
|
||||
continue;
|
||||
}
|
||||
boolean load = Boolean.parseBoolean(parts[1]);
|
||||
if (load) {
|
||||
File sdb = new File(file.getParent(), parts[0]);
|
||||
Log.i(" Importing sdb... '" + sdb + "'");
|
||||
if (!sdb.isFile()) {
|
||||
Log.e(" Failed to import sdb! File is not file or does not exist");
|
||||
continue;
|
||||
}
|
||||
@SuppressWarnings("resource") // This closes the database.. we don't want to do that yet
|
||||
TableReader slave = new TableReader(table, sdb);
|
||||
slave.columnNames = columnNames;
|
||||
slave.columnTypes = columnTypes;
|
||||
slave.insert = insert;
|
||||
slave.readSlave();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readNormalRemainder(BufferedReader reader, int lineNum) throws IOException, SQLException {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
readLine(line, lineNum++);
|
||||
}
|
||||
if (insert != null)
|
||||
insert.executeBatch();
|
||||
}
|
||||
|
||||
private void readLine(String line, int lineNum) throws SQLException {
|
||||
if (line == null)
|
||||
return;
|
||||
switch (lineNum) {
|
||||
case 1:
|
||||
columnNames = fastTabSplit(line);
|
||||
break;
|
||||
case 2:
|
||||
columnTypes = fastTabSplit(line);
|
||||
createTable();
|
||||
createPreparedStatement();
|
||||
break;
|
||||
default:
|
||||
generateInsert(fastTabSplit(line), lineNum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private String [] fastTabSplit(String str) {
|
||||
int count = 1;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (str.charAt(i) == '\t') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
String [] tabs = new String[count];
|
||||
int tabInd = 0;
|
||||
int prevInd = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (str.charAt(i) == '\t') {
|
||||
tabs[tabInd++] = str.substring(prevInd, i);
|
||||
prevInd = i+1;
|
||||
}
|
||||
}
|
||||
if (prevInd < str.length())
|
||||
tabs[tabInd++] = str.substring(prevInd);
|
||||
return tabs;
|
||||
}
|
||||
|
||||
private void createTable() {
|
||||
if (columnNames.length != columnTypes.length)
|
||||
throw new IllegalArgumentException("Names length and types length mismatch");
|
||||
StringBuilder sql = new StringBuilder("CREATE TABLE "+table+" (");
|
||||
for (int i = 0; i < columnNames.length; i++) {
|
||||
if (i > 0)
|
||||
sql.append(", ");
|
||||
sql.append(columnNames[i]);
|
||||
sql.append(' ');
|
||||
sql.append(columnTypes[i]);
|
||||
}
|
||||
sql.append(')');
|
||||
updateQuery(sql.toString());
|
||||
}
|
||||
|
||||
private void createPreparedStatement() {
|
||||
StringBuilder sql = new StringBuilder("INSERT INTO " + table + " VALUES (");
|
||||
for (int i = 0; i < columnNames.length; i++) {
|
||||
if (i > 0)
|
||||
sql.append(", ");
|
||||
sql.append('?');
|
||||
}
|
||||
sql.append(')');
|
||||
insert = prepareStatement(sql.toString());
|
||||
}
|
||||
|
||||
private void generateInsert(String [] data, int line) throws SQLException {
|
||||
if (columnTypes.length != data.length) {
|
||||
Log.e("Could not load record: Types length and data length mismatch. Line: " + line);
|
||||
return;
|
||||
}
|
||||
int column = 0;
|
||||
try {
|
||||
for (int i = 0; i < data.length; i++, column++) {
|
||||
if (columnTypes[i].startsWith("TEXT"))
|
||||
insert.setString(i+1, data[i]);
|
||||
else if (columnTypes[i].startsWith("REAL"))
|
||||
insert.setDouble(i+1, Double.parseDouble(data[i]));
|
||||
else if (columnTypes[i].startsWith("INTEGER"))
|
||||
insert.setLong(i+1, Long.parseLong(data[i]));
|
||||
else
|
||||
throw new SQLException("Data type unsupported by sdb/sqlite! Type: " + columnTypes[i]);
|
||||
}
|
||||
insert.addBatch();
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e("Could not load record: Record has invalid data. Line: " + line + " Column: " + column);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of PSWGCommon. *
|
||||
* *
|
||||
* --------------------------------------------------------------------------------*
|
||||
* *
|
||||
* PSWGCommon is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* PSWGCommon is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with PSWGCommon. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.data.info;
|
||||
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @deprecated use SdbLoader instead in Holocore.
|
||||
*/
|
||||
@Deprecated
|
||||
public class RelationalServerFactory {
|
||||
|
||||
private static final RelationalServerFactory INSTANCE = new RelationalServerFactory();
|
||||
private static final Map <String, Object> FILE_LOAD_LOCKING = new HashMap<>();
|
||||
private static final String BASE_PATH = "serverdata/";
|
||||
|
||||
public static RelationalServerData getServerData(String file, String ... tables) {
|
||||
return INSTANCE.getData(file, tables);
|
||||
}
|
||||
|
||||
public static RelationalServerData getServerDatabase(String file) {
|
||||
return INSTANCE.getDatabase(file);
|
||||
}
|
||||
|
||||
private RelationalServerData getData(String file, String ... tables) {
|
||||
if (!file.endsWith(".db"))
|
||||
throw new IllegalArgumentException("File path for database must end in .db!");
|
||||
file = file.replace('/', File.separatorChar);
|
||||
final Object lock = getFileLocking(file);
|
||||
synchronized (lock) {
|
||||
File f = new File(BASE_PATH, file);
|
||||
RelationalServerData data = new RelationalServerData(f.getPath());
|
||||
if (loadServerData(data, f, tables))
|
||||
return data;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadServerData(RelationalServerData data, File file, String ... tables) {
|
||||
File parent = file.getParentFile();
|
||||
try {
|
||||
if (loadTables(data, parent, tables))
|
||||
return true;
|
||||
data.close();
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
data.close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private RelationalServerData getDatabase(String file) {
|
||||
if (!file.endsWith(".db"))
|
||||
throw new IllegalArgumentException("File path for database must end in .db!");
|
||||
final Object lock = getFileLocking(file);
|
||||
synchronized (lock) {
|
||||
File f = new File(BASE_PATH, file);
|
||||
RelationalServerData data = new RelationalServerData(f.getPath());
|
||||
try {
|
||||
String [] commands = getCommandsFromSchema(f.getPath().substring(0, f.getPath().length()-3) + ".sql");
|
||||
ParserData parserData = new ParserData();
|
||||
for (String command : commands)
|
||||
executeCommand(data, command, parserData);
|
||||
return data;
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
}
|
||||
data.close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadTables(RelationalServerData data, File parent, String [] tables) {
|
||||
for (String table : tables) {
|
||||
table = table.replace('/', File.separatorChar);
|
||||
String path = generatePath(parent, table);
|
||||
table = path.substring(path.lastIndexOf(File.separatorChar)+1, path.lastIndexOf('.'));
|
||||
if (!data.linkTableWithSdb(table, path))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String generatePath(File parent, String table) {
|
||||
String base;
|
||||
if (table.contains(File.separator))
|
||||
base = BASE_PATH + table;
|
||||
else
|
||||
base = parent.getPath() + File.separator + table;
|
||||
if (new File(base + ".msdb").isFile())
|
||||
return base + ".msdb";
|
||||
return base + ".sdb";
|
||||
}
|
||||
|
||||
private void executeCommand(RelationalServerData data, String command, ParserData parserData) {
|
||||
command = command.trim();
|
||||
if (command.startsWith("SELECT") && parserData.getConditional()) {
|
||||
try (ResultSet set = data.executeQuery(command)) {
|
||||
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
} else if (command.startsWith("IF")) { // VERY SIMPLE 'if' logic, no parenthesis and no AND/OR's - expects 3 arguments: <num/var> <op> <num/var>
|
||||
parserData.addConditional(evaluateIf(data, command.substring(2).trim()));
|
||||
} else if (command.startsWith("ENDIF")) {
|
||||
parserData.unwrapLastConditional();
|
||||
} else if (parserData.getConditional()) {
|
||||
data.updateQuery(command);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean evaluateIf(RelationalServerData data, String statement) {
|
||||
String [] args = statement.split(" ", 3);
|
||||
if (args.length != 3) {
|
||||
Log.e("Invalid IF statement: %s", statement);
|
||||
return false;
|
||||
}
|
||||
double num1 = parseToNumber(data, args[0]);
|
||||
String comparator = args[1];
|
||||
double num2 = parseToNumber(data, args[2]);
|
||||
switch (comparator) {
|
||||
case "<": return num1 < num2;
|
||||
case ">": return num1 > num2;
|
||||
case "=": return num1 == num2;
|
||||
case "==": return num1 == num2;
|
||||
case "<=": return num1 <= num2;
|
||||
case ">=": return num1 >= num2;
|
||||
default:
|
||||
Log.e("Invalid comparator: %s", comparator);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private double parseToNumber(RelationalServerData data, String str) {
|
||||
if (str.equals("user_version")) {
|
||||
ResultSet set = data.executeQuery("PRAGMA user_version");
|
||||
try {
|
||||
if (set.next())
|
||||
return set.getDouble(1);
|
||||
else
|
||||
Log.e("Variable 'user_version' has not been set!");
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return Double.parseDouble(str);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e("Number '%s' is not a valid number!", str);
|
||||
}
|
||||
}
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
private String [] getCommandsFromSchema(String schema) throws IOException {
|
||||
String command;
|
||||
try (InputStream input = new FileInputStream(new File(schema))) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(input.available());
|
||||
byte [] block = new byte[1024];
|
||||
while (input.available() > 0) {
|
||||
int size = input.read(block);
|
||||
baos.write(block, 0, size);
|
||||
}
|
||||
command = new String(baos.toByteArray(), Charset.forName("ASCII"));
|
||||
}
|
||||
return command.split(";");
|
||||
}
|
||||
|
||||
private Object getFileLocking(String file) {
|
||||
synchronized (FILE_LOAD_LOCKING) {
|
||||
Object o = FILE_LOAD_LOCKING.get(file);
|
||||
if (o == null)
|
||||
FILE_LOAD_LOCKING.put(file, o = new Object());
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ParserData {
|
||||
|
||||
private RecursiveBoolean conditionalValue;
|
||||
|
||||
public ParserData() {
|
||||
conditionalValue = null;
|
||||
}
|
||||
|
||||
public void addConditional(boolean val) {
|
||||
if (conditionalValue == null)
|
||||
conditionalValue = new RecursiveBoolean(val);
|
||||
else
|
||||
conditionalValue.createRecursive(val);
|
||||
}
|
||||
|
||||
public void unwrapLastConditional() {
|
||||
if (conditionalValue != null && conditionalValue.unwrapLast())
|
||||
conditionalValue = null;
|
||||
}
|
||||
|
||||
public boolean getConditional() {
|
||||
if (conditionalValue == null)
|
||||
return true;
|
||||
return conditionalValue.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class RecursiveBoolean {
|
||||
|
||||
private final boolean val;
|
||||
private RecursiveBoolean recursive;
|
||||
|
||||
public RecursiveBoolean(boolean val) {
|
||||
this.val = val;
|
||||
this.recursive = null;
|
||||
}
|
||||
|
||||
public boolean get() {
|
||||
if (recursive != null)
|
||||
return val && recursive.get();
|
||||
return val;
|
||||
}
|
||||
|
||||
public RecursiveBoolean createRecursive(boolean val) {
|
||||
if (recursive != null)
|
||||
return recursive.createRecursive(val);
|
||||
return (recursive = new RecursiveBoolean(val));
|
||||
}
|
||||
|
||||
public boolean unwrapLast() {
|
||||
RecursiveBoolean recur = this;
|
||||
while (recur.recursive != null && recur.recursive.recursive != null)
|
||||
recur = recur.recursive;
|
||||
if (recur != null && recur.recursive != null) {
|
||||
recur.recursive = null;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user