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

org.obolibrary.oboformat.model.Frame Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
package org.obolibrary.oboformat.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.obolibrary.obo2owl.OboInOwlCardinalityTools;
import org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag;

/** The Class Frame. */
public class Frame {

    /** The Enum FrameType. */
    public enum FrameType {
        /** HEADER. */
        HEADER,
        /** TERM. */
        TERM,
        /** TYPEDEF. */
        TYPEDEF,
        /** INSTANCE. */
        INSTANCE,
        /** ANNOTATION. */
        ANNOTATION
    }

    /** The clauses. */
    protected Collection clauses;
    /** The id. */
    protected String id;
    /** The type. */
    protected FrameType type;

    /** Instantiates a new frame. */
    public Frame() {
        init();
    }

    /**
     * Instantiates a new frame.
     * 
     * @param type the type
     */
    public Frame(FrameType type) {
        init();
        this.type = type;
    }

    /** Init clauses. */
    protected final void init() {
        clauses = new ArrayList<>();
    }

    /**
     * freezing a frame signals that a frame has become quiescent, and that data structures can be
     * adjusted to increase performance or reduce memory consumption. If a frozen frame is
     * subsequently modified it will be thawed as necessary.
     */
    public void freeze() {
        if (clauses.isEmpty()) {
            clauses = Collections.emptyList();
            return;
        }

        for (Clause clause : clauses) {
            clause.freeze();
        }

        if (clauses.size() == 1) {
            clauses = Collections.singletonList(clauses.iterator().next());
            return;
        }

        if (clauses instanceof ArrayList) {
            ArrayList arrayList = (ArrayList) clauses;
            arrayList.trimToSize();
        }

    }

    /**
     * @return the type
     */
    public FrameType getType() {
        return type;
    }

    /**
     * @param type the new type
     */
    public void setType(FrameType type) {
        this.type = type;
    }

    /**
     * @return the id
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the new id
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * @return the clauses
     */
    public Collection getClauses() {
        return clauses;
    }

    /**
     * @param tag the tag
     * @return the clauses for tag
     */
    @Nonnull
    public Collection getClauses(String tag) {
        Collection cls = new ArrayList<>();
        for (Clause cl : clauses) {
            if (cl.getTag().equals(tag)) {
                cls.add(cl);
            }
        }
        return cls;
    }

    /**
     * @param tag the tag
     * @return the clauses for tag
     */
    @Nonnull
    public Collection getClauses(@Nonnull OboFormatTag tag) {
        return getClauses(tag.getTag());
    }

    /**
     * @param tag the tag
     * @return null if no value set, otherwise first value
     */
    @Nullable
    public Clause getClause(String tag) {
        for (Clause cl : clauses) {
            if (cl.getTag().equals(tag)) {
                return cl;
            }
            // TODO - throw exception if more than one clause of this type?
        }
        return null;
    }

    /**
     * @param tag the tag
     * @return the clause for tag
     */
    @Nullable
    public Clause getClause(@Nonnull OboFormatTag tag) {
        return getClause(tag.getTag());
    }

    /**
     * @param clauses the new clauses
     */
    public void setClauses(Collection clauses) {
        this.clauses = clauses;
    }

    /**
     * @param cl the clause
     */
    public void addClause(Clause cl) {
        if (!(clauses instanceof ArrayList)) {
            Collection tmp = new ArrayList<>(clauses.size() + 1);
            tmp.addAll(clauses);
            clauses = tmp;
        }
        clauses.add(cl);
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("Frame(");
        sb.append(id);
        sb.append(' ');
        for (Clause cl : clauses) {
            sb.append(cl);
        }
        sb.append(')');
        String string = sb.toString();
        assert string != null;
        return string;
    }

    /**
     * @param tag the tag
     * @return the tag value for tag
     */
    @Nullable
    public Object getTagValue(String tag) {
        Clause clause = getClause(tag);
        if (clause == null) {
            return null;
        }
        return clause.getValue();
    }

    /**
     * @param tag the tag
     * @return the tag value for tag
     */
    @Nullable
    public Object getTagValue(@Nonnull OboFormatTag tag) {
        return getTagValue(tag.getTag());
    }

    /**
     * @param  the generic type
     * @param tag the tag
     * @param cls the cls
     * @return the tag value for tag and class
     */
    @SuppressWarnings("null")
    @Nullable
    public  T getTagValue(String tag, @Nonnull Class cls) {
        if (getClause(tag) == null) {
            return null;
        }
        Object value = getClause(tag).getValue();
        if (value != null && value.getClass().isAssignableFrom(cls)) {
            return cls.cast(value);
        }
        return null;
    }

    /**
     * @param  the generic type
     * @param tag the tag
     * @param cls the cls
     * @return the tag value for tag and class
     */
    @Nullable
    public  T getTagValue(@Nonnull OboFormatTag tag, @Nonnull Class cls) {
        return getTagValue(tag.getTag(), cls);
    }

    /**
     * @param tag the tag
     * @return the tag values for tag
     */
    @Nonnull
    public Collection getTagValues(@Nonnull OboFormatTag tag) {
        return getTagValues(tag.getTag());
    }

    /**
     * @param tag the tag
     * @return the tag values for tag
     */
    @Nonnull
    public Collection getTagValues(String tag) {
        Collection vals = new ArrayList<>();
        for (Clause c : getClauses(tag)) {
            vals.add(c.getValue());
        }
        return vals;
    }

    /**
     * @param  the generic type
     * @param tag the tag
     * @param cls the cls
     * @return the tag values for tag and class
     */
    @Nonnull
    public  Collection getTagValues(@Nonnull OboFormatTag tag, @Nonnull Class cls) {
        return getTagValues(tag.getTag(), cls);
    }

    /**
     * @param  the generic type
     * @param tag the tag
     * @param cls the cls
     * @return the tag values for tag and class
     */
    @Nonnull
    public  Collection getTagValues(String tag, @Nonnull Class cls) {
        Collection vals = new ArrayList<>();
        for (Clause c : getClauses(tag)) {
            vals.add(c.getValue(cls));
        }
        return vals;
    }

    /**
     * @param tag the tag
     * @return the tag xref list for tag
     */
    @SuppressWarnings("null")
    @Nonnull
    public Collection getTagXrefs(String tag) {
        Collection xrefs = new ArrayList<>();
        for (Object ob : getClause(tag).getValues()) {
            if (ob instanceof Xref) {
                xrefs.add((Xref) ob);
            }
        }
        return xrefs;
    }

    /**
     * @return the tags
     */
    @Nonnull
    public Set getTags() {
        Set tags = new HashSet<>();
        for (Clause cl : getClauses()) {
            tags.add(cl.getTag());
        }
        return tags;
    }

    /**
     * @param extFrame the external frame
     * @throws FrameMergeException the frame merge exception
     */
    public void merge(@Nonnull Frame extFrame) throws FrameMergeException {
        if (this == extFrame) {
            return;
        }
        if (!extFrame.getId().equals(getId())) {
            throw new FrameMergeException("ids do not match");
        }
        if (!extFrame.getType().equals(getType())) {
            throw new FrameMergeException("frame types do not match");
        }
        for (Clause c : extFrame.getClauses()) {
            addClause(c);
        }
        // note we do not perform a document structure check at this point
    }

    /**
     * Check this frame for violations, i.e. cardinality constraint violations.
     * 
     * @throws FrameStructureException the frame structure exception
     * @see OboInOwlCardinalityTools for equivalent checks in OWL
     */
    @SuppressWarnings("null")
    public void check() throws FrameStructureException {
        if (FrameType.HEADER.equals(type)) {
            checkMaxOneCardinality(OboFormatTag.TAG_ONTOLOGY, OboFormatTag.TAG_FORMAT_VERSION,
                OboFormatTag.TAG_DATE, OboFormatTag.TAG_DEFAULT_NAMESPACE,
                OboFormatTag.TAG_SAVED_BY, OboFormatTag.TAG_AUTO_GENERATED_BY);
        }
        if (FrameType.TYPEDEF.equals(type)) {
            checkMaxOneCardinality(OboFormatTag.TAG_DOMAIN, OboFormatTag.TAG_RANGE,
                OboFormatTag.TAG_IS_METADATA_TAG, OboFormatTag.TAG_IS_CLASS_LEVEL_TAG);
        }
        if (!FrameType.HEADER.equals(getType())) {
            if (getClauses(OboFormatTag.TAG_ID).size() != 1) {
                throw new FrameStructureException(this, "cardinality of id field must be 1");
            }
            if (getClause(OboFormatTag.TAG_ID).getValue() == null) {
                throw new FrameStructureException(this, "id field must not be null");
            }
            if (getId() == null) {
                throw new FrameStructureException(this, "id field must be set");
            }
        }
        Collection iClauses = getClauses(OboFormatTag.TAG_INTERSECTION_OF);
        if (iClauses.size() == 1) {
            throw new FrameStructureException(this, "single intersection_of tags are not allowed");
        }
        checkMaxOneCardinality(OboFormatTag.TAG_IS_ANONYMOUS, OboFormatTag.TAG_NAME,
            // OboFormatTag.TAG_NAMESPACE,
            OboFormatTag.TAG_DEF, OboFormatTag.TAG_COMMENT, OboFormatTag.TAG_IS_ANTI_SYMMETRIC,
            OboFormatTag.TAG_IS_CYCLIC, OboFormatTag.TAG_IS_REFLEXIVE,
            OboFormatTag.TAG_IS_SYMMETRIC, OboFormatTag.TAG_IS_TRANSITIVE,
            OboFormatTag.TAG_IS_FUNCTIONAL, OboFormatTag.TAG_IS_INVERSE_FUNCTIONAL,
            OboFormatTag.TAG_IS_OBSELETE, OboFormatTag.TAG_CREATED_BY,
            OboFormatTag.TAG_CREATION_DATE);
    }

    /**
     * Check max one cardinality.
     * 
     * @param tags the tags
     * @throws FrameStructureException frame structure exception
     */
    private void checkMaxOneCardinality(@Nonnull OboFormatTag... tags)
        throws FrameStructureException {
        for (OboFormatTag tag : tags) {
            if (getClauses(tag).size() > 1) {
                throw new FrameStructureException(this,
                    "multiple " + tag.getTag() + " tags not allowed.");
            }
        }
    }
}