我需要创建特定代码以从基于 libGdx 的项目访问 Derby DB 和 FoundationDB SQL解析器,并使用不同的实现在应用程序的桌面和 WebGL 版本之间。桌面应用程序可以访问SQL解析器并可以在本地连接到DB,其他WebGL版本使用GWT RPC服务通过客户端 - 服务器机制访问数据。是否有可能以某种方式实现这种类型的功能?我还想讨论玩具代码的实现,如果可能的话:) :( / p>)
这里是当前(不在WebGL项目上工作)QueryManager代码,存储在主项目文件夹中:
/**
*
*/
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;
}
}
答案 0 :(得分:0)
也许我找到了问题的解决方案。在我的例子中,最好的选择是在根项目中创建一个puppet类,然后覆盖在同一个包中创建相同的类,进入特定于平台的项目,实现内部的不同行为。仅作为一个例子:
/* 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 */
}
}