Package org.openbel.framework.core.compiler

Source Code of org.openbel.framework.core.compiler.SemanticServiceImpl

/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.core.compiler;

import static java.lang.Integer.parseInt;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static org.openbel.framework.common.BELUtilities.hasItems;
import static org.openbel.framework.common.BELUtilities.noItems;
import static org.openbel.framework.common.enums.FunctionEnum.PROTEIN_ABUNDANCE;
import static org.openbel.framework.common.enums.FunctionEnum.GENE_ABUNDANCE;
import static org.openbel.framework.common.enums.FunctionEnum.RNA_ABUNDANCE;
import static org.openbel.framework.common.enums.FunctionEnum.FUSION;
import static org.openbel.framework.common.enums.FunctionEnum.PROTEIN_MODIFICATION;
import static org.openbel.framework.common.enums.FunctionEnum.SUBSTITUTION;
import static org.openbel.framework.common.enums.FunctionEnum.TRUNCATION;
import static org.openbel.framework.common.Strings.*;
import static org.openbel.framework.common.enums.AminoAcid.getAminoAcid;
import static org.openbel.framework.common.enums.CovalentModification.getCovalentModification;
import static org.openbel.framework.common.enums.ValueEncoding.getValueEncoding;
import static org.openbel.framework.common.lang.Signature.WILDCARD_ENCODING;
import static org.openbel.framework.common.lang.Signature.encode;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.enums.FunctionEnum;
import org.openbel.framework.common.enums.RelationshipType;
import org.openbel.framework.common.enums.SemanticStatus;
import org.openbel.framework.common.enums.ValueEncoding;
import org.openbel.framework.common.lang.Function;
import org.openbel.framework.common.lang.Signature;
import org.openbel.framework.common.model.BELObject;
import org.openbel.framework.common.model.Document;
import org.openbel.framework.common.model.Parameter;
import org.openbel.framework.common.model.Statement;
import org.openbel.framework.common.model.StatementGroup;
import org.openbel.framework.common.model.Term;
import org.openbel.framework.common.model.Statement.Object;
import org.openbel.framework.core.indexer.IndexingFailure;
import org.openbel.framework.core.namespace.NamespaceService;
import org.openbel.framework.core.namespace.NamespaceSyntaxWarning;

/**
* BEL semantic service implementation.
*/
public final class SemanticServiceImpl implements SemanticService {
    private final NamespaceService nsService;

    /**
     * Creates a semantic service implementation.
     *
     * @param nsService {@link NamespaceService}, the namespace service
     */
    public SemanticServiceImpl(final NamespaceService nsService) {
        this.nsService = nsService;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void checkParameterizedTerm(final Term term) throws SemanticWarning {
        final FunctionEnum funcEnum = term.getFunctionEnum();

        // Construct the signature
        final StringBuilder bldr = new StringBuilder();
        bldr.append(funcEnum.getDisplayValue());
        bldr.append("(");

        List<BELObject> functionArguments = term.getFunctionArguments();
        if (hasItems(functionArguments)) {
            for (int i = 0; i < functionArguments.size(); i++) {
                final BELObject bo = functionArguments.get(i);

                String arg = null;
                if (bo instanceof Parameter) {
                    arg = processParameter((Parameter) bo);
                } else if (bo instanceof Term) {
                    arg = processTerm((Term) bo);
                    if (arg == null) continue;
                } else {
                    String type = bo.getClass().getName();
                    final String err = "unknown function argument " + type;
                    throw new UnsupportedOperationException(err);
                }
                if (i != 0) bldr.append(",");
                bldr.append(arg);
            }
        }
        bldr.append(")");
        bldr.append(funcEnum.getReturnType().getDisplayValue());

        Signature sig = null;
        try {
            sig = new Signature(bldr.toString());
        } catch (InvalidArgument e) {
            final String lf = term.toBELLongForm();
            final String err = e.getMessage();
            throw new SemanticWarning(lf, err);
        }

        final Function function = funcEnum.getFunction();

        if (!function.validSignature(sig)) {
            final Map<Signature, SemanticStatus> map = function.getStatus(sig);
            final String lf = term.toBELLongForm();
            final String err = format(SEMANTIC_TERM_FAILURE, lf);
            throw new SemanticWarning(null, err, sig, map);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void checkTerm(final Term term) throws SemanticWarning {
        final FunctionEnum funcEnum = term.getFunctionEnum();

        // Construct the signature
        final StringBuilder bldr = new StringBuilder();
        bldr.append(funcEnum.getDisplayValue());
        bldr.append("(");

        List<BELObject> functionArguments = term.getFunctionArguments();
        if (hasItems(functionArguments)) {
            for (int i = 0; i < functionArguments.size(); i++) {
                final BELObject bo = functionArguments.get(i);

                String arg = null;
                if (bo instanceof Term) {
                    arg = processTerm((Term) bo);
                    if (arg == null) continue;
                } else {
                    String type = bo.getClass().getName();
                    final String err = "unhandled function argument " + type;
                    throw new UnsupportedOperationException(err);
                }
                if (i != 0) bldr.append(",");
                bldr.append(arg);
            }
        }
        bldr.append(")");
        bldr.append(funcEnum.getReturnType().getDisplayValue());

        Signature sig = null;
        try {
            sig = new Signature(bldr.toString());
        } catch (InvalidArgument e) {
            final String lf = term.toBELLongForm();
            final String err = e.getMessage();
            throw new SemanticWarning(lf, err);
        }

        final Function function = funcEnum.getFunction();

        if (!function.validSignature(sig)) {
            final Map<Signature, SemanticStatus> map = function.getStatus(sig);
            final String lf = term.toBELLongForm();
            final String err = format(SEMANTIC_TERM_FAILURE, lf);
            throw new SemanticWarning(null, err, sig, map);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void checkRelationship(final Statement statement)
            throws SemanticWarning {
        RelationshipType r = statement.getRelationshipType();
        Object o = statement.getObject();

        if (o != null) {

            // Relationship must be present.
            if (r == null) {
                final String err = SEMANTIC_STATEMENT_REQUIRES_RELATIONSHIP;
                final String name = statement.toBELShortForm();
                throw new SemanticWarning(name, err, null);
            }

        } else {

            // Relationship must be absent.
            if (r != null) {
                final String err = SEMANTIC_STATEMENT_PROVIDES_RELATIONSHIP;
                final String name = statement.toBELShortForm();
                throw new SemanticWarning(name, err, null);
            }

        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void checkListUsage(final Statement statement,
            final Document document)
            throws SemanticWarning {
        Object object = statement.getObject();

        if (object != null && !statement.hasNestedStatement() &&
                object.getTerm().getFunctionEnum() == FunctionEnum.LIST &&
                !statement.getRelationshipType().isListable()) {

            if (document != null) {
                pruneStatement(statement, document);
            }

            final String err = SEMANTIC_LIST_IMPROPER_CONTEXT;
            final String name = statement.toBELShortForm();
            throw new SemanticWarning(name, err, null);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void checkNested(final Statement statement) throws SemanticWarning {
        // Ignore non-nested statements
        if (!statement.hasNestedStatement()) {
            return;
        }

        final RelationshipType relationship = statement.getRelationshipType();
        // No relationship? Ignore it, this is a different semantic check
        if (relationship == null) {
            return;
        }

        // Nested statement is causal, gold star for you
        if (relationship.isCausal()) {
            return;
        }

        // Try to provide context for where the warning is
        final StringBuilder bldr = new StringBuilder();
        bldr.append("Nested statement with non-causal relationship ");
        bldr.append(relationship);

        final String err = SEMANTIC_NESTED_REQUIRE_CAUSAL;
        final String name = bldr.toString();
        throw new SemanticWarning(name, err);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void checkMultiNested(final Statement stmt, final Document doc)
            throws SemanticWarning {
        // is the statement nested?
        if (!stmt.hasNestedStatement()) {
            // not nested
            return;
        }

        // does it contain more than one nested statement?
        Statement objstmt = stmt.getObject().getStatement();
        if (objstmt.getObject().getStatement() == null) {
            // object term in nested statement
            return;
        }

        // Multi-nested statement, prune stmt then throw semantic warning
        pruneStatement(stmt, doc);

        // throw semantic warning
        final StringBuilder bldr = new StringBuilder();
        bldr.append("statement nested more than once, " +
                "pruning statement.");

        final String err = SEMANTIC_MULTI_NESTED;
        final String name = bldr.toString();
        throw new SemanticWarning(name, err);
    }

    /**
     * Prunes the provided {@link Statement statement} from the {@link Document document}.
     */
    private void pruneStatement(final Statement stmt, final Document doc) {
        final List<StatementGroup> stmtgroups = doc.getAllStatementGroups();
        for (final StatementGroup stmtgroup : stmtgroups) {
            final Iterator<Statement> sgi = stmtgroup.getStatements()
                    .iterator();
            while (sgi.hasNext()) {
                final Statement sgs = sgi.next();
                if (stmt.equals(sgs)) {
                    // prune
                    sgi.remove();
                    return;
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<SemanticWarning> checkAbundanceSubsets(final Term term) {
        final FunctionEnum fe = term.getFunctionEnum();
        if (fe != PROTEIN_ABUNDANCE && fe != GENE_ABUNDANCE
                && fe != RNA_ABUNDANCE) {
            return emptyList();
        }

        List<Term> nestedTerms = term.getTerms();
        if (noItems(nestedTerms)) {
            return emptyList();
        }

        List<SemanticWarning> ret = new ArrayList<SemanticWarning>();
        switch (fe) {
        case GENE_ABUNDANCE:
        case RNA_ABUNDANCE:
            for (final Term nestedTerm : nestedTerms) {
                if (nestedTerm.getFunctionEnum() == FUSION) {
                    ret.addAll(checkPFusion(nestedTerm));
                }
            }
            break;
        case PROTEIN_ABUNDANCE:
            for (final Term nestedTerm : nestedTerms) {
                if (!nestedTerm.getFunctionEnum().isProteinDecorator()) {
                    continue;
                }
                ret.addAll(checkAbundanceSubset(nestedTerm));
            }
            break;
        default:
            break;
        }
        return ret;
    }

    private List<SemanticWarning> checkAbundanceSubset(final Term term) {
        final FunctionEnum fe = term.getFunctionEnum();
        if (fe == PROTEIN_MODIFICATION) {
            return checkPModification(term);
        } else if (fe == SUBSTITUTION) {
            return checkPSubstitution(term);
        } else if (fe == TRUNCATION) {
            return checkPTruncation(term);
        } else if (fe == FUSION) {
            return checkPFusion(term);
        }
        return emptyList();
    }

    private List<SemanticWarning> checkPModification(final Term term) {
        List<SemanticWarning> ret = new ArrayList<SemanticWarning>();

        int numargs = term.getNumberOfArguments();

        // Indicates signatures do not match, return
        // (no semantic warning should be generated here for this)
        if (!PROTEIN_MODIFICATION.isValidArgumentCount(numargs)) {
            return emptyList();
        }

        List<Parameter> parameters = term.getParameters();

        // Check mod type
        Parameter parameter = parameters.get(0);
        String pval = parameter.getValue();

        if (!validPType(pval)) {
            String msg;
            if (pval == null) {
                msg = SEMANTIC_NOT_CM;
            } else {
                msg = format(SEMANTIC_PTYPE_NOT_CM, pval);
            }
            ret.add(new SemanticWarning(term.toBELLongForm(), msg));
        }

        if (numargs == 1) {
            return ret;
        }

        // Check mod code
        parameter = parameters.get(1);
        pval = parameter.getValue();

        if (!validAcid(pval)) {
            String msg;
            if (pval == null) {
                msg = SEMANTIC_NOT_AA;
            } else {
                msg = format(SEMANTIC_CODE_NOT_AA, pval);
            }
            ret.add(new SemanticWarning(term.toBELLongForm(), msg));
        }

        if (numargs == 2) {
            return ret;
        }

        // Check mod position
        parameter = parameters.get(2);
        pval = parameter.getValue();

        if (!validPosition(pval)) {
            String msg;
            if (pval == null) {
                msg = SEMANTIC_NOT_INT;
            } else {
                msg = format(SEMANTIC_POS_NOT_INT, pval);
            }
            ret.add(new SemanticWarning(term.toBELLongForm(), msg));
        }
        return ret;
    }

    private List<SemanticWarning> checkPSubstitution(final Term term) {
        List<SemanticWarning> ret = new ArrayList<SemanticWarning>();

        int numargs = term.getNumberOfArguments();

        // Indicates signatures do not match, return
        // (no semantic warning should be generated here for this)
        if (!SUBSTITUTION.isValidArgumentCount(numargs)) {
            return emptyList();
        }

        List<Parameter> parameters = term.getParameters();
        // Sanity check three parameters
        if (numargs != 3) {
            return ret;
        }

        // Check amino acid variant
        Parameter parameter = parameters.get(0);
        String pval = parameter.getValue();

        if (!validAcid(pval)) {
            String msg;
            if (pval == null) {
                msg = SEMANTIC_NOT_AA;
            } else {
                msg = format(SEMANTIC_CODE_NOT_AA, pval);
            }
            ret.add(new SemanticWarning(term.toBELLongForm(), msg));
        }

        // Check mod position
        parameter = parameters.get(1);
        pval = parameter.getValue();

        if (!validPosition(pval)) {
            String msg;
            if (pval == null) {
                msg = SEMANTIC_NOT_INT;
            } else {
                msg = format(SEMANTIC_POS_NOT_INT, pval);
            }
            ret.add(new SemanticWarning(term.toBELLongForm(), msg));
        }

        // Check amino acid variant
        parameter = parameters.get(2);
        pval = parameter.getValue();

        if (!validAcid(pval)) {
            String msg;
            if (pval == null) {
                msg = SEMANTIC_NOT_AA;
            } else {
                msg = format(SEMANTIC_CODE_NOT_AA, pval);
            }
            ret.add(new SemanticWarning(term.toBELLongForm(), msg));
        }

        return ret;
    }

    private List<SemanticWarning> checkPTruncation(final Term term) {
        List<SemanticWarning> ret = new ArrayList<SemanticWarning>();

        int numargs = term.getNumberOfArguments();

        // Indicates signatures do not match, return
        // (no semantic warning should be generated here for this)
        if (!TRUNCATION.isValidArgumentCount(numargs)) {
            return emptyList();
        }

        List<Parameter> parameters = term.getParameters();
        // Sanity check one parameter
        if (numargs != 1) {
            return ret;
        }

        // Check mod position
        Parameter parameter = parameters.get(0);
        String pval = parameter.getValue();

        if (!validPosition(pval)) {
            String msg;
            if (pval == null) {
                msg = SEMANTIC_NOT_INT;
            } else {
                msg = format(SEMANTIC_POS_NOT_INT, pval);
            }
            ret.add(new SemanticWarning(term.toBELLongForm(), msg));
        }

        return ret;
    }

    private List<SemanticWarning> checkPFusion(final Term term) {
        List<SemanticWarning> ret = new ArrayList<SemanticWarning>();

        int numargs = term.getNumberOfArguments();

        // Indicates signatures do not match, return
        // (no semantic warning should be generated here for this)
        if (!FUSION.isValidArgumentCount(numargs)) {
            return emptyList();
        }

        List<Parameter> parameters = term.getParameters();
        // Sanity check three parameters - we only semantically validate last
        // two are valid positions
        if (parameters.size() != 3) {
            return ret;
        }

        for (int i = 1; i <= 2; i++) {
            Parameter parameter = parameters.get(i);
            String pval = parameter.getValue();

            if (!validPosition(pval)) {
                String msg;
                if (pval == null) {
                    msg = SEMANTIC_NOT_INT;
                } else {
                    msg = format(SEMANTIC_POS_NOT_INT, pval);
                }
                ret.add(new SemanticWarning(term.toBELLongForm(), msg));
            }
        }

        return ret;
    }

    /*
     * Check protein abundance 'type' is valid.
     */
    private boolean validPType(String pval) {
        if (getCovalentModification(pval) == null) {
            return false;
        }
        return true;
    }

    /*
     * Check amino acid is valid.
     */
    private boolean validAcid(String pval) {
        if (getAminoAcid(pval) == null) {
            return false;
        }
        return true;
    }

    /*
     * Check position is valid.
     */
    private boolean validPosition(String pval) {
        if (pval == null) {
            return false;
        }
        try {
            int ival = parseInt(pval);
            if (ival < 1) {
                return false;
            }
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

    /*
     * Returns the parameter formatted as a string, suitable for semantic
     * checking.
     */
    private String processParameter(final Parameter p) {
        try {
            String encoding = nsService.lookup(p);
            if (encoding == null) {
                return encode(WILDCARD_ENCODING);
            }

            final ValueEncoding ve = getValueEncoding(encoding);
            if (ve == null) {
                return encode(encoding);
            }
            return encode(ve.getDisplayValue());
        } catch (NamespaceSyntaxWarning e) {
            return encode(WILDCARD_ENCODING);
        } catch (IndexingFailure idxf) {
            return encode(WILDCARD_ENCODING);
        }
    }

    /*
     * Returns the term formatted as a string, suitable for semantic checking.
     */
    private String processTerm(final Term t) {
        return encode(t.getFunctionEnum().getReturnType());
    }
}
TOP

Related Classes of org.openbel.framework.core.compiler.SemanticServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.