Add interface between templates and toadlets.
[Sone.git] / src / main / java / net / pterodactylus / sone / web / page / Page.java
1 /*
2  * shortener - Page.java - Copyright © 2010 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.ByteArrayInputStream;
21 import java.io.InputStream;
22 import java.io.UnsupportedEncodingException;
23 import java.net.URI;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import freenet.clients.http.ToadletContext;
28 import freenet.support.api.HTTPRequest;
29
30 /**
31  * A page is responsible for handling HTTP requests and creating appropriate
32  * responses.
33  * 
34  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
35  */
36 public interface Page {
37
38         /**
39          * Returns the path of this toadlet.
40          * 
41          * @return The path of this toadlet
42          */
43         public String getPath();
44
45         /**
46          * Handles a request.
47          * 
48          * @param request
49          *            The request to handle
50          * @return The response
51          */
52         public Response handleRequest(Request request);
53
54         /**
55          * Container for request data.
56          * 
57          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
58          */
59         public class Request {
60
61                 /** The URI that was accessed. */
62                 private final URI uri;
63
64                 /** The HTTP method that was used. */
65                 private final String method;
66
67                 /** The HTTP request. */
68                 private final HTTPRequest httpRequest;
69
70                 /** The toadlet context. */
71                 private final ToadletContext toadletContext;
72
73                 /**
74                  * Creates a new request that holds the given data.
75                  * 
76                  * @param uri
77                  *            The URI of the request
78                  * @param method
79                  *            The HTTP method of the request
80                  * @param httpRequest
81                  *            The HTTP request
82                  * @param toadletContext
83                  *            The toadlet context of the request
84                  */
85                 public Request(URI uri, String method, HTTPRequest httpRequest, ToadletContext toadletContext) {
86                         this.uri = uri;
87                         this.method = method;
88                         this.httpRequest = httpRequest;
89                         this.toadletContext = toadletContext;
90                 }
91
92                 /**
93                  * Returns the URI that was accessed.
94                  * 
95                  * @return The accessed URI
96                  */
97                 public URI getURI() {
98                         return uri;
99                 }
100
101                 /**
102                  * Returns the HTTP method that was used to access the page.
103                  * 
104                  * @return The HTTP method
105                  */
106                 public String getMethod() {
107                         return method;
108                 }
109
110                 /**
111                  * Returns the HTTP request.
112                  * 
113                  * @return The HTTP request
114                  */
115                 public HTTPRequest getHttpRequest() {
116                         return httpRequest;
117                 }
118
119                 /**
120                  * Returns the toadlet context.
121                  * 
122                  * @return The toadlet context
123                  */
124                 public ToadletContext getToadletContext() {
125                         return toadletContext;
126                 }
127
128         }
129
130         /**
131          * Container for the HTTP response of a {@link Page}.
132          * 
133          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
134          */
135         public class Response {
136
137                 /** The HTTP status code of the response. */
138                 private final int statusCode;
139
140                 /** The HTTP status text of the response. */
141                 private final String statusText;
142
143                 /** The content type of the response. */
144                 private final String contentType;
145
146                 /** The headers of the response. */
147                 private final Map<String, String> headers;
148
149                 /** The content of the response body. */
150                 private final InputStream content;
151
152                 /**
153                  * Creates a new response.
154                  * 
155                  * @param statusCode
156                  *            The HTTP status code of the response
157                  * @param statusText
158                  *            The HTTP status text of the response
159                  * @param contentType
160                  *            The content type of the response
161                  * @param text
162                  *            The text in the response body
163                  */
164                 public Response(int statusCode, String statusText, String contentType, String text) {
165                         this(statusCode, statusText, contentType, getBytes(text));
166                 }
167
168                 /**
169                  * Creates a new response.
170                  * 
171                  * @param statusCode
172                  *            The HTTP status code of the response
173                  * @param statusText
174                  *            The HTTP status text of the response
175                  * @param contentType
176                  *            The content type of the response
177                  * @param content
178                  *            The content of the reponse body
179                  */
180                 public Response(int statusCode, String statusText, String contentType, byte[] content) {
181                         this(statusCode, statusText, contentType, null, content);
182                 }
183
184                 /**
185                  * Creates a new response.
186                  * 
187                  * @param statusCode
188                  *            The HTTP status code of the response
189                  * @param statusText
190                  *            The HTTP status text of the response
191                  * @param contentType
192                  *            The content type of the response
193                  * @param headers
194                  *            The headers of the response
195                  */
196                 public Response(int statusCode, String statusText, String contentType, Map<String, String> headers) {
197                         this(statusCode, statusText, contentType, headers, (InputStream) null);
198                 }
199
200                 /**
201                  * Creates a new response.
202                  * 
203                  * @param statusCode
204                  *            The HTTP status code of the response
205                  * @param statusText
206                  *            The HTTP status text of the response
207                  * @param contentType
208                  *            The content type of the response
209                  * @param headers
210                  *            The headers of the response
211                  * @param content
212                  *            The content of the reponse body
213                  */
214                 public Response(int statusCode, String statusText, String contentType, Map<String, String> headers, byte[] content) {
215                         this(statusCode, statusText, contentType, headers, new ByteArrayInputStream(content));
216                 }
217
218                 /**
219                  * Creates a new response.
220                  * 
221                  * @param statusCode
222                  *            The HTTP status code of the response
223                  * @param statusText
224                  *            The HTTP status text of the response
225                  * @param contentType
226                  *            The content type of the response
227                  * @param headers
228                  *            The headers of the response
229                  * @param content
230                  *            The content of the reponse body
231                  */
232                 public Response(int statusCode, String statusText, String contentType, Map<String, String> headers, InputStream content) {
233                         this.statusCode = statusCode;
234                         this.statusText = statusText;
235                         this.contentType = contentType;
236                         this.headers = headers;
237                         this.content = content;
238                 }
239
240                 /**
241                  * Returns the HTTP status code of the response.
242                  * 
243                  * @return The HTTP status code
244                  */
245                 public int getStatusCode() {
246                         return statusCode;
247                 }
248
249                 /**
250                  * Returns the HTTP status text.
251                  * 
252                  * @return The HTTP status text
253                  */
254                 public String getStatusText() {
255                         return statusText;
256                 }
257
258                 /**
259                  * Returns the content type of the response.
260                  * 
261                  * @return The content type of the reponse
262                  */
263                 public String getContentType() {
264                         return contentType;
265                 }
266
267                 /**
268                  * Returns HTTP headers of the response. May be {@code null} if no
269                  * headers are returned.
270                  * 
271                  * @return The response headers, or {@code null} if there are no
272                  *         response headers
273                  */
274                 public Map<String, String> getHeaders() {
275                         return headers;
276                 }
277
278                 /**
279                  * Returns the content of the response body. May be {@code null} if the
280                  * response does not have a body.
281                  * 
282                  * @return The content of the response body
283                  */
284                 public InputStream getContent() {
285                         return content;
286                 }
287
288                 //
289                 // PRIVATE METHODS
290                 //
291
292                 /**
293                  * Returns the UTF-8 representation of the given text.
294                  * 
295                  * @param text
296                  *            The text to encode
297                  * @return The encoded text
298                  */
299                 private static byte[] getBytes(String text) {
300                         try {
301                                 return text.getBytes("UTF-8");
302                         } catch (UnsupportedEncodingException uee1) {
303                                 /* every JVM needs to support UTF-8. */
304                         }
305                         return null;
306                 }
307
308                 /**
309                  * Creates a header map containing a single header.
310                  * 
311                  * @param name
312                  *            The name of the header
313                  * @param value
314                  *            The value of the header
315                  * @return The map containing the single header
316                  */
317                 protected static Map<String, String> createHeader(String name, String value) {
318                         Map<String, String> headers = new HashMap<String, String>();
319                         headers.put(name, value);
320                         return headers;
321                 }
322
323         }
324
325         /**
326          * {@link Response} implementation that performs an HTTP redirect.
327          * 
328          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
329          */
330         public class RedirectResponse extends Response {
331
332                 /**
333                  * Creates a new redirect response to the new location.
334                  * 
335                  * @param newLocation
336                  *            The new location
337                  */
338                 public RedirectResponse(String newLocation) {
339                         this(newLocation, true);
340                 }
341
342                 /**
343                  * Creates a new redirect response to the new location.
344                  * 
345                  * @param newLocation
346                  *            The new location
347                  * @param permanent
348                  *            Whether the redirect should be marked as permanent
349                  */
350                 public RedirectResponse(String newLocation, boolean permanent) {
351                         super(permanent ? 302 : 307, "Redirected", null, createHeader("Location", newLocation));
352                 }
353
354         }
355
356 }