Package org.openbel.framework.ws.dialect

Source Code of org.openbel.framework.ws.dialect.CustomDialect

/**
* 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.ws.dialect;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.openbel.framework.api.Dialect;
import org.openbel.framework.api.Equivalencer;
import org.openbel.framework.api.EquivalencerException;
import org.openbel.framework.api.Kam;
import org.openbel.framework.api.Kam.KamNode;
import org.openbel.framework.api.internal.KAMStoreDaoImpl.BelTerm;
import org.openbel.framework.api.KAMStore;
import org.openbel.framework.api.KAMStoreException;
import org.openbel.framework.common.bel.parser.BELParser;
import org.openbel.framework.common.model.BELObject;
import org.openbel.framework.common.model.Namespace;
import org.openbel.framework.common.model.Parameter;
import org.openbel.framework.common.model.Term;
import org.openbel.framework.common.protonetwork.model.SkinnyUUID;

/**
* {@link Dialect} implementation that allows control over the {@link Namespace}
* s used in conversion. An ordered list of {@link Namespace}s can be assigned
* to each of the {@link NamespaceDomain}s; labeling for each {@link Parameter}
* in a supporting term will use these priorities to determine a String value.
* If a value cannot be found for a {@link Parameter} in the desired namespace,
* the next namespace in the list will be attempted. When all preferences are
* exhausted the label will default to the default label of the term.<br>
* This implementation also allows definition of the {@link BELSyntax} to be used
* and whether or not to strip the namespace prefixes from the returned labels.<br>
* <br>
* Construction of this class is limited to
* {@link DialectFactory#createCustomDialect(org.openbel.framework.core.kamstore.data.jdbc.KAMCatalogDao.KamInfo, List, List, List, BELSyntax, boolean)}
* <br>
* This implementation caches labels for nodes and is thus suitable only for a
* single {@link Kam}. Usage across {@link Kam}s is not guarded against but will
* cause unpredictable results.<br>
* This implementation is thread-safe.
*
* @author Steve Ungerer
*/
public class CustomDialect implements Dialect {
    private final KAMStore kAMStore;
    private final Equivalencer equivalencer = new Equivalencer();

    private boolean removeNamespacePrefix = false;
    private boolean displayLongForm = false;
    private List<Namespace> geneNamespaces = new ArrayList<Namespace>(0);
    private List<Namespace> bpNamespaces = new ArrayList<Namespace>(0);
    private List<Namespace> chemNamespaces = new ArrayList<Namespace>(0);

    private Map<String, String> labelCache =
            new ConcurrentHashMap<String, String>();

    private Map<String, Namespace> kamNamespaces; // prefix : namespace
    private Map<String, NamespaceDomain> nsDomains; // prefix : domain

    private boolean initialized;
    private int hashCode;

    /**
     * Construct a new instance of a {@link CustomDialect}.
     * Post-construction the appropriate mutation must occur with
     * {@link #initialize()} being invoked prior to usage.
     *
     * @param kAMStore
     * @throws KAMStoreException
     */
    CustomDialect(KAMStore kAMStore) throws KAMStoreException {
        this.kAMStore = kAMStore;
    }

    /**
     * Set the {@link Namespace} priority for {@link NamespaceDomain#Gene}
     * namespaces.
     *
     * @param geneNamespaces
     */
    void setGeneNamespaces(List<Namespace> geneNamespaces) {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; mutation not allowed");
        }
        this.geneNamespaces = geneNamespaces;
    }

    /**
     * Set the {@link Namespace} priority for
     * {@link NamespaceDomain#BiologicalProcess} namespaces.
     *
     * @param bpNamespaces
     */
    void setBpNamespaces(List<Namespace> bpNamespaces) {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; mutation not allowed");
        }
        this.bpNamespaces = bpNamespaces;
    }

    /**
     * Set the {@link Namespace} priority for {@link NamespaceDomain#Chemical}
     * namespaces.
     *
     * @param chemNamespaces
     */
    void setChemNamespaces(List<Namespace> chemNamespaces) {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; mutation not allowed");
        }
        this.chemNamespaces = chemNamespaces;
    }

    /**
     * Set the {@link Namespace} {@link Map} used in finding resource locations
     * for a namespace prefix.<br>
     * Map key: the namespace prefix used in the {@link Kam}<br>
     * Map value: resource location of the namespace.
     *
     * @param kamNamespaces
     */
    void setKamNamespaces(Map<String, Namespace> kamNamespaces) {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; mutation not allowed");
        }
        this.kamNamespaces = kamNamespaces;
    }

    /**
     * Set the {@link NamespaceDomain} {@link Map} used to determine the domain
     * of a particular {@link Namespace}.<br>
     * Map key: the namespace prefix used in the {@link Kam}<br>
     * Map value: {@link NamespaceDomain} of the namespace.
     *
     * @param nsDomains
     */
    void setNsDomains(Map<String, NamespaceDomain> nsDomains) {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; mutation not allowed");
        }
        this.nsDomains = nsDomains;
    }

    /**
     * Set the dialect to display labels in BEL long form
     *
     * @param displayLongForm
     */
    void setDisplayLongForm(boolean displayLongForm) {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; mutation not allowed");
        }
        this.displayLongForm = displayLongForm;
    }

    /**
     * Set the dialect to strip namespace prefixes from labels.<br>
     * Note that prefixes will remain in place if none of the user-configured
     * namespaces can be used to display the label and the default label is
     * used.
     *
     * @param removeNamespacePrefix
     */
    void setRemoveNamespacePrefix(boolean removeNamespacePrefix) {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; mutation not allowed");
        }
        this.removeNamespacePrefix = removeNamespacePrefix;
    }

    /**
     * Initialize the dialect. Must be invoked post-mutation.
     */
    void initialize() {
        if (initialized) {
            throw new IllegalStateException(
                    "Dialect already initialized; re-initialization not allowed");
        }
        this.hashCode = new HashCodeBuilder().append(geneNamespaces)
                .append(bpNamespaces).append(chemNamespaces)
                .append(displayLongForm).append(removeNamespacePrefix)
                .toHashCode();
        this.initialized = true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getLabel(KamNode kamNode) {
        if (!initialized) {
            throw new IllegalStateException("Dialect not initialized");
        }
        String label = labelCache.get(kamNode.getLabel());
        if (label == null) {
            try {
                label = labelNode(kamNode);
            } catch (Exception e) {
                // TODO exception
            }
            labelCache.put(kamNode.getLabel(), label);
        }
        return label;
    }

    /**
     * Internal method to obtain a label for a node. Grabs the first
     * {@link BelTerm} that supports the node, parses it, and converts it to the
     * preferred namespaces to obtain a label.
     *
     * @param node
     * @return
     * @throws KAMStoreException
     */
    protected String labelNode(KamNode node) throws KAMStoreException {
        List<BelTerm> terms = kAMStore.getSupportingTerms(node);
        if (!terms.isEmpty()) {
            BelTerm bt = terms.get(0);
            Term parsed;
            try {
                parsed = BELParser.parseTerm(bt.getLabel());
            } catch (Exception e) {
                return null;
            }
            Term converted = convert(parsed);

            return displayLongForm ? converted.toBELLongForm() : converted
                    .toBELShortForm();
        }
        return null;
    }

    /**
     * Convert a {@link Term} to preferred namespaces
     *
     * @param orig
     * @return
     */
    protected Term convert(Term orig) {
        Term t = new Term(orig.getFunctionEnum());
        for (BELObject o : orig.getFunctionArguments()) {
            t.addFunctionArgument(convert(o));
        }
        return t;
    }

    /**
     * Convert a {@link BELObject}. Currently handles only {@link Term}s and
     * {@link Parameter}s as these are the only objects supported by Term.
     *
     * @param o
     * @return
     * @see Term#addFunctionArgument(BELObject)
     */
    protected BELObject convert(BELObject o) {
        Class<?> clazz = o.getClass();
        if (Term.class.isAssignableFrom(clazz)) {
            return convert((Term) o);
        } else if (Parameter.class.isAssignableFrom(clazz)) {
            return convert((Parameter) o);
        } else {
            throw new UnsupportedOperationException("BEL object type "
                    + o.getClass() + " is not supported");
        }
    }

    /**
     * Convert a parameter to the preferred namespaces.
     *
     * @param orig
     * @return the converted {@link Parameter} or the original parameter if no
     *         conversion was possible
     */
    protected Parameter convert(Parameter orig) {
        if (orig.getNamespace() == null) {
            return orig;
        }
        // determine domain of parameter namespace
        NamespaceDomain domain = nsDomains.get(orig.getNamespace().getPrefix());
        if (domain == null) {
            return orig;
        }

        // iterate appropriate collection to find equiv
        List<Namespace> coll;
        switch (domain) {
        case BiologicalProcess:
            coll = bpNamespaces;
            break;
        case Chemical:
            coll = chemNamespaces;
            break;
        case Gene:
            coll = geneNamespaces;
            break;
        default:
            throw new UnsupportedOperationException("Unknown domain: " + domain);
        }

        try {
            SkinnyUUID uuid = equivalencer.getUUID(
                    getNamespace(orig.getNamespace()), orig.getValue());
            if (uuid == null) {
                // no equivalents anywhere
                return orig;
            }
            // find first equivalent in list of desired
            for (Namespace ns : coll) {
                String v = equivalencer.equivalence(uuid, ns);
                if (v != null) {
                    return removeNamespacePrefix ? new Parameter(null, v)
                            : new Parameter(ns, v);
                }
            }
        } catch (EquivalencerException e) {
            // TODO exception
            return null;
        }

        // if no equiv, use param as-is
        return orig;
    }

    /**
     * Get a fully populated namespace object with valid resource location.
     * (namespaces parsed by BELParser will not have a valid resource location)
     *
     * @param ns
     * @return
     */
    protected Namespace getNamespace(Namespace ns) {
        return kamNamespaces.get(ns.getPrefix());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return hashCode;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof CustomDialect)) {
            return false;
        }
        CustomDialect rhs = (CustomDialect) obj;
        return new EqualsBuilder().append(geneNamespaces, rhs.geneNamespaces)
                .append(bpNamespaces, rhs.bpNamespaces)
                .append(chemNamespaces, rhs.chemNamespaces)
                .append(displayLongForm, rhs.displayLongForm)
                .append(removeNamespacePrefix, rhs.removeNamespacePrefix)
                .isEquals();
    }

}
TOP

Related Classes of org.openbel.framework.ws.dialect.CustomDialect

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.