All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cyc.kb.client.KbObjectImpl Maven / Gradle / Ivy

package com.cyc.kb.client;

/*
 * #%L
 * File: KbObjectImpl.java
 * Project: KB 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.CycAccess;
import com.cyc.base.CycAccessManager;
import com.cyc.base.cycobject.CycAssertion;
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.CycVariable;
import com.cyc.base.cycobject.DenotationalTerm;
import com.cyc.base.cycobject.Formula;
import com.cyc.base.cycobject.FormulaSentence;
import com.cyc.base.cycobject.Fort;
import com.cyc.base.cycobject.Guid;
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 com.cyc.baseclient.CycObjectFactory;
import com.cyc.baseclient.CycServerInfoImpl;
import com.cyc.baseclient.cycobject.CycArrayList;
import com.cyc.baseclient.cycobject.CycConstantImpl;
import com.cyc.baseclient.cycobject.CycFormulaSentence;
import com.cyc.baseclient.cycobject.DefaultCycObject;
import com.cyc.baseclient.cycobject.NautImpl;
import com.cyc.baseclient.datatype.DateConverter;
import static com.cyc.baseclient.subl.functions.CycEvaluateFunction.CYC_EVALUATE_INDEXICAL;
import com.cyc.baseclient.subl.functions.CycEvaluateFunction.UnevaluatableExpressionException;
import static com.cyc.baseclient.subl.functions.SublFunctions.INDEXICAL_P;
import com.cyc.kb.Assertion;
import com.cyc.kb.BinaryPredicate;
import com.cyc.kb.Context;
import com.cyc.kb.Fact;
import com.cyc.kb.KbCollection;
import com.cyc.kb.KbFactory;
import com.cyc.kb.KbFunction;
import com.cyc.kb.KbIndividual;
import com.cyc.kb.KbObject;
import com.cyc.kb.KbPredicate;
import com.cyc.kb.KbTerm;
import com.cyc.kb.Sentence;
import com.cyc.kb.client.config.KbConfiguration;
import com.cyc.kb.client.quant.QuantifiedInstanceRestrictedVariable;
import com.cyc.kb.exception.CreateException;
import com.cyc.kb.exception.DeleteException;
import com.cyc.kb.exception.InvalidNameException;
import com.cyc.kb.exception.KbException;
import com.cyc.kb.exception.KbRuntimeException;
import com.cyc.kb.exception.KbServerSideException;
import com.cyc.kb.exception.KbTypeException;
import com.cyc.kb.exception.StaleKbObjectException;
import com.cyc.nl.Paraphraser;
import com.cyc.nl.ParaphraserFactory;
import com.cyc.session.CycSession;
import com.cyc.session.CycSessionManager;
import com.cyc.session.exception.SessionCommunicationException;
import com.cyc.session.exception.SessionConfigurationException;
import com.cyc.session.exception.SessionException;
import com.cyc.session.exception.SessionInitializationException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The base class for all the other classes in this package. Each KBObject is
 * basically a facade for an object in the Cyc KB, and as such it provides
 * common methods to make, retrieve, and remove CycL Assertions.
 * 

* * @author Vijay Raj * @version "$Id: KbObjectImpl.java 172772 2017-07-06 00:48:22Z nwinant $" */ public class KbObjectImpl implements KbObject { /** * The CORE object wrapped by all KBObjects. The type of object wrapped by * each subclass of KBObject will be a subclass of CycObject class. * * INTERNAL DEVELOPERS: There is a strong assumption in the KB API that the * CycObjects are immutable. No defensive copy is made when KB API objects are * constructed or when returned by getCore()!! */ CycObject core = null; /** * !!!EXPERIMENTAL!! Can change any time without notice. */ List quantification = new ArrayList(); private static final Logger log = LoggerFactory.getLogger(KbObjectImpl.class.getCanonicalName()); /** * Set the flag to false after API provide delete operation. */ //should change to true when the KBObject is deleted from the KB, or otherwise invalidated. private boolean isValid = true; /** * Cache for {@link #isIndexical() } */ private Boolean indexical = null; /** * Not part of the KB API. This default constructor only has the effect of * ensuring that there is access to a Cyc server. */ KbObjectImpl() {} /** * Not part of the KB API. Base class constructor currently used only for unit * testing. *

* * @param co The CycObject being wrapped. * * @throws KbRuntimeException if there is a problem connecting to Cyc. */ // We will not document the run time exceptions all the way up the stack. @Deprecated KbObjectImpl(CycObject co) { this(); core = co; } /** * Retrieves the current CycSession. * * @return CycSession * * @throws KbRuntimeException if there is a problem retrieving the current CycSession. */ protected CycSession getSession() { try { return CycSessionManager.getCurrentSession(); } catch (Exception ex) { throw new KbRuntimeException("Encountered a problem with the current CycSession.", ex); } } /** * Retrieves the current CycAccess. * * @return CycAccess * * @throws KbRuntimeException if there is a problem connecting to Cyc. */ protected CycAccess getAccess() { try { return CycAccessManager.getAccessManager().fromSession(getSession()); } catch (Exception ex) { throw new KbRuntimeException("Encountered a problem with the current CycAccess.", ex); } } static protected CycAccess getStaticAccess() { try { return CycAccessManager.getCurrentAccess(); } catch (SessionException ex) { throw new KbRuntimeException(ex.getMessage(), ex); } } /** * Get the KBObject that corresponds to cycObject. * Throws exceptions if the object isn't in the KB. * * This is a very general factory method to build a KBObject from any * arbitrary CycObject without any kind of semantic check on the CycObject. * This is used as a "catch all" in the API, but otherwise it should never be * used. * * @param cycObject the underlying CycObject to be wrapped * * @return the KBObject wrapping the cycObject. * * @throws CreateException * @todo update documentation to state what this really does */ @SuppressWarnings("deprecation") public static KbObject get(CycObject cycObject) throws CreateException, KbTypeException { try { return KbObjectFactory.get(cycObject, KbObjectImpl.class); } catch (KbTypeException te) { // This type is not possible, since we are not checking for a specific Cyc collection // Fix API if this ever happens throw new KbRuntimeException(te.getMessage(), te); } } public static KbObject get(String nameOrId) throws CreateException, KbTypeException { try { return KbObjectFactory.get(nameOrId, KbObjectImpl.class); } catch (KbTypeException te){ // This type is not possible, since we are not checking for a specific Cyc collection // Fix API if this ever happens throw new KbRuntimeException(te.getMessage(), te); } } /** * For a given class c that extends KBObject, return * the KBCollection that the class corresponds to. * * For Example, getBaseCycType(Context.class) will return * KBCollection.get("Context"); * * @param c the subclass of KBObject whose underlying #$Collection is desired * * @return the KBCollection representation of underlying #$Collection backing * the class */ static KbCollection getBaseCycType(Class c) { Method getTypeString = null; try { getTypeString = c.getDeclaredMethod("getClassTypeString"); } catch (NoSuchMethodException e) { throw new IllegalArgumentException(c + " does not have a known base Cyc type."); } try { return KbCollectionImpl.get((String) getTypeString.invoke((Object[]) null, (Object[]) null)); } catch (KbException te) { // We expect the getTypeString return string to be in the KB since it is // a fundamental concept. CreateException and KBTypeException are possible // but can't recover from such an exception anyways. throw new KbRuntimeException(te.getMessage(), te); } catch (Exception e) { throw new KbRuntimeException(e.getMessage(), e); } } /** * For a given class c that extends KBObject, return * the CycObject, a CycDenotationalTerm that the class * corresponds to. * * For Example, getBaseCycTypeCore(Context.class) will return new * CycConstantImpl("Individual", new * Guid("bd58da02-9c29-11b1-9dad-c379636f7270")) * * @param c the subclass of KBObject whose underlying #$Collection is desired * * @return the CycObject representation of underlying #$Collection backing the * class */ static CycObject getBaseCycTypeCore(Class c) { try { final Method getType = c.getDeclaredMethod("getClassTypeCore"); return (CycObject) getType.invoke((Object[]) null, (Object[]) null); } catch (Exception e) { // We expect NoSuchMethodException and IllegalArgumentException both of which are // internal API errors. So just throw RuntimeException throw new KbRuntimeException(e.getMessage(), e); } } /** * @see KBObject#getFacts(KBPredicate, int, Context) */ @Override public Collection getFacts(KbPredicate p, int thisArgPos, Context ctx) { return getFacts(p, this, thisArgPos, ctx); } /** * Gets the asserted facts visible from ctx, using the predicate * pred, with matchArg at the position * matchArgPos of the fact. Ignores this object. *

* * @param pred the Predicate of the returned fact * @param matchArg the Object in the matchArgPos * @param matchArgPos * @param ctx the Context. If null, returns facts from the default context * {@link KBAPIDefaultContext#forQuery()} * * @return a collection of facts, empty if none are found */ @SuppressWarnings("deprecation") protected Collection getFacts(KbPredicate pred, KbObject matchArg, int matchArgPos, Context ctx) { try { final String ctxStr = (ctx == null) ? KbConfiguration.getDefaultContext().forQuery().stringApiValue() //"#$BaseKB" : ctx.stringApiValue(); String command = "(" + SublConstants.getInstance().withInferenceMtRelevance.stringApiValue() + " " + ctxStr + " (" + SublConstants.getInstance().gatherGafArgIndex.stringApiValue() + " " + matchArg.stringApiValue() + " " + matchArgPos + " " + pred.stringApiValue() + "))"; log.trace("getfacts: {}", command); Object res = getAccess().converse().converseObject(command); log.trace("getfacts response: {}", res); Set facts = new HashSet(); if (!CycObjectFactory.nil.equals(res)) { CycList assertList = (CycList) res; for (Object o : assertList) { if (o instanceof CycAssertion) { try { facts.add(FactImpl.get((CycAssertion) o)); } catch (KbException kbe) { // Nothing to do. We did get the facts we are building // but something went wrong. Just don't add it to the list. } } } } return facts; } catch (CycConnectionException ex) { throw new KbRuntimeException(ex); } catch (CycApiException ex) { throw new KbRuntimeException(ex.getMessage(), ex); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getValues(java.lang.String, int, int, java.lang.String) */ @Override public Collection getValues(String predStr, int thisArgPos, int getArgPos, String ctxStr) { KbPredicateImpl pred; ContextImpl ctx = null; try { pred = KbPredicateImpl.get(predStr); if (!(ctxStr == null || ctxStr.equals(""))) { ctx = ContextImpl.get(ctxStr); } } catch (KbException kae) { throw new IllegalArgumentException(kae.getMessage(), kae); } return this.getValues(pred, this, thisArgPos, getArgPos, ctx); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getValues(com.cyc.kb.KBPredicateImpl, int, int, com.cyc.kb.ContextImpl) */ @Override public Collection getValues(KbPredicate pred, int thisArgPos, int getArgPos, Context ctx) { return this.getValues(pred, this, thisArgPos, getArgPos, ctx); } /** * This method gets all facts with predicate pred and * this at the thisArgPos arg position of the fact, * as visible from ctx, and returns as O objects * based on the arguments in the getArgPos argument position of * the facts. * * @param pred the predicate of the facts * @param thisArgPos the argument position of this object in the candidate * facts * @param getArgPos the argument position of the returned objects in the * candidate facts * @param O the type of the objects returned * @param ctx the context where the facts are found. If null, returns facts * from the default context {@link KBAPIDefaultContext#forQuery()} * * @return a collection of objects of type O * * @see KBObject#getFacts(KBPredicate, int, Context) for a method that returns * the facts, rather than just the objects at a specific argument position of * the facts. */ private Collection getValues(KbPredicate pred, KbObject matchArg, int matchArgPos, int getArgPos, Context ctx) { Set myvalues = new HashSet(); java.util.Collection facts = getFacts(pred, matchArg, matchArgPos, ctx); for (Fact a : facts) { CycAssertion ca = (CycAssertion) a.getCore(); CycList g = ca.getGaf().getArgs(); Object o = g.get(getArgPos); try { myvalues.add(KbObjectImpl.checkAndCastObject(o)); } catch (KbException kbe) { // Don't do anything. } // TODO: Need to unify casting and typing of KBObject. And individual // types. // TODO: Need to decide what exception to throw if an KBObject can't // be typed into a subclass here. // TODO: Need to decide if instanceof check should be present } log.debug("Results from getValues: {}", myvalues); return myvalues; } /** * @see com.cyc.kb.KBObject#getValues(com.cyc.kb.KBPredicate, int, int, * java.lang.Object, int, com.cyc.kb.Context) */ @Override public Collection getValues(KbPredicate pred, int thisArgPos, int getArgPos, Object matchArg, int matchArgPos, Context ctx) { return this.getValues(pred, this, thisArgPos, getArgPos, matchArg, matchArgPos, ctx); } /** * gets the objects in getPos of relevant facts as O * objects, with the condition that the fact has the predicate * pred, the object at match1ArgPos is match1Arg and * the object at the match2ArgPos arg position is * match2Arg. *

* * @param pred the predicate of the facts * @param match1Arg the object in argument position match1ArgPos * @param match1ArgPos the argument position of match1Arg in the candidate * facts * @param getPos the argument position of the returned objects in the * candidate facts * @param match2Arg the object in the argument position match2ArgPos * @param match2ArgPos the argument position that must contain the match2Arg * @param O the type of the objects returned * @param ctx the context. If null, returns facts from the default context * {@link KBAPIDefaultContext#forQuery()} * * @return a collection of objects of type O * @throws KbException * * @see #getFacts(com.cyc.kb.KBPredicate, int, com.cyc.kb.Context) */ private Collection getValues(KbPredicate pred, KbObject match1Arg, int match1ArgPos, int getPos, Object match2Arg, int match2ArgPos, Context ctx) { Set myvalues = new HashSet(); Collection facts = getFacts(pred, match1Arg, match1ArgPos, ctx); Object cycAccessFilter; if (match2Arg instanceof KbObjectImpl) { cycAccessFilter = ((KbObject) match2Arg).getCore(); } else { cycAccessFilter = match2Arg; } for (Fact a : facts) { CycAssertion ca = (CycAssertion) a.getCore(); CycList g = ca.getGaf().getArgs(); Object o = g.get(getPos); if (g.get(match2ArgPos).equals(cycAccessFilter)) { try { myvalues.add(KbObjectImpl.checkAndCastObject(o)); } catch (KbException kbe) { // Don't do anything. } } // TODO: Need to unify casting and typing of KBObject. And individual // types. // TODO: Need to decide what exception to throw if an KBObject can't // be typed into a subclass here. // TODO: Need to decide if instanceof check should be present } return myvalues; } /** * @see com.cyc.kb.KBObject#addFact(com.cyc.kb.Context, * com.cyc.kb.KBPredicate, int, java.lang.Object...) */ @Override public Fact addFact(Context ctx, KbPredicate pred, int thisArgPos, Object... otherArgs) throws KbTypeException, CreateException { List argList = new ArrayList(Arrays.asList(otherArgs)); argList.add(thisArgPos - 1, (Object) this); SentenceImpl s = new SentenceImpl(pred, argList.toArray()); return FactImpl.findOrCreate(s, ctx); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getQuotedIsa() */ @Override public Collection getQuotedIsa() { return this.getValues(Constants.quotedIsa(), 1, 2, Constants.inferencePSCMt()); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#addQuotedIsa(com.cyc.kb.KBCollectionImpl, com.cyc.kb.ContextImpl) */ @Override public void addQuotedIsa(KbCollection c, Context ctx) throws KbTypeException, CreateException { this.addArg2(Constants.quotedIsa(), c, ctx); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#instantiates(java.lang.String, java.lang.String) */ @Override public KbObject instantiates(String colStr, String ctxStr) throws KbTypeException, CreateException { return instantiates(KbCollectionImpl.get(colStr), ContextImpl.get(ctxStr)); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#instantiates(com.cyc.kb.KBCollectionImpl, com.cyc.kb.ContextImpl) */ @Override public KbObject instantiates(KbCollection col, Context ctx) throws KbTypeException, CreateException { addFact(ctx, Constants.isa(), 1, (Object) col); return this; } /* (non-Javadoc) * @see com.cyc.kb.KBObject#instantiates(com.cyc.kb.KBCollectionImpl) */ @Override public KbObject instantiates(KbCollection col) throws KbTypeException, CreateException { addFact(KbConfiguration.getDefaultContext().forAssertion(), Constants.isa(), 1, (Object) col); return this; } @Override public Sentence instantiatesSentence(KbCollection col) throws KbTypeException, CreateException { return new SentenceImpl(Constants.isa(), this, (Object) col); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isInstanceOf(com.cyc.kb.KBCollectionImpl) */ @Override public boolean isInstanceOf(KbCollection col) { try { return getAccess().getInspectorTool().isa(this.getCore(), (Fort) col.getCore()); } catch (CycConnectionException e) { throw new KbRuntimeException(e.getMessage(), e); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isInstanceOf(java.lang.String) */ @Override public boolean isInstanceOf(String colStr) { return isInstanceOf(KbUtils.getKBObjectForArgument(colStr, KbCollectionImpl.class)); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isInstanceOf(com.cyc.kb.KBCollectionImpl, com.cyc.kb.ContextImpl) */ @Override public boolean isInstanceOf(KbCollection col, Context ctx) { try { return getAccess().getInspectorTool().isa(this.getCore(), getCore(col), getCore(ctx)); } catch (CycConnectionException e) { throw new KbRuntimeException(e.getMessage(), e); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isInstanceOf(java.lang.String, java.lang.String) */ @Override public boolean isInstanceOf(String colStr, String ctxStr) { return isInstanceOf(KbUtils.getKBObjectForArgument(colStr, KbCollectionImpl.class), KbUtils.getKBObjectForArgument(ctxStr, ContextImpl.class)); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isQuotedInstanceOf(com.cyc.kb.KBCollectionImpl) */ @Override public boolean isQuotedInstanceOf(KbCollection col) { try { return getAccess().getInspectorTool().isQuotedIsa(this.getCore(), (Fort) col.getCore()); } catch (CycConnectionException ioe) { throw new KbRuntimeException(ioe.getMessage(), ioe); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isQuotedInstanceOf(java.lang.String) */ @Override public boolean isQuotedInstanceOf(String colStr) { return isQuotedInstanceOf(KbUtils.getKBObjectForArgument(colStr, KbCollectionImpl.class)); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isQuotedInstanceOf(com.cyc.kb.KBCollectionImpl, com.cyc.kb.ContextImpl) */ @Override public boolean isQuotedInstanceOf(KbCollection col, Context ctx) { try { return getAccess().getInspectorTool().isQuotedIsa(this.getCore(), getCore(col), getCore(ctx)); } catch (CycConnectionException ioe) { throw new KbRuntimeException(ioe.getMessage(), ioe); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isQuotedInstanceOf(java.lang.String, java.lang.String) */ @Override public boolean isQuotedInstanceOf(String colStr, String ctxStr) { return isQuotedInstanceOf(KbUtils.getKBObjectForArgument(colStr, KbCollectionImpl.class), KbUtils.getKBObjectForArgument(ctxStr, ContextImpl.class)); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isAsserted(com.cyc.kb.ContextImpl, com.cyc.kb.KBPredicateImpl, int, java.lang.Object) */ @Override public Boolean isAsserted(Context ctx, KbPredicate pred, int thisArgPos, Object... otherArgs) { try { getFact(ctx, pred, thisArgPos, otherArgs); return true; } catch (Exception e) { return false; } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getFact(com.cyc.kb.ContextImpl, com.cyc.kb.KBPredicateImpl, int, java.lang.Object) */ @Override public Fact getFact(Context ctx, KbPredicate pred, int thisArgPos, Object... otherArgs) throws KbTypeException, CreateException { List argList = new ArrayList(Arrays.asList(otherArgs)); argList.add(thisArgPos, (Object) this); SentenceImpl s = new SentenceImpl(pred, argList.toArray()); return FactImpl.findOrCreate(s, ctx); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getSentence(com.cyc.kb.KBPredicateImpl, int, java.lang.Object) */ // KB API does not do any introspection.. so if we want to use Query API, we should construct // a fully qualified sentence for the given predicate. That can only be possible when all // other variables are passed in. // @Override public Sentence getSentence(KbPredicate pred, int thisArgPos, Object... otherArgs) throws KbTypeException, CreateException { List argList = new ArrayList(Arrays.asList(otherArgs)); argList.add(0, pred); argList.add(thisArgPos, (Object) this); return new SentenceImpl(argList.toArray()); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#addArg1(com.cyc.kb.BinaryPredicateImpl, java.lang.Object, com.cyc.kb.ContextImpl) */ // @todo add versions of this that take Strings as well as KBObjects. @Override public Fact addArg1(BinaryPredicate binPred, Object arg1, Context ctx) throws KbTypeException, CreateException { List argList = new ArrayList(); argList.add(arg1); argList.add(this); SentenceImpl s = new SentenceImpl(binPred, argList.toArray()); return FactImpl.findOrCreate(s, ctx); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#addArg2(com.cyc.kb.BinaryPredicateImpl, java.lang.Object, com.cyc.kb.ContextImpl) */ // @todo add versions of this that take Strings as well as KBObjects. @Override public Fact addArg2(BinaryPredicate binPred, Object arg2, Context ctx) throws KbTypeException, CreateException { List argList = new ArrayList(); argList.add(this); argList.add(arg2); if (this instanceof QuantifiedInstanceRestrictedVariable || arg2 instanceof QuantifiedInstanceRestrictedVariable) { List argsWithPredicate = new ArrayList(argList); argsWithPredicate.add(0, binPred); try { return new TypeFactImpl(ctx, argsWithPredicate.toArray()); } catch (KbException kbe) { throw new CreateException(kbe.getMessage(), kbe); } } else { SentenceImpl s = new SentenceImpl(binPred, argList.toArray()); return FactImpl.findOrCreate(s, ctx); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getComments() */ @Override public Collection getComments() { return getComments(KbConfiguration.getDefaultContext().forQuery()); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getComments(java.lang.String) */ @Override public Collection getComments(String ctxStr) { return getComments(KbUtils.getKBObjectForArgument(ctxStr, ContextImpl.class)); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getComments(com.cyc.kb.ContextImpl) */ @Override public Collection getComments(Context ctx) { return this.getValues(Constants.getInstance().COMMENT_PRED, 1, 2, ctx); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#addComment(java.lang.String, java.lang.String) */ @Override public Fact addComment(String comment, String ctx) throws KbTypeException, CreateException { return addComment(comment, ContextImpl.get(ctx)); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#addComment(java.lang.String, com.cyc.kb.ContextImpl) */ @Override public Fact addComment(String comment, Context ctx) throws KbTypeException, CreateException { List argList = new ArrayList(); argList.add((Object) this); argList.add((Object) comment); SentenceImpl s = new SentenceImpl(Constants.getInstance().COMMENT_PRED, argList.toArray()); return FactImpl.findOrCreate(s, ctx); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getArgument(int) */ @Override public O getArgument(int getPos) throws KbTypeException, CreateException { Object o; if (this.getCore() instanceof Nart) { Nart cn = (Nart) this.getCore(); o = cn.getArgument(getPos);// .getReferencedConstants().get(getPos); } else if (this.getCore() instanceof Naut) { Naut cn = (Naut) this.getCore(); o = cn.getArgument(getPos);// .getReferencedConstants().get(getPos); } else if (this instanceof Assertion) { try { o = ((CycAssertion) this.getCore()).getArg(getPos, getAccess()); } catch (CycApiException ex) { throw new KbServerSideException(ex.getMessage(), ex); } catch (CycConnectionException ex) { throw new KbRuntimeException(ex.getMessage(), ex); } } else if (this.getCore() instanceof CycList) { CycList cl = (CycList) this.getCore(); o = cl.get(getPos); } else if (this.getCore() instanceof FormulaSentence) { FormulaSentence cfs = (FormulaSentence) this.getCore(); o = cfs.getArg(getPos); } else if (this.getCore() instanceof CycConstant) { throw new UnsupportedOperationException( "The object: " + this.toString() + " is an Atomic term. It does not have arguments."); } else { throw new IllegalArgumentException("Unable to determine the arg " + getPos + " of " + this.toString()); } return (O) KbObjectImpl.checkAndCastObject(o); } /** * Attempts to return a CycObject (or a Java primitive object) based on the * KBObject (or a Java primitive object). * * A CycObject or a subclass of it, is the primary representation of the BaseClient. * It represents the same concept in the KB as the KBObject. The CycObject is * useful when the user has to do something the KB API does not support. * * @param arg the inputs KBObject that will be converted to a CycObject * * @return the CycObject representation of the input ARG */ public static Object convertKBObjectToCycObject(Object arg) { if (arg instanceof KbObject) { return ((KbObject) arg).getCore(); } else if (arg instanceof List) { if (((List) arg).isEmpty()) { return THE_EMPTY_LIST; } else { CycList cl = new CycArrayList(); for (Object listElem : (List)arg) { cl.add(convertKBObjectToCycObject(listElem)); } Naut cn = new NautImpl(THE_LIST, cl.toArray()); return cn; } } else if (arg instanceof Set) { if (((Set)arg).isEmpty()) { return THE_EMPTY_SET; } else { CycList cl = new CycArrayList(); for (Object setElem : (Set)arg) { cl.add(convertKBObjectToCycObject(setElem)); } Naut cn = new NautImpl(THE_SET, cl.toArray()); return cn; } } else if (arg instanceof Date) { DateConverter.getInstance(); CycObject co = DateConverter.toCycDate((Date) arg); return co; } else { return arg; } } @Override public boolean isIndexical() throws SessionCommunicationException { // TODO: should we cache this value? - nwinant, 2017-07-05 if (this.indexical == null) { try { this.indexical = INDEXICAL_P.eval(getAccess(), getCore()); } catch (CycConnectionException | CycApiException ex) { throw new SessionCommunicationException(ex); } } return this.indexical; } @Override public O resolveIndexical() throws SessionCommunicationException, KbTypeException, CreateException { try { final Object referent = CYC_EVALUATE_INDEXICAL.eval(getAccess(), getCore()); return (O) KbObjectImpl.checkAndCastObject(referent); } catch (UnevaluatableExpressionException ex) { final String msg = isIndexical() ? "Cannot resolve indexical " + this : "Cannot resolve; is not an indexical: " + this; throw new KbTypeException(msg, ex); } catch (CycConnectionException | CycApiException ex) { throw new SessionCommunicationException(ex); } } @Override public O possiblyResolveIndexical(Map substitutions) throws SessionCommunicationException, KbTypeException { final Object referent = substitutions.get(this); if (referent != null) { if (!isIndexical()) { throw new KbTypeException("Found referent for non-indexical: " + this + " -> " + referent); } if (this.equals(referent)) { throw new KbTypeException( "Indexical cannot have itself as a referent: " + this + " -> " + referent); } log.debug("Found possible referent for {} -> {}", this, referent); try { return (O) referent; } catch (ClassCastException ex) { throw new KbTypeException( "Referent is not of expected class: " + this + " -> " + referent, ex); } } if (isIndexical()) { try { resolveIndexical(); } catch (KbTypeException | CreateException ex) { throw new KbTypeException("Indexical is not resolvable or auto-resolvable: " + this, ex); } } return (O) this; } /** * Replace non-destructively a set of objects with another set of objects, in a * Non-Atomic Term or a Sentence. Replacement is not supported within Assertions, * Atomic Terms, Variables and Symbols. Although, set of objects replaced can * be any KBObject or Java primitive object. * * @param type of object to be replaced * @param type of object replaced with * @param substitutions the replacement mapping * * @return A new object with the substitutions made in the original object * * @throws KbTypeException * @throws CreateException */ protected O replaceTerms(Map substitutions) throws KbTypeException, CreateException { final Map substitutionCores = new HashMap(); for (Object key : substitutions.keySet()) { final Object keyCore = KbObjectImpl.convertKBObjectToCycObject(key); final Object valueCore = KbObjectImpl.convertKBObjectToCycObject(substitutions.get(key)); substitutionCores.put(keyCore, valueCore); } if (this.getCore() instanceof NonAtomicTerm) { NonAtomicTerm nat = (NonAtomicTerm) this.getCore(); Formula natFormulaMod = nat.getFormula().applySubstitutionsNonDestructive(substitutionCores); NonAtomicTerm natMod = new NautImpl(natFormulaMod.getArgs()); return (O) KbTermImpl.findOrCreate(natMod); } else if (this.getCore() instanceof FormulaSentence) { FormulaSentence f = (FormulaSentence) this.getCore(); FormulaSentence fMod = (FormulaSentence) f.applySubstitutionsNonDestructive(substitutionCores); return (O) new SentenceImpl(fMod); } else { // Anything else, we won't replace, including, Atomic terms // Assertions, Variables, Symbols etc. return (O) this; } } /** * Attempts to return an Object (expected to be of type T) for the input * Object o. * * For basic Java objects like String, Number and Date, the object is returned * without any modification. CycObjects are converted to KBObjects, of the * most specific type possible. * * @param o object to be mapped to KBObject * * @return the KBObject constructed. * @throws CreateException */ static public T checkAndCastObject(Object o) throws CreateException { if (o instanceof CycObject) { return (T) KbObjectImpl.convertCycObject((CycObject) o); } else if (o instanceof String || o instanceof Number || o instanceof Date) { return (T) o; } else { throw new IllegalArgumentException("Unable to coerce " + o + "(" + o.getClass() + ")."); // return null; } } static private final CycConstant THE_LIST = new CycConstantImpl("TheList", new Guid("bdcc9f7c-9c29-11b1-9dad-c379636f7270")); static private final CycConstant THE_EMPTY_LIST = new CycConstantImpl("TheEmptyList", new Guid("bd79c885-9c29-11b1-9dad-c379636f7270")); static private final CycConstant THE_SET = new CycConstantImpl("TheSet", new Guid("bd58e476-9c29-11b1-9dad-c379636f7270")); static private final CycConstant THE_EMPTY_SET = new CycConstantImpl("TheEmptySet", new Guid("bdf8edae-9c29-11b1-9dad-c379636f7270")); static private Object convertCycObject(CycObject cyco) throws CreateException { try { // First try converting to a Set, List, or Date: if (cyco instanceof CycArrayList) { CycList cl = (CycArrayList) cyco; if (cl.get(0) instanceof CycConstantImpl) { try { KbTerm kbt = KbTermImpl.get((CycConstant) cl.get(0)); if (kbt instanceof KbFunction) { KbFunction kbf = (KbFunction) kbt; // Do not check arity if its a VariableArityFunction, since that check throws an exception if ((kbf.isVariableArity() || kbf.getArity() == cl.size() - 1) && kbf.isUnreifiable()) { cyco = new NautImpl(cl); } } else if (kbt instanceof KbPredicate) { KbPredicate kbp = (KbPredicate) kbt; // Do not check arity if its a VariableArityFunction, since that check throws an exception if (kbp.isVariableArity() || kbp.getArity() == cl.size() - 1) { cyco = new CycFormulaSentence(cl); } else if (kbt instanceof LogicalConnectiveImpl || kbt instanceof QuantifierImpl) { cyco = new CycFormulaSentence(cl); } } } catch (Exception e) { // ignore and move on } } } // handle an empty list if (cyco instanceof CycConstant) { final CycConstant c = (CycConstant) cyco; if (c.equals(THE_EMPTY_LIST)) { return new ArrayList(); } else if (c.equals(THE_EMPTY_SET)) { return new HashSet(); } } if (cyco instanceof Naut) { final Naut cn = (Naut) cyco; final DenotationalTerm functor = (cn).getFunctor(); if (functor.equals(THE_SET) || functor.equals(THE_LIST)) { final Collection c = functor.equals(THE_SET) ? new HashSet() : new ArrayList(); for (Object item : cn.getArguments()) { // TODO: Build a KBObject out of the Object item c.add(KbObjectImpl.checkAndCastObject(item)); } try { return c; } catch (ClassCastException ex) { //Guess we weren't looking for a Set/List. } } else if (shouldConvertToJavaDates() && DateConverter.isCycDate(cn)) { try { return DateConverter.parseCycDate(cn); } catch (ClassCastException ex) { System.out.println("Class Cast exception on a date."); //Guess we weren't looking for a Date. } } } // return convertToKBObject(cyco); return KbFactory.getApiObject(cyco); } catch (KbTypeException ex) { throw new CreateException(ex); } } private static boolean shouldConvertToJavaDates() throws CreateException { try { return CycSessionManager.getCurrentSession().getOptions().getShouldConvertToJavaDates(); } catch (SessionConfigurationException | SessionCommunicationException | SessionInitializationException ex) { throw new CreateException(ex); } } private static KbObject convertToKBObject(CycObject cyco) throws CreateException { try { if (cyco instanceof CycVariable) { return new VariableImpl(cyco); } else if (cyco instanceof CycSymbol) { return new SymbolImpl(cyco); } else if (cyco instanceof CycAssertion) { return AssertionImpl.get(cyco); } else if (cyco instanceof FormulaSentence) { return new SentenceImpl(cyco); } // Find most specific type, convert it to that and cast to T: CycObject tightCol = null; try { tightCol = getStaticAccess().getInspectorTool().categorizeTermWRTApi(cyco); } catch (CycConnectionException cce) { throw new KbRuntimeException(cce.getMessage(), cce); } if (tightCol != null && KbObjectFactory.CYC_OBJECT_TO_KB_API_CLASS.get(tightCol) != null) { return KbObjectFactory.get(cyco, KbObjectFactory.CYC_OBJECT_TO_KB_API_CLASS.get(tightCol)); } else { return KbObjectImpl.get(cyco); } } catch (KbTypeException ex) { throw new CreateException(ex); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isAtomic() */ @Override public Boolean isAtomic() { if (this.getCore() instanceof CycConstant || this.getCore() instanceof CycVariable || this.getCore() instanceof CycSymbol) { return true; } else { return false; } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isAssertion() */ @Override public Boolean isAssertion() { if (this.getCore() instanceof CycAssertion) { return true; } else { return false; } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isVariable() */ public boolean isVariable() { if (this.getCore() instanceof CycVariable) { return true; } else { return false; } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getRestriction() */ @Override public Sentence getRestriction() { if (this.isVariable()) { List l = new ArrayList(); l.add(Constants.isa()); l.add(this); l.add(this.getType()); try { return new SentenceImpl(l.toArray()); } catch (KbTypeException kte) { throw new KbRuntimeException(kte.getMessage(), kte); } catch (CreateException ex) { throw new KbRuntimeException(ex.getMessage(), ex); } } else { return null; //new ArrayList(); } } // (Quantifier OTHER_OPTIONAL_VARS Sentence) /* (non-Javadoc) * @see com.cyc.kb.KBObject#getQuantification() */ public List getQuantification() throws KbException { if (this.isVariable()) { // By default return "some" (#$thereExits) quantifer for object if (this.quantification.isEmpty()) { return new ArrayList(); /* List nl = new ArrayList(); nl.add(Quantifier.get("thereExists")); nl.add(this); return nl; */ } else { List nl = new ArrayList(); nl.addAll(this.quantification); nl.add(this); return nl; } /* List l = new ArrayList(); l.add(Predicate.get("thereExists")); l.add(this); return l; */ } else { return new ArrayList(); } } // In the interest of making immutable objects we will not // implement setQuantification() /* (non-Javadoc) * @see com.cyc.kb.KBObject#setQuantification() */ public void setQuantification() { throw new UnsupportedOperationException(); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#formulaArity() */ @Override public Integer formulaArity() { if (this.getCore() instanceof CycConstantImpl) { return 0; } else if (this.getCore() instanceof Nart) { Nart cn = (Nart) this.getCore(); return cn.getArity();// .getReferencedConstants().get(getPos); } else if (this.getCore() instanceof NautImpl) { NautImpl cn = (NautImpl) this.getCore(); return cn.getArity();// .getReferencedConstants().get(getPos); } else if (this.getCore() instanceof CycAssertion) { CycAssertion ca = (CycAssertion) this.getCore(); return ((CycList) ca.getFormula().get(1)).size(); //TODO: Careful!! No error checking what so ever!! } else if (this.getCore() instanceof FormulaSentence) { FormulaSentence cfs = (FormulaSentence) this.getCore(); return cfs.getArity(); } else { return (Integer) null; } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getCore() */ // TODO: Make sure that CycObject and all its subclasses are immutable. // JIRA: BASEAPI-17 @Override public CycObject getCore() { return core; } @Deprecated public static KbObjectImpl from(KbObject obj) { return (KbObjectImpl) obj; } @Deprecated public static CycObject getCore(Object obj) { if (obj instanceof KbObjectImpl) { return KbObjectImpl.from((KbObject) obj).getCore(); } return (CycObject) obj; } /* (non-Javadoc) * @see com.cyc.kb.KBObject#stringApiValue() */ @Override public String stringApiValue() { if (!isValid()) { throw new StaleKbObjectException("The reference to " + this + " object is stale. " + "Possibly because it was delete using x.delete() method."); } return core.stringApiValue(); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#delete() */ @Override public void delete() throws DeleteException { try { if (core instanceof Fort) { getAccess().getUnassertTool().kill((Fort) core, true, KbConfiguration.getShouldTranscriptOperations()); isValid = false; } /* * else if (core instanceof CycAssertion) { CycAssertion ca = * (CycAssertion) core; if (ca.isGaf()){ * cyc.unassertGaf(ca.getGaf(), ca.getMt()); } else { throw new * Exception ("Couldn't delete the fact: " + core.toString()); } } */ else { throw new DeleteException("Couldn't kill: " + core.toString() + ". It was not a Fort."); } } catch (CycConnectionException e) { throw new KbRuntimeException( "Couldn't kill the constant " + core.toString(), e); } catch (CycApiException cae) { throw new KbRuntimeException("Could not kill the constant: " + core + " very likely because it is not in the KB. " + cae.getMessage(), cae); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#isValid() */ @Override public Boolean isValid() { return isValid; } /** * Package private method to set the validity of object from subclasses, for * example Assertion class. * * @param valid */ void setIsValid(boolean valid) { isValid = valid; } /* (non-Javadoc) * @see com.cyc.kb.KBObject#rename(java.lang.String) */ @Override public KbObject rename(final String name) throws InvalidNameException { if (core instanceof CycConstantImpl) { try { getAccess().getObjectTool().rename(((CycConstantImpl) core), name, true, KbConfiguration.getShouldTranscriptOperations()); } catch (CycConnectionException e) { throw new KbRuntimeException("Unable to rename " + this + " to " + name, e); } catch (CycApiException cae) { throw new InvalidNameException(cae.getMessage(), cae); } return this; } else { throw new UnsupportedOperationException("Couldn't rename " + core + ". Not an atomic term (i.e. a CycConstant.) Check if the object isAtomic() before rename operation."); } } /* (non-Javadoc) * @see com.cyc.kb.KBObject#toString() */ @Override public String toString() { return core.toString(); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#toNLString() */ @Override public String toNlString() throws SessionException { Paraphraser p = ParaphraserFactory .getInstance(ParaphraserFactory.ParaphrasableType.KBOBJECT); return p.paraphrase(this).getString(); } /* (non-Javadoc) * @see com.cyc.kb.KBObject#getId() */ @Override public String getId() { try { return DefaultCycObject.toCompactExternalId(core, getAccess()); } catch (CycConnectionException e) { // DefaultCycObject.toCompactExternalId throws exception if core is // null // or not a CycObject. // This should never happen in our case. // TODO: Check for null core in the constructor. Happens in Facts e.printStackTrace(); } return ""; } /* (non-Javadoc) * @see com.cyc.kb.KBObject#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((core == null) ? 0 : core.hashCode()); return result; } /* (non-Javadoc) * @see com.cyc.kb.KBObject#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } KbObjectImpl other = (KbObjectImpl) obj; if (core == null) { if (other.core != null) { return false; } } else if (!core.equals(other.core)) { return false; } return true; } /* (non-Javadoc) * @see com.cyc.kb.KBObject#equalsSemantically(java.lang.Object) */ @Override public boolean equalsSemantically(Object object) { if (this == object) { return true; } if (object == null || !(object instanceof KbObjectImpl)) { return false; } KbObjectImpl other = (KbObjectImpl) object; if (core == null) { if (other.core != null) { return false; } } else if (!core.equals(other.core)) { return false; } return true; } @Override public boolean isQuoted() throws KbTypeException, CreateException { return (formulaArity() == 1) && (getArgument(0) == Constants.getInstance().QUOTE_FUNC); } @Override public KbIndividual quote() throws KbTypeException, CreateException { return Constants.getInstance().QUOTE_FUNC .findOrCreateFunctionalTerm(KbIndividualImpl.class, this); } @Override public O unquote() throws KbTypeException, CreateException { if (!isQuoted()) { throw new KbTypeException("This object is not quoted, so it cannot be unquoted: " + this); } return getArgument(1); } @Override public KbIndividual toQuoted() throws KbTypeException, CreateException { return !isQuoted() ? quote() : (KbIndividual) this; } @Override public O toUnquoted() throws KbTypeException, CreateException { Object result = this; while ((result instanceof KbObject) && ((KbObject) result).isQuoted()) { result = ((KbObject) result).unquote(); } return (O) result; } /** * Return the KBCollection as a KBObject of the Cyc term that underlies this * class. For example, calling this on a KBCollection object will * return KBCollectionImpl.get("#$Collection"). * * @return the KBCollection of the underlying Cyc term of the class. */ @Override public KbObject getType() { return getClassType(); } /** * Return the KBCollection as a KBObject of the Cyc term that underlies this * class. For example, calling this on a KBCollection object will * return KBCollectionImpl.get("#$Collection"). * * @return the KBCollection of the underlying Cyc term of the class. */ public static KbObject getClassType() { try { return KbCollectionImpl.get(getClassTypeString()); } catch (KbException kae) { throw new KbRuntimeException(kae.getMessage(), kae); } } String getTypeString() { return getClassTypeString(); } static String getClassTypeString() { return "#$Thing"; } private KbCollection typeCore = null; private Map kboData = new HashMap(); public KbCollection getTypeCore() { return typeCore; } public void setTypeCore(KbCollection typeCore) { this.typeCore = typeCore; } public Map getKboData() { return kboData; } public void setKboData(Map kboData) { this.kboData = kboData; } public URI toURI(KBURIType urlType) throws URISyntaxException { // TODO: This should be moved somewhere else. It could be added to the KBObject interface // in the Core API Spec, or moved altogether to the KM API. - nwinant, 2015-07-03 final CycServerInfoImpl serverInfo = (CycServerInfoImpl) getAccess().getServerInfo(); if (KBURIType.CYC_BROWSER.equals(urlType)) { return new URI(serverInfo.getBaseBrowserUrl() + "/cgi-bin/cg?cb-cf&" + this.getId()); } throw new KbRuntimeException("No such " + KBURIType.class.getSimpleName() + " known: " + urlType); } public static enum KBURIType { // TODO: This could also include an API_WS, KEA, OWL, etc. - nwinant, 2015-07-03 CYC_BROWSER } }