Deep copy all file options when cloning project
[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                 for (Entry<String, FileOption> fileOption : fileOptions.entrySet()) {
98                         fileOptions.put(fileOption.getKey(), new FileOption(fileOption.getValue()));
99                 }
100         }
101
102         /**
103          * Returns the name of the project.
104          *
105          * @return The name of the project
106          */
107         public String getName() {
108                 return name;
109         }
110
111         /**
112          * Sets the name of the project.
113          *
114          * @param name
115          *            The name of the project
116          */
117         public void setName(String name) {
118                 this.name = name;
119         }
120
121         /**
122          * Returns the description of the project.
123          *
124          * @return The description of the project
125          */
126         public String getDescription() {
127                 return description;
128         }
129
130         /**
131          * Sets the description of the project.
132          *
133          * @param description
134          *            The description of the project
135          */
136         public void setDescription(String description) {
137                 this.description = description;
138         }
139
140         /**
141          * Returns the local path of the project.
142          *
143          * @return The local path of the project
144          */
145         public String getLocalPath() {
146                 return localPath;
147         }
148
149         /**
150          * Sets the local path of the project.
151          *
152          * @param localPath
153          *            The local path of the project
154          */
155         public void setLocalPath(String localPath) {
156                 this.localPath = localPath;
157         }
158
159         /**
160          * Returns the name of the index file of the project, relative to the
161          * project’s local path.
162          *
163          * @return The name of the index file of the project
164          */
165         public String getIndexFile() {
166                 return indexFile;
167         }
168
169         /**
170          * Sets the name of the index file of the project, relative to the project’s
171          * local path.
172          *
173          * @param indexFile
174          *            The name of the index file of the project
175          */
176         public void setIndexFile(String indexFile) {
177                 this.indexFile = indexFile;
178         }
179
180         /**
181          * Returns the time the project was last inserted, in milliseconds since the
182          * epoch.
183          *
184          * @return The time of the last insertion
185          */
186         public long getLastInsertionTime() {
187                 return lastInsertionTime;
188         }
189
190         /**
191          * Sets the time the project was last inserted, in milliseconds since the
192          * last epoch.
193          *
194          * @param lastInserted
195          *            The time of the last insertion
196          */
197         public void setLastInsertionTime(long lastInserted) {
198                 lastInsertionTime = lastInserted;
199         }
200
201         /**
202          * Returns the remote path of the project. The remote path is the path that
203          * directly follows the request URI of the project.
204          *
205          * @return The remote path of the project
206          */
207         public String getPath() {
208                 return path;
209         }
210
211         /**
212          * Sets the remote path of the project. The remote path is the path that
213          * directly follows the request URI of the project.
214          *
215          * @param path
216          *            The remote path of the project
217          */
218         public void setPath(String path) {
219                 this.path = path;
220         }
221
222         /**
223          * Returns the insert URI of the project.
224          *
225          * @return The insert URI of the project
226          */
227         public String getInsertURI() {
228                 return insertURI;
229         }
230
231         /**
232          * Sets the insert URI of the project.
233          *
234          * @param insertURI
235          *            The insert URI of the project
236          */
237         public void setInsertURI(String insertURI) {
238                 this.insertURI = shortenURI(insertURI);
239         }
240
241         /**
242          * Returns the request URI of the project.
243          *
244          * @return The request URI of the project
245          */
246         public String getRequestURI() {
247                 return requestURI;
248         }
249
250         /**
251          * Sets the request URI of the project.
252          *
253          * @param requestURI
254          *            The request URI of the project
255          */
256         public void setRequestURI(String requestURI) {
257                 this.requestURI = shortenURI(requestURI);
258         }
259
260         /**
261          * Returns whether files for this project should always be inserted, even
262          * when unchanged.
263          *
264          * @return {@code true} to always force inserts on this project,
265          *         {@code false} otherwise
266          */
267         public boolean isAlwaysForceInsert() {
268                 return alwaysForceInserts;
269         }
270
271         /**
272          * Sets whether files for this project should always be inserted, even when
273          * unchanged.
274          *
275          * @param alwaysForceInsert
276          *            {@code true} to always force inserts on this project,
277          *            {@code false} otherwise
278          */
279         public void setAlwaysForceInsert(boolean alwaysForceInsert) {
280                 this.alwaysForceInserts = alwaysForceInsert;
281         }
282
283         /**
284          * Returns whether hidden files are ignored, i.e. not inserted.
285          *
286          * @return {@code true} if hidden files are not inserted, {@code false}
287          *         otherwise
288          */
289         public boolean isIgnoreHiddenFiles() {
290                 return ignoreHiddenFiles;
291         }
292
293         /**
294          * Sets whether hidden files are ignored, i.e. not inserted.
295          *
296          * @param ignoreHiddenFiles
297          *            {@code true} if hidden files are not inserted, {@code false}
298          *            otherwise
299          */
300         public void setIgnoreHiddenFiles(boolean ignoreHiddenFiles) {
301                 this.ignoreHiddenFiles = ignoreHiddenFiles;
302         }
303
304         /**
305          * {@inheritDoc}
306          * <p>
307          * This method returns the name of the project.
308          */
309         @Override
310         public String toString() {
311                 return name;
312         }
313
314         /**
315          * Shortens the given URI by removing scheme and key-type prefixes.
316          *
317          * @param uri
318          *            The URI to shorten
319          * @return The shortened URI
320          */
321         private static String shortenURI(String uri) {
322                 String shortUri = uri;
323                 if (shortUri.startsWith("freenet:")) {
324                         shortUri = shortUri.substring("freenet:".length());
325                 }
326                 if (shortUri.startsWith("SSK@")) {
327                         shortUri = shortUri.substring("SSK@".length());
328                 }
329                 if (shortUri.startsWith("USK@")) {
330                         shortUri = shortUri.substring("USK@".length());
331                 }
332                 if (shortUri.endsWith("/")) {
333                         shortUri = shortUri.substring(0, shortUri.length() - 1);
334                 }
335                 return shortUri;
336         }
337
338         /**
339          * Shortens the name of the given file by removing the local path of the
340          * project and leading file separators.
341          *
342          * @param file
343          *            The file whose name should be shortened
344          * @return The shortened name of the file
345          */
346         public String shortenFilename(File file) {
347                 String filename = file.getPath();
348                 if (filename.startsWith(localPath)) {
349                         filename = filename.substring(localPath.length());
350                         if (filename.startsWith(File.separator)) {
351                                 filename = filename.substring(1);
352                         }
353                 }
354                 return filename;
355         }
356
357         /**
358          * Returns the options for the file with the given name. If the file does
359          * not yet have any options, a new set of default options is created and
360          * returned.
361          *
362          * @param filename
363          *            The name of the file, relative to the project root
364          * @return The options for the file
365          */
366         public FileOption getFileOption(String filename) {
367                 FileOption fileOption = fileOptions.get(filename);
368                 if (fileOption == null) {
369                         fileOption = new FileOption(MimeTypes.getMimeType(filename.substring(filename.lastIndexOf('.') + 1)));
370                         fileOptions.put(filename, fileOption);
371                 }
372                 return fileOption;
373         }
374
375         /**
376          * Sets options for a file.
377          *
378          * @param filename
379          *            The filename to set the options for, relative to the project
380          *            root
381          * @param fileOption
382          *            The options to set for the file, or <code>null</code> to
383          *            remove the options for the file
384          */
385         public void setFileOption(String filename, FileOption fileOption) {
386                 if (fileOption != null) {
387                         fileOptions.put(filename, fileOption);
388                 } else {
389                         fileOptions.remove(filename);
390                 }
391         }
392
393         /**
394          * Returns all file options.
395          *
396          * @return All file options
397          */
398         public Map<String, FileOption> getFileOptions() {
399                 return Collections.unmodifiableMap(fileOptions);
400         }
401
402         /**
403          * Sets all file options.
404          *
405          * @param fileOptions
406          *            The file options
407          */
408         public void setFileOptions(Map<String, FileOption> fileOptions) {
409                 this.fileOptions.clear();
410                 this.fileOptions.putAll(fileOptions);
411         }
412
413         /**
414          * {@inheritDoc}
415          * <p>
416          * Projects are compared by their name only.
417          */
418         @Override
419         public int compareTo(Project project) {
420                 return name.compareToIgnoreCase(project.name);
421         }
422
423         /**
424          * Returns the edition of the project.
425          *
426          * @return The edition of the project
427          */
428         public int getEdition() {
429                 return edition;
430         }
431
432         /**
433          * Sets the edition of the project.
434          *
435          * @param edition
436          *            The edition to set
437          */
438         public void setEdition(int edition) {
439                 this.edition = edition;
440         }
441
442         /**
443          * Constructs the final request URI including the edition number.
444          *
445          * @param offset
446          *            The offset for the edition number
447          * @return The final request URI
448          */
449         public String getFinalRequestURI(int offset) {
450                 return "USK@" + requestURI + "/" + path + "/" + (edition + offset) + "/";
451         }
452
453         /**
454          * Performs some post-processing on the project after it was inserted
455          * successfully. At the moment it copies the current hashes of all file
456          * options to the last insert hashes, updating the hashes for the next
457          * insert.
458          */
459         public void onSuccessfulInsert() {
460                 for (Entry<String, FileOption> fileOptionEntry : fileOptions.entrySet()) {
461                         FileOption fileOption = fileOptionEntry.getValue();
462                         if ((fileOption.getCurrentHash() != null) && (fileOption.getCurrentHash().length() > 0) && (!fileOption.getCurrentHash().equals(fileOption.getLastInsertHash()) || fileOption.isForceInsert())) {
463                                 fileOption.setLastInsertEdition(edition);
464                                 fileOption.setLastInsertHash(fileOption.getCurrentHash());
465                                 fileOption.setLastInsertFilename(fileOption.getChangedName().or(fileOptionEntry.getKey()));
466                         }
467                         fileOption.setForceInsert(false);
468                 }
469         }
470
471 }