net.pterodactylus.sone.data.Profile.java Source code

Java tutorial

Introduction

Here is the source code for net.pterodactylus.sone.data.Profile.java

Source

/*
 * Sone - Profile.java - Copyright  20102013 David Roden
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package net.pterodactylus.sone.data;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;

/**
 * A profile stores personal information about a {@link Sone}. All information
 * is optional and can be {@code null}.
 *
 * @author <a href="mailto:bombe@pterodactylus.net">David Bombe Roden</a>
 */
public class Profile implements Fingerprintable {

    /** The Sone this profile belongs to. */
    private final Sone sone;

    /** The first name. */
    private volatile String firstName;

    /** The middle name(s). */
    private volatile String middleName;

    /** The last name. */
    private volatile String lastName;

    /** The day of the birth date. */
    private volatile Integer birthDay;

    /** The month of the birth date. */
    private volatile Integer birthMonth;

    /** The year of the birth date. */
    private volatile Integer birthYear;

    /** The ID of the avatar image. */
    private volatile String avatar;

    /** Additional fields in the profile. */
    private final List<Field> fields = Collections.synchronizedList(new ArrayList<Field>());

    /**
     * Creates a new empty profile.
     *
     * @param sone
     *            The Sone this profile belongs to
     */
    public Profile(Sone sone) {
        this.sone = sone;
    }

    /**
     * Creates a copy of a profile.
     *
     * @param profile
     *            The profile to copy
     */
    public Profile(Profile profile) {
        this.sone = profile.sone;
        this.firstName = profile.firstName;
        this.middleName = profile.middleName;
        this.lastName = profile.lastName;
        this.birthDay = profile.birthDay;
        this.birthMonth = profile.birthMonth;
        this.birthYear = profile.birthYear;
        this.avatar = profile.avatar;
        this.fields.addAll(profile.fields);
    }

    //
    // ACCESSORS
    //

    /**
     * Returns the Sone this profile belongs to.
     *
     * @return The Sone this profile belongs to
     */
    public Sone getSone() {
        return sone;
    }

    /**
     * Returns the first name.
     *
     * @return The first name
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * Sets the first name.
     *
     * @param firstName
     *            The first name to set
     * @return This profile (for method chaining)
     */
    public Profile setFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    /**
     * Returns the middle name(s).
     *
     * @return The middle name
     */
    public String getMiddleName() {
        return middleName;
    }

    /**
     * Sets the middle name.
     *
     * @param middleName
     *            The middle name to set
     * @return This profile (for method chaining)
     */
    public Profile setMiddleName(String middleName) {
        this.middleName = middleName;
        return this;
    }

    /**
     * Returns the last name.
     *
     * @return The last name
     */
    public String getLastName() {
        return lastName;
    }

    /**
     * Sets the last name.
     *
     * @param lastName
     *            The last name to set
     * @return This profile (for method chaining)
     */
    public Profile setLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

    /**
     * Returns the day of the birth date.
     *
     * @return The day of the birth date (from 1 to 31)
     */
    public Integer getBirthDay() {
        return birthDay;
    }

    /**
     * Sets the day of the birth date.
     *
     * @param birthDay
     *            The day of the birth date (from 1 to 31)
     * @return This profile (for method chaining)
     */
    public Profile setBirthDay(Integer birthDay) {
        this.birthDay = birthDay;
        return this;
    }

    /**
     * Returns the month of the birth date.
     *
     * @return The month of the birth date (from 1 to 12)
     */
    public Integer getBirthMonth() {
        return birthMonth;
    }

    /**
     * Sets the month of the birth date.
     *
     * @param birthMonth
     *            The month of the birth date (from 1 to 12)
     * @return This profile (for method chaining)
     */
    public Profile setBirthMonth(Integer birthMonth) {
        this.birthMonth = birthMonth;
        return this;
    }

    /**
     * Returns the year of the birth date.
     *
     * @return The year of the birth date
     */
    public Integer getBirthYear() {
        return birthYear;
    }

    /**
     * Returns the ID of the currently selected avatar image.
     *
     * @return The ID of the currently selected avatar image, or {@code null} if
     *         no avatar is selected.
     */
    public String getAvatar() {
        return avatar;
    }

    /**
     * Sets the avatar image.
     *
     * @param avatar
     *            The new avatar image, or {@code null} to not select an avatar
     *            image.
     * @return This Sone
     */
    public Profile setAvatar(Image avatar) {
        if (avatar == null) {
            this.avatar = null;
            return this;
        }
        checkArgument(avatar.getSone().equals(sone), "avatar must belong to Sone");
        this.avatar = avatar.getId();
        return this;
    }

    /**
     * Sets the year of the birth date.
     *
     * @param birthYear
     *            The year of the birth date
     * @return This profile (for method chaining)
     */
    public Profile setBirthYear(Integer birthYear) {
        this.birthYear = birthYear;
        return this;
    }

    /**
     * Returns the fields of this profile.
     *
     * @return The fields of this profile
     */
    public List<Field> getFields() {
        return new ArrayList<Field>(fields);
    }

    /**
     * Returns whether this profile contains the given field.
     *
     * @param field
     *            The field to check for
     * @return {@code true} if this profile contains the field, false otherwise
     */
    public boolean hasField(Field field) {
        return fields.contains(field);
    }

    /**
     * Returns the field with the given ID.
     *
     * @param fieldId
     *            The ID of the field to get
     * @return The field, or {@code null} if this profile does not contain a
     *         field with the given ID
     */
    public Field getFieldById(String fieldId) {
        checkNotNull(fieldId, "fieldId must not be null");
        for (Field field : fields) {
            if (field.getId().equals(fieldId)) {
                return field;
            }
        }
        return null;
    }

    /**
     * Returns the field with the given name.
     *
     * @param fieldName
     *            The name of the field to get
     * @return The field, or {@code null} if this profile does not contain a
     *         field with the given name
     */
    public Field getFieldByName(String fieldName) {
        for (Field field : fields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }
        return null;
    }

    /**
     * Appends a new field to the list of fields.
     *
     * @param fieldName
     *            The name of the new field
     * @return The new field
     * @throws IllegalArgumentException
     *             if the name is not valid
     */
    public Field addField(String fieldName) throws IllegalArgumentException {
        checkNotNull(fieldName, "fieldName must not be null");
        checkArgument(fieldName.length() > 0, "fieldName must not be empty");
        checkState(getFieldByName(fieldName) == null, "fieldName must be unique");
        @SuppressWarnings("synthetic-access")
        Field field = new Field().setName(fieldName);
        fields.add(field);
        return field;
    }

    /**
     * Moves the given field up one position in the field list. The index of the
     * field to move must be greater than {@code 0} (because you obviously can
     * not move the first field further up).
     *
     * @param field
     *            The field to move up
     */
    public void moveFieldUp(Field field) {
        checkNotNull(field, "field must not be null");
        checkArgument(hasField(field), "field must belong to this profile");
        checkArgument(getFieldIndex(field) > 0, "field index must be > 0");
        int fieldIndex = getFieldIndex(field);
        fields.remove(field);
        fields.add(fieldIndex - 1, field);
    }

    /**
     * Moves the given field down one position in the field list. The index of
     * the field to move must be less than the index of the last field (because
     * you obviously can not move the last field further down).
     *
     * @param field
     *            The field to move down
     */
    public void moveFieldDown(Field field) {
        checkNotNull(field, "field must not be null");
        checkArgument(hasField(field), "field must belong to this profile");
        checkArgument(getFieldIndex(field) < fields.size() - 1, "field index must be < " + (fields.size() - 1));
        int fieldIndex = getFieldIndex(field);
        fields.remove(field);
        fields.add(fieldIndex + 1, field);
    }

    /**
     * Removes the given field.
     *
     * @param field
     *            The field to remove
     */
    public void removeField(Field field) {
        checkNotNull(field, "field must not be null");
        checkArgument(hasField(field), "field must belong to this profile");
        fields.remove(field);
    }

    //
    // PRIVATE METHODS
    //

    /**
     * Returns the index of the field with the given name.
     *
     * @param field
     *            The name of the field
     * @return The index of the field, or {@code -1} if there is no field with
     *         the given name
     */
    private int getFieldIndex(Field field) {
        return fields.indexOf(field);
    }

    //
    // INTERFACE Fingerprintable
    //

    /**
     * {@inheritDoc}
     */
    @Override
    public String getFingerprint() {
        Hasher hash = Hashing.sha256().newHasher();
        hash.putString("Profile(");
        if (firstName != null) {
            hash.putString("FirstName(").putString(firstName).putString(")");
        }
        if (middleName != null) {
            hash.putString("MiddleName(").putString(middleName).putString(")");
        }
        if (lastName != null) {
            hash.putString("LastName(").putString(lastName).putString(")");
        }
        if (birthDay != null) {
            hash.putString("BirthDay(").putInt(birthDay).putString(")");
        }
        if (birthMonth != null) {
            hash.putString("BirthMonth(").putInt(birthMonth).putString(")");
        }
        if (birthYear != null) {
            hash.putString("BirthYear(").putInt(birthYear).putString(")");
        }
        if (avatar != null) {
            hash.putString("Avatar(").putString(avatar).putString(")");
        }
        hash.putString("ContactInformation(");
        for (Field field : fields) {
            hash.putString(field.getName()).putString("(").putString(field.getValue()).putString(")");
        }
        hash.putString(")");
        hash.putString(")");

        return hash.hash().toString();
    }

    /**
     * Container for a profile field.
     *
     * @author <a href="mailto:bombe@pterodactylus.net">David Bombe Roden</a>
     */
    public class Field {

        /** The ID of the field. */
        private final String id;

        /** The name of the field. */
        private String name;

        /** The value of the field. */
        private String value;

        /**
         * Creates a new field with a random ID.
         */
        private Field() {
            this(UUID.randomUUID().toString());
        }

        /**
         * Creates a new field with the given ID.
         *
         * @param id
         *            The ID of the field
         */
        private Field(String id) {
            this.id = checkNotNull(id, "id must not be null");
        }

        /**
         * Returns the ID of this field.
         *
         * @return The ID of this field
         */
        public String getId() {
            return id;
        }

        /**
         * Returns the name of this field.
         *
         * @return The name of this field
         */
        public String getName() {
            return name;
        }

        /**
         * Sets the name of this field. The name must not be {@code null} and
         * must not match any other fields in this profile but my match the name
         * of this field.
         *
         * @param name
         *            The new name of this field
         * @return This field
         */
        public Field setName(String name) {
            checkNotNull(name, "name must not be null");
            checkArgument(getFieldByName(name) == null, "name must be unique");
            this.name = name;
            return this;
        }

        /**
         * Returns the value of this field.
         *
         * @return The value of this field
         */
        public String getValue() {
            return value;
        }

        /**
         * Sets the value of this field. While {@code null} is allowed, no
         * guarantees are made that {@code null} values are correctly persisted
         * across restarts of the plugin!
         *
         * @param value
         *            The new value of this field
         * @return This field
         */
        public Field setValue(String value) {
            this.value = value;
            return this;
        }

        //
        // OBJECT METHODS
        //

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean equals(Object object) {
            if (!(object instanceof Field)) {
                return false;
            }
            Field field = (Field) object;
            return id.equals(field.id);
        }

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

    }

}