2 * FreenetSone - Sone.java - Copyright © 2010 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sone.data;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.HashSet;
24 import java.util.List;
26 import java.util.UUID;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
30 import net.pterodactylus.util.logging.Logging;
31 import freenet.keys.FreenetURI;
34 * A Sone defines everything about a user: her profile, her status updates, her
35 * replies, her likes and dislikes, etc.
37 * Operations that modify the Sone need to synchronize on the Sone in question.
39 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
44 private static final Logger logger = Logging.getLogger(Sone.class);
46 /** A GUID for this Sone. */
47 private final UUID id;
49 /** The name of this Sone. */
52 /** The URI under which the Sone is stored in Freenet. */
53 private FreenetURI requestUri;
55 /** The URI used to insert a new version of this Sone. */
56 /* This will be null for remote Sones! */
57 private FreenetURI insertUri;
59 /** The profile of this Sone. */
60 private Profile profile;
62 /** All friend Sones. */
63 private final Set<Sone> friendSones = new HashSet<Sone>();
66 private final List<Post> posts = new ArrayList<Post>();
69 private final Set<Reply> replies = new HashSet<Reply>();
71 /** Modification count. */
72 private volatile long modificationCounter = 0;
80 public Sone(String id) {
81 this.id = UUID.fromString(id);
89 * Returns the ID of this Sone.
91 * @return The ID of this Sone
93 public String getId() {
98 * Returns the name of this Sone.
100 * @return The name of this Sone
102 public String getName() {
107 * Sets the name of this Sone.
110 * The name of this Sone
111 * @return This sone (for method chaining)
113 public Sone setName(String name) {
119 * Returns the request URI of this Sone.
121 * @return The request URI of this Sone
123 public FreenetURI getRequestUri() {
128 * Sets the request URI of this Sone.
131 * The request URI of this Sone
132 * @return This Sone (for method chaining)
134 public Sone setRequestUri(FreenetURI requestUri) {
135 this.requestUri = requestUri;
140 * Returns the insert URI of this Sone.
142 * @return The insert URI of this Sone
144 public FreenetURI getInsertUri() {
149 * Sets the insert URI of this Sone.
152 * The insert URI of this Sone
153 * @return This Sone (for method chaining)
155 public Sone setInsertUri(FreenetURI insertUri) {
156 this.insertUri = insertUri;
161 * Returns a copy of the profile. If you want to update values in the
162 * profile of this Sone, update the values in the returned {@link Profile}
163 * and use {@link #setProfile(Profile)} to change the profile in this Sone.
165 * @return A copy of the profile
167 public Profile getProfile() {
168 return new Profile(profile);
172 * Sets the profile of this Sone. A copy of the given profile is stored so
173 * that subsequent modifications of the given profile are not reflected in
179 public synchronized void setProfile(Profile profile) {
180 this.profile = new Profile(profile);
181 modificationCounter++;
185 * Returns all friend Sones of this Sone.
187 * @return The friend Sones of this Sone
189 public Set<Sone> getFriends() {
190 return Collections.unmodifiableSet(friendSones);
194 * Returns whether this Sone has the given Sone as a friend Sone.
197 * The friend Sone to check for
198 * @return {@code true} if this Sone has the given Sone as a friend,
199 * {@code false} otherwise
201 public boolean hasFriend(Sone friendSone) {
202 return friendSones.contains(friendSone);
206 * Adds the given Sone as a friend Sone.
209 * The friend Sone to add
210 * @return This Sone (for method chaining)
212 public synchronized Sone addFriend(Sone friendSone) {
213 if (!friendSone.equals(this) && friendSones.add(friendSone)) {
214 modificationCounter++;
220 * Removes the given Sone as a friend Sone.
223 * The friend Sone to remove
224 * @return This Sone (for method chaining)
226 public synchronized Sone removeFriend(Sone friendSone) {
227 if (friendSones.remove(friendSone)) {
228 modificationCounter++;
234 * Returns the list of posts of this Sone, sorted by time, newest first.
236 * @return All posts of this Sone
238 public List<Post> getPosts() {
239 List<Post> sortedPosts = new ArrayList<Post>(posts);
240 Collections.sort(sortedPosts, new Comparator<Post>() {
243 public int compare(Post leftPost, Post rightPost) {
244 return (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, rightPost.getTime() - leftPost.getTime()));
252 * Adds the given post to this Sone. The post will not be added if its
253 * {@link Post#getSone() Sone} is not this Sone.
258 public synchronized void addPost(Post post) {
259 if (post.getSone().equals(this) && posts.add(post)) {
260 logger.log(Level.FINEST, "Adding %s to “%s”.", new Object[] { post, getName() });
261 modificationCounter++;
266 * Removes the given post from this Sone.
271 public synchronized void removePost(Post post) {
272 if (post.getSone().equals(this) && posts.remove(post)) {
273 modificationCounter++;
278 * Returns all replies this Sone made.
280 * @return All replies this Sone made
282 public Set<Reply> getReplies() {
283 logger.log(Level.FINEST, "Friends of %s: %s", new Object[] { this, friendSones });
284 return Collections.unmodifiableSet(replies);
288 * Adds a reply to this Sone. If the given reply was not made by this Sone,
289 * nothing is added to this Sone.
294 public synchronized void addReply(Reply reply) {
295 if (reply.getSone().equals(this) && replies.add(reply)) {
296 modificationCounter++;
301 * Removes a reply from this Sone.
304 * The reply to remove
306 public synchronized void removeReply(Reply reply) {
307 if (reply.getSone().equals(this) && replies.remove(reply)) {
308 modificationCounter++;
313 * Returns the modification counter.
315 * @return The modification counter
317 public synchronized long getModificationCounter() {
318 return modificationCounter;
322 * Sets the modification counter.
324 * @param modificationCounter
325 * The new modification counter
327 public synchronized void setModificationCounter(long modificationCounter) {
328 this.modificationCounter = modificationCounter;
332 * Updates the suggested edition in both the request URI and the insert URI.
335 * The request URI that resulted from an insert
337 public void updateUris(FreenetURI requestUri) {
338 /* TODO - check for the correct URI. */
339 long latestEdition = requestUri.getSuggestedEdition();
340 this.requestUri = this.requestUri.setSuggestedEdition(latestEdition);
341 if (this.insertUri != null) {
342 this.insertUri = this.insertUri.setSuggestedEdition(latestEdition);
354 public int hashCode() {
355 return id.hashCode();
362 public boolean equals(Object object) {
363 if (!(object instanceof Sone)) {
366 return ((Sone) object).id.equals(id);
373 public String toString() {
374 return getClass().getName() + "[id=" + id + ",name=" + name + ",requestUri=" + requestUri + ",insertUri=" + insertUri + ",friends(" + friendSones.size() + "),posts(" + posts.size() + "),replies(" + replies.size() + ")]";