ca.mcgill.cs.swevo.jayfx.model.Relation.java Source code

Java tutorial

Introduction

Here is the source code for ca.mcgill.cs.swevo.jayfx.model.Relation.java

Source

/* JayFX - A Fact Extractor Plug-in for Eclipse
 * Copyright (C) 2006  McGill University (http://www.cs.mcgill.ca/~swevo/jayfx)
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * $Revision: 1.6 $
 */

package ca.mcgill.cs.swevo.jayfx.model;

import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Vector;

import org.jdom2.Attribute;
import org.jdom2.Element;

/**
 * Encapsulate various services related to relations.
 */
public enum Relation {

    EXPLICITLY_CALLS(Type.ID_EXPLICITLY_CALLS, true), ANNOTATES(Type.ID_ANNOTATES, true), CONTAINS(Type.ID_CONTAINS,
            true), CHECKS(Type.ID_CHECKS, true), CREATES(Type.ID_CREATES, true), DECLARES_METHOD(
                    Type.ID_DECLARES_METHOD,
                    true), DECLARES_FIELD(Type.ID_DECLARES_FIELD, true), DECLARES_TYPE(Type.ID_DECLARES_TYPE,
                            true), EXTENDS_CLASS(Type.ID_EXTENDS_CLASS, true), EXTENDS_INTERFACES(
                                    Type.ID_EXTENDS_INTERFACES,
                                    true), HAS_PARAMETER_TYPES(Type.ID_HAS_PARAMETER_TYPES, true), HAS_RETURN_TYPE(
                                            Type.ID_HAS_RETURN_TYPE,
                                            true), IMPLEMENTS_INTERFACE(Type.ID_IMPLEMENTS_INTERFACE,
                                                    true), OF_TYPE(Type.ID_OF_TYPE, true), TRANS_EXTENDS(
                                                            Type.ID_TRANS_EXTENDS,
                                                            true), TRANS_IMPLEMENTS(Type.ID_TRANS_IMPLEMENTS, true),

    ACCESSES(Type.ID_ACCESSES, true), SETS(Type.ID_SETS, true), GETS(Type.ID_GETS, true), ADVISES(Type.ID_ADVISES,
            true), CALLS(Type.ID_CALLS, true), IMPLEMENTS_METHOD(Type.ID_IMPLEMENTS_METHOD,
                    true), INHERITS(Type.ID_INHERITS, true), OVERRIDES(Type.ID_OVERRIDES,
                            true), OVERLOADS(Type.ID_OVERLOADS, true), USES(Type.ID_USES, true),

    IDENTITY(Type.ID_IDENTITY, true), STATIC_CALLS(Type.ID_STATIC_CALLS, true), REFERENCES(Type.ID_REFERENCES,
            true),

    T_EXPLICITLY_CALLS(Type.ID_EXPLICITLY_CALLS, false), T_CHECKS(Type.ID_CHECKS, false), T_CREATES(Type.ID_CREATES,
            false), T_DECLARES(Type.ID_DECLARES, false), T_EXTENDS_CLASS(Type.ID_EXTENDS_CLASS,
                    false), T_EXTENDS_INTERFACES(Type.ID_EXTENDS_INTERFACES, false), T_HAS_PARAMETER_TYPES(
                            Type.ID_HAS_PARAMETER_TYPES, false), T_HAS_RETURN_TYPE(Type.ID_HAS_RETURN_TYPE,
                                    false), T_IMPLEMENTS_INTERFACE(Type.ID_IMPLEMENTS_INTERFACE, false), T_OF_TYPE(
                                            Type.ID_OF_TYPE, false), T_TRANS_EXTENDS(Type.ID_TRANS_EXTENDS,
                                                    false), T_TRANS_IMPLEMENTS(Type.ID_TRANS_IMPLEMENTS, false),

    T_ACCESSES(Type.ID_ACCESSES, false), T_CALLS(Type.ID_CALLS, false), T_IMPLEMENTS_METHOD(
            Type.ID_IMPLEMENTS_METHOD, false), T_INHERITS(Type.ID_INHERITS,
                    false), T_OVERRIDES(Type.ID_OVERRIDES, false), T_USES(Type.ID_USES, false),

    T_IDENTITY(Type.ID_IDENTITY, false), T_STATIC_CALLS(Type.ID_STATIC_CALLS,
            false), T_REFERENCES(Type.ID_REFERENCES, false);

    /**
     * 
     */
    private static final String TYPE = "type";

    /**
     * Type enum encapsulates the following information of a relation: i. code
     * name ii. direct name iii. transpose name of the relation iv. detailed
     * description
     * 
     * @author iyuen
     * @see ca.mcgill.cs.swevo.jayfx.model.Relation
     */
    public enum Type {
        /*
         * Primitive: 0-9
         */
        ID_EXPLICITLY_CALLS("explicitly_calls", "e-calling", "e-called by",
                "a method calls a method explicitly"), ID_ANNOTATES("annotates", "annotating", "annotated by",
                        "an annotation annotates something"), ID_CONTAINS("contains", "contains", "contains",
                                "a package contains a type"), ID_CHECKS("checks", "checking", "checked by",
                                        "a method checks the run_time type of an object for a specific type"), ID_CREATES(
                                                "creates", "creating", "created by",
                                                "a method creates an object of a type"), ID_DECLARES("declares",
                                                        "declaring", "declared by",
                                                        "a class declares a member"), ID_DECLARES_FIELD(
                                                                "declares_field", "declaring field",
                                                                "field declared by",
                                                                "a class declares a field"), ID_DECLARES_METHOD(
                                                                        "declares_method", "declaring method",
                                                                        "method declared by",
                                                                        "a class declares a method"), ID_DECLARES_TYPE(
                                                                                "declares_type", "declaring type",
                                                                                "type declared by",
                                                                                "a class declares a type"), ID_EXTENDS_CLASS(
                                                                                        "extends_class",
                                                                                        "extending", "extended by",
                                                                                        "a class directly extends a class"), ID_EXTENDS_INTERFACES(
                                                                                                "extends_interface",
                                                                                                "i-extending",
                                                                                                "i-extended by",
                                                                                                "an interface directly extends an interface"), ID_HAS_PARAMETER_TYPES(
                                                                                                        "as-parameter-types",
                                                                                                        "having p-types",
                                                                                                        "p-type of",
                                                                                                        "a method has parameters of types"), ID_HAS_RETURN_TYPE(
                                                                                                                "has-return-type",
                                                                                                                "having r-type",
                                                                                                                "r-type of",
                                                                                                                "a method has return type"), ID_IMPLEMENTS_INTERFACE(
                                                                                                                        "implements_interface",
                                                                                                                        "implementing",
                                                                                                                        "implemented by",
                                                                                                                        "a class directly implements an interface"), ID_OF_TYPE(
                                                                                                                                "of-type",
                                                                                                                                "being of type",
                                                                                                                                "type of",
                                                                                                                                "a field is of type"),

        ID_TRANS_EXTENDS("transitively_extends", "transitively extending", "transitively extended by",
                "a class transitively extends a class"), ID_TRANS_IMPLEMENTS("transitively_implements",
                        "transitively implementing", "transitively implemented by",
                        "a class transitively implements an interface"),

        ID_ACCESSES("accesses_field", "accessing", "accessed by",
                "a method accesses a field, either to read or write"), ID_SETS("sets_field", "setting", "set by",
                        "a method sets a field"), ID_GETS("gets_field", "getting", "got by",
                                "a method gets a field"),

        ID_ADVISES("advises", "advising", "advised by", "an advise advises something"), ID_CALLS("calls", "calling",
                "called by", "a method calls a method"), ID_IMPLEMENTS_METHOD("implements_method", "m-implementing",
                        "m-implemented by", "a method implements an interface method"), ID_INHERITS("inherits",
                                "inheriting", "inherited by", "a class inherits fields and methods"), ID_OVERRIDES(
                                        "overrides", "overriding", "overridden by",
                                        "a method overrides a method"), ID_OVERLOADS("overloads", "overloading",
                                                "overloaded by", "a method overloads a method"), ID_USES("uses",
                                                        "using", "used by", "a method uses a program element"),

        ID_IDENTITY("identity", "is", "is", "an element is itself"), ID_STATIC_CALLS("statically_calls",
                "statically calls", "statically called by",
                "a method statically calls another method"), ID_REFERENCES("references", "references",
                        "referenced by", "a class/method references a class/method/field"),

        ID_ERROR("error", "error", "error", "error");

        private final String aCode;
        private final String aDirectName;
        private final String aTransposeName;
        private final String aDescription;

        Type(final String pCode, final String pDirectName, final String pTransposeName, final String pDescription) {
            this.aCode = pCode;
            this.aDirectName = pDirectName;
            this.aTransposeName = pTransposeName;
            this.aDescription = pDescription;
        }

        public String getCode() {
            return this.aCode;
        }

        public String getDescription() {
            return this.aDescription;
        }

        public String getDirectName() {
            return this.aDirectName;
        }

        public String getTransposeName() {
            return this.aTransposeName;
        }
    }

    private static EnumSet<Relation> aRelationSet;
    private static EnumSet<Relation> tRelationSet; // Transpose
    private static EnumMap<Type, Relation> aRelationMap;
    private static EnumMap<Type, Relation> tRelationMap; // Transpose
    private static final String TRANSPOSE_CODE = "*";

    static {
        Relation.aRelationSet = EnumSet.range(Relation.EXPLICITLY_CALLS, Relation.REFERENCES);
        Relation.tRelationSet = EnumSet.complementOf(Relation.aRelationSet);
        // cRelationSet = EnumSet.range(Relation.T_EXPLICITLY_CALLS,
        // Relation.T_REFERENCES);

        Relation.aRelationMap = new EnumMap<Type, Relation>(Type.class);
        Relation.tRelationMap = new EnumMap<Type, Relation>(Type.class);

        for (final Relation lRelation : Relation.aRelationSet)
            Relation.aRelationMap.put(lRelation.getType(), lRelation);
        for (final Relation lTransRelation : Relation.tRelationSet)
            Relation.tRelationMap.put(lTransRelation.getType(), lTransRelation);
    }

    /**
     * @return All relations.
     */
    public static Relation[] getAllRelations() {

        return Relation.values();
    }

    public static Relation[] getAllRelations(final boolean pDirect) {
        final Relation[] rArray = new Relation[Relation.aRelationSet.size()];
        if (pDirect)
            return Relation.aRelationSet.toArray(rArray);
        else
            return Relation.tRelationSet.toArray(rArray);

    }

    /**
     * Returns all the relations for which a domain category is valid.
     */
    public static Relation[] getAllRelations(final Category pCategory, final boolean pDirect) {
        final Vector<Relation> lReturn = new Vector<Relation>();

        if (pDirect) {
            for (final Relation r : Relation.aRelationSet)
                if (r.hasDomainCategory(pCategory))
                    lReturn.addElement(r);
        } else
            for (final Relation t : Relation.tRelationSet)
                if (t.hasDomainCategory(pCategory))
                    lReturn.addElement(t);

        return lReturn.toArray(new Relation[lReturn.size()]);
    }

    /**
     * Returns a flyweight relation.
     * 
     * @param pEncoding
     *            The full encoding of the relation, prefixed in the case of a
     *            transposed relation.
     * @return The unique relation object corresponding to pEncoding.
     * @exception UnsupportedRelationException
     *                if the encoding does not resolve to a known exception
     */
    public static Relation getRelation(final String pEncoding) throws UnsupportedRelationException {
        String lCode = pEncoding;
        // if
        if (lCode.startsWith(Relation.TRANSPOSE_CODE)) //
        {
            lCode = pEncoding.substring(Relation.TRANSPOSE_CODE.length(), pEncoding.length());
            for (final Type relationType : Type.values())
                if (lCode.equals(relationType.getCode()))
                    return Relation.tRelationMap.get(relationType); // return
            // the
            // transpose
            // relation
        } else
            for (final Type lRelationType : Type.values())
                if (lCode.equals(lRelationType.getCode()))
                    return Relation.aRelationMap.get(lRelationType);

        throw new UnsupportedRelationException("Code: " + lCode);
    }

    private final boolean aDirect;

    private final Type aId;

    /**
     * Construct a relation by specifying the relation Id and whether it is a
     * direct or transposed relation.
     * 
     * @param pId
     *            The id code for the relation.
     * @param pDirect
     *            true for a direct relation, false for a transpose relation.
     * @exception UnsupportedRelationException
     *                if the id does not correspond to a recognized relation.
     */
    private Relation(final Type pId, final boolean pDirect) {
        this.aId = pId;
        this.aDirect = pDirect;
    }

    /**
     * @return A Description of this relation, in English.
     */
    public String getDescription() {
        return this.aId.getDescription();
    }

    /**
     * @return The direct relation corresponding to this relation, whether or
     *         not the relation is transpose.
     */
    public Relation getDirectRelation() {
        if (this.isDirect())
            return this;
        else
            return Relation.aRelationMap.get(this.aId);
    }

    /**
     * @return The complete encoding for this relation, that is, the simple
     *         code, prefixed with the transpose code in the case of a transpose
     *         relation.
     */
    public String getFullCode() {
        if (this.isDirect())
            return this.aId.getCode();
        else
            return Relation.TRANSPOSE_CODE + this.aId.getCode();
    }

    /**
     * @return If this is a direct relation, returns the corresponding
     *         transpose. If this is a transpose relation, returns the
     *         corresponding direct relation.
     */
    public Relation getInverseRelation() {
        if (this.isDirect())
            return Relation.tRelationMap.get(this.aId);
        else
            return this.getDirectRelation();
    }

    /**
     * @return The name of the relation.
     */
    public String getName() {
        if (this.isDirect())
            return this.aId.getDirectName();
        else
            return this.aId.getTransposeName();
    }

    /**
     * Returns whether a relation as a specified domain category. A domain
     * category indicates the categories of elements which can be in a valid
     * domain for a relation.
     * 
     * @param pCategory
     *            The category to test for.
     * @return True if this relation can have elements of category pCategory in
     *         its domain.
     */
    public boolean hasDomainCategory(final Category pCategory) {
        boolean lReturn = false;
        if (pCategory == Category.CLASS) {
            if (this == DECLARES_METHOD || this == EXTENDS_CLASS || this == EXTENDS_INTERFACES
                    || this == IMPLEMENTS_INTERFACE || this == INHERITS || this == REFERENCES || this == T_CHECKS
                    || this == T_CREATES || this == T_EXTENDS_CLASS || this == T_EXTENDS_INTERFACES
                    || this == T_HAS_PARAMETER_TYPES || this == T_HAS_RETURN_TYPE || this == T_IMPLEMENTS_INTERFACE
                    || this == T_OF_TYPE || this == T_USES || this == IDENTITY || this == T_IDENTITY
                    || this == TRANS_EXTENDS || this == TRANS_IMPLEMENTS || this == T_TRANS_EXTENDS
                    || this == T_TRANS_IMPLEMENTS || this == T_REFERENCES)
                lReturn = true;
        } else if (pCategory == Category.METHOD) {
            if (this == ACCESSES || this == SETS || this == GETS || this == CALLS || this == EXPLICITLY_CALLS
                    || this == CHECKS || this == CREATES || this == HAS_PARAMETER_TYPES || this == HAS_RETURN_TYPE
                    || this == IMPLEMENTS_METHOD || this == OVERRIDES || this == OVERLOADS || this == USES
                    || this == REFERENCES || this == T_EXPLICITLY_CALLS || this == T_DECLARES || this == T_CALLS
                    || this == T_IMPLEMENTS_METHOD || this == T_INHERITS || this == T_OVERRIDES || this == T_USES
                    || this == IDENTITY || this == T_IDENTITY || this == STATIC_CALLS || this == T_STATIC_CALLS
                    || this == T_REFERENCES)
                lReturn = true;
        } else if (pCategory == Category.FIELD)
            if (this == OF_TYPE || this == T_DECLARES || this == T_ACCESSES || this == T_INHERITS || this == T_USES
                    || this == IDENTITY || this == T_IDENTITY || this == T_REFERENCES)
                lReturn = true;
        return lReturn;
    }

    /**
     * @return Whether this relation implies pRelation. For example, CALLS
     *         implies USES.
     */
    public boolean implies(final Relation pRelation) {
        if (this.getDirectRelation() == Relation.CALLS || this.getDirectRelation() == Relation.CREATES
                || this.getDirectRelation() == Relation.ACCESSES)
            if (pRelation.getDirectRelation() == Relation.USES)
                return true;
        if (this.getDirectRelation() == Relation.IMPLEMENTS_INTERFACE
                && pRelation.getDirectRelation() == Relation.TRANS_IMPLEMENTS)
            return true;
        if (this.getDirectRelation() == Relation.EXTENDS_CLASS
                && pRelation.getDirectRelation() == Relation.TRANS_EXTENDS)
            return true;
        if (this.getDirectRelation() == Relation.T_ACCESSES || this.getDirectRelation() == Relation.T_CALLS
                || this.getDirectRelation() == Relation.T_CHECKS || this.getDirectRelation() == Relation.T_CREATES
                || this.getDirectRelation() == Relation.T_EXTENDS_CLASS
                || this.getDirectRelation() == Relation.T_EXTENDS_INTERFACES
                || this.getDirectRelation() == Relation.T_HAS_PARAMETER_TYPES
                || this.getDirectRelation() == Relation.T_HAS_RETURN_TYPE
                || this.getDirectRelation() == Relation.T_IMPLEMENTS_INTERFACE
                || this.getDirectRelation() == Relation.T_OF_TYPE
                || this.getDirectRelation() == Relation.T_STATIC_CALLS)
            if (pRelation.getDirectRelation() == Relation.REFERENCES)
                return true;
        return false;
    }

    /**
     * @return True if this is a direct relation.
     */
    public boolean isDirect() {
        return this.aDirect;
    }

    /**
     * @return Whether the relation is a primitive relation.
     */
    public boolean isPrimitive() {
        return this.aId.ordinal() <= 9;
    }

    /**
     * @return Whether the relation is a union of two or more relations, or not.
     */
    public boolean isUnion() {
        boolean lReturn = false;
        if (this.aId == Type.ID_ACCESSES || this.aId == Type.ID_CALLS || this.aId == Type.ID_USES
                || this.aId == Type.ID_REFERENCES)
            lReturn = true;
        return lReturn;
    }

    /**
     * @return The full code for this relation.
     */
    // public String toString() {
    // return this.getFullCode();
    // }
    private Type getType() {
        return this.aId;
    }

    /**
     * @return
     */
    public Element getXML() {
        Element ret = new Element(this.getClass().getSimpleName());
        ret.setAttribute(TYPE, this.toString());
        return ret;
    }

    public static Relation valueOf(Element elem) {
        Attribute typeAttribute = elem.getAttribute(TYPE);
        String typeString = typeAttribute.getValue();
        return valueOf(typeString);
    }

    /**
     * @return
     */
    public boolean isAdvisable() {
        switch (this) {
        case CALLS:
        case EXPLICITLY_CALLS:
        case GETS:
        case SETS:
        case STATIC_CALLS:
            return true;
        default:
            return false;
        }
    }
}