/* * 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. * * Contributions from 2013-2017 where performed either by US government * employees, or under US Veterans Health Administration contracts. * * US Veterans Health Administration contributions by government employees * are work of the U.S. Government and are not subject to copyright * protection in the United States. Portions contributed by government * employees are USGovWork (17USC §105). Not subject to copyright. * * Contribution by contractors to the US Veterans Health Administration * during this period are contractually contributed under the * Apache License, Version 2.0. * * See: https://www.usa.gov/government-works * * Contributions prior to 2013: * * Copyright (C) International Health Terminology Standards Development Organisation. * Licensed under the Apache License, Version 2.0. * */ package sh.isaac.provider.taxonomy; //~--- JDK imports ------------------------------------------------------------ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.NavigableSet; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.StampedLock; import java.util.stream.IntStream; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; //~--- non-JDK imports -------------------------------------------------------- import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.glassfish.hk2.runlevel.RunLevel; import org.jvnet.hk2.annotations.Service; import sh.isaac.api.ConceptActiveService; import sh.isaac.api.ConfigurationService; import sh.isaac.api.Get; import sh.isaac.api.IdentifierService; import sh.isaac.api.LookupService; import sh.isaac.api.SystemStatusService; import sh.isaac.api.TaxonomyService; import sh.isaac.api.TaxonomySnapshotService; import sh.isaac.api.bootstrap.TermAux; import sh.isaac.api.collections.ConceptSequenceSet; import sh.isaac.api.collections.LruCache; import sh.isaac.api.commit.ChronologyChangeListener; import sh.isaac.api.commit.CommitRecord; import sh.isaac.api.commit.CommitStates; import sh.isaac.api.component.concept.ConceptChronology; import sh.isaac.api.component.concept.ConceptService; import sh.isaac.api.component.sememe.SememeChronology; import sh.isaac.api.component.sememe.SememeType; import sh.isaac.api.component.sememe.version.LogicGraphSememe; import sh.isaac.api.component.sememe.version.SememeVersion; import sh.isaac.api.coordinate.LogicCoordinate; import sh.isaac.api.coordinate.PremiseType; import sh.isaac.api.coordinate.StampCoordinate; import sh.isaac.api.coordinate.TaxonomyCoordinate; import sh.isaac.api.dag.Graph; import sh.isaac.api.dag.Node; import sh.isaac.api.identity.StampedVersion; import sh.isaac.api.logic.LogicNode; import sh.isaac.api.logic.LogicalExpression; import sh.isaac.api.snapshot.calculator.RelativePositionCalculator; import sh.isaac.api.tree.Tree; import sh.isaac.api.tree.TreeNodeVisitData; import sh.isaac.api.tree.hashtree.HashTreeBuilder; import sh.isaac.model.configuration.LogicCoordinates; import sh.isaac.model.logic.IsomorphicResultsBottomUp; import sh.isaac.model.logic.node.AndNode; import sh.isaac.model.logic.node.internal.ConceptNodeWithSequences; import sh.isaac.model.logic.node.internal.RoleNodeSomeWithSequences; import sh.isaac.model.waitfree.CasSequenceObjectMap; import sh.isaac.provider.taxonomy.graph.GraphCollector; //~--- classes ---------------------------------------------------------------- /** * The Class TaxonomyProvider. * * @author kec */ @Service @RunLevel(value = 1) public class TaxonomyProvider implements TaxonomyService, ConceptActiveService, ChronologyChangeListener { /** The Constant LOG. */ private static final Logger LOG = LogManager.getLogger(); /** The Constant TAXONOMY. */ private static final String TAXONOMY = "taxonomy"; /** The Constant ORIGIN_DESTINATION_MAP. */ private static final String ORIGIN_DESTINATION_MAP = "origin-destination.map"; //~--- fields -------------------------------------------------------------- /** The destination origin record set. */ private final ConcurrentSkipListSet<DestinationOriginRecord> destinationOriginRecordSet = new ConcurrentSkipListSet<>(); /** The load required. */ private final AtomicBoolean loadRequired = new AtomicBoolean(); /** The logic coordinate. */ private final LogicCoordinate logicCoordinate = LogicCoordinates.getStandardElProfile(); /** The isa sequence. */ private final int isaSequence = TermAux.IS_A.getConceptSequence(); /** The role group sequence. */ private final int roleGroupSequence = TermAux.ROLE_GROUP.getConceptSequence(); /** The provider uuid. */ private final UUID providerUuid = UUID.randomUUID(); /** The sememe sequences for unhandled changes. */ private final ConcurrentSkipListSet<Integer> sememeSequencesForUnhandledChanges = new ConcurrentSkipListSet<>(); /** The stamped lock. */ private final StampedLock stampedLock = new StampedLock(); /** The database validity. */ private DatabaseValidity databaseValidity = DatabaseValidity.NOT_SET; /** The tree cache. */ private final LruCache<Integer, Tree> treeCache = new LruCache<>(5); /** * The {@code taxonomyMap} associates concept sequence keys with a primitive * taxonomy record, which represents the destination, stamp, and taxonomy * flags for parent and child concepts. */ private final CasSequenceObjectMap<TaxonomyRecordPrimitive> originDestinationTaxonomyRecordMap; /** The folder path. */ private final Path folderPath; /** The taxonomy provider folder. */ private final Path taxonomyProviderFolder; /** The identifier service. */ private IdentifierService identifierService; //~--- constant enums ------------------------------------------------------ /** * The Enum AllowedRelTypes. */ private enum AllowedRelTypes { /** The hierarchical only. */ HIERARCHICAL_ONLY, /** The all rels. */ ALL_RELS; } //~--- constructors -------------------------------------------------------- /** * Instantiates a new taxonomy provider. * * @throws IOException Signals that an I/O exception has occurred. */ private TaxonomyProvider() throws IOException { this.folderPath = LookupService.getService(ConfigurationService.class) .getChronicleFolderPath(); this.taxonomyProviderFolder = this.folderPath.resolve(TAXONOMY); if (!Files.exists(this.taxonomyProviderFolder)) { this.databaseValidity = DatabaseValidity.MISSING_DIRECTORY; } this.loadRequired.set(!Files.exists(this.taxonomyProviderFolder)); Files.createDirectories(this.taxonomyProviderFolder); this.originDestinationTaxonomyRecordMap = new CasSequenceObjectMap<>(new TaxonomyRecordSerializer(), this.taxonomyProviderFolder, "seg.", ".taxonomy.map"); LOG.info("CradleTaxonomyProvider constructed"); } //~--- methods ------------------------------------------------------------- /** * Clear database validity value. */ @Override public void clearDatabaseValidityValue() { // Reset to enforce analysis this.databaseValidity = DatabaseValidity.NOT_SET; } /** * Handle change. * * @param cc the cc */ @Override public void handleChange(ConceptChronology<? extends StampedVersion> cc) { // not interested on concept changes } /** * Handle change. * * @param sc the sc */ @Override public void handleChange(SememeChronology<? extends SememeVersion<?>> sc) { if (sc.getSememeType() == SememeType.LOGIC_GRAPH) { this.sememeSequencesForUnhandledChanges.add(sc.getSememeSequence()); } } /** * Handle commit. * * @param commitRecord the commit record */ @Override public void handleCommit(CommitRecord commitRecord) { // If a logic graph changed, clear our cache. if (this.sememeSequencesForUnhandledChanges.size() > 0) { this.treeCache.clear(); } UpdateTaxonomyAfterCommitTask.get(this, commitRecord, this.sememeSequencesForUnhandledChanges, this.stampedLock); } /** * Update status. * * @param conceptChronology the concept chronology */ @Override public void updateStatus(ConceptChronology<?> conceptChronology) { final int conceptSequence = conceptChronology.getConceptSequence(); TaxonomyRecordPrimitive parentTaxonomyRecord; if (this.originDestinationTaxonomyRecordMap.containsKey(conceptSequence)) { parentTaxonomyRecord = this.originDestinationTaxonomyRecordMap.get(conceptSequence) .get(); } else { parentTaxonomyRecord = new TaxonomyRecordPrimitive(); } conceptChronology.getVersionStampSequences().forEach((stampSequence) -> { parentTaxonomyRecord.getTaxonomyRecordUnpacked() .addStampRecord(conceptSequence, conceptSequence, stampSequence, TaxonomyFlags.CONCEPT_STATUS.bits); }); this.originDestinationTaxonomyRecordMap.put(conceptSequence, parentTaxonomyRecord); } /** * Update taxonomy. * * @param logicGraphChronology the logic graph chronology */ @Override public void updateTaxonomy(SememeChronology<LogicGraphSememe<?>> logicGraphChronology) { final int conceptSequence = this.identifierService.getConceptSequence(logicGraphChronology.getReferencedComponentNid()); final Optional<TaxonomyRecordPrimitive> record = this.originDestinationTaxonomyRecordMap.get(conceptSequence); TaxonomyRecordPrimitive parentTaxonomyRecord; if (record.isPresent()) { parentTaxonomyRecord = record.get(); } else { parentTaxonomyRecord = new TaxonomyRecordPrimitive(); } TaxonomyFlags taxonomyFlags; if (logicGraphChronology.getAssemblageSequence() == this.logicCoordinate.getInferredAssemblageSequence()) { taxonomyFlags = TaxonomyFlags.INFERRED; } else { taxonomyFlags = TaxonomyFlags.STATED; } final List<Graph<? extends LogicGraphSememe<?>>> versionGraphList = logicGraphChronology.getVersionGraphList(); versionGraphList.forEach((versionGraph) -> { processVersionNode(versionGraph.getRoot(), parentTaxonomyRecord, taxonomyFlags); }); this.originDestinationTaxonomyRecordMap.put(conceptSequence, parentTaxonomyRecord); } /** * Was ever kind of. * * @param childId the child id * @param parentId the parent id * @return true, if successful */ @Override public boolean wasEverKindOf(int childId, int parentId) { childId = Get.identifierService() .getConceptSequence(childId); parentId = Get.identifierService() .getConceptSequence(parentId); if (childId == parentId) { return true; } long stamp = this.stampedLock.tryOptimisticRead(); final boolean wasEverKindOf = recursiveFindAncestor(childId, parentId, new HashSet<>()); if (this.stampedLock.validate(stamp)) { return wasEverKindOf; } stamp = this.stampedLock.readLock(); try { return recursiveFindAncestor(childId, parentId, new HashSet<>()); } finally { this.stampedLock.unlock(stamp); } } /** * Filter origin sequences. * * @param origins the origins * @param parentSequence the parent sequence * @param typeSequenceSet the type sequence set * @return the int stream */ private IntStream filterOriginSequences(IntStream origins, int parentSequence, ConceptSequenceSet typeSequenceSet) { return origins.filter((originSequence) -> { final Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originSequence); if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); return taxonomyRecord.containsSequenceViaType(parentSequence, typeSequenceSet, TaxonomyFlags.ALL_RELS); } return false; }); } /** * Filter origin sequences. * * @param origins the origins * @param parentSequence the parent sequence * @param typeSequenceSet the type sequence set * @param tc the tc * @return the int stream */ private IntStream filterOriginSequences(IntStream origins, int parentSequence, ConceptSequenceSet typeSequenceSet, TaxonomyCoordinate tc) { return origins.filter((originSequence) -> { final Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originSequence); if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); if (taxonomyRecord.conceptSatisfiesStamp(originSequence, tc.getStampCoordinate())) { return taxonomyRecord.containsSequenceViaType(parentSequence, typeSequenceSet, tc, TaxonomyFlags.ALL_RELS); } } return false; }); } /** * Filter origin sequences. * * @param origins the origins * @param parentSequence the parent sequence * @param typeSequence the type sequence * @param flags the flags * @return the int stream */ private IntStream filterOriginSequences(IntStream origins, int parentSequence, int typeSequence, int flags) { return origins.filter((originSequence) -> { final Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originSequence); if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); return taxonomyRecord.containsSequenceViaTypeWithFlags(parentSequence, typeSequence, flags); } return false; }); } /** * Filter origin sequences. * * @param origins the origins * @param parentSequence the parent sequence * @param typeSequence the type sequence * @param tc the tc * @param allowedRelTypes the allowed rel types * @return the int stream */ private IntStream filterOriginSequences(IntStream origins, int parentSequence, int typeSequence, TaxonomyCoordinate tc, AllowedRelTypes allowedRelTypes) { return origins.filter((originSequence) -> { final Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originSequence); if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); if (taxonomyRecord.conceptSatisfiesStamp(originSequence, tc.getStampCoordinate())) { if (allowedRelTypes == AllowedRelTypes.ALL_RELS) { return taxonomyRecord.containsSequenceViaType(parentSequence, typeSequence, tc, TaxonomyFlags.ALL_RELS); } return taxonomyRecord.containsSequenceViaType(parentSequence, typeSequence, tc); } } return false; }); } /** * Process new logic graph. * * @param firstVersion the first version * @param parentTaxonomyRecord the parent taxonomy record * @param taxonomyFlags the taxonomy flags */ private void processNewLogicGraph(LogicGraphSememe firstVersion, TaxonomyRecordPrimitive parentTaxonomyRecord, TaxonomyFlags taxonomyFlags) { if (firstVersion.getCommitState() == CommitStates.COMMITTED) { final LogicalExpression expression = firstVersion.getLogicalExpression(); expression.getRoot().getChildStream().forEach((necessaryOrSufficientSet) -> { necessaryOrSufficientSet.getChildStream() .forEach((LogicNode andOrOrLogicNode) -> andOrOrLogicNode.getChildStream() .forEach((LogicNode aLogicNode) -> { processRelationshipRoot( aLogicNode, parentTaxonomyRecord, taxonomyFlags, firstVersion.getStampSequence(), expression); })); }); } } /** * Process relationship root. * * @param logicalLogicNode the logical logic node * @param parentTaxonomyRecord the parent taxonomy record * @param taxonomyFlags the taxonomy flags * @param stampSequence the stamp sequence * @param comparisonExpression the comparison expression */ private void processRelationshipRoot(LogicNode logicalLogicNode, TaxonomyRecordPrimitive parentTaxonomyRecord, TaxonomyFlags taxonomyFlags, int stampSequence, LogicalExpression comparisonExpression) { switch (logicalLogicNode.getNodeSemantic()) { case CONCEPT: updateIsaRel((ConceptNodeWithSequences) logicalLogicNode, parentTaxonomyRecord, taxonomyFlags, stampSequence, comparisonExpression.getConceptSequence()); break; case ROLE_SOME: updateSomeRole((RoleNodeSomeWithSequences) logicalLogicNode, parentTaxonomyRecord, taxonomyFlags, stampSequence, comparisonExpression.getConceptSequence()); break; case FEATURE: // Features do not have taxonomy implications... break; default: throw new UnsupportedOperationException("Can't handle: " + logicalLogicNode.getNodeSemantic()); } } /** * Process version node. * * @param node the node * @param parentTaxonomyRecord the parent taxonomy record * @param taxonomyFlags the taxonomy flags */ private void processVersionNode(Node<? extends LogicGraphSememe> node, TaxonomyRecordPrimitive parentTaxonomyRecord, TaxonomyFlags taxonomyFlags) { if (node.getParent() == null) { processNewLogicGraph(node.getData(), parentTaxonomyRecord, taxonomyFlags); } else { final LogicalExpression comparisonExpression = node.getParent() .getData() .getLogicalExpression(); final LogicalExpression referenceExpression = node.getData() .getLogicalExpression(); final IsomorphicResultsBottomUp isomorphicResults = new IsomorphicResultsBottomUp(referenceExpression, comparisonExpression); isomorphicResults.getAddedRelationshipRoots().forEach((logicalNode) -> { final int stampSequence = node.getData() .getStampSequence(); processRelationshipRoot(logicalNode, parentTaxonomyRecord, taxonomyFlags, stampSequence, comparisonExpression); }); isomorphicResults.getDeletedRelationshipRoots().forEach((logicalNode) -> { final int activeStampSequence = node.getData() .getStampSequence(); final int stampSequence = Get.stampService() .getRetiredStampSequence(activeStampSequence); processRelationshipRoot(logicalNode, parentTaxonomyRecord, taxonomyFlags, stampSequence, comparisonExpression); }); } node.getChildren().forEach((childNode) -> { processVersionNode(childNode, parentTaxonomyRecord, taxonomyFlags); }); } /** * Recursive find ancestor. * * @param childSequence the child sequence * @param parentSequence the parent sequence * @param examined the examined * @return true, if successful */ private boolean recursiveFindAncestor(int childSequence, int parentSequence, HashSet<Integer> examined) { // currently unpacking from array to object. // TODO operate directly on array if unpacking is a performance bottleneck. if (examined.contains(childSequence)) { return false; } examined.add(childSequence); final Optional<TaxonomyRecordPrimitive> record = this.originDestinationTaxonomyRecordMap.get(childSequence); if (record.isPresent()) { final TaxonomyRecordUnpacked childTaxonomyRecords = new TaxonomyRecordUnpacked(record.get().getArray()); final int[] conceptSequencesForType = childTaxonomyRecords.getConceptSequencesForType(this.isaSequence) .toArray(); if (Arrays.stream(conceptSequencesForType) .anyMatch((int parentSequenceOfType) -> parentSequenceOfType == parentSequence)) { return true; } return Arrays.stream(conceptSequencesForType) .anyMatch((int intermediateChild) -> recursiveFindAncestor(intermediateChild, parentSequence, examined)); } return false; } /** * Recursive find ancestor. * * @param childSequence the child sequence * @param parentSequence the parent sequence * @param tc the tc * @return true, if successful */ private boolean recursiveFindAncestor(int childSequence, int parentSequence, TaxonomyCoordinate tc) { // currently unpacking from array to object. // TODO operate directly on array if unpacking is a performance bottleneck. final Optional<TaxonomyRecordPrimitive> record = this.originDestinationTaxonomyRecordMap.get(childSequence); if (record.isPresent()) { final TaxonomyRecordUnpacked childTaxonomyRecords = new TaxonomyRecordUnpacked(record.get().getArray()); final int[] activeConceptSequences = childTaxonomyRecords.getConceptSequencesForType(this.isaSequence, tc) .toArray(); if (Arrays.stream(activeConceptSequences) .anyMatch((int activeParentSequence) -> activeParentSequence == parentSequence)) { return true; } return Arrays.stream(activeConceptSequences) .anyMatch((int intermediateChild) -> recursiveFindAncestor(intermediateChild, parentSequence, tc)); } return false; } /** * Recursive find ancestors. * * @param childSequence the child sequence * @param ancestors the ancestors * @param tc the tc */ private void recursiveFindAncestors(int childSequence, ConceptSequenceSet ancestors, TaxonomyCoordinate tc) { // currently unpacking from array to object. // TODO operate directly on array if unpacking is a performance bottleneck. final Optional<TaxonomyRecordPrimitive> record = this.originDestinationTaxonomyRecordMap.get(childSequence); if (record.isPresent()) { final TaxonomyRecordUnpacked childTaxonomyRecords = new TaxonomyRecordUnpacked(record.get().getArray()); final int[] activeConceptSequences = childTaxonomyRecords.getConceptSequencesForType(this.isaSequence, tc) .toArray(); Arrays.stream(activeConceptSequences).forEach((parent) -> { if (!ancestors.contains(parent)) { ancestors.add(parent); recursiveFindAncestors(parent, ancestors, tc); } }); } } /** * Start me. */ @PostConstruct private void startMe() { try { LOG.info("Starting TaxonomyService post-construct"); if (!this.loadRequired.get()) { LOG.info("Reading taxonomy."); final boolean isPopulated = this.originDestinationTaxonomyRecordMap.initialize(); final File inputFile = new File(this.taxonomyProviderFolder.toFile(), ORIGIN_DESTINATION_MAP); try (DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(inputFile)))) { final int size = in.readInt(); for (int i = 0; i < size; i++) { this.destinationOriginRecordSet.add(new DestinationOriginRecord(in.readInt(), in.readInt())); } } if (isPopulated) { this.databaseValidity = DatabaseValidity.POPULATED_DIRECTORY; } } Get.commitService() .addChangeListener(this); this.identifierService = Get.identifierService(); } catch (final Exception e) { LookupService.getService(SystemStatusService.class) .notifyServiceConfigurationFailure("Cradle Taxonomy Provider", e); throw new RuntimeException(e); } } /** * Stop me. */ @PreDestroy private void stopMe() { LOG.info("Writing taxonomy."); this.originDestinationTaxonomyRecordMap.write(); final File outputFile = new File(this.taxonomyProviderFolder.toFile(), ORIGIN_DESTINATION_MAP); outputFile.getParentFile() .mkdirs(); try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)))) { out.writeInt(this.destinationOriginRecordSet.size()); this.destinationOriginRecordSet.forEach((rec) -> { try { out.writeInt(rec.getDestinationSequence()); out.writeInt(rec.getOriginSequence()); } catch (final IOException ex) { throw new RuntimeException(ex); } }); } catch (final IOException e) { throw new RuntimeException(e); } } /** * Update isa rel. * * @param conceptNode the concept node * @param parentTaxonomyRecord the parent taxonomy record * @param taxonomyFlags the taxonomy flags * @param stampSequence the stamp sequence * @param originSequence the origin sequence */ private void updateIsaRel(ConceptNodeWithSequences conceptNode, TaxonomyRecordPrimitive parentTaxonomyRecord, TaxonomyFlags taxonomyFlags, int stampSequence, int originSequence) { parentTaxonomyRecord.getTaxonomyRecordUnpacked() .addStampRecord(conceptNode.getConceptSequence(), this.isaSequence, stampSequence, taxonomyFlags.bits); this.destinationOriginRecordSet.add(new DestinationOriginRecord(conceptNode.getConceptSequence(), originSequence)); } /** * Update some role. * * @param someNode the some node * @param parentTaxonomyRecord the parent taxonomy record * @param taxonomyFlags the taxonomy flags * @param stampSequence the stamp sequence * @param originSequence the origin sequence */ private void updateSomeRole(RoleNodeSomeWithSequences someNode, TaxonomyRecordPrimitive parentTaxonomyRecord, TaxonomyFlags taxonomyFlags, int stampSequence, int originSequence) { if (someNode.getTypeConceptSequence() == this.roleGroupSequence) { final AndNode andNode = (AndNode) someNode.getOnlyChild(); andNode.getChildStream().forEach((roleGroupSomeNode) -> { if (roleGroupSomeNode instanceof RoleNodeSomeWithSequences) { updateSomeRole((RoleNodeSomeWithSequences) roleGroupSomeNode, parentTaxonomyRecord, taxonomyFlags, stampSequence, originSequence); } else { // TODO Dan put this here to stop a pile of errors.... // one of the types coming back was a FeatureNodeWithSequences - not sure what to do with it. } }); } else { if (someNode.getOnlyChild() instanceof ConceptNodeWithSequences) { final ConceptNodeWithSequences restrictionNode = (ConceptNodeWithSequences) someNode.getOnlyChild(); parentTaxonomyRecord.getTaxonomyRecordUnpacked() .addStampRecord(restrictionNode.getConceptSequence(), someNode.getTypeConceptSequence(), stampSequence, taxonomyFlags.bits); this.destinationOriginRecordSet.add(new DestinationOriginRecord(restrictionNode.getConceptSequence(), originSequence)); } else { // TODO dan put this here to stop a pile of errors. It was returning AndNode. Not sure what to do with it } } } //~--- get methods --------------------------------------------------------- /** * Gets the all circular relationship origin sequences. * * @param tc the tc * @return the all circular relationship origin sequences */ @Override public IntStream getAllCircularRelationshipOriginSequences(TaxonomyCoordinate tc) { final ConceptService conceptService = Get.conceptService(); final StampCoordinate stampCoordinate = tc.getStampCoordinate(); return Get.identifierService().getParallelConceptSequenceStream().filter((conceptSequence) -> { if (conceptService.isConceptActive(conceptSequence, stampCoordinate)) { if (getAllCircularRelationshipTypeSequences(conceptSequence, tc).anyMatch( ((typeSequence) -> true))) { return true; } } return false; }); } /** * Gets the all circular relationship type sequences. * * @param originId the origin id * @param tc the tc * @return the all circular relationship type sequences */ @Override public IntStream getAllCircularRelationshipTypeSequences(int originId, TaxonomyCoordinate tc) { final int originSequence = Get.identifierService() .getConceptSequence(originId); final ConceptSequenceSet ancestors = getAncestorOfSequenceSet(originId, tc); if (tc.getTaxonomyType() != PremiseType.INFERRED) { ancestors.or(getAncestorOfSequenceSet(originId, tc.makeAnalog(PremiseType.INFERRED))); } final ConceptSequenceSet excludedTypes = ConceptSequenceSet.of(this.isaSequence); final IntStream.Builder typeSequenceBuilder = IntStream.builder(); getAllRelationshipDestinationSequencesNotOfType(originId, excludedTypes, tc).filter((destinationSequence) -> ancestors.contains(destinationSequence)).forEach((destinationSequence) -> { getAllTypesForRelationship(originSequence, destinationSequence, tc).forEach( (typeSequence) -> typeSequenceBuilder.accept(typeSequence)); }); return typeSequenceBuilder.build(); } /** * Gets the all relationship destination sequences. * * @param originId the origin id * @return the all relationship destination sequences */ @Override public IntStream getAllRelationshipDestinationSequences(int originId) { originId = Get.identifierService() .getConceptSequence(originId); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequences(); } return IntStream.empty(); } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequences(); } } finally { this.stampedLock.unlock(stamp); } return IntStream.empty(); } /** * Gets the all relationship destination sequences. * * @param originId the origin id * @param tc the tc * @return the all relationship destination sequences */ @Override public IntStream getAllRelationshipDestinationSequences(int originId, TaxonomyCoordinate tc) { // lock handled by called method return getAllRelationshipDestinationSequencesOfType(originId, new ConceptSequenceSet(), tc); } /** * Gets the all relationship destination sequences not of type. * * @param originId the origin id * @param typeSequenceSet the type sequence set * @param tc the tc * @return the all relationship destination sequences not of type */ @Override public IntStream getAllRelationshipDestinationSequencesNotOfType(int originId, ConceptSequenceSet typeSequenceSet, TaxonomyCoordinate tc) { originId = Get.identifierService() .getConceptSequence(originId); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequencesNotOfType(typeSequenceSet, tc); } return IntStream.empty(); } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequencesNotOfType(typeSequenceSet, tc); } } finally { this.stampedLock.unlock(stamp); } return IntStream.empty(); } /** * Gets the all relationship destination sequences of type. * * @param originId the origin id * @param typeSequenceSet the type sequence set * @return the all relationship destination sequences of type */ @Override public IntStream getAllRelationshipDestinationSequencesOfType(int originId, ConceptSequenceSet typeSequenceSet) { originId = Get.identifierService() .getConceptSequence(originId); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequencesOfType(typeSequenceSet); } return IntStream.empty(); } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequencesOfType(typeSequenceSet); } } finally { this.stampedLock.unlock(stamp); } return IntStream.empty(); } /** * Gets the all relationship destination sequences of type. * * @param originId the origin id * @param typeSequenceSet the type sequence set * @param tc the tc * @return the all relationship destination sequences of type */ @Override public IntStream getAllRelationshipDestinationSequencesOfType(int originId, ConceptSequenceSet typeSequenceSet, TaxonomyCoordinate tc) { originId = Get.identifierService() .getConceptSequence(originId); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequencesOfType(typeSequenceSet, tc); } return IntStream.empty(); } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getDestinationSequencesOfType(typeSequenceSet, tc); } } finally { this.stampedLock.unlock(stamp); } return IntStream.empty(); } /** * Gets the all relationship origin sequences. * * @param destination the destination * @return the all relationship origin sequences */ @Override public IntStream getAllRelationshipOriginSequences(int destination) { // lock handled by getOriginSequenceStream return getOriginSequenceStream(destination); } /** * Gets the all relationship origin sequences. * * @param destination the destination * @param tc the tc * @return the all relationship origin sequences */ @Override public IntStream getAllRelationshipOriginSequences(int destination, TaxonomyCoordinate tc) { // Set of all concept sequences that point to the parent. // lock handled by getOriginSequenceStream final IntStream origins = getOriginSequenceStream(destination); return filterOriginSequences(origins, destination, this.isaSequence, tc, AllowedRelTypes.ALL_RELS); } /** * Gets the all relationship origin sequences of type. * * @param destinationId the destination id * @param typeSequenceSet the type sequence set * @return the all relationship origin sequences of type */ @Override public IntStream getAllRelationshipOriginSequencesOfType(int destinationId, ConceptSequenceSet typeSequenceSet) { destinationId = Get.identifierService() .getConceptSequence(destinationId); long stamp = this.stampedLock.tryOptimisticRead(); // Set of all concept sequences that point to the parent. IntStream origins = getOriginSequenceStream(destinationId); if (this.stampedLock.validate(stamp)) { return filterOriginSequences(origins, destinationId, typeSequenceSet); } stamp = this.stampedLock.readLock(); try { origins = getOriginSequenceStream(destinationId); return filterOriginSequences(origins, destinationId, typeSequenceSet); } finally { this.stampedLock.unlock(stamp); } } /** * Gets the all relationship origin sequences of type. * * @param destinationId the destination id * @param typeSequenceSet the type sequence set * @param tc the tc * @return the all relationship origin sequences of type */ @Override public IntStream getAllRelationshipOriginSequencesOfType(int destinationId, ConceptSequenceSet typeSequenceSet, TaxonomyCoordinate tc) { destinationId = Get.identifierService() .getConceptSequence(destinationId); long stamp = this.stampedLock.tryOptimisticRead(); // Set of all concept sequences that point to the parent. IntStream origins = getOriginSequenceStream(destinationId); if (this.stampedLock.validate(stamp)) { return filterOriginSequences(origins, destinationId, typeSequenceSet, tc); } stamp = this.stampedLock.readLock(); try { origins = getOriginSequenceStream(destinationId); return filterOriginSequences(origins, destinationId, typeSequenceSet, tc); } finally { this.stampedLock.unlock(stamp); } } /** * Gets the all types for relationship. * * @param originId the origin id * @param destinationId the destination id * @param tc the tc * @return the all types for relationship */ @Override public IntStream getAllTypesForRelationship(int originId, int destinationId, TaxonomyCoordinate tc) { originId = Get.identifierService() .getConceptSequence(originId); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getTypesForRelationship(destinationId, tc); } return IntStream.empty(); } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(originId); if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .getTypesForRelationship(destinationId, tc); } } finally { this.stampedLock.unlock(stamp); } return IntStream.empty(); } /** * Gets the ancestor of sequence set. * * @param childId the child id * @param tc the tc * @return the ancestor of sequence set */ @Override public ConceptSequenceSet getAncestorOfSequenceSet(int childId, TaxonomyCoordinate tc) { final ConceptSequenceSet ancestors = new ConceptSequenceSet(); recursiveFindAncestors(Get.identifierService() .getConceptSequence(childId), ancestors, tc); return ancestors; } /** * Checks if child of. * * @param childId the child id * @param parentId the parent id * @param tc the tc * @return true, if child of */ @Override public boolean isChildOf(int childId, int parentId, TaxonomyCoordinate tc) { childId = Get.identifierService() .getConceptSequence(childId); parentId = Get.identifierService() .getConceptSequence(parentId); final RelativePositionCalculator computer = RelativePositionCalculator.getCalculator(tc.getStampCoordinate()); final int flags = TaxonomyFlags.getFlagsFromTaxonomyCoordinate(tc); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> record = this.originDestinationTaxonomyRecordMap.get(childId); if (this.stampedLock.validate(stamp)) { if (record.isPresent()) { final TaxonomyRecordUnpacked childTaxonomyRecords = new TaxonomyRecordUnpacked(record.get().getArray()); final Optional<TypeStampTaxonomyRecords> parentStampRecordsOptional = childTaxonomyRecords.getConceptSequenceStampRecords(parentId); if (parentStampRecordsOptional.isPresent()) { final TypeStampTaxonomyRecords parentStampRecords = parentStampRecordsOptional.get(); if (computer.isLatestActive(parentStampRecords.getStampsOfTypeWithFlags(this.isaSequence, flags))) { if (this.stampedLock.validate(stamp)) { return true; } } } } return false; } stamp = this.stampedLock.readLock(); try { record = this.originDestinationTaxonomyRecordMap.get(childId); if (record.isPresent()) { final TaxonomyRecordUnpacked childTaxonomyRecords = new TaxonomyRecordUnpacked(record.get().getArray()); final Optional<TypeStampTaxonomyRecords> parentStampRecordsOptional = childTaxonomyRecords.getConceptSequenceStampRecords(parentId); if (parentStampRecordsOptional.isPresent()) { final TypeStampTaxonomyRecords parentStampRecords = parentStampRecordsOptional.get(); if (computer.isLatestActive(parentStampRecords.getStampsOfTypeWithFlags(this.isaSequence, flags))) { if (this.stampedLock.validate(stamp)) { return true; } } } } } finally { this.stampedLock.unlock(stamp); } return false; } /** * Gets the child of sequence set. * * @param parentId the parent id * @param tc the tc * @return the child of sequence set */ @Override public ConceptSequenceSet getChildOfSequenceSet(int parentId, TaxonomyCoordinate tc) { // Set of all concept sequences that point to the parent. // lock handled by getOriginSequenceStream final IntStream origins = getOriginSequenceStream(parentId); return ConceptSequenceSet.of(filterOriginSequences(origins, parentId, this.isaSequence, tc, AllowedRelTypes.HIERARCHICAL_ONLY)); } /** * Checks if concept active. * * @param conceptSequence the concept sequence * @param stampCoordinate the stamp coordinate * @return true, if concept active */ @Override public boolean isConceptActive(int conceptSequence, StampCoordinate stampCoordinate) { long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(conceptSequence); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .isConceptActive(conceptSequence, stampCoordinate); } return false; } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(conceptSequence); if (taxonomyRecordOptional.isPresent()) { return taxonomyRecordOptional.get() .isConceptActive(conceptSequence, stampCoordinate); } return false; } finally { this.stampedLock.unlock(stamp); } } /** * Gets the database folder. * * @return the database folder */ @Override public Path getDatabaseFolder() { return this.taxonomyProviderFolder; } /** * Gets the database validity status. * * @return the database validity status */ @Override public DatabaseValidity getDatabaseValidityStatus() { return this.databaseValidity; } /** * Gets the destination origin record set. * * @return the destination origin record set */ public ConcurrentSkipListSet<DestinationOriginRecord> getDestinationOriginRecordSet() { return this.destinationOriginRecordSet; } /** * Checks if kind of. * * @param childId the child id * @param parentId the parent id * @param tc the tc * @return true, if kind of */ @Override public boolean isKindOf(int childId, int parentId, TaxonomyCoordinate tc) { childId = Get.identifierService() .getConceptSequence(childId); parentId = Get.identifierService() .getConceptSequence(parentId); if (childId == parentId) { return true; } long stamp = this.stampedLock.tryOptimisticRead(); final boolean isKindOf = recursiveFindAncestor(childId, parentId, tc); if (this.stampedLock.validate(stamp)) { return isKindOf; } stamp = this.stampedLock.readLock(); try { return recursiveFindAncestor(childId, parentId, tc); } finally { this.stampedLock.unlock(stamp); } } /** * Gets the kind of sequence set. * * @param rootId the root id * @param tc the tc * @return the kind of sequence set */ @Override public ConceptSequenceSet getKindOfSequenceSet(int rootId, TaxonomyCoordinate tc) { rootId = Get.identifierService() .getConceptSequence(rootId); long stamp = this.stampedLock.tryOptimisticRead(); // TODO Look at performance of getTaxonomyTree... Tree tree = getTaxonomyTree(tc); final ConceptSequenceSet kindOfSet = ConceptSequenceSet.of(rootId); tree.depthFirstProcess(rootId, (TreeNodeVisitData t, int conceptSequence) -> { kindOfSet.add(conceptSequence); }); if (this.stampedLock.validate(stamp)) { return kindOfSet; } stamp = this.stampedLock.readLock(); try { tree = getTaxonomyTree(tc); final ConceptSequenceSet kindOfSet2 = ConceptSequenceSet.of(rootId); tree.depthFirstProcess(rootId, (TreeNodeVisitData t, int conceptSequence) -> { kindOfSet2.add(conceptSequence); }); return kindOfSet2; } finally { this.stampedLock.unlock(stamp); } } /** * Gets the listener uuid. * * @return the listener uuid */ @Override public UUID getListenerUuid() { return this.providerUuid; } /** * Gets the origin destination taxonomy records. * * @return the origin destination taxonomy records */ public CasSequenceObjectMap<TaxonomyRecordPrimitive> getOriginDestinationTaxonomyRecords() { return this.originDestinationTaxonomyRecordMap; } /** * Gets the origin sequence stream. * * @param parentId the parent id * @return the origin sequence stream */ private IntStream getOriginSequenceStream(int parentId) { // Set of all concept sequences that point to the parent. parentId = Get.identifierService() .getConceptSequence(parentId); long stamp = this.stampedLock.tryOptimisticRead(); NavigableSet<DestinationOriginRecord> subSet = this.destinationOriginRecordSet.subSet(new DestinationOriginRecord(parentId, Integer.MIN_VALUE), new DestinationOriginRecord(parentId, Integer.MAX_VALUE)); if (this.stampedLock.validate(stamp)) { return subSet.stream() .mapToInt((DestinationOriginRecord record) -> record.getOriginSequence()); } stamp = this.stampedLock.readLock(); try { subSet = this.destinationOriginRecordSet.subSet(new DestinationOriginRecord(parentId, Integer.MIN_VALUE), new DestinationOriginRecord(parentId, Integer.MAX_VALUE)); return subSet.stream() .mapToInt((DestinationOriginRecord record) -> record.getOriginSequence()); } finally { this.stampedLock.unlock(stamp); } } /** * Gets the roots. * * @param tc the tc * @return the roots */ @Override public IntStream getRoots(TaxonomyCoordinate tc) { long stamp = this.stampedLock.tryOptimisticRead(); Tree tree = getTaxonomyTree(tc); if (!this.stampedLock.validate(stamp)) { stamp = this.stampedLock.readLock(); try { tree = getTaxonomyTree(tc); } finally { this.stampedLock.unlock(stamp); } } return tree.getRootSequenceStream(); } /** * Gets the snapshot. * * @param tc the tc * @return the snapshot */ @Override public TaxonomySnapshotService getSnapshot(TaxonomyCoordinate tc) { return new TaxonomySnapshotProvider(tc); } /** * Gets the taxonomy child sequences. * * @param parentId the parent id * @return the taxonomy child sequences */ @Override public IntStream getTaxonomyChildSequences(int parentId) { // Set of all concept sequences that point to the parent. // lock handled by getOriginSequenceStream final IntStream origins = getOriginSequenceStream(parentId); return filterOriginSequences(origins, parentId, this.isaSequence, TaxonomyFlags.ALL_RELS); } /** * Gets the taxonomy child sequences. * * @param parentId the parent id * @param tc the tc * @return the taxonomy child sequences */ @Override public IntStream getTaxonomyChildSequences(int parentId, TaxonomyCoordinate tc) { // Set of all concept sequences that point to the parent. // lock handled by getOriginSequenceStream final IntStream origins = getOriginSequenceStream(parentId); return filterOriginSequences(origins, parentId, this.isaSequence, tc, AllowedRelTypes.HIERARCHICAL_ONLY); } /** * Gets the taxonomy parent sequences. * * @param childId the child id * @return the taxonomy parent sequences */ @Override public IntStream getTaxonomyParentSequences(int childId) { childId = Get.identifierService() .getConceptSequence(childId); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(childId); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); return taxonomyRecord.getParentSequences() .distinct(); } return IntStream.empty(); } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(childId); if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); return taxonomyRecord.getParentSequences() .distinct(); } return IntStream.empty(); } finally { this.stampedLock.unlock(stamp); } } /** * Gets the taxonomy parent sequences. * * @param childId the child id * @param tc the tc * @return the taxonomy parent sequences */ @Override public IntStream getTaxonomyParentSequences(int childId, TaxonomyCoordinate tc) { childId = Get.identifierService() .getConceptSequence(childId); long stamp = this.stampedLock.tryOptimisticRead(); Optional<TaxonomyRecordPrimitive> taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(childId); if (this.stampedLock.validate(stamp)) { if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); return taxonomyRecord.getParentSequences(tc); } return IntStream.empty(); } stamp = this.stampedLock.readLock(); try { taxonomyRecordOptional = this.originDestinationTaxonomyRecordMap.get(childId); if (taxonomyRecordOptional.isPresent()) { final TaxonomyRecordPrimitive taxonomyRecord = taxonomyRecordOptional.get(); return taxonomyRecord.getParentSequences(tc); } return IntStream.empty(); } finally { this.stampedLock.unlock(stamp); } } /** * Gets the taxonomy tree. * * @param tc the tc * @return the taxonomy tree */ @Override public Tree getTaxonomyTree(TaxonomyCoordinate tc) { // TODO determine if the returned tree is thread safe for multiple accesses in parallel, if not, may need a pool of these. Tree temp = this.treeCache.get(tc.hashCode()); { if (temp != null) { return temp; } } long stamp = this.stampedLock.tryOptimisticRead(); IntStream conceptSequenceStream = Get.identifierService() .getParallelConceptSequenceStream(); GraphCollector collector = new GraphCollector(this.originDestinationTaxonomyRecordMap, tc); HashTreeBuilder graphBuilder = conceptSequenceStream.collect(HashTreeBuilder::new, collector, collector); if (this.stampedLock.validate(stamp)) { temp = graphBuilder.getSimpleDirectedGraphGraph(); this.treeCache.put(tc.hashCode(), temp); return temp; } stamp = this.stampedLock.readLock(); try { conceptSequenceStream = Get.identifierService() .getParallelConceptSequenceStream(); collector = new GraphCollector(this.originDestinationTaxonomyRecordMap, tc); graphBuilder = conceptSequenceStream.collect(HashTreeBuilder::new, collector, collector); temp = graphBuilder.getSimpleDirectedGraphGraph(); this.treeCache.put(tc.hashCode(), temp); return temp; } finally { this.stampedLock.unlock(stamp); } } //~--- inner classes ------------------------------------------------------- /** * The Class TaxonomySnapshotProvider. */ private class TaxonomySnapshotProvider implements TaxonomySnapshotService { /** The tc. */ TaxonomyCoordinate tc; //~--- constructors ----------------------------------------------------- /** * Instantiates a new taxonomy snapshot provider. * * @param tc the tc */ public TaxonomySnapshotProvider(TaxonomyCoordinate tc) { this.tc = tc; } //~--- get methods ------------------------------------------------------ /** * Gets the all relationship destination sequences. * * @param originId the origin id * @return the all relationship destination sequences */ @Override public IntStream getAllRelationshipDestinationSequences(int originId) { return TaxonomyProvider.this.getAllRelationshipDestinationSequences(originId, this.tc); } /** * Gets the all relationship destination sequences of type. * * @param originId the origin id * @param typeSequenceSet the type sequence set * @return the all relationship destination sequences of type */ @Override public IntStream getAllRelationshipDestinationSequencesOfType(int originId, ConceptSequenceSet typeSequenceSet) { return TaxonomyProvider.this.getAllRelationshipDestinationSequencesOfType(originId, typeSequenceSet, this.tc); } /** * Gets the all relationship origin sequences. * * @param destination the destination * @return the all relationship origin sequences */ @Override public IntStream getAllRelationshipOriginSequences(int destination) { return TaxonomyProvider.this.getAllRelationshipOriginSequences(destination, this.tc); } /** * Gets the all relationship origin sequences of type. * * @param destinationId the destination id * @param typeSequenceSet the type sequence set * @return the all relationship origin sequences of type */ @Override public IntStream getAllRelationshipOriginSequencesOfType(int destinationId, ConceptSequenceSet typeSequenceSet) { return TaxonomyProvider.this.getAllRelationshipOriginSequencesOfType(destinationId, typeSequenceSet, this.tc); } /** * Checks if child of. * * @param childId the child id * @param parentId the parent id * @return true, if child of */ @Override public boolean isChildOf(int childId, int parentId) { return TaxonomyProvider.this.isChildOf(childId, parentId, this.tc); } /** * Checks if kind of. * * @param childId the child id * @param parentId the parent id * @return true, if kind of */ @Override public boolean isKindOf(int childId, int parentId) { return TaxonomyProvider.this.isKindOf(childId, parentId, this.tc); } /** * Gets the kind of sequence set. * * @param rootId the root id * @return the kind of sequence set */ @Override public ConceptSequenceSet getKindOfSequenceSet(int rootId) { return TaxonomyProvider.this.getKindOfSequenceSet(rootId, this.tc); } /** * Gets the roots. * * @return the roots */ @Override public IntStream getRoots() { return TaxonomyProvider.this.getRoots(this.tc); } /** * Gets the taxonomy child sequences. * * @param parentId the parent id * @return the taxonomy child sequences */ @Override public IntStream getTaxonomyChildSequences(int parentId) { return TaxonomyProvider.this.getTaxonomyChildSequences(parentId, this.tc); } /** * Gets the taxonomy parent sequences. * * @param childId the child id * @return the taxonomy parent sequences */ @Override public IntStream getTaxonomyParentSequences(int childId) { return TaxonomyProvider.this.getTaxonomyParentSequences(childId, this.tc); } /** * Gets the taxonomy tree. * * @return the taxonomy tree */ @Override public Tree getTaxonomyTree() { return TaxonomyProvider.this.getTaxonomyTree(this.tc); } } }