es.ucm.fdi.ac.Annotation.java Source code

Java tutorial

Introduction

Here is the source code for es.ucm.fdi.ac.Annotation.java

Source

/**
 * AC - A source-code copy detector
 *
 *     For more information please visit:  http://github.com/manuel-freire/ac
 *
 * ****************************************************************************
 *
 * This file is part of AC, version 2.0
 *
 * AC 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.
 *
 * AC 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 AC.  If not, see <http://www.gnu.org/licenses/>.
 */

package es.ucm.fdi.ac;

import es.ucm.fdi.util.XMLSerializable;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import org.jdom2.Element;

import static es.ucm.fdi.util.I18N.m;

/**
 * An annotation represents a note (authored by the system or a human) 
 * regarding a given submission.
 *
 * @author mfreire
 */
public class Annotation implements XMLSerializable {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm;ss (Z)");

    /**
     * Types of annotation
     */
    public enum Label {
        /** same person, two submissions that are (understandably) very similar */
        Duplicate,
        /** different person, two submissions that are a confirmed, evil copy */
        Copy,
        /** both look similar but, according to author, are not an evil copy */
        Notcopy,
        /** the author is not sure if this is a copy, and wants to explain why */
        Suspect,
        /** other type of annotation */
        Other,
    };

    private Date date;
    private String author;

    /** another submission's ID. Can be null for general comments */
    private String target;
    /** Commentary of the annotation. Can be empty */
    private String commentary;
    /** List of labels for this annotation. Cannot be empty */
    private final ArrayList<Label> labels = new ArrayList<Label>();

    /*
     * localFile and targetFile atributes precisely indicate
     * which files are objects of the annotation.
     * Both arguments are optional, and are expected to be relative
     * paths to the submission (for localFile) and the target attribute
     * of the annotation (for targetFile).
     */
    private String localFile;
    private String targetFile;

    /**
     * Create an empty annotation instance
     */
    public Annotation() {
    }

    public Annotation(String author, Label label) {
        this.author = author;
        this.date = new Date();
        labels.add(label);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("Annotation [");
        for (Label label : getLabels()) {
            sb.append(" ").append(label.toString());
        }
        sb.append("]");
        if (commentary != null) {
            sb.append(": ").append(commentary);
        }
        return sb.toString();
    }

    /**
     * @return the date
     */
    public Date getDate() {
        return date;
    }

    /**
     * @param date the date to set
     */
    public void setDate(Date date) {
        this.date = date;
    }

    /**
     * @return the author
     */
    public String getAuthor() {
        return author;
    }

    /**
     * @param author the author to set
     */
    public void setAuthor(String author) {
        this.author = author;
    }

    /**
     * @return the localFile
     */
    public String getLocalFile() {
        return localFile;
    }

    /**
     * @param localFile the localFile to set
     */
    public void setLocalFile(String localFile) {
        this.localFile = localFile;
    }

    /**
     * @return the targetFile
     */
    public String getTargetFile() {
        return targetFile;
    }

    /**
     * @param targetFile the targetFile to set
     */
    public void setTargetFile(String targetFile) {
        this.targetFile = targetFile;
    }

    /**
     * @return the commentary
     */
    public String getCommentary() {
        return commentary;
    }

    /**
     * @param commentary the commentary to set
     */
    public void setCommentary(String commentary) {
        this.commentary = commentary;
    }

    /**
     * @return the target
     */
    public String getTarget() {
        return target;
    }

    /**
     * @param target the target to set
     */
    public void setTarget(String target) {
        this.target = target;
    }

    /**
     * List of labels for this annotation. Cannot be empty 
     * @return the labels
     */
    public ArrayList<Label> getLabels() {
        return labels;
    }

    public Element saveToXML() throws IOException {
        Element element = new Element("annotation");

        // Add labels attribute
        StringBuilder labelsString = new StringBuilder();
        for (Label l : labels) {
            labelsString.append(l.toString());
            labelsString.append(" ");
        }
        element.setAttribute("labels", labelsString.toString().trim());

        // Add comment
        if (commentary != null) {
            element.setText(commentary.trim());
        }

        // Add optional attributes
        if (author != null) {
            element.setAttribute("author", author.trim());
        }
        if (date != null) {
            element.setAttribute("date", dateFormat.format(date));
        }
        if (target != null) {
            element.setAttribute("target", target);
        }
        if (localFile != null) {
            element.setAttribute("localFile", localFile);
        }
        if (targetFile != null) {
            element.setAttribute("targetFile", targetFile);
        }

        return element;
    }

    public void loadFromXML(Element element) throws IOException {
        String labelsAttribute = element.getAttributeValue("labels");
        labels.clear();
        for (String labelString : labelsAttribute.split(" ")) {
            labels.add(Label.valueOf(labelString.toLowerCase()));
        }

        author = element.getAttributeValue("author");
        target = element.getAttributeValue("target");

        localFile = element.getAttributeValue("localFile");
        if (localFile != null) {
            while (localFile.endsWith("/")) {
                localFile = localFile.substring(0, localFile.length() - 1);
            }
        }
        targetFile = element.getAttributeValue("targetFile");
        if (targetFile != null) {
            while (targetFile.endsWith("/")) {
                targetFile = targetFile.substring(0, targetFile.length() - 1);
            }
        }
        if (element.getAttributeValue("date") != null) {
            try {
                date = dateFormat.parse(element.getAttributeValue("date"));
            } catch (ParseException ex) {
                throw new IOException("Error parsing annotation date", ex);
            }
        }

        if (element.getText() != null) {
            commentary = element.getText().trim();
        }
    }

    /**
     * Tests the annotation validity
     * @param a analysis to validate against
     * @param s submission against which this annotation was made
     * @param messages where errors will be written for human consumption; 
     *      can be null
     * @return true if valid
     */
    public boolean isValid(Analysis a, Submission s, ArrayList<String> messages) {
        if (messages == null) {
            messages = new ArrayList<String>();
        }

        if (labels.isEmpty()) {
            messages.add(m("annotation.error.no-labels"));
        }
        if (localFile != null && !s.containsSource(localFile)) {
            messages.add(m("annotation.error.local-file-not-found", localFile));
        }
        if (target != null) {
            Submission other = a.getSubmission(target);
            if (other == null) {
                messages.add(m("annotation.error.target-not-found", target));
            } else {
                if (!other.containsSource(targetFile)) {
                    messages.add(m("annotation.error.target-file-not-found", targetFile));
                }
            }
        }
        return !messages.isEmpty();
    }
}