com.cyc.query.client.QueryReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cyc-query-client Show documentation
Show all versions of cyc-query-client Show documentation
Query API implementation for requesting and handling answers to arbitrarily complex questions
posed to a Cyc server.
package com.cyc.query.client;
/*
* #%L
* File: QueryReader.java
* Project: Query Client
* %%
* Copyright (C) 2013 - 2017 Cycorp, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.cyc.base.CycAccessManager;
import com.cyc.base.cycobject.CycConstant;
import com.cyc.base.cycobject.CycList;
import com.cyc.base.cycobject.CycObject;
import com.cyc.base.cycobject.CycSymbol;
import com.cyc.base.cycobject.DenotationalTerm;
import com.cyc.base.cycobject.ElMt;
import com.cyc.base.cycobject.FormulaSentence;
import com.cyc.base.cycobject.Nart;
import com.cyc.base.cycobject.Naut;
import com.cyc.base.cycobject.NonAtomicTerm;
import com.cyc.base.exception.CycApiException;
import com.cyc.base.exception.CycConnectionException;
import static com.cyc.baseclient.CycObjectFactory.makeCycSymbol;
import static com.cyc.baseclient.connection.SublApiHelper.wrapVariableBinding;
import com.cyc.baseclient.cycobject.CycConstantImpl;
import com.cyc.baseclient.cycobject.ElMtCycNautImpl;
import com.cyc.baseclient.cycobject.ElMtNartImpl;
import com.cyc.baseclient.cycobject.GuidImpl;
import com.cyc.baseclient.inference.params.DefaultInferenceParameters;
import static com.cyc.baseclient.xml.cycml.CycmlDecoder.translateObject;
import com.cyc.kb.Context;
import com.cyc.kb.KbIndividual;
import com.cyc.kb.Sentence;
import com.cyc.kb.client.ContextImpl;
import com.cyc.kb.client.KbIndividualImpl;
import com.cyc.kb.client.SentenceImpl;
import com.cyc.kb.exception.KbException;
import com.cyc.query.Query;
import com.cyc.query.QueryFactory;
import com.cyc.query.exception.QueryConstructionException;
import com.cyc.query.exception.QueryRuntimeException;
import com.cyc.query.parameters.InferenceParameters;
import com.cyc.session.exception.SessionException;
import com.cyc.xml.query.CyclQuery;
import com.cyc.xml.query.CyclQueryUnmarshaller;
import com.cyc.xml.query.PropertyValue;
import com.cyc.xml.query.QueryFormula;
import com.cyc.xml.query.QueryID;
import com.cyc.xml.query.QueryInferenceProperties;
import com.cyc.xml.query.QueryInferenceProperty;
import com.cyc.xml.query.QueryMt;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.bind.JAXBException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Support for reading in a QueryImpl from XML.
*
* @see com.cyc.query.client.QueryImpl
* @author baxter
*/
public class QueryReader {
static private final Logger LOGGER = LoggerFactory.getLogger(QueryReader.class);
final CyclQueryUnmarshaller unmarshaller;
/**
* Create a new QueryReader.
*
* @throws JAXBException
*/
public QueryReader() throws JAXBException {
unmarshaller = new CyclQueryUnmarshaller();
}
QueryReader(CyclQueryUnmarshaller unmarshaller) throws JAXBException {
this.unmarshaller = unmarshaller;
}
/**
* Read a query from an XML stream.
*
* @param stream
* @return the query
* @throws KbException if any needed KBObjects cannot be found or created.
* @throws QueryConstructionException if any other problem is encountered
*/
protected Query queryFromXML(final InputStream stream) throws KbException,
QueryConstructionException {
try {
final Object contentTree = unmarshaller.unmarshal(stream);
if (contentTree instanceof CyclQuery) {
return convertQuery((CyclQuery) contentTree);
} else {
throw new IllegalArgumentException("Can't convert " + contentTree);
}
} catch (JAXBException ex) {
throw new RuntimeException(ex);
}
}
/**
* Returns a Query object defined by a query term.
*
* @param queryTerm
* @return a Query object defined by queryTerm
* @throws KbException if any needed KBObjects cannot be found or created.
* @throws com.cyc.query.exception.QueryConstructionException
* @throws QueryRuntimeException if there is some other kind of problem
*/
protected Query queryFromTerm(KbIndividual queryTerm) throws KbException,
QueryConstructionException, QueryRuntimeException {
final String coreCommand = "(get-cycl-query-in-xml " + queryTerm.stringApiValue() + ")";
final String command
= wrapVariableBinding(
coreCommand,
makeCycSymbol("*cycl-query-include-namespace?*"),
makeCycSymbol("T"));
try {
//final String xmlString = processXml(CycAccessManager.getCurrentAccess().converse().converseString(command));
//final String xmlString = CycAccessManager.getCurrentAccess().converse().converseString(command);
final String rawXmlString = CycAccessManager.getCurrentAccess().converse().converseString(command);
LOGGER.debug(
"Query XML:\n"
+ "---->>>>>> [START Query XML] ------------------------------------>>>>>>\n"
+ "{}\n"
+ "<<<<<<---- [END Query XML] <<<<<<------------------------------------",
rawXmlString);
final String xmlString = processXml(rawXmlString);
return queryFromXML(new ByteArrayInputStream(xmlString.getBytes()));
} catch (KbException e) {
throw e;
} catch (CycApiException | CycConnectionException | SessionException e) {
throw new QueryRuntimeException( e);
}
}
/**
* Convert a CyclQuery to a QueryImpl.
*
* @param cyclQuery
* @return the new QueryImpl object.
* @throws KbException if any needed KBObjects cannot be found or created.
* @throws QueryConstructionException if any other problem is encountered
* constructing the QueryImpl object.
* @see CyclQuery
*/
public Query convertQuery(CyclQuery cyclQuery) throws KbException, QueryConstructionException {
final DenotationalTerm queryId = convertID(cyclQuery.getQueryID());
final Sentence querySentence = new SentenceImpl(convertFormula(
cyclQuery.getQueryFormula()));
final Context queryContext = convertMt(cyclQuery.getQueryMt());
InferenceParameters queryParams = null;
for (final Object obj : cyclQuery.getQueryCommentOrQueryInferencePropertiesOrQueryIndexicals()) {
if (obj instanceof QueryInferenceProperties) {
try {
queryParams = convertParams((QueryInferenceProperties) obj);
} catch (SessionException ex) {
throw new QueryConstructionException("Couldn't convert parameters.", ex);
}
}
}
final QueryImpl query = (QueryImpl) QueryFactory
.getQuery(querySentence, queryContext, queryParams);
System.out.println("QUERY ID: " + queryId);
query.setId(KbIndividualImpl.findOrCreate(queryId));
return query;
}
private DenotationalTerm convertID(QueryID queryId) {
if (queryId.getConstant() != null) {
return (CycConstant) translateObject(queryId.getConstant());
} else {
return (NonAtomicTerm) translateObject(queryId.getFunction());
}
}
private FormulaSentence convertFormula(QueryFormula queryFormula) {
return (FormulaSentence) translateObject(
queryFormula.getSentence());
}
private Context convertMt(QueryMt queryMt) throws KbException {
if (queryMt.getConstant() != null) {
return ContextImpl.get(((CycConstant) translateObject(
queryMt.getConstant())).stringApiValue());
} else {
final NonAtomicTerm mtNAT = (NonAtomicTerm) translateObject(
queryMt.getFunction());
final ElMt elmt = (mtNAT instanceof Nart) //@todo mtNat can probably be sent directly to Context.get(), without trying to convert to either an ELMt or a CycNaut
? ElMtNartImpl.makeElMtNart((Nart) mtNAT)
: ElMtCycNautImpl.makeElMtCycNaut(
((Naut) mtNAT).getArgs());
return ContextImpl.get(elmt);
}
}
// The code below was commented out as part of an egregious hack to allow list-based inference parameters like :result-sort-order. Once
// that hack is backed out, this can become the main code here again.
//
// private InferenceParameters convertParams (
// QueryInferenceProperties queryInferenceProperties) throws SessionException {
// final StringBuilder sb = new StringBuilder();
// for (final QueryInferenceProperty qip : queryInferenceProperties.getQueryInferenceProperty()) {
// if (sb.length() > 0) {
// sb.append(" ");
// }
// final String symbolName = qip.getPropertySymbol().getContent().trim();
// sb.append(":").append(symbolName).append(" ");
// appendPropertyValue(qip.getPropertyValue(), sb);
// }
// final String paramString = sb.toString();
// return new DefaultInferenceParameters(CycAccessManager.getCurrentAccess(), paramString);
// }
//
// private void appendPropertyValue(final PropertyValue val,
// final StringBuilder sb) {
// if (val.getConstant() != null) {
// sb.append(((CycConstant) translateObject(
// val.getConstant())).stringApiValue());
// } else if (val.getFunction() != null) {
// sb.append(((NonAtomicTerm) translateObject(
// val.getFunction())).stringApiValue());
// } else if (val.getNumber() != null) {
// sb.append((val.getNumber()));
// } else if (val.getSentence() != null) {
// sb.append(((FormulaSentence) translateObject(
// val.getSentence())).stringApiValue());
// } else if (val.getSymbol() != null) {
// sb.append(((CycSymbol) translateObject(
// val.getSymbol())).stringApiValue());
// }
// }
// FIXME: remove this - nwinant, 2017-03-14
// The code below contains an egregious hack to allow list-based inference parameters like :result-sort-order.
// The basic problem is that the parameter values are passed around in CycML, and the CycML DTD/XSD has no support for SubL lists (though
// there's a hack in the Cyc-side CycML generator to allow them to be produced). Thus,
// this hack was added to temporarily turns lists into cyc sentences, and then once they're parsed into appropriate java structures,
// the extra sentences are cleaned up.
private static final CycObject MUNGING_TEMP_PRED = new CycConstantImpl("JustATemporaryPredicate", new GuidImpl("704e2e28-0aba-4a8d-8434-9b07d71191e6"));
private static final boolean MUNGE_LISTS_IF_NECESSARY = true;
private static final boolean SKIP_MALFORMED_INFERENCE_PARAMETERS_AND_THEIR_VALUES = false;
protected boolean hasMungedLists = false;
private void warnOrThrowException(boolean shouldWarn, String errorMsg, String warnConsequenceMsg) {
if (shouldWarn) {
LOGGER.error(errorMsg + warnConsequenceMsg);
} else {
throw new QueryRuntimeException(errorMsg);
}
}
private InferenceParameters convertParams (
QueryInferenceProperties queryInferenceProperties) throws SessionException {
final StringBuilder sb = new StringBuilder();
for (final QueryInferenceProperty qip : queryInferenceProperties.getQueryInferenceProperty()) {
final String symbolName = ":" + qip.getPropertySymbol().getContent().trim();
final String valueString = parsePropertyValue(qip.getPropertyValue());
if (symbolName.equals(":")) {
warnOrThrowException(SKIP_MALFORMED_INFERENCE_PARAMETERS_AND_THEIR_VALUES,
"Inference property name is empty",
"; skipping parameter because SKIP_MALFORMED_INFERENCE_PARAMETERS="
+ SKIP_MALFORMED_INFERENCE_PARAMETERS_AND_THEIR_VALUES + ".");
} else if ((valueString == null) || valueString.trim().isEmpty()) {
warnOrThrowException(SKIP_MALFORMED_INFERENCE_PARAMETERS_AND_THEIR_VALUES,
"Could not parse value for inference property \"" + symbolName + "\"",
"; skipping parameter because SKIP_MALFORMED_INFERENCE_PARAMETERS="
+ SKIP_MALFORMED_INFERENCE_PARAMETERS_AND_THEIR_VALUES + ".");
} else {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(symbolName).append(" ").append(valueString);
}
}
final String paramString = sb.toString();
LOGGER.debug("InferenceParameters string: \"{}\"", paramString);
return new DefaultInferenceParameters(CycAccessManager.getCurrentAccess(), paramString);
}
private String parsePropertyValue(final PropertyValue val) {
if (val.getConstant() != null) {
return ((CycConstant) translateObject(
val.getConstant())).stringApiValue();
} else if (val.getFunction() != null) {
return ((NonAtomicTerm) translateObject(
val.getFunction())).stringApiValue();
} else if (val.getNumber() != null) {
return val.getNumber();
} else if (val.getSentence() != null) {
if (hasMungedLists) {
final FormulaSentence sentence = ((FormulaSentence) translateObject(val.getSentence()));
if (MUNGING_TEMP_PRED.equals(sentence.getArg0())) {
final CycList args = sentence.getArgs();
args.remove(0);
return args.cyclify();
}
return sentence.stringApiValue();
} else {
return ((FormulaSentence) translateObject(
val.getSentence())).stringApiValue();
}
} else if (val.getSymbol() != null) {
return ((CycSymbol) translateObject(
val.getSymbol())).stringApiValue();
} else {
return null;
}
}
private int count(String str, String findStr) {
int lastIndex = 0;
int count = 0;
while (lastIndex != -1) {
lastIndex = str.indexOf(findStr, lastIndex);
if (lastIndex != -1) {
count++;
lastIndex += findStr.length();
}
}
return count;
}
private String processXml(String rawXml) {
if (!MUNGE_LISTS_IF_NECESSARY) {
return rawXml;
}
final String LIST_BEGIN_TAG = "";
final String LIST_CLOSE_TAG = "
";
hasMungedLists = rawXml.contains(LIST_BEGIN_TAG);
final String result;
if (hasMungedLists) {
final String SENT_BEGIN_TAG = "";
final String SENT_CLOSE_TAG = " ";
final String TEMP_PRED_NAME = "JustATemporaryPredicate";
LOGGER.info("MUNGED XML! Working around...");
final String intermediateXml = rawXml;
result = intermediateXml
.replaceFirst(
LIST_BEGIN_TAG,
SENT_BEGIN_TAG + ""
+ "\n"
+ " 704e2e28-0aba-4a8d-8434-9b07d71191e6 \n"
+ " " + TEMP_PRED_NAME + " \n"
+ " ")
.replaceFirst(
LIST_CLOSE_TAG,
" " + SENT_CLOSE_TAG)
.replaceAll(
"- ", "")
.replaceAll(
"
", "");
if (LOGGER.isDebugEnabled()) {
System.out.println("[[--XML was processed to convert occurrences to --]]");
LOGGER.debug(
"Processed Query XML:\n"
+ "---->>>>>> [START *PROCESSED* Query XML] ------------------------>>>>>>\n"
+ "{}\n"
+ "<<<<<<---- [END *PROCESSED* Query XML] <<<<<<------------------------",
result);
LOGGER.debug("{} instances of {}", count(result, LIST_BEGIN_TAG), LIST_BEGIN_TAG);
LOGGER.debug("{} instances of {}", count(result, LIST_CLOSE_TAG), LIST_CLOSE_TAG);
LOGGER.debug("{} instances of {}", count(result, TEMP_PRED_NAME), TEMP_PRED_NAME);
LOGGER.debug("{} instances of {}", count(result, SENT_BEGIN_TAG), SENT_BEGIN_TAG);
LOGGER.debug("{} instances of {}", count(result, SENT_CLOSE_TAG), SENT_CLOSE_TAG);
}
} else {
result = rawXml;
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy