package ring.persistence;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.w3c.dom.Node;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.ResourceIterator;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
import ring.nrapi.business.BusinessObject;
/**
* Class for running XQuery against the XML database and
* converting the results into an arbitrary object.
* @author projectmoon
*
*/
public class XQuery {
private String query;
private Loadpoint loadpoint = Loadpoint.STATIC;
private Map<String, Object> declaredVariables = new HashMap<String, Object>();
public XQuery() {}
public XQuery(String query) {
this.query = query;
}
public XQuery(File xqFile) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(xqFile));
String line = "";
query = "";
while ((line = reader.readLine()) != null) {
query += line + "\n";
}
}
public XQuery(InputStream xqStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(xqStream));
String line = "";
query = "";
while ((line = reader.readLine()) != null) {
query += line + "\n";
}
}
public XQuery(Loadpoint loadpoint, String query) {
this.loadpoint = loadpoint;
this.query = query;
}
public void declareVariable(String variable, Object value) {
/*
if (!variable.startsWith("$")) {
throw new IllegalArgumentException("declareVariable: Variable ID must begin with $");
}
else {
variable = variable.replace("$", "\\$");
System.out.println("Variable: " + variable);
query = query.replaceAll(variable, value.toString());
}
*/
declaredVariables.put(variable, value);
}
public void setLoadpoint(Loadpoint point) {
loadpoint = point;
}
public Loadpoint getLoadpoint() {
return loadpoint;
}
public void setQuery(String query) {
this.query = query;
}
public String getQuery() {
return query;
}
public void executeUpdate() throws XMLDBException {
ExistDB db = new ExistDB();
Collection col = getCollection(db);
db.query(col, getQuery(), declaredVariables);
col.close();
}
/**
* Queries the database and returns a ResourceList of Resources that were found.
* This ResourceList can be iterated over with a foreach loop, unlike the regular
* ResourceSet. It also provides a close() method for when operations on the resources
* are complete. Make sure to always call close() on the ResourceList.
* @return
* @throws XMLDBException
*/
public ResourceList execute() throws XMLDBException {
ExistDB db = new ExistDB();
Collection col = getCollection(db);
ResourceSet xmlDocs = db.query(col, getQuery(), declaredVariables);
return new ResourceList(col, xmlDocs);
}
public <T extends BusinessObject> List<T> execute(Class<T> cl) throws XMLDBException, JAXBException {
if (getLoadpoint() == Loadpoint.DEFAULT) {
return loadFromDefault(cl);
}
else {
ExistDB db = new ExistDB();
Collection col = getCollection(db);
return loadFromCollection(cl, db, col);
}
}
private <T extends BusinessObject> List<T> loadFromDefault(Class<T> cl) throws XMLDBException, JAXBException {
ExistDB db = new ExistDB();
Collection col = db.getCollection(ExistDBStore.GAME_COLLECTION);
List<T> results = loadFromCollection(cl, db, col);
if (results.size() > 0) {
return results;
}
else {
//Fall back to static
col.close(); //release previous collection
col = db.getCollection(ExistDBStore.STATIC_COLLECTION);
return loadFromCollection(cl, db, col);
}
}
private <T extends BusinessObject> List<T> loadFromCollection(Class<T> cl, ExistDB db, Collection col) throws XMLDBException, JAXBException {
ResourceSet xmlDocs = db.query(col, getQuery(), declaredVariables);
List<T> results = new ArrayList<T>((int)xmlDocs.getSize());
ResourceIterator iter = xmlDocs.getIterator();
while (iter.hasMoreResources()) {
XMLResource res = (XMLResource)iter.nextResource();
T conv = convertToObject(res, cl);
results.add(conv);
}
col.close();
return results;
}
private Collection getCollection(ExistDB db) throws XMLDBException {
if (loadpoint == Loadpoint.GAME) {
return db.getCollection(ExistDBStore.GAME_COLLECTION);
}
else if (loadpoint == Loadpoint.STATIC){
return db.getCollection(ExistDBStore.STATIC_COLLECTION);
}
else if (loadpoint == Loadpoint.PLAYERS) {
return db.getCollection(ExistDBStore.PLAYERS_COLLECTION);
}
else {
throw new UnsupportedOperationException();
}
}
@SuppressWarnings("unchecked")
private <T extends BusinessObject> T convertToObject(XMLResource res, Class<T> cl) throws JAXBException, XMLDBException {
JAXBContext ctx = JAXBContext.newInstance(cl);
Unmarshaller um = ctx.createUnmarshaller();
um.setListener(new ParentRelationshipCreator());
Node node = res.getContentAsDOM();
T conv = (T)um.unmarshal(node);
conv.setStoreAsUpdate(true);
conv.createChildRelationships();
return conv;
}
}