问题
I need to create specific code to access a Derby DB and the FoundationDB SQL parser from a libGdx based project, with a different implementation between the Desktop and the WebGL version of the application. The Desktop application can access the SQL parser and can connect to the DB locally, otherwhise the WebGL version uses the GWT RPC service to access data via a client-server mechanism. Is it possible to implement in a certain way this type of functionality? I would like also to discuss over a toy code implementation, if it's possible :)
Here's the current (not working on the WebGL project) QueryManager code, stored in the main project folder:
/**
*
*/
package it.viscioletti.sqlapprentice.sql;
import it.viscioletti.sqlapprentice.data.FieldDescription;
import it.viscioletti.sqlapprentice.data.FieldType;
import it.viscioletti.sqlapprentice.data.Row;
import it.viscioletti.sqlapprentice.data.TableDescription;
import it.viscioletti.sqlapprentice.gui.table.TableGui;
import it.viscioletti.sqlapprentice.utils.Constants;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Vector;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.foundationdb.sql.StandardException;
import com.foundationdb.sql.parser.SQLParser;
import com.foundationdb.sql.parser.StatementNode;
/**
* @author Federico
*
*/
public class QueryManager {
/* Member Variables: */
private float tablesAreaW, tablesAreaH, textAreaH;
private Connection conn;
private ResultSet rs;
private Statement stmt;
private String sql;
private TableGui resultTable;
/* Constructors: */
/** @throws SQLException */
public QueryManager(String sql) {
// stores the SQL String
this.sql = sql.trim();
// sets sizes used by the QueryManager
float w = Gdx.graphics.getWidth(), h = Gdx.graphics.getHeight();
tablesAreaW = (w / 10) * 7;
tablesAreaH = (h / 10) * 6;
textAreaH = h - (h / 10) - tablesAreaH;
}
/* Methods: */
/** Checks the query sintax using Derby DBMS
* @throws SQLException */
public void checkSintax() throws SQLException {
// connects to the DB
connect();
/* tries to execute the query.
* If is all fine, this method doesn't return anything,
* otherwise it will throws a SQLException to the calling class */
String[] sqlArray = sql.split(" ");
// checks if is an INSERT INTO query type and then executes
if(sqlArray[0].toUpperCase().equals("INSERT")) {
System.out.println("Eseguo la INSERT (QM)"); // TODO remove later
stmt.executeUpdate(sql); //TODO remove later
} else
stmt.executeQuery(sql);
}
/** Connects to the DB
* @throws SQLException */
private void connect() throws SQLException {
// gets the connection to Derby DB
conn = DriverManager.getConnection( Constants.CONNECTION_URL );
// creates the statement for the connection
stmt = conn.createStatement();
}
/** Executes the query and returns a TableGui object
* @return The TableGui object result of the query
* @throws SQLException */
public TableGui getResultTable() throws SQLException {
// connects to the DB
connect();
// gets the result set object of the executed query
rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
Vector<FieldDescription> fieldDescriptions = new Vector<FieldDescription>();
// stores each column name of the table
String[] fieldNames = new String[rsmd.getColumnCount()];
FieldType[] fieldTypes = new FieldType[rsmd.getColumnCount()];
int idPos = -1;
// the column numeration into the ResultsSetMetaData goes from 1 to column number
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
// stores the position of SQLAPPRENTICEID, only if exists
if(rsmd.getColumnName(i).trim().equals(Constants.TABLE_ID))
idPos = i - 1;
// gets the field name and adds it to the field names array
fieldNames[i-1] = rsmd.getColumnName(i).trim();
FieldType ft;
// gets the column type and adds it to the field types array
switch(rsmd.getColumnType(i)) {
case Types.CHAR:
case Types.VARCHAR:
ft = FieldType.CHAR;
break;
case Types.INTEGER:
ft = FieldType.INTEGER;
break;
default:
ft = null;
assert false;
}
// adds the field type to the array
fieldTypes[i - 1] = ft;
// if its not a SQLAPPRENTICETABLEID
if(!rsmd.getColumnName(i).trim().equals(Constants.TABLE_ID)) {
// creates a new FieldDescription with appropriates column names and field types
FieldDescription fd = new FieldDescription(fieldNames[i-1], ft);
// adds it to the vector
fieldDescriptions.add(fd);
}
}
// creates the TableDescription for the given table
TableDescription td = new TableDescription(rsmd.getTableName(1), fieldDescriptions);
TextureAtlas atlas = new TextureAtlas("ui/atlas.pack");
Skin skin = new Skin(Gdx.files.internal("ui/applicationScreenSkin.json"), atlas);
resultTable = new TableGui(skin, td);
// sets bounds of the new table created
resultTable.setBounds(tablesAreaW / 2, tablesAreaH, tablesAreaW, tablesAreaH);
// draws debug lines
resultTable.debug(); //TODO remove later
resultTable.addTableHeader();
// size of values array
int valSize = (idPos == -1) ? fieldNames.length : fieldNames.length - 1;
// stores the values of each table row
Object[] values = new Object[valSize];
// retrieves automatically the result set content
while (rs.next()) {
// uses a second index for values array because if the
// resultset has the id field in it, it's bigger than values
int j = 0,
// initialize id variable on every iteration
id = 0;
for (int i = 0; i < fieldNames.length; i++) {
if(idPos != i) {
switch(fieldTypes[i]) {
case CHAR:
// trims the string returned because of the white spaces
values[j] = rs.getString(i + 1).trim();
break;
case INTEGER:
values[j] = rs.getInt(i + 1);
break;
default: assert false;
}
j++;
} else
id = rs.getInt(i + 1);
}
resultTable.addRow(new Row(id, td, values));
}
resultTable.setBounds((tablesAreaW / 2) - (resultTable.getTableWidth() / 2),
textAreaH + (tablesAreaH / 2) - (resultTable.getTableHeight() / 2),
resultTable.getTableWidth(), resultTable.getTableHeight());
return resultTable;
}
/** Checks if the device ha
* Parses the query and returns its description
* @return the QueryDescription */
public QueryDescription dispatchParse() {
if(Gdx.app.getType() == ApplicationType.Desktop) {
System.out.println();
try {
return localParse();
} catch (StandardException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if(Gdx.app.getType() == ApplicationType.WebGL) {
System.out.println();
}
return null;
}
/** Parses locally the query and returns its description
* @return the QueryDescription
* @throws StandardException */
public QueryDescription localParse() throws StandardException {
// creates a new SQL parser to parse the query
SQLParser parser = new SQLParser();
// parses the query
StatementNode stmt = parser.parseStatement(sql);
// using the visitor design pattern to explore the query tree
QueryVisitor qv = new QueryVisitor();
stmt.accept(qv);
// creates the query description
return qv.createDescription();
}
/** Parses the query server-side and returns its description
* @return the QueryDescription */
public QueryDescription serverParse() {
return null;
}
}
回答1:
Maybe I've found a solution to the problem. In my case the best option is to create a puppet class in the root project, and then overwrite creating the same class, in the same package, into the platform-specific projects, implementing the different behavior inside. Just as an example:
/* The puppet class into the root project: */
public class DBManager implements DBManagerInterface {
public DBManager() {
}
@Override
public void executeQuery(String sql) {
}
}
/* the desktop project: */
public class DBManager implements DBManagerInterface {
public DBManager() {
}
@Override
public void executeQuery(String sql) {
/* insert here the code to execute a query
locally on the desktop application */
}
}
/* the WebGL project: */
public class DBManager implements DBManagerInterface {
public DBManager() {
}
@Override
public void executeQuery(String sql) {
/* insert here the code to execute a query
using a client-server interaction via GWT RPC */
}
}
来源:https://stackoverflow.com/questions/25743610/libgdx-platform-specific-code