Remove javadoc comments from overriding methods.
[Sone.git] / src / main / java / net / pterodactylus / sone / web / page / FreenetTemplatePage.java
1 /*
2  * Sone - FreenetTemplatePage.java - Copyright © 2010–2013 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.web.page;
19
20 import java.io.IOException;
21 import java.io.StringWriter;
22 import java.net.URI;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30
31 import net.pterodactylus.util.logging.Logging;
32 import net.pterodactylus.util.template.Template;
33 import net.pterodactylus.util.template.TemplateContext;
34 import net.pterodactylus.util.template.TemplateContextFactory;
35 import net.pterodactylus.util.web.Method;
36 import net.pterodactylus.util.web.Page;
37 import net.pterodactylus.util.web.RedirectResponse;
38 import net.pterodactylus.util.web.Response;
39 import freenet.clients.http.LinkEnabledCallback;
40 import freenet.clients.http.PageMaker;
41 import freenet.clients.http.PageNode;
42 import freenet.clients.http.ToadletContext;
43 import freenet.support.HTMLNode;
44
45 /**
46  * Base class for all {@link Page}s that are rendered with {@link Template}s and
47  * fit into Freenet’s web interface.
48  *
49  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
50  */
51 public class FreenetTemplatePage implements FreenetPage, LinkEnabledCallback {
52
53         /** The logger. */
54         private static final Logger logger = Logging.getLogger(FreenetTemplatePage.class);
55
56         /** The path of the page. */
57         private final String path;
58
59         /** The template context factory. */
60         private final TemplateContextFactory templateContextFactory;
61
62         /** The template to render. */
63         private final Template template;
64
65         /** Where to redirect for invalid form passwords. */
66         private final String invalidFormPasswordRedirectTarget;
67
68         /**
69          * Creates a new template page.
70          *
71          * @param path
72          *            The path of the page
73          * @param templateContextFactory
74          *            The template context factory
75          * @param template
76          *            The template to render
77          * @param invalidFormPasswordRedirectTarget
78          *            The target to redirect to if a POST request does not contain
79          *            the correct form password
80          */
81         public FreenetTemplatePage(String path, TemplateContextFactory templateContextFactory, Template template, String invalidFormPasswordRedirectTarget) {
82                 this.path = path;
83                 this.templateContextFactory = templateContextFactory;
84                 this.template = template;
85                 this.invalidFormPasswordRedirectTarget = invalidFormPasswordRedirectTarget;
86         }
87
88         @Override
89         public String getPath() {
90                 return path;
91         }
92
93         /**
94          * Returns the title of the page.
95          *
96          * @param request
97          *            The request to serve
98          * @return The title of the page
99          */
100         @SuppressWarnings("static-method")
101         protected String getPageTitle(FreenetRequest request) {
102                 return null;
103         }
104
105         @Override
106         public boolean isPrefixPage() {
107                 return false;
108         }
109
110         @Override
111         public Response handleRequest(FreenetRequest request, Response response) throws IOException {
112                 String redirectTarget = getRedirectTarget(request);
113                 if (redirectTarget != null) {
114                         return new RedirectResponse(redirectTarget);
115                 }
116
117                 if (isFullAccessOnly() && !request.getToadletContext().isAllowedFullAccess()) {
118                         return response.setStatusCode(401).setStatusText("Not authorized").setContentType("text/html");
119                 }
120                 ToadletContext toadletContext = request.getToadletContext();
121                 if (request.getMethod() == Method.POST) {
122                         /* require form password. */
123                         String formPassword = request.getHttpRequest().getPartAsStringFailsafe("formPassword", 32);
124                         if (!formPassword.equals(toadletContext.getContainer().getFormPassword())) {
125                                 return new RedirectResponse(invalidFormPasswordRedirectTarget);
126                         }
127                 }
128                 PageMaker pageMaker = toadletContext.getPageMaker();
129                 PageNode pageNode = pageMaker.getPageNode(getPageTitle(request), toadletContext);
130                 for (String styleSheet : getStyleSheets()) {
131                         pageNode.addCustomStyleSheet(styleSheet);
132                 }
133                 for (Map<String, String> linkNodeParameters : getAdditionalLinkNodes(request)) {
134                         HTMLNode linkNode = pageNode.headNode.addChild("link");
135                         for (Entry<String, String> parameter : linkNodeParameters.entrySet()) {
136                                 linkNode.addAttribute(parameter.getKey(), parameter.getValue());
137                         }
138                 }
139                 String shortcutIcon = getShortcutIcon();
140                 if (shortcutIcon != null) {
141                         pageNode.addForwardLink("icon", shortcutIcon);
142                 }
143
144                 TemplateContext templateContext = templateContextFactory.createTemplateContext();
145                 templateContext.mergeContext(template.getInitialContext());
146                 try {
147                         long start = System.nanoTime();
148                         processTemplate(request, templateContext);
149                         long finish = System.nanoTime();
150                         logger.log(Level.FINEST, String.format("Template was rendered in %.2fms.", ((finish - start) / 1000) / 1000.0));
151                 } catch (RedirectException re1) {
152                         return new RedirectResponse(re1.getTarget());
153                 }
154
155                 StringWriter stringWriter = new StringWriter();
156                 template.render(templateContext, stringWriter);
157                 pageNode.content.addChild("%", stringWriter.toString());
158
159                 postProcess(request, templateContext);
160
161                 return response.setStatusCode(200).setStatusText("OK").setContentType("text/html").write(pageNode.outer.generate());
162         }
163
164         /**
165          * Can be overridden to return a custom set of style sheets that are to be
166          * included in the page’s header.
167          *
168          * @return Additional style sheets to load
169          */
170         @SuppressWarnings("static-method")
171         protected Collection<String> getStyleSheets() {
172                 return Collections.emptySet();
173         }
174
175         /**
176          * Returns the name of the shortcut icon to include in the page’s header.
177          *
178          * @return The URL of the shortcut icon, or {@code null} for no icon
179          */
180         @SuppressWarnings("static-method")
181         protected String getShortcutIcon() {
182                 return null;
183         }
184
185         /**
186          * Can be overridden when extending classes need to set variables in the
187          * template before it is rendered.
188          *
189          * @param request
190          *            The request that is rendered
191          * @param templateContext
192          *            The template context to set variables in
193          * @throws RedirectException
194          *             if the processing page wants to redirect after processing
195          */
196         protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
197                 /* do nothing. */
198         }
199
200         /**
201          * This method will be called after
202          * {@link #processTemplate(FreenetRequest, TemplateContext)} has processed
203          * the template and the template was rendered. This method will not be
204          * called if {@link #processTemplate(FreenetRequest, TemplateContext)}
205          * throws a {@link RedirectException}!
206          *
207          * @param request
208          *            The request being processed
209          * @param templateContext
210          *            The template context that supplied the rendered data
211          */
212         protected void postProcess(FreenetRequest request, TemplateContext templateContext) {
213                 /* do nothing. */
214         }
215
216         /**
217          * Can be overridden to redirect the user to a different page, in case a log
218          * in is required, or something else is wrong.
219          *
220          * @param request
221          *            The request that is processed
222          * @return The URL to redirect to, or {@code null} to not redirect
223          */
224         @SuppressWarnings("static-method")
225         protected String getRedirectTarget(FreenetRequest request) {
226                 return null;
227         }
228
229         /**
230          * Returns additional &lt;link&gt; nodes for the HTML’s &lt;head&gt; node.
231          *
232          * @param request
233          *            The request for which to return the link nodes
234          * @return All link nodes that should be added to the HTML head
235          */
236         @SuppressWarnings("static-method")
237         protected List<Map<String, String>> getAdditionalLinkNodes(FreenetRequest request) {
238                 return Collections.emptyList();
239         }
240
241         /**
242          * Returns whether this page should only be allowed for requests from hosts
243          * with full access.
244          *
245          * @return {@code true} if this page should only be allowed for hosts with
246          *         full access, {@code false} to allow this page for any host
247          */
248         @SuppressWarnings("static-method")
249         protected boolean isFullAccessOnly() {
250                 return false;
251         }
252
253         @Override
254         public boolean isLinkExcepted(URI link) {
255                 return false;
256         }
257
258         //
259         // INTERFACE LinkEnabledCallback
260         //
261
262         @Override
263         public boolean isEnabled(ToadletContext toadletContext) {
264                 return !isFullAccessOnly();
265         }
266
267         /**
268          * Exception that can be thrown to signal that a subclassed {@link Page}
269          * wants to redirect the user during the
270          * {@link FreenetTemplatePage#processTemplate(FreenetRequest, TemplateContext)}
271          * method call.
272          *
273          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
274          */
275         public static class RedirectException extends Exception {
276
277                 /** The target to redirect to. */
278                 private final String target;
279
280                 /**
281                  * Creates a new redirect exception.
282                  *
283                  * @param target
284                  *            The target of the redirect
285                  */
286                 public RedirectException(String target) {
287                         this.target = target;
288                 }
289
290                 /**
291                  * Returns the target to redirect to.
292                  *
293                  * @return The target to redirect to
294                  */
295                 public String getTarget() {
296                         return target;
297                 }
298
299         }
300
301 }