Override Object.toString().
[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          * Encodes text in a way that makes it possible for the text to be stored in
103          * a {@link SimpleFieldSet}. Backslashes, CR, and LF are prepended with a
104          * backslash.
105          *
106          * @param text
107          *            The text to encode
108          * @return The encoded text
109          */
110         protected String encodeString(String text) {
111                 return text.replaceAll("\\\\", "\\\\").replaceAll("\n", "\\\\n").replaceAll("\r", "\\\\r");
112         }
113
114         /**
115          * Returns a Sone whose ID is a parameter in the given simple field set.
116          *
117          * @param simpleFieldSet
118          *            The simple field set containing the ID of the Sone
119          * @param parameterName
120          *            The name under which the Sone ID is stored in the simple field
121          *            set
122          * @param localOnly
123          *            {@code true} to only return local Sones, {@code false} to
124          *            return any Sones
125          * @return The Sone
126          * @throws FcpException
127          *             if there is no Sone ID stored under the given parameter name,
128          *             or if the Sone ID is invalid
129          */
130         protected Sone getSone(SimpleFieldSet simpleFieldSet, String parameterName, boolean localOnly) throws FcpException {
131                 try {
132                         String soneId = simpleFieldSet.getString(parameterName);
133                         Sone sone = localOnly ? core.getLocalSone(soneId, false) : core.getSone(soneId, false);
134                         if (sone == null) {
135                                 throw new FcpException("Could not load Sone from “" + soneId + "”.");
136                         }
137                         return sone;
138                 } catch (FSParseException fspe1) {
139                         throw new FcpException("Could not load Sone ID from “" + parameterName + "”.", fspe1);
140                 }
141         }
142
143         /**
144          * Returns a post whose ID is a parameter in the given simple field set.
145          *
146          * @param simpleFieldSet
147          *            The simple field set containing the ID of the post
148          * @param parameterName
149          *            The name under which the post ID is stored in the simple field
150          *            set
151          * @return The post
152          * @throws FcpException
153          *             if there is no post ID stored under the given parameter name,
154          *             or if the post ID is invalid
155          */
156         protected Post getPost(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
157                 try {
158                         String postId = simpleFieldSet.getString(parameterName);
159                         Post post = core.getPost(postId, false);
160                         if (post == null) {
161                                 throw new FcpException("Could not load post from “" + postId + "”.");
162                         }
163                         return post;
164                 } catch (FSParseException fspe1) {
165                         throw new FcpException("Could not post ID from “" + parameterName + "”.", fspe1);
166                 }
167         }
168
169         /**
170          * Returns a reply whose ID is a parameter in the given simple field set.
171          *
172          * @param simpleFieldSet
173          *            The simple field set containing the ID of the reply
174          * @param parameterName
175          *            The name under which the reply ID is stored in the simple
176          *            field set
177          * @return The reply
178          * @throws FcpException
179          *             if there is no reply ID stored under the given parameter
180          *             name, or if the reply ID is invalid
181          */
182         protected Reply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException {
183                 try {
184                         String replyId = simpleFieldSet.getString(parameterName);
185                         Reply reply = core.getReply(replyId, false);
186                         if (reply == null) {
187                                 throw new FcpException("Could not load reply from “" + replyId + "”.");
188                         }
189                         return reply;
190                 } catch (FSParseException fspe1) {
191                         throw new FcpException("Could not reply ID from “" + parameterName + "”.", fspe1);
192                 }
193         }
194
195         /**
196          * Creates a simple field set from the given collection of Sones.
197          *
198          * @param sones
199          *            The Sones to encode
200          * @param prefix
201          *            The prefix for the field names (may be empty but not
202          *            {@code null})
203          * @return The simple field set containing the given Sones
204          */
205         protected SimpleFieldSet encodeSones(Collection<? extends Sone> sones, String prefix) {
206                 SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder();
207
208                 int soneIndex = 0;
209                 soneBuilder.put(prefix + "Count", sones.size());
210                 for (Sone sone : sones) {
211                         String sonePrefix = prefix + soneIndex++ + ".";
212                         soneBuilder.put(sonePrefix + "ID", sone.getId());
213                         soneBuilder.put(sonePrefix + "Name", sone.getName());
214                         soneBuilder.put(sonePrefix + "NiceName", SoneAccessor.getNiceName(sone));
215                         soneBuilder.put(sonePrefix + "Time", sone.getTime());
216                 }
217
218                 return soneBuilder.get();
219         }
220
221         /**
222          * Creates a simple field set from the given post.
223          *
224          * @param post
225          *            The post to encode
226          * @param prefix
227          *            The prefix for the field names (may be empty but not
228          *            {@code null})
229          * @param includeReplies
230          *            {@code true} to include replies, {@code false} to not include
231          *            replies
232          * @return The simple field set containing the post
233          */
234         protected SimpleFieldSet encodePost(Post post, String prefix, boolean includeReplies) {
235                 SimpleFieldSetBuilder postBuilder = new SimpleFieldSetBuilder();
236
237                 postBuilder.put(prefix + "ID", post.getId());
238                 postBuilder.put(prefix + "Sone", post.getSone().getId());
239                 if (post.getRecipient() != null) {
240                         postBuilder.put(prefix + "Recipient", post.getRecipient().getId());
241                 }
242                 postBuilder.put(prefix + "Time", post.getTime());
243                 postBuilder.put(prefix + "Text", encodeString(post.getText()));
244                 postBuilder.put(encodeLikes(core.getLikes(post), prefix + "Likes."));
245
246                 if (includeReplies) {
247                         List<Reply> replies = core.getReplies(post);
248                         postBuilder.put(encodeReplies(replies, prefix));
249                 }
250
251                 return postBuilder.get();
252         }
253
254         /**
255          * Creates a simple field set from the given collection of posts.
256          *
257          * @param posts
258          *            The posts to encode
259          * @param prefix
260          *            The prefix for the field names (may be empty but not
261          *            {@code null})
262          * @param includeReplies
263          *            {@code true} to include the replies, {@code false} to not
264          *            include the replies
265          * @return The simple field set containing the posts
266          */
267         protected SimpleFieldSet encodePosts(Collection<? extends Post> posts, String prefix, boolean includeReplies) {
268                 SimpleFieldSetBuilder postBuilder = new SimpleFieldSetBuilder();
269
270                 int postIndex = 0;
271                 postBuilder.put(prefix + "Count", posts.size());
272                 for (Post post : posts) {
273                         String postPrefix = prefix + postIndex++;
274                         postBuilder.put(encodePost(post, postPrefix + ".", includeReplies));
275                         if (includeReplies) {
276                                 postBuilder.put(encodeReplies(Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLIES_FILTER), postPrefix + "."));
277                         }
278                 }
279
280                 return postBuilder.get();
281         }
282
283         /**
284          * Creates a simple field set from the given collection of replies.
285          *
286          * @param replies
287          *            The replies to encode
288          * @param prefix
289          *            The prefix for the field names (may be empty, but not
290          *            {@code null})
291          * @return The simple field set containing the replies
292          */
293         protected SimpleFieldSet encodeReplies(Collection<? extends Reply> replies, String prefix) {
294                 SimpleFieldSetBuilder replyBuilder = new SimpleFieldSetBuilder();
295
296                 int replyIndex = 0;
297                 replyBuilder.put(prefix + "Replies.Count", replies.size());
298                 for (Reply reply : replies) {
299                         String replyPrefix = prefix + "Replies." + replyIndex++ + ".";
300                         replyBuilder.put(replyPrefix + "ID", reply.getId());
301                         replyBuilder.put(replyPrefix + "Sone", reply.getSone().getId());
302                         replyBuilder.put(replyPrefix + "Time", reply.getTime());
303                         replyBuilder.put(replyPrefix + "Text", encodeString(reply.getText()));
304                 }
305
306                 return replyBuilder.get();
307         }
308
309         /**
310          * Creates a simple field set from the given collection of Sones that like
311          * an element.
312          *
313          * @param likes
314          *            The liking Sones
315          * @param prefix
316          *            The prefix for the field names (may be empty but not
317          *            {@code null})
318          * @return The simple field set containing the likes
319          */
320         protected SimpleFieldSet encodeLikes(Collection<? extends Sone> likes, String prefix) {
321                 SimpleFieldSetBuilder likesBuilder = new SimpleFieldSetBuilder();
322
323                 int likeIndex = 0;
324                 likesBuilder.put(prefix + "Count", likes.size());
325                 for (Sone sone : likes) {
326                         String sonePrefix = prefix + likeIndex++ + ".";
327                         likesBuilder.put(sonePrefix + "ID", sone.getId());
328                 }
329
330                 return likesBuilder.get();
331         }
332
333         //
334         // OBJECT METHODS
335         //
336
337         /**
338          * {@inheritDoc}
339          */
340         @Override
341         public String toString() {
342                 return getClass().getName() + "[writeAccess=" + writeAccess + "]";
343         }
344
345 }