package tr.com.srdc.mdr.core.store.query;
import java.util.ArrayList;
import java.util.List;
import tr.com.srdc.mdr.core.impl.ai.DataElementImpl;
import tr.com.srdc.mdr.core.impl.ai.EnumeratedConceptualDomainImpl;
import tr.com.srdc.mdr.core.impl.ai.EnumeratedValueDomainImpl;
import tr.com.srdc.mdr.core.impl.ai.NonEnumeratedConceptualDomainImpl;
import tr.com.srdc.mdr.core.impl.ai.NonEnumeratedValueDomainImpl;
import tr.com.srdc.mdr.core.impl.ai.PropertyImpl;
import tr.com.srdc.mdr.core.model.Util;
import tr.com.srdc.mdr.core.model.iso11179.ConceptualDomainResource;
import tr.com.srdc.mdr.core.model.iso11179.DataElementResource;
import tr.com.srdc.mdr.core.model.iso11179.PropertyResource;
import tr.com.srdc.mdr.core.model.iso11179.ValueDomainResource;
import tr.com.srdc.mdr.core.store.MDRDatabase;
import virtuoso.jena.driver.VirtGraph;
import virtuoso.jena.driver.VirtuosoQueryExecutionFactory;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Resource;
public class VirtuosoQueryFactory extends ResourceQueryFactory {
public VirtuosoQueryFactory(MDRDatabase mdrDatabase) {
super(mdrDatabase);
}
@Override
protected QueryExecution createQueryExecution(String queryString,
OntModel ontModel) {
return VirtuosoQueryExecutionFactory.create(queryString,
(VirtGraph) this.mdrDatabase.getJenaStore().getGraph());
}
@Override
public int getNumberOfDataElementSearch(String keyword, String contextURI,
TextSearchType searchType) {
StringBuilder queryString = new StringBuilder(PREFIX_MDR)
.append(PREFIX_RDFS)
.append("SELECT (COUNT (DISTINCT ?de) as ?count) FROM <")
.append(MDRDatabase.BASE_URI)
.append("> WHERE {")
.append("?de rdfs:subClassOf mdr:DataElement .")
.append("?de mdr:having ?aic .")
.append("?aic mdr:administeredItemContextTerminologicalEntry ?te .")
.append("?te mdr:containingTerminologicalEntryLanguage ?ls .")
.append("?ls mdr:containingNameEntry ?designation .")
.append("?designation mdr:name ?name .");
if (!Util.isNull(contextURI)) {
queryString.append("?aic mdr:administeredItemContextContext <")
.append(contextURI).append("> .");
}
// checks if keyword is empty
if (keyword.matches("\\s*")) {
return 0;
}
if (searchType == null || searchType.equals(TextSearchType.Exact)) {
queryString.append(exactMatchKeyword(keyword));
}
else if (searchType.equals(TextSearchType.WildCard)) {
queryString.append(atLeastOneKeyword(keyword));
}
else {
queryString.append(allWordsKeyword(keyword));
}
queryString.append(" .}");
QueryExecution qexec = this.createQueryExecution(
queryString.toString(), this.mdrDatabase.getOntModel());
int size = 0;
try {
ResultSet rs = qexec.execSelect();
while (rs.hasNext()) {
QuerySolution qs = rs.next();
size = qs.getLiteral("count").getInt();
}
} finally {
qexec.close();
}
return size;
}
@Override
public List<? super DataElementResource> searchDataElement(String keyword,
String contextURI, TextSearchType searchType, int limit, int offset) {
List<DataElementResource> dataElementList = new ArrayList<DataElementResource>();
StringBuilder queryString = new StringBuilder(PREFIX_MDR)
.append(PREFIX_RDFS)
.append("SELECT ?de FROM <")
.append(MDRDatabase.BASE_URI)
.append("> WHERE {")
.append("?de rdfs:subClassOf mdr:DataElement .")
.append("?de mdr:having ?aic .")
.append("?aic mdr:administeredItemContextTerminologicalEntry ?te .")
.append("?te mdr:containingTerminologicalEntryLanguage ?ls .")
.append("?ls mdr:containingNameEntry ?designation .")
.append("?designation mdr:name ?name .");
if (!Util.isNull(contextURI)) {
queryString.append("?aic mdr:administeredItemContextContext <")
.append(contextURI).append("> .");
}
// checks if keyword is empty
if (keyword.matches("\\s*")) {
return dataElementList;
}
if (searchType == null || searchType.equals(TextSearchType.Exact)) {
queryString.append(exactMatchKeyword(keyword));
}
else if (searchType.equals(TextSearchType.WildCard)) {
queryString.append(atLeastOneKeyword(keyword));
}
else {
queryString.append(allWordsKeyword(keyword));
}
queryString.append(" OPTION (score ?sc) .} ORDER BY ?sc LIMIT ")
.append(limit).append(" OFFSET ").append(offset);
QueryExecution qexec = this.createQueryExecution(
queryString.toString(), this.mdrDatabase.getOntModel());
try {
ResultSet rs = qexec.execSelect();
while (rs.hasNext()) {
QuerySolution qs = rs.next();
DataElementResource de = new DataElementImpl(
qs.getResource("de"), mdrDatabase);
dataElementList.add(de);
}
} finally {
qexec.close();
}
return dataElementList;
}
@Override
public List<? super PropertyResource> searchProperty(String keyword,
String contextURI, TextSearchType searchType) {
List<PropertyResource> propertyList = new ArrayList<PropertyResource>();
StringBuilder queryString = new StringBuilder(PREFIX_MDR)
.append(PREFIX_RDFS)
.append("SELECT ?property FROM <")
.append(MDRDatabase.BASE_URI)
.append("> WHERE {")
.append("?property rdfs:subClassOf mdr:Property .")
.append("?property mdr:having ?aic .")
.append("?aic mdr:administeredItemContextTerminologicalEntry ?te .")
.append("?te mdr:containingTerminologicalEntryLanguage ?ls .")
.append("?ls mdr:containingNameEntry ?designation .")
.append("?designation mdr:name ?name .");
if (!Util.isNull(contextURI)) {
queryString.append("?aic mdr:administeredItemContextContext <")
.append(contextURI).append("> .");
}
if (keyword.matches("\\s*")) {
return propertyList;
}
if (searchType == null || searchType.equals(TextSearchType.Exact)) {
queryString.append(exactMatchKeyword(keyword));
}
else if (searchType.equals(TextSearchType.WildCard)) {
queryString.append(atLeastOneKeyword(keyword));
}
else {
queryString.append(allWordsKeyword(keyword));
}
queryString.append(" .}");
QueryExecution qexec = this.createQueryExecution(
queryString.toString(), this.mdrDatabase.getOntModel());
try {
ResultSet rs = qexec.execSelect();
while (rs.hasNext()) {
QuerySolution qs = rs.next();
PropertyResource prop = new PropertyImpl(
qs.getResource("property"), mdrDatabase);
propertyList.add(prop);
}
} finally {
qexec.close();
}
return propertyList;
}
@Override
public List<? super ConceptualDomainResource> searchConceptualDomain(
String keyword, String contextURI, TextSearchType searchType) {
List<ConceptualDomainResource> cdList = new ArrayList<ConceptualDomainResource>();
StringBuilder queryString = new StringBuilder(PREFIX_MDR)
.append(PREFIX_RDFS)
.append("SELECT ?cd FROM <")
.append(MDRDatabase.BASE_URI)
.append("> WHERE {")
.append("?cdClass rdfs:subClassOf mdr:ConceptualDomain .")
.append("?cd rdfs:subClassOf ?cdClass .")
.append("?cd mdr:having ?aic .")
.append("?aic mdr:administeredItemContextTerminologicalEntry ?te .")
.append("?te mdr:containingTerminologicalEntryLanguage ?ls .")
.append("?ls mdr:containingNameEntry ?designation .")
.append("?designation mdr:name ?name .");
if (!Util.isNull(contextURI)) {
queryString.append("?aic mdr:administeredItemContextContext <")
.append(contextURI).append("> .");
}
if (keyword.matches("\\s*")) {
return cdList;
}
if (searchType == null || searchType.equals(TextSearchType.Exact)) {
queryString.append(exactMatchKeyword(keyword));
}
else if (searchType.equals(TextSearchType.WildCard)) {
queryString.append(atLeastOneKeyword(keyword));
}
else {
queryString.append(allWordsKeyword(keyword));
}
queryString.append(" .}");
QueryExecution qexec = this.createQueryExecution(
queryString.toString(), this.mdrDatabase.getOntModel());
try {
ResultSet rs = qexec.execSelect();
while (rs.hasNext()) {
QuerySolution qs = rs.next();
// here conceptualDomain is checked whether its enumerated or
// not, proper instantiation is done
Resource tempRes = this.mdrDatabase.getOntModel().getResource(
qs.getResource("cd").getURI());
OntClass res = tempRes.as(OntClass.class);
if (res.hasSuperClass(mdrDatabase.getVocabulary().EnumeratedConceptualDomain)) {
cdList.add(new EnumeratedConceptualDomainImpl(res,
mdrDatabase));
} else {
cdList.add(new NonEnumeratedConceptualDomainImpl(res,
mdrDatabase));
}
}
} finally {
qexec.close();
}
return cdList;
}
@Override
public List<? super ValueDomainResource> searchValueDomain(String keyword,
String uri, TextSearchType searchType) {
List<ValueDomainResource> vdList = new ArrayList<ValueDomainResource>();
StringBuilder queryString = new StringBuilder(PREFIX_MDR)
.append(PREFIX_RDFS)
.append("SELECT ?cd FROM <")
.append(MDRDatabase.BASE_URI)
.append("> WHERE {")
.append("?cdClass rdfs:subClassOf mdr:ValueDomain .")
.append("?cd rdfs:subClassOf ?cdClass .")
.append("?cd mdr:having ?aic .")
.append("?aic mdr:administeredItemContextTerminologicalEntry ?te .")
.append("?te mdr:containingTerminologicalEntryLanguage ?ls .")
.append("?ls mdr:containingNameEntry ?designation .")
.append("?designation mdr:name ?name .");
if (!Util.isNull(uri)) {
queryString.append("?aic mdr:administeredItemContextContext <")
.append(uri).append("> .");
}
if (keyword.matches("\\s*")) {
return vdList;
}
if (searchType == null || searchType.equals(TextSearchType.Exact)) {
queryString.append(exactMatchKeyword(keyword));
}
else if (searchType.equals(TextSearchType.WildCard)) {
queryString.append(atLeastOneKeyword(keyword));
}
else {
queryString.append(allWordsKeyword(keyword));
}
queryString.append(" .}");
QueryExecution qexec = this.createQueryExecution(
queryString.toString(), this.mdrDatabase.getOntModel());
try {
ResultSet rs = qexec.execSelect();
while (rs.hasNext()) {
QuerySolution qs = rs.next();
// here conceptualDomain is checked whether its enumerated or
// not, proper instantiation is done
Resource tempRes = this.mdrDatabase.getOntModel().getResource(
qs.getResource("cd").getURI());
OntClass res = tempRes.as(OntClass.class);
if (res.hasSuperClass(mdrDatabase.getVocabulary().EnumeratedValueDomain)) {
vdList.add(new EnumeratedValueDomainImpl(res, mdrDatabase));
} else {
vdList.add(new NonEnumeratedValueDomainImpl(res,
mdrDatabase));
}
}
} finally {
qexec.close();
}
return vdList;
}
/**
* Creates a text match keyword for exact match according to Virtuoso query
* syntax.
*
* @param keyword
* Query keywords seperated from each other with whitespaces
* @return
*/
private String exactMatchKeyword(String keyword) {
String[] keywords = keyword.split("\\s+");
StringBuilder queryString = new StringBuilder();
queryString.append("?name bif:contains '\"");
for (int i = 0; i < keywords.length - 1; i++) {
queryString.append(keywords[i]).append(" ");
}
queryString.append(keywords[keywords.length - 1]).append(" \"' ");
return queryString.toString();
}
/**
* Creates a text match keyword for wild card search according to Virtuoso
* query syntax.
*
* @param keyword
* Query keywords seperated from each other with whitespaces
* @return
*/
private String atLeastOneKeyword(String keyword) {
String[] keywords = keyword.split("\\s+");
StringBuilder queryString = new StringBuilder();
queryString.append("?name bif:contains '\"");
String lastWord = keywords[keywords.length - 1];
if (lastWord.length() < 4) {
keyword = concat(keywords);
}
if (keyword.length() < 4) {
queryString.append(keyword).append("\"' ");
} else {
// wildcard search
queryString.append(keyword).append("*\"' ");
}
return queryString.toString();
}
/**
* Creates a text match keyword for matching all words according to Virtuoso
* query syntax.
*
* @param keyword
* Query keywords seperated from each other with whitespaces
* @return
*/
private String allWordsKeyword(String keyword) {
String[] keywords = keyword.split("\\s+");
StringBuilder queryString = new StringBuilder();
queryString.append("?name pf:textMatch '");
for (int i = 0; i < keywords.length - 1; i++) {
queryString.append(keywords[i]).append(" AND ");
}
queryString.append(keywords[keywords.length - 1]).append(" ' ");
return queryString.toString();
}
/**
* This method is taken from the TerminologyServer written by anil. Since
* Virtuoso Text Index supports wildcard searches only with words longer
* than 4 letters, this case should be handled carefully.
*
* @param parts
* Concanates array of string into one with spaces in between
* them
* @return
*/
private String concat(String[] parts) {
StringBuilder sb = new StringBuilder();
boolean flag = false;
for (int i = 0; i < parts.length - 1; i++) {
sb.append(parts[i]);
sb.append(' ');
flag = true;
}
if (!flag)
return parts[0];
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
}