836a2cd115f292370a2e443c5daea2f1f7260322
[jSite.git] / src / main / java / de / todesbaum / jsite / application / Project.java
1 /*
2  * jSite - Project.java - Copyright © 2006–2014 David Roden
3  *
4  * This program is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free Software
6  * Foundation; either version 2 of the License, or (at your option) any later
7  * version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16  * Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 package de.todesbaum.jsite.application;
20
21 import java.io.File;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Map.Entry;
26
27 import net.pterodactylus.util.io.MimeTypes;
28
29 /**
30  * Container for project information.
31  *
32  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
33  */
34 public class Project implements Comparable<Project> {
35
36         /** The name of the project. */
37         protected String name;
38
39         /** The description of the project. */
40         protected String description;
41
42         /** The insert URI of the project. */
43         protected String insertURI;
44
45         /** The request URI of the project. */
46         protected String requestURI;
47
48         /** The index file of the project. */
49         protected String indexFile;
50
51         /** The local path of the project. */
52         protected String localPath;
53
54         /** The remote path of the URI. */
55         protected String path;
56
57         /** The time of the last insertion. */
58         protected long lastInsertionTime;
59
60         /** The edition to insert to. */
61         protected int edition;
62
63         /** Whether to always force inserts. */
64         private boolean alwaysForceInserts;
65
66         /** Whether to ignore hidden directory. */
67         private boolean ignoreHiddenFiles;
68
69         /** Options for files. */
70         protected Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
71
72         /**
73          * Empty constructor.
74          */
75         public Project() {
76                 /* do nothing. */
77         }
78
79         /**
80          * Creates a new project from an existing one.
81          *
82          * @param project
83          *            The project to clone
84          */
85         public Project(Project project) {
86                 name = project.name;
87                 description = project.description;
88                 insertURI = project.insertURI;
89                 requestURI = project.requestURI;
90                 path = project.path;
91                 edition = project.edition;
92                 localPath = project.localPath;
93                 indexFile = project.indexFile;
94                 lastInsertionTime = project.lastInsertionTime;
95                 alwaysForceInserts = project.alwaysForceInserts;
96                 ignoreHiddenFiles = project.ignoreHiddenFiles;
97                 fileOptions = new HashMap<String, FileOption>(project.fileOptions);
98         }
99
100         /**
101          * Returns the name of the project.
102          *
103          * @return The name of the project
104          */
105         public String getName() {
106                 return name;
107         }
108
109         /**
110          * Sets the name of the project.
111          *
112          * @param name
113          *            The name of the project
114          */
115         public void setName(String name) {
116                 this.name = name;
117         }
118
119         /**
120          * Returns the description of the project.
121          *
122          * @return The description of the project
123          */
124         public String getDescription() {
125                 return description;
126         }
127
128         /**
129          * Sets the description of the project.
130          *
131          * @param description
132          *            The description of the project
133          */
134         public void setDescription(String description) {
135                 this.description = description;
136         }
137
138         /**
139          * Returns the local path of the project.
140          *
141          * @return The local path of the project
142          */
143         public String getLocalPath() {
144                 return localPath;
145         }
146
147         /**
148          * Sets the local path of the project.
149          *
150          * @param localPath
151          *            The local path of the project
152          */
153         public void setLocalPath(String localPath) {
154                 this.localPath = localPath;
155         }
156
157         /**
158          * Returns the name of the index file of the project, relative to the
159          * project’s local path.
160          *
161          * @return The name of the index file of the project
162          */
163         public String getIndexFile() {
164                 return indexFile;
165         }
166
167         /**
168          * Sets the name of the index file of the project, relative to the project’s
169          * local path.
170          *
171          * @param indexFile
172          *            The name of the index file of the project
173          */
174         public void setIndexFile(String indexFile) {
175                 this.indexFile = indexFile;
176         }
177
178         /**
179          * Returns the time the project was last inserted, in milliseconds since the
180          * epoch.
181          *
182          * @return The time of the last insertion
183          */
184         public long getLastInsertionTime() {
185                 return lastInsertionTime;
186         }
187
188         /**
189          * Sets the time the project was last inserted, in milliseconds since the
190          * last epoch.
191          *
192          * @param lastInserted
193          *            The time of the last insertion
194          */
195         public void setLastInsertionTime(long lastInserted) {
196                 lastInsertionTime = lastInserted;
197         }
198
199         /**
200          * Returns the remote path of the project. The remote path is the path that
201          * directly follows the request URI of the project.
202          *
203          * @return The remote path of the project
204          */
205         public String getPath() {
206                 return path;
207         }
208
209         /**
210          * Sets the remote path of the project. The remote path is the path that
211          * directly follows the request URI of the project.
212          *
213          * @param path
214          *            The remote path of the project
215          */
216         public void setPath(String path) {
217                 this.path = path;
218         }
219
220         /**
221          * Returns the insert URI of the project.
222          *
223          * @return The insert URI of the project
224          */
225         public String getInsertURI() {
226                 return insertURI;
227         }
228
229         /**
230          * Sets the insert URI of the project.
231          *
232          * @param insertURI
233          *            The insert URI of the project
234          */
235         public void setInsertURI(String insertURI) {
236                 this.insertURI = shortenURI(insertURI);
237         }
238
239         /**
240          * Returns the request URI of the project.
241          *
242          * @return The request URI of the project
243          */
244         public String getRequestURI() {
245                 return requestURI;
246         }
247
248         /**
249          * Sets the request URI of the project.
250          *
251          * @param requestURI
252          *            The request URI of the project
253          */
254         public void setRequestURI(String requestURI) {
255                 this.requestURI = shortenURI(requestURI);
256         }
257
258         /**
259          * Returns whether files for this project should always be inserted, even
260          * when unchanged.
261          *
262          * @return {@code true} to always force inserts on this project,
263          *         {@code false} otherwise
264          */
265         public boolean isAlwaysForceInsert() {
266                 return alwaysForceInserts;
267         }
268
269         /**
270          * Sets whether files for this project should always be inserted, even when
271          * unchanged.
272          *
273          * @param alwaysForceInsert
274          *            {@code true} to always force inserts on this project,
275          *            {@code false} otherwise
276          */
277         public void setAlwaysForceInsert(boolean alwaysForceInsert) {
278                 this.alwaysForceInserts = alwaysForceInsert;
279         }
280
281         /**
282          * Returns whether hidden files are ignored, i.e. not inserted.
283          *
284          * @return {@code true} if hidden files are not inserted, {@code false}
285          *         otherwise
286          */
287         public boolean isIgnoreHiddenFiles() {
288                 return ignoreHiddenFiles;
289         }
290
291         /**
292          * Sets whether hidden files are ignored, i.e. not inserted.
293          *
294          * @param ignoreHiddenFiles
295          *            {@code true} if hidden files are not inserted, {@code false}
296          *            otherwise
297          */
298         public void setIgnoreHiddenFiles(boolean ignoreHiddenFiles) {
299                 this.ignoreHiddenFiles = ignoreHiddenFiles;
300         }
301
302         /**
303          * {@inheritDoc}
304          * <p>
305          * This method returns the name of the project.
306          */
307         @Override
308         public String toString() {
309                 return name;
310         }
311
312         /**
313          * Shortens the given URI by removing scheme and key-type prefixes.
314          *
315          * @param uri
316          *            The URI to shorten
317          * @return The shortened URI
318          */
319         private static String shortenURI(String uri) {
320                 String shortUri = uri;
321                 if (shortUri.startsWith("freenet:")) {
322                         shortUri = shortUri.substring("freenet:".length());
323                 }
324                 if (shortUri.startsWith("SSK@")) {
325                         shortUri = shortUri.substring("SSK@".length());
326                 }
327                 if (shortUri.startsWith("USK@")) {
328                         shortUri = shortUri.substring("USK@".length());
329                 }
330                 if (shortUri.endsWith("/")) {
331                         shortUri = shortUri.substring(0, shortUri.length() - 1);
332                 }
333                 return shortUri;
334         }
335
336         /**
337          * Shortens the name of the given file by removing the local path of the
338          * project and leading file separators.
339          *
340          * @param file
341          *            The file whose name should be shortened
342          * @return The shortened name of the file
343          */
344         public String shortenFilename(File file) {
345                 String filename = file.getPath();
346                 if (filename.startsWith(localPath)) {
347                         filename = filename.substring(localPath.length());
348                         if (filename.startsWith(File.separator)) {
349                                 filename = filename.substring(1);
350                         }
351                 }
352                 return filename;
353         }
354
355         /**
356          * Returns the options for the file with the given name. If the file does
357          * not yet have any options, a new set of default options is created and
358          * returned.
359          *
360          * @param filename
361          *            The name of the file, relative to the project root
362          * @return The options for the file
363          */
364         public FileOption getFileOption(String filename) {
365                 FileOption fileOption = fileOptions.get(filename);
366                 if (fileOption == null) {
367                         fileOption = new FileOption(MimeTypes.getMimeType(filename.substring(filename.lastIndexOf('.') + 1)));
368                         fileOptions.put(filename, fileOption);
369                 }
370                 return fileOption;
371         }
372
373         /**
374          * Sets options for a file.
375          *
376          * @param filename
377          *            The filename to set the options for, relative to the project
378          *            root
379          * @param fileOption
380          *            The options to set for the file, or <code>null</code> to
381          *            remove the options for the file
382          */
383         public void setFileOption(String filename, FileOption fileOption) {
384                 if (fileOption != null) {
385                         fileOptions.put(filename, fileOption);
386                 } else {
387                         fileOptions.remove(filename);
388                 }
389         }
390
391         /**
392          * Returns all file options.
393          *
394          * @return All file options
395          */
396         public Map<String, FileOption> getFileOptions() {
397                 return Collections.unmodifiableMap(fileOptions);
398         }
399
400         /**
401          * Sets all file options.
402          *
403          * @param fileOptions
404          *            The file options
405          */
406         public void setFileOptions(Map<String, FileOption> fileOptions) {
407                 this.fileOptions.clear();
408                 this.fileOptions.putAll(fileOptions);
409         }
410
411         /**
412          * {@inheritDoc}
413          * <p>
414          * Projects are compared by their name only.
415          */
416         @Override
417         public int compareTo(Project project) {
418                 return name.compareToIgnoreCase(project.name);
419         }
420
421         /**
422          * Returns the edition of the project.
423          *
424          * @return The edition of the project
425          */
426         public int getEdition() {
427                 return edition;
428         }
429
430         /**
431          * Sets the edition of the project.
432          *
433          * @param edition
434          *            The edition to set
435          */
436         public void setEdition(int edition) {
437                 this.edition = edition;
438         }
439
440         /**
441          * Constructs the final request URI including the edition number.
442          *
443          * @param offset
444          *            The offset for the edition number
445          * @return The final request URI
446          */
447         public String getFinalRequestURI(int offset) {
448                 return "USK@" + requestURI + "/" + path + "/" + (edition + offset) + "/";
449         }
450
451         /**
452          * Performs some post-processing on the project after it was inserted
453          * successfully. At the moment it copies the current hashes of all file
454          * options to the last insert hashes, updating the hashes for the next
455          * insert.
456          */
457         public void onSuccessfulInsert() {
458                 for (Entry<String, FileOption> fileOptionEntry : fileOptions.entrySet()) {
459                         FileOption fileOption = fileOptionEntry.getValue();
460                         if ((fileOption.getCurrentHash() != null) && (fileOption.getCurrentHash().length() > 0) && (!fileOption.getCurrentHash().equals(fileOption.getLastInsertHash()) || fileOption.isForceInsert())) {
461                                 fileOption.setLastInsertEdition(edition);
462                                 fileOption.setLastInsertHash(fileOption.getCurrentHash());
463                                 fileOption.setLastInsertFilename(fileOption.getChangedName().or(fileOptionEntry.getKey()));
464                         }
465                         fileOption.setForceInsert(false);
466                 }
467         }
468
469 }