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

org.protempa.KnowledgeSourceImpl Maven / Gradle / Ivy

There is a newer version: 5.2-Alpha-2
Show newest version
/*
 * #%L
 * Protempa Framework
 * %%
 * Copyright (C) 2012 - 2013 Emory University
 * %%
 * 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%
 */
package org.protempa;

import org.protempa.valueset.ValueSet;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.arp.javautil.arrays.Arrays;
import org.protempa.backend.BackendInitializationException;
import org.protempa.backend.BackendNewInstanceException;
import org.protempa.backend.KnowledgeSourceBackendUpdatedEvent;
import org.protempa.backend.ksb.KnowledgeSourceBackend;
import org.protempa.query.And;

/**
 * A read-only "interface" to an externally-maintained knowledge base. The user
 * must specify a backend in the constructor from where information about
 * primitive parameters and abstract parameters can be obtained.
 *
 * @author Andrew Post
 */
public final class KnowledgeSourceImpl
        extends AbstractSource implements KnowledgeSource {

    /**
     * PROTEMPA knowledge base.
     */
    private final PropositionDefinitionReader propDefReader;
    private final AbstractionDefinitionReader abstractionDefReader;
    private final ContextDefinitionReader contextDefReader;
    private final TemporalPropositionDefinitionReader tempPropDefReader;
    private SubtreePropositionDefinitionGetterRegular inDataSourceGetter;
    private SubtreePropositionDefinitionGetterRegular collectSubtreeGetter;

    public KnowledgeSourceImpl(KnowledgeSourceBackend... backends) {
        super(backends);
        this.propDefReader = new PropositionDefinitionReader();
        this.abstractionDefReader = new AbstractionDefinitionReader();
        this.contextDefReader = new ContextDefinitionReader();
        this.tempPropDefReader = new TemporalPropositionDefinitionReader();
    }

    /**
     * Connect to the knowledge source backend(s).
     */
    private void initializeIfNeeded() throws BackendInitializationException,
            BackendNewInstanceException {
        if (isClosed()) {
            throw new IllegalStateException("Knowledge source already closed!");
        }
        if (this.inDataSourceGetter == null) {
            this.inDataSourceGetter
                    = new SubtreePropositionDefinitionGetterRegular(this, true);
        }
        if (this.collectSubtreeGetter == null) {
            this.collectSubtreeGetter
                    = new SubtreePropositionDefinitionGetterRegular(this, false);
        }
    }

    private void initializeIfNeeded(String template, String... propIds)
            throws KnowledgeSourceReadException {
        try {
            initializeIfNeeded();
        } catch (BackendInitializationException | BackendNewInstanceException ex) {
            String action = MessageFormat.format(template, StringUtils.join(propIds, ", "));
            throw new KnowledgeSourceReadException(
                    "An error occurred " + action, ex);
        }
    }

    private void initializeIfNeeded(String action)
            throws KnowledgeSourceReadException {
        initializeIfNeeded(action, null);
    }

    @Override
    public List readInverseIsA(
            PropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }
        List result = new ArrayList<>();
        initializeIfNeeded("reading inverseIsA of {0}", propDef.getId());
        String[] propIds = propDef.getInverseIsA();
        result.addAll(readPropositionDefinitions(propIds));
        return result;
    }

    @Override
    public List readIsA(PropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }

        return readIsA(propDef.getId());
    }

    @Override
    public List readIsAPropIds(PropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }

        return readIsAPropIds(propDef.getId());
    }

    @Override
    public List readInverseIsA(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        PropositionDefinition propDef = readPropositionDefinition(id);
        if (propDef == null) {
            return Collections.emptyList();
        } else {
            return readInverseIsA(propDef);
        }
    }

    @Override
    public List readIsA(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set isAs = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(isAs, backend.readIsA(id));
        }
        return readPropositionDefinitions(isAs.toArray(new String[isAs.size()]));
    }

    @Override
    public List readIsAPropIds(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set isAs = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(isAs, backend.readIsA(id));
        }
        return new ArrayList<>(isAs);
    }

    @Override
    public List readAbstractedFrom(
            AbstractionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }
        initializeIfNeeded("reading abstractedFrom of {0}",
                propDef.getId());

        Set propIds = propDef.getAbstractedFrom();
        return readPropositionDefinitions(propIds.toArray(new String[propIds.size()]));
    }

    @Override
    public List readAbstractedInto(
            PropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }

        return readAbstractedInto(propDef.getId());
    }

    @Override
    public List readAbstractedIntoPropIds(
            PropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }

        return readAbstractedIntoPropIds(propDef.getId());
    }

    @Override
    public List readAbstractedFrom(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        AbstractionDefinition propDef = readAbstractionDefinition(id);
        if (propDef == null) {
            return Collections.emptyList();
        } else {
            return readAbstractedFrom(propDef);
        }
    }

    @Override
    public List readAbstractedInto(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set abstractedIntos = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(abstractedIntos,
                    backend.readAbstractedInto(id));
        }
        return readAbstractionDefinitions(abstractedIntos.toArray(new String[abstractedIntos.size()]));
    }

    @Override
    public List readAbstractedIntoPropIds(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set abstractedIntos = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(abstractedIntos,
                    backend.readAbstractedInto(id));
        }
        return new ArrayList<>(abstractedIntos);
    }

    @Override
    public List readInduces(
            TemporalPropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }

        return readInduces(propDef.getId());
    }

    @Override
    public List readInducesPropIds(
            TemporalPropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }

        return readInducesPropIds(propDef.getId());
    }

    @Override
    public List readInduces(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set induces = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(induces,
                    backend.readInduces(id));
        }
        return readContextDefinitions(induces.toArray(new String[induces.size()]));
    }

    @Override
    public List readInducesPropIds(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set induces = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(induces,
                    backend.readInduces(id));
        }
        return new ArrayList<>(induces);
    }

    @Override
    public List readSubContextOfs(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set subContextOfs = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(subContextOfs,
                    backend.readSubContextOfs(id));
        }
        return readContextDefinitions(subContextOfs.toArray(new String[subContextOfs.size()]));
    }

    @Override
    public List readSubContextOfPropIds(String id)
            throws KnowledgeSourceReadException {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        Set subContextOfs = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            Arrays.addAll(subContextOfs,
                    backend.readSubContextOfs(id));
        }
        return new ArrayList<>(subContextOfs);
    }

    @Override
    public List readSubContextOfs(ContextDefinition cd)
            throws KnowledgeSourceReadException {
        if (cd == null) {
            throw new IllegalArgumentException("cd cannot be null");
        }
        return readSubContextOfs(cd.getId());
    }

    @Override
    public List readSubContextOfPropIds(ContextDefinition cd)
            throws KnowledgeSourceReadException {
        if (cd == null) {
            throw new IllegalArgumentException("cd cannot be null");
        }
        return readSubContextOfPropIds(cd.getId());
    }

    @Override
    public List readSubContexts(String contextId) throws KnowledgeSourceReadException {
        if (contextId == null) {
            throw new IllegalArgumentException("contextId cannot be null");
        }
        ContextDefinition pd = readContextDefinition(contextId);
        if (pd != null) {
            return readSubContexts(pd);
        } else {
            return new ArrayList<>(0);
        }

    }

    @Override
    public List readSubContexts(ContextDefinition contextDef) throws KnowledgeSourceReadException {
        if (contextDef == null) {
            throw new IllegalArgumentException("contextDef cannot be null");
        }
        initializeIfNeeded("reading subContexts of {0}",
                contextDef.getId());

        String[] propIds = contextDef.getSubContexts();
        return readContextDefinitions(propIds);
    }

    @Override
    public List readParents(
            PropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }

        List result = readParentPropIds(propDef);

        return readPropositionDefinitions(result.toArray(new String[result.size()]));
    }

    @Override
    public List readParentPropIds(PropositionDefinition propDef)
            throws KnowledgeSourceReadException {
        if (propDef == null) {
            throw new IllegalArgumentException("propDef cannot be null");
        }
        List subContextOfs;
        List induces;
        if (propDef instanceof ContextDefinition) {
            subContextOfs = readSubContextOfPropIds((ContextDefinition) propDef);
            induces = readInducesPropIds((ContextDefinition) propDef);
        } else {
            subContextOfs = Collections.emptyList();
            induces = Collections.emptyList();
        }

        List ad = readAbstractedIntoPropIds(propDef);
        List pd = readIsAPropIds(propDef);
        Set result = new HashSet<>();
        result.addAll(subContextOfs);
        result.addAll(induces);
        result.addAll(ad);
        result.addAll(pd);
        return new ArrayList<>(result);
    }

    @Override
    public List readParents(String propId)
            throws KnowledgeSourceReadException {
        if (propId == null) {
            throw new IllegalArgumentException("propId cannot be null");
        }
        PropositionDefinition pd = readPropositionDefinition(propId);
        if (pd != null) {
            return readParents(pd);
        } else {
            return new ArrayList<>(0);
        }
    }

    @Override
    public List readParentPropIds(String propId)
            throws KnowledgeSourceReadException {
        if (propId == null) {
            throw new IllegalArgumentException("propId cannot be null");
        }
        PropositionDefinition pd = readPropositionDefinition(propId);
        if (pd != null) {
            return readParentPropIds(pd);
        } else {
            return new ArrayList<>(0);
        }
    }

    @Override
    public List readInducedBy(String contextId) throws KnowledgeSourceReadException {
        if (contextId == null) {
            throw new IllegalArgumentException("contextId cannot be null");
        }
        ContextDefinition pd = readContextDefinition(contextId);
        if (pd != null) {
            return readInducedBy(pd);
        } else {
            return new ArrayList<>(0);
        }
    }

    @Override
    public List readInducedBy(ContextDefinition contextDef) throws KnowledgeSourceReadException {
        if (contextDef == null) {
            throw new IllegalArgumentException("contextDef cannot be null");
        }
        List result = new ArrayList<>();
        initializeIfNeeded("reading inducedBy of {0}",
                contextDef.getId());

        TemporalExtendedPropositionDefinition[] tepds = contextDef.getInducedBy();
        Set propIds = new HashSet<>();
        for (TemporalExtendedPropositionDefinition tepd : tepds) {
            propIds.add(tepd.getPropositionId());
        }
        return readTemporalPropositionDefinitions(propIds.toArray(new String[propIds.size()]));
    }

    @Override
    public boolean hasTemporalPropositionDefinition(String id) throws KnowledgeSourceReadException {
        return this.tempPropDefReader.has(id);
    }

    @Override
    public TemporalPropositionDefinition readTemporalPropositionDefinition(String id) throws KnowledgeSourceReadException {
        return this.tempPropDefReader.read(id);
    }

    @Override
    public List readTemporalPropositionDefinitions(String... propIds) throws KnowledgeSourceReadException {
        return this.tempPropDefReader.read(propIds);
    }

    private abstract class AbstractDefinitionReader {

        final E read(String id) throws KnowledgeSourceReadException {
            if (id == null) {
                throw new IllegalArgumentException("id cannot be null");
            }
            initializeIfNeeded("reading the proposition definition {0}", id);

            E result = null;
            if (result == null) {
                for (KnowledgeSourceBackend backend : getBackends()) {
                    result = readFromBackend(id, backend);
                    if (result != null) {
                        return result;
                    }
                }
            }
            return result;
        }

        final List read(String[] ids) throws KnowledgeSourceReadException {
            assert ids != null : "ids cannot be null";
            initializeIfNeeded("reading the proposition definitions {0}", ids);

            List result = new ArrayList<>();

            for (KnowledgeSourceBackend backend : getBackends()) {
                result.addAll(readFromBackend(Arrays.asList(ids), backend));
            }
            return result;
        }

        final boolean has(String id) throws KnowledgeSourceReadException {
            if (id == null) {
                throw new IllegalArgumentException("id cannot be null");
            }
            return read(id) != null;
        }

        protected abstract E readFromBackend(String id,
                KnowledgeSourceBackend backend)
                throws KnowledgeSourceReadException;

        protected abstract List readFromBackend(List ids,
                KnowledgeSourceBackend backend)
                throws KnowledgeSourceReadException;

    }

    private final class PropositionDefinitionReader extends AbstractDefinitionReader {

        @Override
        protected PropositionDefinition readFromBackend(String id,
                KnowledgeSourceBackend backend)
                throws KnowledgeSourceReadException {
            return backend.readPropositionDefinition(id);
        }

        @Override
        protected List readFromBackend(List ids, KnowledgeSourceBackend backend) throws KnowledgeSourceReadException {
            return backend.readPropositionDefinitions(ids.toArray(new String[ids.size()]));
        }
    }

    private final class AbstractionDefinitionReader
            extends AbstractDefinitionReader {

        @Override
        protected AbstractionDefinition readFromBackend(String id,
                KnowledgeSourceBackend backend)
                throws KnowledgeSourceReadException {
            return backend.readAbstractionDefinition(id);
        }

        @Override
        protected List readFromBackend(List ids, KnowledgeSourceBackend backend) throws KnowledgeSourceReadException {
            return backend.readAbstractionDefinitions(ids.toArray(new String[ids.size()]));
        }

    }

    private final class ContextDefinitionReader
            extends AbstractDefinitionReader {

        @Override
        protected ContextDefinition readFromBackend(String id, KnowledgeSourceBackend backend) throws KnowledgeSourceReadException {
            return backend.readContextDefinition(id);
        }

        @Override
        protected List readFromBackend(List ids, KnowledgeSourceBackend backend) throws KnowledgeSourceReadException {
            return backend.readContextDefinitions(ids.toArray(new String[ids.size()]));
        }

    }

    private final class TemporalPropositionDefinitionReader
            extends AbstractDefinitionReader {

        @Override
        protected TemporalPropositionDefinition readFromBackend(String id, KnowledgeSourceBackend backend) throws KnowledgeSourceReadException {
            return backend.readTemporalPropositionDefinition(id);
        }

        @Override
        protected List readFromBackend(List ids, KnowledgeSourceBackend backend) throws KnowledgeSourceReadException {
            return backend.readTemporalPropositionDefinitions(ids.toArray(new String[ids.size()]));
        }

    }

    /**
     * Returns the specified proposition definition.
     *
     * @param id a proposition id {@link String}. Cannot be null.
     * @return a {@link PropositionDefinition}, or null if none was
     * found with the given id.
     * @throws KnowledgeSourceReadException if an error occurred reading from
     * the knowledge base.
     */
    @Override
    public PropositionDefinition readPropositionDefinition(String id)
            throws KnowledgeSourceReadException {
        return this.propDefReader.read(id);
    }

    @Override
    public List readPropositionDefinitions(String... propIds)
            throws KnowledgeSourceReadException {
        return this.propDefReader.read(propIds);
    }

    @Override
    public boolean hasPropositionDefinition(String id)
            throws KnowledgeSourceReadException {
        return this.propDefReader.has(id);
    }

    @Override
    public AbstractionDefinition readAbstractionDefinition(String id) throws KnowledgeSourceReadException {
        return this.abstractionDefReader.read(id);
    }

    @Override
    public List readAbstractionDefinitions(String... propIds) throws KnowledgeSourceReadException {
        return this.abstractionDefReader.read(propIds);
    }

    @Override
    public ContextDefinition readContextDefinition(String id) throws KnowledgeSourceReadException {
        return this.contextDefReader.read(id);
    }

    @Override
    public List readContextDefinitions(String... propIds) throws KnowledgeSourceReadException {
        return this.contextDefReader.read(propIds);
    }

    @Override
    public boolean hasAbstractionDefinition(String id) throws KnowledgeSourceReadException {
        return this.abstractionDefReader.has(id);
    }

    @Override
    public boolean hasContextDefinition(String id) throws KnowledgeSourceReadException {
        return this.contextDefReader.has(id);
    }

    @Override
    public ValueSet readValueSet(String id) throws KnowledgeSourceReadException {
        ValueSet result = null;
        initializeIfNeeded("reading the value set {0}", id);
        if (getBackends() != null) {
            for (KnowledgeSourceBackend backend : getBackends()) {
                result = backend.readValueSet(id);
                if (result != null) {
                    return result;
                }
            }
        }
        return result;
    }

    @Override
    public boolean hasValueSet(String id) throws KnowledgeSourceReadException {
        boolean result = false;
        if (!result) {
            initializeIfNeeded("reading the value set {0}", id);
            for (KnowledgeSourceBackend backend : getBackends()) {
                result = backend.readValueSet(id) != null;
                if (result) {
                    return result;
                }
            }
        }
        return result;
    }

    @Override
    public void close() throws SourceCloseException {
        clear();
        super.close();
    }

    @Override
    public void clear() {
    }

    @Override
    public Set collectPropIdDescendantsUsingAllNarrower(boolean inDataSourceOnly, String... propIds)
            throws KnowledgeSourceReadException {
        initializeIfNeeded(
                "Getting proposition ids for {0} with inDataSource set to true",
                StringUtils.join(propIds, ","));
        ProtempaUtil.checkArrayForNullElement(propIds, "propIds");
        return this.inDataSourceGetter.subtreePropIds(inDataSourceOnly, propIds);
    }

    @Override
    public Set collectPropDefDescendantsUsingAllNarrower(
            boolean inDataSourceOnly, String... propIds) throws KnowledgeSourceReadException {
        initializeIfNeeded(
                "Getting proposition definitions for {0} with inDataSource set to true",
                StringUtils.join(propIds, ","));
        ProtempaUtil.checkArrayForNullElement(propIds, "propIds");
        return this.inDataSourceGetter.subtreePropDefs(inDataSourceOnly, propIds);
    }

    @Override
    public Set collectPropIdDescendantsUsingInverseIsA(String... propIds) throws KnowledgeSourceReadException {
        initializeIfNeeded(
                "Getting proposition ids for {0}",
                StringUtils.join(propIds, ","));
        ProtempaUtil.checkArrayForNullElement(propIds, "propIds");
        return this.collectSubtreeGetter.subtreePropIds(false, propIds);
    }

    @Override
    public Set collectPropDefDescendantsUsingInverseIsA(String... propIds) throws KnowledgeSourceReadException {
        initializeIfNeeded(
                "Getting proposition definitions for {0}",
                StringUtils.join(propIds, ","));
        ProtempaUtil.checkArrayForNullElement(propIds, "propIds");
        return this.collectSubtreeGetter.subtreePropDefs(false, propIds);
    }

    /**
     * Gets the mappings from term IDs to proposition IDs for each backend.
     *
     * @return a {@link Map} of {@link String}s to a {@link List} of
     * Strings, with the keys being {@link Term} IDs and the values
     * being lists of {@link PropositionDefinition} IDs.
     */
    @Override
    public List getPropositionDefinitionsByTerm(
            And termSubsumptionClause)
            throws KnowledgeSourceReadException {
        List result = new ArrayList<>();
        initializeIfNeeded("getting proposition definitions by term");
        for (KnowledgeSourceBackend backend : getBackends()) {
            result.addAll(backend.getPropositionsByTermSubsumption(termSubsumptionClause));
        }

        return result;
    }

    @Override
    public void backendUpdated(KnowledgeSourceBackendUpdatedEvent event) {
        clear();
        fireKnowledgeSourceUpdated();
    }

    /**
     * Notifies registered listeners that the knowledge source has been updated.
     *
     * @see KnowledgeSourceUpdatedEvent
     * @see SourceListener
     */
    private void fireKnowledgeSourceUpdated() {
        fireSourceUpdated(new KnowledgeSourceUpdatedEvent(this));
    }

    /**
     * Gets the proposition Definitions from each backend that match the
     * searchKey
     *
     * @param searchKey
     * @return
     * @throws KnowledgeSourceReadException
     */
    @Override
    public List getMatchingPropIds(String searchKey)
            throws KnowledgeSourceReadException {
        ProtempaUtil.logger().log(Level.INFO,
                "Searching knowledge source For search string {0}", searchKey);
        Set searchResults = getSearchResultsFromBackend(searchKey);
        return new ArrayList<>(searchResults);
    }

    private Set getSearchResultsFromBackend(String searchKey)
            throws KnowledgeSourceReadException {
        Set results = new HashSet<>();
        for (KnowledgeSourceBackend backend : getBackends()) {
            results.addAll(backend.getKnowledgeSourceSearchResults(searchKey));
        }
        return results;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy