package gov.nist.registry.common2.registry;
import gov.nist.registry.common2.exception.ExceptionUtil;
import gov.nist.registry.common2.exception.MetadataException;
import gov.nist.registry.common2.exception.MetadataValidationException;
import gov.nist.registry.common2.exception.XMLParserException;
import gov.nist.registry.common2.exception.XdsException;
import gov.nist.registry.common2.exception.XdsInternalException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openhealthtools.openexchange.config.PropertyFacade;
import org.openhealthtools.openxds.XdsFactory;
import org.openhealthtools.openxds.log.LogMessage;
import org.openhealthtools.openxds.log.LoggerException;
import org.openhealthtools.openxds.registry.api.RegistryQueryException;
import org.openhealthtools.openxds.registry.api.RegistrySQLQueryContext;
import org.openhealthtools.openxds.registry.api.RegistryStoredQueryContext;
import org.openhealthtools.openxds.registry.api.XdsRegistryQueryService;
public class BackendRegistry {
ErrorLogger response;
LogMessage log_message;
String reason = "";
private final static Log logger = LogFactory.getLog(BackendRegistry.class);
public BackendRegistry(ErrorLogger response, LogMessage logMessage) {
this.response = response;
this.log_message = logMessage;
}
public BackendRegistry(ErrorLogger response, LogMessage log_message, String reason) {
this.response = response;
this.log_message = log_message;
this.reason = reason;
}
public void setReason(String reason) {
this.reason = reason;
}
static QName object_ref_qname = new QName("ObjectRef");
static QName id_qname = new QName("id");
/**
* Submits an SQL query to the backend registry expecting ObjectRefs to be returned.
* @param sql SQL text
* @return list of UUIDs
* @throws XMLParserException error parsing XML response from back end registry
* @throws LoggerException error writing to test log facility
* @throws XdsException all other errors
*/
public List<String> queryForObjectRefs(String sql) throws XMLParserException, LoggerException, XdsException {
OMElement result = query(sql, false /* leaf_class */);
List<String> ors = new ArrayList<String>();
if (result == null) // error occured
return ors;
OMElement sql_query_result = MetadataSupport.firstChildWithLocalName(result, "RegistryObjectList");
if (sql_query_result != null) {
for (OMElement or : MetadataSupport.childrenWithLocalName(sql_query_result, "ObjectRef")) {
String id = or.getAttributeValue(id_qname);
if (id != null && !id.equals(""))
ors.add(id);
}
}
return ors;
}
static String sql_query_header =
"<AdhocQueryRequest\n" +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
"xmlns:rs=\"urn:oasis:names:tc:ebxml-regrep:registry:xsd:2.1\"\n" +
"xmlns:rim=\"urn:oasis:names:tc:ebxml-regrep:rim:xsd:2.1\"\n" +
"xmlns:q = \"urn:oasis:names:tc:ebxml-regrep:query:xsd:2.1\"\n" +
"xmlns=\"urn:oasis:names:tc:ebxml-regrep:query:xsd:2.1\"\n" +
">\n";
/**
* Build and execute an AdhocQuery request. This is different from basic_query which it calls
* because it repairs buggy metadata sometimes returned from current back end registry.
* @param sql query SQL
* @param leaf_class return is to be LeafClass (full metadata). Alternative is ObjectRefs.
* @return RegistryResponse
* @throws LoggerException error writing to test log facility
* @throws XMLParserException error XML parsing back end registry response
* @throws MetadataException error interpreting registry metadata
* @throws MetadataValidationException error interpreting registry metadata
* @throws XdsInternalException other error
*/
public OMElement query(String sql, boolean leaf_class) throws LoggerException, XMLParserException, MetadataException, MetadataValidationException, XdsInternalException {
OMElement result = basic_query(sql, leaf_class);
// add in homeCommunityId to all major
//Metadata m = MetadataParser.parseNonSubmission(result);
// above constructor will remove duplicates and therefore not fix all metadata
Metadata m = new Metadata();
m.addMetadata(result, true); // it seems this parm should be false, but this works?????
m.fixClassifications();
for (OMElement ele : m.getAllObjects()) {
add_v3_attributes(ele);
for (Iterator it=ele.getChildElements(); it.hasNext(); ) {
OMElement ele2 = (OMElement) it.next();
if (ele2.getLocalName().equals("ExternalIdentifier")) add_v3_attributes(ele2);
if (ele2.getLocalName().equals("Classification")) add_v3_attributes(ele2);
}
}
return result;
}
/**
* Build and execute an AdhocQuery request.
* @param sql query SQL
* @param leaf_class return is to be LeafClass (full metadata). Alternative is ObjectRefs.
* @return
* @throws XMLParserException error XML parsing back end registry response
* @throws LoggerException error writing to test log facility
* @throws XdsInternalException other error
*/
public OMElement basic_query(String sql, boolean leaf_class)
throws XMLParserException, LoggerException, XdsInternalException {
if (log_message != null)
log_message.addOtherParam("ebxmlrr request (" + reason + ")", sql);
XdsRegistryQueryService qm = XdsFactory.getXdsRegistryQueryService();
RegistrySQLQueryContext context = new RegistrySQLQueryContext(sql, leaf_class);
OMElement response_xml = null;
try {
response_xml = qm.sqlQuery(context);
}catch(RegistryQueryException e) {
throw new XdsInternalException("Registry query exception - " + e.getMessage() + " \nQuery was:\n"+ sql, e);
}
if (log_message != null)
log_message.addOtherParam("ebxmlrr response", response.toString());
if (! response_xml.getLocalName().equals("AdhocQueryResponse")) {
try {
throw new XdsInternalException("Return from ebxmlrr is '" + response_xml.getLocalName() + "' but should be 'AdhocQueryResponse'");
} catch (Exception e) {
response.add_error("XDSRegistryError", "Return from ebxmlrr is '" + response_xml.getLocalName() + "' but should be 'AdhocQueryResponse'", RegistryUtility.exception_details(e), log_message);
}
return null;
}
if (! response_xml.getAttributeValue(new QName("status")).equals("urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Success")) {
String msg = "Status from ebxmlrr is '" + response_xml.getAttributeValue(new QName("status")) +
"' but should be 'Success'. Error message(s) are:\n";
String msg_copy = msg;
RegistryResponseParser rr = new RegistryResponseParser(response_xml);
ArrayList<String> errs = rr.get_error_code_contexts();
for (int i=0; i<errs.size(); i++) {
String err = (String) errs.get(i);
if (err.indexOf("QueryManagerImpl") > -1) {
// ebxmlrr could not parse query
msg = msg_copy + "Query engine error: " + ExceptionUtil.firstNLines(rr.get_regrep_error_msg(),4); // + rr.get_regrep_error_msg();
msg = ExceptionUtil.firstNLines(msg, 4);
break;
}
//msg += (String) err + "\n";
}
msg += "\nQuery was:\n" + sql;
throw new XdsInternalException(msg);
}
return response_xml;
}
private void add_v3_attributes(OMElement ele) {
ele.addAttribute("home", "", null);
ele.addAttribute("lid", ele.getAttributeValue(MetadataSupport.id_qname), null);
insert_version_info(ele);
}
void insert_version_info(OMElement parent) {
if (MetadataSupport.firstChildWithLocalName(parent, "VersionInfo") != null) return;
OMElement vi = MetadataSupport.om_factory.createOMElement("VersionInfo", MetadataSupport.ebRIMns3);
vi.addAttribute("versionName", "1.1", null);
parent.addChild(vi);
}
/**
* Issue pre-formatted query to back end registry
* @param ahqr the query
* @return RegistryResponse
* @throws LoggerException error writing to test log facility
* @throws XdsInternalException all other errors
*/
public OMElement query(OMElement ahqr) throws LoggerException, XdsInternalException {
if (log_message != null)
log_message.addOtherParam("ebxmlrr request (" + reason + ")", ahqr.toString());
//TODO: initiate RegistryQueryManager
XdsRegistryQueryService qm = null;
//TODO: convert ahqr OMElement to context, extract id and query parameters
String id = "123"; //
Map params = new HashMap();
RegistryStoredQueryContext context = new RegistryStoredQueryContext(id, params, true /*LeafClass*/);
OMElement response = null;
try {
response = qm.storedQuery(context);
}catch(RegistryQueryException e) {
throw new XdsInternalException("Registry query exception - " + e.getMessage(), e);
}
if (log_message != null)
log_message.addOtherParam("ebxmlrr response", response.toString());
OMElement response_xml = null;
if (! response.getLocalName().equals("RegistryResponse")) {
throw new XdsInternalException("Return from ebxmlrr is '" + response_xml.getLocalName() + "' but should be 'RegistryResponse'");
}
if (! response_xml.getAttributeValue(new QName("status")).equals("Success")) {
String msg = "Status from ebxmlrr is '" + response_xml.getAttributeValue(new QName("status")) +
"' but should be 'Success'. Error message(s) are:\n";
String msg_copy = msg;
RegistryResponseParser rr = new RegistryResponseParser(response_xml);
ArrayList<String> errs = rr.get_error_code_contexts();
for (int i=0; i<errs.size(); i++) {
String err = (String) errs.get(i);
if (err.indexOf("QueryManagerImpl") > -1) {
// ebxmlrr could not parse query
msg = msg_copy + "Query engine error: " + ExceptionUtil.firstNLines(rr.get_regrep_error_msg(),4); // + rr.get_regrep_error_msg();
msg = ExceptionUtil.firstNLines(msg, 4);
break;
}
//msg += (String) err + "\n";
}
msg += "\nQuery was:\n" + ahqr.toString();
throw new XdsInternalException(msg);
}
return response_xml;
}
}