Merge branch 'fcp-interface' into next
[Sone.git] / src / main / java / net / pterodactylus / sone / fcp / AbstractSoneCommand.java
1 /*
2  * Sone - FcpInterface.java - Copyright © 2011 David Roden
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 package net.pterodactylus.sone.fcp;
19
20 import java.util.Collection;
21 import java.util.List;
22
23 import net.pterodactylus.sone.core.Core;
24 import net.pterodactylus.sone.data.Post;
25 import net.pterodactylus.sone.data.Reply;
26 import net.pterodactylus.sone.data.Sone;
27 import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder;
28 import net.pterodactylus.sone.freenet.fcp.AbstractCommand;
29 import net.pterodactylus.sone.freenet.fcp.Command;
30 import net.pterodactylus.sone.freenet.fcp.FcpException;
31 import net.pterodactylus.sone.template.SoneAccessor;
32 import net.pterodactylus.util.filter.Filters;
33 import freenet.node.FSParseException;
34 import freenet.support.SimpleFieldSet;
35
36 /**
37  * Abstract base implementation of a {@link Command} with Sone-related helper
38  * methods.
39  *
40  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
41  */
42 public abstract class AbstractSoneCommand extends AbstractCommand {
43
44         /** The Sone core. */
45         private final Core core;
46
47         /** Whether this command needs write access. */
48         private final boolean writeAccess;
49
50         /**
51          * Creates a new abstract Sone FCP command.
52          *
53          * @param core
54          *            The Sone core
55          */
56         protected AbstractSoneCommand(Core core) {
57                 this(core, false);
58         }
59
60         /**
61          * Creates a new abstract Sone FCP command.
62          *
63          * @param core
64          *            The Sone core
65          * @param writeAccess
66          *            {@code true} if this command requires write access,
67          *            {@code false} otherwise
68          */
69         protected AbstractSoneCommand(Core core, boolean writeAccess) {
70                 this.core = core;
71                 this.writeAccess = writeAccess;
72         }
73
74         //
75         // ACCESSORS
76         //
77
78         /**
79          * Returns the Sone core.
80          *
81          * @return The Sone core
82          */
83         protected Core getCore() {
84                 return core;
85         }
86
87         /**
88          * Returns whether this command requires write access.
89          *
90          * @return {@code true} if this command require write access, {@code false}
91          *         otherwise
92          */
93         public boolean requiresWriteAccess() {
94                 return writeAccess;
95         }
96
97         //
98         // PROTECTED METHODS
99         //
100
101         /**
102          * Returns a Sone whose ID is a parameter in the given simple field set.
103          *
104          * @param simpleFieldSet
105          *            The simple field set containing the ID of the Sone
106          * @param parameterName
107          *            The name under which the Sone ID is stored in the simple field
108          *            set
109          * @param localOnly
110          *            {@code true} to only return local Sones, {@code false} to
111          *            return any Sones
112          * @return The Sone
113          * @throws FcpException
114          *             if there is no Sone ID stored under the given parameter name,
115          *             or if the Sone ID is invalid
116          */
117         protected Sone getSone(SimpleFieldSet simpleFieldSet, String parameterName, boolean localOnly) throws FcpException {
118                 try {
119                         String soneId = simpleFieldSet.getString(parameterName);
120                         Sone sone = localOnly ? core.getLocalSone(soneId, false) : core.getSone(soneId, false);
121                         if (sone == null) {
122                                 throw new FcpException("Could not load Sone from “" + soneId + "”.");
123                         }
124                         return sone;
125                 } catch (FSParseException fspe1) {
126                         throw new FcpException("Could not load Sone ID from “" + parameterName + "”.", fspe1);
127                 }
128         }
129
130         /**
131          * Returns a post whose ID is a parameter in the given simple field set.
132          *
133          * @param simpleFieldSet
134          *            The simple field set containing the ID of the post
135          * @param parameterName
136          *            The name under which the post ID is stored in the simple field
137          *            set
138          * @return The post
139          * @throws FcpException
140          *             if there is no post ID stored under the given parameter name,
141          *             or if the post ID is invalid
142          */
143         protected Post getPost(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
144                 try {
145                         String postId = simpleFieldSet.getString(parameterName);
146                         Post post = core.getPost(postId, false);
147                         if (post == null) {
148                                 throw new FcpException("Could not load post from “" + postId + "”.");
149                         }
150                         return post;
151                 } catch (FSParseException fspe1) {
152                         throw new FcpException("Could not post ID from “" + parameterName + "”.", fspe1);
153                 }
154         }
155
156         /**
157          * Returns a reply whose ID is a parameter in the given simple field set.
158          *
159          * @param simpleFieldSet
160          *            The simple field set containing the ID of the reply
161          * @param parameterName
162          *            The name under which the reply ID is stored in the simple
163          *            field set
164          * @return The reply
165          * @throws FcpException
166          *             if there is no reply ID stored under the given parameter
167          *             name, or if the reply ID is invalid
168          */
169         protected Reply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
170                 try {
171                         String replyId = simpleFieldSet.getString(parameterName);
172                         Reply reply = core.getReply(replyId, false);
173                         if (reply == null) {
174                                 throw new FcpException("Could not load reply from “" + replyId + "”.");
175                         }
176                         return reply;
177                 } catch (FSParseException fspe1) {
178                         throw new FcpException("Could not reply ID from “" + parameterName + "”.", fspe1);
179                 }
180         }
181
182         /**
183          * Creates a simple field set from the given collection of Sones.
184          *
185          * @param sones
186          *            The Sones to encode
187          * @param prefix
188          *            The prefix for the field names (may be empty but not
189          *            {@code null})
190          * @return The simple field set containing the given Sones
191          */
192         protected SimpleFieldSet encodeSones(Collection<? extends Sone> sones, String prefix) {
193                 SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder();
194
195                 int soneIndex = 0;
196                 soneBuilder.put(prefix + "Count", sones.size());
197                 for (Sone sone : sones) {
198                         String sonePrefix = prefix + soneIndex++ + ".";
199                         soneBuilder.put(sonePrefix + "ID", sone.getId());
200                         soneBuilder.put(sonePrefix + "Name", sone.getName());
201                         soneBuilder.put(sonePrefix + "NiceName", SoneAccessor.getNiceName(sone));
202                         soneBuilder.put(sonePrefix + "Time", sone.getTime());
203                 }
204
205                 return soneBuilder.get();
206         }
207
208         /**
209          * Creates a simple field set from the given post.
210          *
211          * @param post
212          *            The post to encode
213          * @param prefix
214          *            The prefix for the field names (may be empty but not
215          *            {@code null})
216          * @param includeReplies
217          *            {@code true} to include replies, {@code false} to not include
218          *            replies
219          * @return The simple field set containing the post
220          */
221         protected SimpleFieldSet encodePost(Post post, String prefix, boolean includeReplies) {
222                 SimpleFieldSetBuilder postBuilder = new SimpleFieldSetBuilder();
223
224                 postBuilder.put(prefix + "ID", post.getId());
225                 postBuilder.put(prefix + "Sone", post.getSone().getId());
226                 if (post.getRecipient() != null) {
227                         postBuilder.put(prefix + "Recipient", post.getRecipient().getId());
228                 }
229                 postBuilder.put(prefix + "Time", post.getTime());
230                 postBuilder.put(prefix + "Text", post.getText());
231                 postBuilder.put(encodeLikes(core.getLikes(post), prefix + "Likes."));
232
233                 if (includeReplies) {
234                         List<Reply> replies = core.getReplies(post);
235                         postBuilder.put(encodeReplies(replies, prefix));
236                 }
237
238                 return postBuilder.get();
239         }
240
241         /**
242          * Creates a simple field set from the given collection of posts.
243          *
244          * @param posts
245          *            The posts to encode
246          * @param prefix
247          *            The prefix for the field names (may be empty but not
248          *            {@code null})
249          * @param includeReplies
250          *            {@code true} to include the replies, {@code false} to not
251          *            include the replies
252          * @return The simple field set containing the posts
253          */
254         protected SimpleFieldSet encodePosts(Collection<? extends Post> posts, String prefix, boolean includeReplies) {
255                 SimpleFieldSetBuilder postBuilder = new SimpleFieldSetBuilder();
256
257                 int postIndex = 0;
258                 postBuilder.put(prefix + "Count", posts.size());
259                 for (Post post : posts) {
260                         String postPrefix = prefix + postIndex++;
261                         postBuilder.put(encodePost(post, postPrefix + ".", includeReplies));
262                         if (includeReplies) {
263                                 postBuilder.put(encodeReplies(Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLIES_FILTER), postPrefix + "."));
264                         }
265                 }
266
267                 return postBuilder.get();
268         }
269
270         /**
271          * Creates a simple field set from the given collection of replies.
272          *
273          * @param replies
274          *            The replies to encode
275          * @param prefix
276          *            The prefix for the field names (may be empty, but not
277          *            {@code null})
278          * @return The simple field set containing the replies
279          */
280         protected SimpleFieldSet encodeReplies(Collection<? extends Reply> replies, String prefix) {
281                 SimpleFieldSetBuilder replyBuilder = new SimpleFieldSetBuilder();
282
283                 int replyIndex = 0;
284                 replyBuilder.put(prefix + "Replies.Count", replies.size());
285                 for (Reply reply : replies) {
286                         String replyPrefix = prefix + "Replies." + replyIndex++ + ".";
287                         replyBuilder.put(replyPrefix + "ID", reply.getId());
288                         replyBuilder.put(replyPrefix + "Sone", reply.getSone().getId());
289                         replyBuilder.put(replyPrefix + "Time", reply.getTime());
290                         replyBuilder.put(replyPrefix + "Text", reply.getText());
291                 }
292
293                 return replyBuilder.get();
294         }
295
296         /**
297          * Creates a simple field set from the given collection of Sones that like
298          * an element.
299          *
300          * @param likes
301          *            The liking Sones
302          * @param prefix
303          *            The prefix for the field names (may be empty but not
304          *            {@code null})
305          * @return The simple field set containing the likes
306          */
307         protected SimpleFieldSet encodeLikes(Collection<? extends Sone> likes, String prefix) {
308                 SimpleFieldSetBuilder likesBuilder = new SimpleFieldSetBuilder();
309
310                 int likeIndex = 0;
311                 likesBuilder.put(prefix + "Count", likes.size());
312                 for (Sone sone : likes) {
313                         String sonePrefix = prefix + likeIndex++ + ".";
314                         likesBuilder.put(sonePrefix + "ID", sone.getId());
315                 }
316
317                 return likesBuilder.get();
318         }
319
320 }