X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fdata%2FProfile.java;h=61cf2911f372e93aa33b329ee9a81e14353689af;hb=0a4b6fc252003c71f4bdef09560e87982838d9c8;hp=f6e2bed96beca28c8a31c3e546ff9910739fc53e;hpb=671f7e20aab401e972ede3c7d8eb30d92f4dc547;p=Sone.git diff --git a/src/main/java/net/pterodactylus/sone/data/Profile.java b/src/main/java/net/pterodactylus/sone/data/Profile.java index f6e2bed..61cf291 100644 --- a/src/main/java/net/pterodactylus/sone/data/Profile.java +++ b/src/main/java/net/pterodactylus/sone/data/Profile.java @@ -1,5 +1,5 @@ /* - * FreenetSone - Profile.java - Copyright © 2010 David Roden + * Sone - Profile.java - Copyright © 2010–2013 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 @@ -17,14 +17,22 @@ package net.pterodactylus.sone.data; +import static com.google.common.base.Optional.absent; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Optional.of; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.lang.Math.max; +import static java.lang.Math.min; +import static java.util.UUID.randomUUID; + import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import net.pterodactylus.util.validation.Validation; +import com.google.common.base.Optional; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; /** * A profile stores personal information about a {@link Sone}. All information @@ -34,35 +42,26 @@ import net.pterodactylus.util.validation.Validation; */ public class Profile implements Fingerprintable { - /** The first name. */ - private volatile String firstName; - - /** The middle name(s). */ - private volatile String middleName; - - /** The last name. */ - private volatile String lastName; + /** The Sone this profile belongs to. */ + private final Sone sone; - /** The day of the birth date. */ - private volatile Integer birthDay; + private volatile Name name = new Name(); + private volatile BirthDate birthDate = new BirthDate(); - /** 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 fields = Collections.synchronizedList(new ArrayList()); - - /** The field values. */ - private final Map fieldValues = Collections.synchronizedMap(new HashMap()); + private final List fields = Collections.synchronizedList(new ArrayList()); /** * Creates a new empty profile. + * + * @param sone + * The Sone this profile belongs to */ - public Profile() { - /* do nothing. */ + public Profile(Sone sone) { + this.sone = sone; } /** @@ -72,17 +71,11 @@ public class Profile implements Fingerprintable { * The profile to copy */ public Profile(Profile profile) { - if (profile == null) { - return; - } - 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.sone = profile.sone; + this.name = profile.name; + this.birthDate = profile.birthDate; + this.avatar = profile.avatar; this.fields.addAll(profile.fields); - this.fieldValues.putAll(profile.fieldValues); } // @@ -90,294 +83,185 @@ public class Profile implements Fingerprintable { // /** - * Returns the first name. + * Returns the Sone this profile belongs to. * - * @return The first name + * @return The Sone this profile belongs to */ - public String getFirstName() { - return firstName; + public Sone getSone() { + return sone; } - /** - * 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; + public String getFirstName() { + return name.getFirst().orNull(); } - /** - * 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; + return name.getMiddle().orNull(); } - /** - * 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; + return name.getLast().orNull(); } - /** - * 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; + return birthDate.getDay().orNull(); } - /** - * Returns the month of the birth date. - * - * @return The month of the birth date (from 1 to 12) - */ public Integer getBirthMonth() { - return birthMonth; + return birthDate.getMonth().orNull(); } - /** - * 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; + public Integer getBirthYear() { + return birthDate.getYear().orNull(); } - /** - * Returns the year of the birth date. - * - * @return The year of the birth date - */ - public Integer getBirthYear() { - return birthYear; + public String getAvatar() { + return avatar; } - /** - * 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; + public Profile setAvatar(Optional avatarId) { + this.avatar = avatarId.orNull(); return this; } - /** - * Appends a new field to the list of fields. - * - * @param field - * The field to add - * @throws IllegalArgumentException - * if the name is not valid - */ - public void addField(String field) throws IllegalArgumentException { - Validation.begin().isNotNull("Field Name", field).check().isGreater("Field Name Length", field.length(), 0).isEqual("Field Name Unique", !fields.contains(field), true).check(); - fields.add(field); + public List getFields() { + return new ArrayList(fields); } - /** - * Moves the field with the given index 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 fieldIndex - * The index of the field to move - */ - public void moveFieldUp(int fieldIndex) { - Validation.begin().isGreater("Field Index", fieldIndex, 0).isLess("Field Index", fieldIndex, fields.size()).check(); - String field = fields.remove(fieldIndex); - fields.add(fieldIndex - 1, field); + public boolean hasField(Field field) { + return fields.contains(field); } - /** - * Moves the field with the given name up one position in the field list. - * The field must not be the first field (because you obviously can not move - * the first field further up). - * - * @param field - * The name of the field to move - */ - public void moveFieldUp(String field) { - Validation.begin().isNotNull("Field Name", field).check().isGreater("Field Name Length", field.length(), 0).isEqual("Field Name Existing", fields.contains(field), true).check(); - moveFieldUp(getFieldIndex(field)); + public Optional getFieldById(String fieldId) { + checkNotNull(fieldId, "fieldId must not be null"); + for (Field field : fields) { + if (field.getId().equals(fieldId)) { + return of(field); + } + } + return absent(); } - /** - * Moves the field with the given index 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 fieldIndex - * The index of the field to move - */ - public void moveFieldDown(int fieldIndex) { - Validation.begin().isGreaterOrEqual("Field Index", fieldIndex, 0).isLess("Field Index", fieldIndex, fields.size() - 1).check(); - String field = fields.remove(fieldIndex); - fields.add(fieldIndex + 1, field); + public Optional getFieldByName(String fieldName) { + for (Field field : fields) { + if (field.getName().equals(fieldName)) { + return of(field); + } + } + return absent(); } - /** - * Moves the field with the given name down one position in the field list. - * The field must not be the last field (because you obviously can not move - * the last field further down). - * - * @param field - * The name of the field to move - */ - public void moveFieldDown(String field) { - Validation.begin().isNotNull("Field Name", field).check().isGreater("Field Name Length", field.length(), 0).isEqual("Field Name Existing", fields.contains(field), true).check(); - moveFieldDown(getFieldIndex(field)); + public Field addField(String fieldName) throws IllegalArgumentException { + checkNotNull(fieldName, "fieldName must not be null"); + checkArgument(fieldName.length() > 0, "fieldName must not be empty"); + checkArgument(!getFieldByName(fieldName).isPresent(), "fieldName must be unique"); + @SuppressWarnings("synthetic-access") + Field field = new Field(fieldName); + fields.add(field); + return field; } - /** - * Removes the field at the given index. - * - * @param fieldIndex - * The index of the field to remove - */ - public void removeField(int fieldIndex) { - Validation.begin().isGreaterOrEqual("Field Index", fieldIndex, 0).isLess("Field Index", fieldIndex, fields.size()).check(); - String field = fields.remove(fieldIndex); - fieldValues.remove(field); + public void renameField(Field field, String newName) { + int indexOfField = getFieldIndex(field); + if (indexOfField == -1) { + return; + } + fields.set(indexOfField, new Field(field.getId(), newName, field.getValue())); } - /** - * Removes the field with the given name. - * - * @param field - * The name of the field - */ - public void removeField(String field) { - Validation.begin().isNotNull("Field Name", field).check().isGreater("Field Name Length", field.length(), 0).isEqual("Field Name Existing", fields.contains(field), true).check(); - removeField(getFieldIndex(field)); + public void setField(Field field, String newValue) { + int indexOfField = getFieldIndex(field); + if (indexOfField == -1) { + return; + } + fields.set(indexOfField, new Field(field.getId(), field.getName(), newValue)); } - /** - * Returns the value of the field with the given name. - * - * @param field - * The name of the field - * @return The value of the field, or {@code null} if there is no such field - */ - public String getField(String field) { - return fieldValues.get(field); + public void moveFieldUp(Field field) { + checkNotNull(field, "field must not be null"); + checkArgument(hasField(field), "field must belong to this profile"); + int fieldIndex = getFieldIndex(field); + fields.remove(field); + fields.add(max(fieldIndex - 1, 0), field); } - /** - * Sets the value of the field with the given name. - * - * @param fieldIndex - * The index of the field - * @param value - * The value of the field - */ - public void setField(int fieldIndex, String value) { - Validation.begin().isGreaterOrEqual("Field Index", fieldIndex, 0).isLess("Field Index", fieldIndex, fields.size()).check(); - setField(fields.get(fieldIndex), value); + public void moveFieldDown(Field field) { + checkNotNull(field, "field must not be null"); + checkArgument(hasField(field), "field must belong to this profile"); + int fieldIndex = getFieldIndex(field); + fields.remove(field); + fields.add(min(fieldIndex + 1, fields.size()), field); } - /** - * Sets the value of the field with the given name. - * - * @param field - * The name of the field - * @param value - * The value of the field - */ - public void setField(String field, String value) { - Validation.begin().isNotNull("Field Name", field).check().isGreater("Field Name Length", field.length(), 0).isEqual("Field Name Existing", fields.contains(field), true).check(); - fieldValues.put(field, value); + public void removeField(Field field) { + checkNotNull(field, "field must not be null"); + fields.remove(field); } - /** - * Returns a list of all fields stored in this profile. - * - * @return The fields of this profile - */ - public List getFieldNames() { - return Collections.unmodifiableList(fields); + public Modifier modify() { + return new Modifier() { + private Optional firstName = name.getFirst(); + private Optional middleName = name.getMiddle(); + private Optional lastName = name.getLast(); + private Optional birthYear = birthDate.getYear(); + private Optional birthMonth = birthDate.getMonth(); + private Optional birthDay = birthDate.getDay(); + + @Override + public Modifier setFirstName(String firstName) { + this.firstName = fromNullable(firstName); + return this; + } + + @Override + public Modifier setMiddleName(String middleName) { + this.middleName = fromNullable(middleName); + return this; + } + + @Override + public Modifier setLastName(String lastName) { + this.lastName = fromNullable(lastName); + return this; + } + + @Override + public Modifier setBirthYear(Integer birthYear) { + this.birthYear = fromNullable(birthYear); + return this; + } + + @Override + public Modifier setBirthMonth(Integer birthMonth) { + this.birthMonth = fromNullable(birthMonth); + return this; + } + + @Override + public Modifier setBirthDay(Integer birthDay) { + this.birthDay = fromNullable(birthDay); + return this; + } + + @Override + public Profile update() { + Profile.this.name = new Name(firstName, middleName, lastName); + Profile.this.birthDate = new BirthDate(birthYear, birthMonth, birthDay); + return Profile.this; + } + }; } - /** - * Renames a fields. - * - * @param fieldIndex - * The index of the field to rename - * @param fieldName - * The new name of the field - */ - public void setFieldName(int fieldIndex, String fieldName) { - Validation.begin().isGreaterOrEqual("Field Index", fieldIndex, 0).isLess("Field Index", fieldIndex, fields.size()).isNotNull("Field Name", fieldName).isEqual("New Field Name Unique", !fields.contains(fieldName) || (getFieldIndex(fieldName) == fieldIndex), true).check(); - String value = fieldValues.remove(fields.get(fieldIndex)); - fields.set(fieldIndex, fieldName); - fieldValues.put(fieldName, value); - } + public interface Modifier { + + Modifier setFirstName(String firstName); + Modifier setMiddleName(String middleName); + Modifier setLastName(String lastName); + Modifier setBirthYear(Integer birthYear); + Modifier setBirthMonth(Integer birthMonth); + Modifier setBirthDay(Integer birthDay); + Profile update(); - /** - * Returns all field names and their values, ordered the same way - * {@link #getFieldNames()} returns the names of the fields. - * - * @return All field names and values - */ - public Map getFields() { - Map fields = new LinkedHashMap(); - for (String field : getFieldNames()) { - fields.put(field, getField(field)); - } - return fields; } // @@ -392,7 +276,7 @@ public class Profile implements Fingerprintable { * @return The index of the field, or {@code -1} if there is no field with * the given name */ - private int getFieldIndex(String field) { + private int getFieldIndex(Field field) { return fields.indexOf(field); } @@ -400,39 +284,172 @@ public class Profile implements Fingerprintable { // INTERFACE Fingerprintable // - /** - * {@inheritDoc} - */ @Override public String getFingerprint() { - StringBuilder fingerprint = new StringBuilder(); - fingerprint.append("Profile("); - if (firstName != null) { - fingerprint.append("FirstName(").append(firstName).append(')'); + Hasher hash = Hashing.sha256().newHasher(); + hash.putString("Profile("); + hash.putString(name.getFingerprint()); + hash.putString(birthDate.getFingerprint()); + if (avatar != null) { + hash.putString("Avatar(").putString(avatar).putString(")"); } - if (middleName != null) { - fingerprint.append("MiddleName(").append(middleName).append(')'); + hash.putString("ContactInformation("); + for (Field field : fields) { + if (field.getValue() != null) { + hash.putString(field.getName()).putString("(").putString(field.getValue()).putString(")"); + } } - if (lastName != null) { - fingerprint.append("LastName(").append(lastName).append(')'); + hash.putString(")"); + hash.putString(")"); + + return hash.hash().toString(); + } + + /** + * Container for a profile field. + * + * @author David ‘Bombe’ Roden + */ + public static class Field { + + private final String id; + private final String name; + private final String value; + + public Field(String name) { + this(name, null); } - if (birthDay != null) { - fingerprint.append("BirthDay(").append(birthDay).append(')'); + + public Field(String name, String value) { + this(randomUUID().toString(), name, value); } - if (birthMonth != null) { - fingerprint.append("BirthMonth(").append(birthMonth).append(')'); + + public Field(String id, String name, String value) { + this.id = checkNotNull(id, "id must not be null"); + this.name = name; + this.value = value; + } + + public String getId() { + return id; } - if (birthYear != null) { - fingerprint.append("BirthYear(").append(birthYear).append(')'); + + public String getName() { + return name; + } + + public String getValue() { + return value; } - fingerprint.append("ContactInformation("); - for (String field : fields) { - fingerprint.append(field).append('(').append(fieldValues.get(field)).append(')'); + + @Override + public boolean equals(Object object) { + if (!(object instanceof Field)) { + return false; + } + Field field = (Field) object; + return id.equals(field.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + } + + public static class Name implements Fingerprintable { + + private final Optional first; + private final Optional middle; + private final Optional last; + + public Name() { + this(Optional.absent(), Optional.absent(), Optional.absent()); + } + + public Name(Optional first, Optional middle, Optional last) { + this.first = first; + this.middle = middle; + this.last = last; + } + + public Optional getFirst() { + return first; + } + + public Optional getMiddle() { + return middle; + } + + public Optional getLast() { + return last; + } + + @Override + public String getFingerprint() { + Hasher hash = Hashing.sha256().newHasher(); + hash.putString("Name("); + if (first.isPresent()) { + hash.putString("First(").putString(first.get()).putString(")"); + } + if (middle.isPresent()) { + hash.putString("Middle(").putString(middle.get()).putString(")"); + } + if (last.isPresent()) { + hash.putString("Last(").putString(last.get()).putString(")"); + } + hash.putString(")"); + return hash.hash().toString(); + } + + } + + public static class BirthDate implements Fingerprintable { + + private final Optional year; + private final Optional month; + private final Optional day; + + public BirthDate() { + this(Optional.absent(), Optional.absent(), Optional.absent()); + } + + public BirthDate(Optional year, Optional month, Optional day) { + this.year = year; + this.month = month; + this.day = day; + } + + public Optional getYear() { + return year; + } + + public Optional getMonth() { + return month; + } + + public Optional getDay() { + return day; + } + + @Override + public String getFingerprint() { + Hasher hash = Hashing.sha256().newHasher(); + hash.putString("Birthdate("); + if (year.isPresent()) { + hash.putString("Year(").putInt(year.get()).putString(")"); + } + if (month.isPresent()) { + hash.putString("Month(").putInt(month.get()).putString(")"); + } + if (day.isPresent()) { + hash.putString("Day(").putInt(day.get()).putString(")"); + } + hash.putString(")"); + return hash.hash().toString(); } - fingerprint.append(")"); - fingerprint.append(")"); - return fingerprint.toString(); } }