2 * jSite - Project.java - Copyright © 2006–2014 David Roden
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
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
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.
19 package de.todesbaum.jsite.application;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
27 import java.util.Map.Entry;
29 import net.pterodactylus.util.io.MimeTypes;
32 * Container for project information.
34 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
36 public class Project implements Comparable<Project> {
38 /** The name of the project. */
39 protected String name;
41 /** The description of the project. */
42 protected String description;
44 /** The insert URI of the project. */
45 protected String insertURI;
47 /** The request URI of the project. */
48 protected String requestURI;
50 /** The index file of the project. */
51 protected String indexFile;
53 /** The local path of the project. */
54 protected String localPath;
56 /** The remote path of the URI. */
57 protected String path;
59 /** The time of the last insertion. */
60 protected long lastInsertionTime;
62 /** The edition to insert to. */
63 protected int edition;
65 /** Whether to always force inserts. */
66 private boolean alwaysForceInserts;
68 /** Whether to ignore hidden directory. */
69 private boolean ignoreHiddenFiles;
71 /** Options for files. */
72 protected Map<String, FileOption> fileOptions = new HashMap<String, FileOption>();
82 * Creates a new project from an existing one.
85 * The project to clone
87 public Project(Project project) {
89 description = project.description;
90 insertURI = project.insertURI;
91 requestURI = project.requestURI;
93 edition = project.edition;
94 localPath = project.localPath;
95 indexFile = project.indexFile;
96 lastInsertionTime = project.lastInsertionTime;
97 alwaysForceInserts = project.alwaysForceInserts;
98 ignoreHiddenFiles = project.ignoreHiddenFiles;
99 for (Entry<String, FileOption> fileOption : fileOptions.entrySet()) {
100 fileOptions.put(fileOption.getKey(), new FileOption(fileOption.getValue()));
105 * Returns the name of the project.
107 * @return The name of the project
109 public String getName() {
114 * Sets the name of the project.
117 * The name of the project
119 public void setName(String name) {
124 * Returns the description of the project.
126 * @return The description of the project
128 public String getDescription() {
133 * Sets the description of the project.
136 * The description of the project
138 public void setDescription(String description) {
139 this.description = description;
143 * Returns the local path of the project.
145 * @return The local path of the project
147 public String getLocalPath() {
152 * Sets the local path of the project.
155 * The local path of the project
157 public void setLocalPath(String localPath) {
158 this.localPath = localPath;
162 * Returns the name of the index file of the project, relative to the
163 * project’s local path.
165 * @return The name of the index file of the project
167 public String getIndexFile() {
172 * Sets the name of the index file of the project, relative to the project’s
176 * The name of the index file of the project
178 public void setIndexFile(String indexFile) {
179 this.indexFile = indexFile;
183 * Returns the time the project was last inserted, in milliseconds since the
186 * @return The time of the last insertion
188 public long getLastInsertionTime() {
189 return lastInsertionTime;
193 * Sets the time the project was last inserted, in milliseconds since the
196 * @param lastInserted
197 * The time of the last insertion
199 public void setLastInsertionTime(long lastInserted) {
200 lastInsertionTime = lastInserted;
204 * Returns the remote path of the project. The remote path is the path that
205 * directly follows the request URI of the project.
207 * @return The remote path of the project
209 public String getPath() {
214 * Sets the remote path of the project. The remote path is the path that
215 * directly follows the request URI of the project.
218 * The remote path of the project
220 public void setPath(String path) {
225 * Returns the insert URI of the project.
227 * @return The insert URI of the project
229 public String getInsertURI() {
234 * Sets the insert URI of the project.
237 * The insert URI of the project
239 public void setInsertURI(String insertURI) {
240 this.insertURI = shortenURI(insertURI);
244 * Returns the request URI of the project.
246 * @return The request URI of the project
248 public String getRequestURI() {
253 * Sets the request URI of the project.
256 * The request URI of the project
258 public void setRequestURI(String requestURI) {
259 this.requestURI = shortenURI(requestURI);
263 * Returns whether files for this project should always be inserted, even
266 * @return {@code true} to always force inserts on this project,
267 * {@code false} otherwise
269 public boolean isAlwaysForceInsert() {
270 return alwaysForceInserts;
274 * Sets whether files for this project should always be inserted, even when
277 * @param alwaysForceInsert
278 * {@code true} to always force inserts on this project,
279 * {@code false} otherwise
281 public void setAlwaysForceInsert(boolean alwaysForceInsert) {
282 this.alwaysForceInserts = alwaysForceInsert;
286 * Returns whether hidden files are ignored, i.e. not inserted.
288 * @return {@code true} if hidden files are not inserted, {@code false}
291 public boolean isIgnoreHiddenFiles() {
292 return ignoreHiddenFiles;
296 * Sets whether hidden files are ignored, i.e. not inserted.
298 * @param ignoreHiddenFiles
299 * {@code true} if hidden files are not inserted, {@code false}
302 public void setIgnoreHiddenFiles(boolean ignoreHiddenFiles) {
303 this.ignoreHiddenFiles = ignoreHiddenFiles;
309 * This method returns the name of the project.
312 public String toString() {
317 * Shortens the given URI by removing scheme and key-type prefixes.
321 * @return The shortened URI
323 private static String shortenURI(String uri) {
324 String shortUri = uri;
325 if (shortUri.startsWith("freenet:")) {
326 shortUri = shortUri.substring("freenet:".length());
328 if (shortUri.startsWith("SSK@")) {
329 shortUri = shortUri.substring("SSK@".length());
331 if (shortUri.startsWith("USK@")) {
332 shortUri = shortUri.substring("USK@".length());
334 if (shortUri.endsWith("/")) {
335 shortUri = shortUri.substring(0, shortUri.length() - 1);
341 * Shortens the name of the given file by removing the local path of the
342 * project and leading file separators.
345 * The file whose name should be shortened
346 * @return The shortened name of the file
348 public String shortenFilename(File file) {
349 String filename = file.getPath();
350 if (filename.startsWith(localPath)) {
351 filename = filename.substring(localPath.length());
352 if (filename.startsWith(File.separator)) {
353 filename = filename.substring(1);
360 * Returns the options for the file with the given name. If the file does
361 * not yet have any options, a new set of default options is created and
365 * The name of the file, relative to the project root
366 * @return The options for the file
368 public FileOption getFileOption(String filename) {
369 FileOption fileOption = fileOptions.get(filename);
370 String defaultMimeType = "application/octet-stream";
371 if (fileOption == null) {
372 List<String> suffixes = getSuffixes(filename);
373 for (String suffix : suffixes) {
374 String mimeType = MimeTypes.getMimeType(suffix);
375 if (!mimeType.equals(defaultMimeType)) {
376 defaultMimeType = mimeType;
380 fileOption = new FileOption(defaultMimeType);
382 fileOptions.put(filename, fileOption);
386 private List<String> getSuffixes(String filename) {
387 List<String> suffixes = new ArrayList<>();
388 int dot = filename.lastIndexOf(".");
390 String suffix = filename.substring(dot + 1);
391 suffixes.add(0, suffix);
392 dot = filename.lastIndexOf(".", dot - 1);
398 * Sets options for a file.
401 * The filename to set the options for, relative to the project
404 * The options to set for the file, or <code>null</code> to
405 * remove the options for the file
407 public void setFileOption(String filename, FileOption fileOption) {
408 if (fileOption != null) {
409 fileOptions.put(filename, fileOption);
411 fileOptions.remove(filename);
416 * Returns all file options.
418 * @return All file options
420 public Map<String, FileOption> getFileOptions() {
421 return Collections.unmodifiableMap(fileOptions);
425 * Sets all file options.
430 public void setFileOptions(Map<String, FileOption> fileOptions) {
431 this.fileOptions.clear();
432 this.fileOptions.putAll(fileOptions);
438 * Projects are compared by their name only.
441 public int compareTo(Project project) {
442 return name.compareToIgnoreCase(project.name);
446 * Returns the edition of the project.
448 * @return The edition of the project
450 public int getEdition() {
455 * Sets the edition of the project.
460 public void setEdition(int edition) {
461 this.edition = edition;
465 * Constructs the final request URI including the edition number.
468 * The offset for the edition number
469 * @return The final request URI
471 public String getFinalRequestURI(int offset) {
472 return "USK@" + requestURI + "/" + path + "/" + (edition + offset) + "/";
476 * Performs some post-processing on the project after it was inserted
477 * successfully. At the moment it copies the current hashes of all file
478 * options to the last insert hashes, updating the hashes for the next
481 public void onSuccessfulInsert() {
482 for (Entry<String, FileOption> fileOptionEntry : fileOptions.entrySet()) {
483 FileOption fileOption = fileOptionEntry.getValue();
484 if ((fileOption.getCurrentHash() != null) && (fileOption.getCurrentHash().length() > 0) && (!fileOption.getCurrentHash().equals(fileOption.getLastInsertHash()) || fileOption.isForceInsert())) {
485 fileOption.setLastInsertEdition(edition);
486 fileOption.setLastInsertHash(fileOption.getCurrentHash());
487 fileOption.setLastInsertFilename(fileOption.getChangedName().orElse(fileOptionEntry.getKey()));
489 fileOption.setForceInsert(false);