c103b689e649c11f1674a27a5be788e2429a6923
[meviz.git] / src / main / java / eu / svjatoslav / meviz / htmlindexer / FilesystemIndexer.java
1 /*
2  * Meviz - Various tools collection to work with multimedia.
3  * Copyright (C) 2012, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU General Public License
7  * as published by the Free Software Foundation.
8  */
9
10 package eu.svjatoslav.meviz.htmlindexer;
11
12 import java.io.BufferedReader;
13 import java.io.File;
14 import java.io.FileNotFoundException;
15 import java.io.FileReader;
16 import java.io.IOException;
17 import java.io.UnsupportedEncodingException;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.List;
21
22 import org.apache.log4j.Logger;
23
24 import eu.svjatoslav.commons.file.IOHelper;
25 import eu.svjatoslav.commons.network.UrlParamEncoder;
26 import eu.svjatoslav.meviz.htmlindexer.layouts.MixedLayout;
27 import eu.svjatoslav.meviz.htmlindexer.metadata.Dimension;
28 import eu.svjatoslav.meviz.htmlindexer.metadata.DirectoryMetadata;
29 import eu.svjatoslav.meviz.htmlindexer.metadata.MetadadaHelper;
30 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.AbstractFile;
31 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.DirectoryFile;
32 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.GeneralFile;
33 import eu.svjatoslav.meviz.htmlindexer.metadata.fileTypes.Picture;
34
35 /**
36  * Main class of HTML indexer.
37  */
38
39 public class FilesystemIndexer extends AbstractIndexer {
40
41         public static final Logger logger = Logger
42                         .getLogger(FilesystemIndexer.class);
43
44         private final HashSet<String> validMetadataFiles = new HashSet<String>();
45
46         private final File directoryToIndex;
47
48         private String thumbnailsPath;
49
50         private File metadataFile;
51
52         private DirectoryMetadata metadata;
53
54         private final IndexingOptions indexingOptions;
55
56         private final List<String> pathElements;
57
58         private HashSet<Layout> layouts;
59
60         public FilesystemIndexer(final File directoryToIndex,
61                         final IndexingOptions indexingOptions,
62                         final List<String> pathElements) throws IOException,
63                         ImageFormatError {
64
65                 this.directoryToIndex = directoryToIndex;
66                 this.indexingOptions = indexingOptions;
67                 this.pathElements = pathElements;
68
69                 if (!directoryToIndex.canRead())
70                         return;
71
72                 validMetadataFiles.add(Constants.METADATA_FILE_NAME);
73
74                 initializeThumbnailsDirectory();
75                 loadOrCreateMetadata();
76
77                 initializeLayouts();
78
79                 updateMetadata();
80
81                 metadata.removeUnusedMetadataEntries();
82
83                 generateHtmlFromMetadata(layouts);
84
85                 removeUnusedThumbnailFiles();
86
87                 // save directory metadata
88                 if (metadata.changed)
89                         MetadadaHelper.saveDirectoryMetadata(metadataFile, metadata);
90
91         }
92
93         public boolean canWriteIndexFile(final File indexFile)
94                         throws FileNotFoundException, IOException {
95                 boolean canWriteIndexFile = false;
96
97                 if (indexFile.exists()) {
98                         // if file already exists, make sure that we can overwrite
99                         // it
100                         final FileReader fileReader = new FileReader(indexFile);
101                         final BufferedReader reader = new BufferedReader(fileReader);
102
103                         parseFile: {
104                                 while (true) {
105                                         final String line = reader.readLine();
106
107                                         if (line == null)
108                                                 break parseFile;
109
110                                         if (line.contains(Constants.HTML_MAGIC_STRING)) {
111                                                 canWriteIndexFile = true;
112                                                 break parseFile;
113                                         }
114                                 }
115                         }
116
117                         reader.close();
118                         fileReader.close();
119                 } else
120                         canWriteIndexFile = true;
121                 return canWriteIndexFile;
122         }
123
124         public void cleanupUnusedMetadataFiles() {
125                 final File thumbnailsDirectory = new File(thumbnailsPath);
126
127                 for (final File file : thumbnailsDirectory.listFiles())
128                         if (!validMetadataFiles.contains(file.getName()))
129                                 file.delete();
130         }
131
132         public void generateHtmlFromMetadata(final HashSet<Layout> layouts) {
133                 // Generate HTML from metadata
134                 for (final Layout layout : layouts) {
135
136                         final String indexFilePath = directoryToIndex.getAbsolutePath()
137                                         + "/index" + layout.getFileNameSuffix() + ".html";
138
139                         try {
140
141                                 final File indexFile = new File(indexFilePath);
142                                 if (canWriteIndexFile(indexFile)) {
143
144                                         indexForLayout(layout);
145
146                                         IOHelper.overwriteFileIfContentDiffers(indexFile, layout
147                                                         .getHtml(true, true).getBytes());
148                                 }
149                         } catch (final Exception e) {
150                                 logger.error("Error writing index file to:" + indexFilePath, e);
151                         }
152                 }
153         }
154
155         public List<String> getChildPath(final File file) {
156
157                 final List<String> result = new ArrayList<String>();
158                 result.addAll(pathElements);
159                 result.add(file.getName());
160
161                 return result;
162         }
163
164         @Override
165         public String getDirectoryUrl(final AbstractFile directory,
166                         final IndexingContext context) {
167                 return directory.fileName + "/index.html";
168         }
169
170         @Override
171         public String getParentDirectoryUrl(final IndexingContext context) {
172                 return "../index.html";
173         }
174
175         @Override
176         public String getThumbnailUrl(final Picture picture,
177                         final Dimension desiredDimension, final IndexingContext context) {
178
179                 // in case thumbnail size was equal to original, then return original
180                 // file path
181                 if (picture.getDimensions().equals(desiredDimension))
182                         return picture.fileName;
183
184                 final String thumbnailFileName = picture
185                                 .getRelativeThumbnailFileName(desiredDimension);
186
187                 validMetadataFiles.add(thumbnailFileName);
188                 final File thumbnailFile = new File(thumbnailsPath + thumbnailFileName);
189
190                 if (!thumbnailFile.exists()) {
191
192                         final File originalFile = new File(
193                                         directoryToIndex.getAbsolutePath() + "/" + picture.fileName);
194
195                         // generate new thumbnail
196                         Picture.makeThumbnail(originalFile, thumbnailFile,
197                                         desiredDimension.getAwtDimension());
198                 }
199                 return Constants.THUMBNAILS_DIRECTORY_NAME + "/"
200                                 + UrlParamEncoder.encode(thumbnailFileName);
201         }
202
203         public void indexForLayout(final Layout layout)
204                         throws UnsupportedEncodingException {
205
206                 for (final AbstractFile abstractFile : metadata.getFiles())
207                         if (abstractFile instanceof GeneralFile) {
208
209                                 if (isOgv(abstractFile.getFileExtension()))
210                                         layout.enlistOgv(abstractFile);
211                                 else
212                                         layout.enlistFile(abstractFile);
213
214                         } else if (abstractFile instanceof Picture)
215                                 layout.enlistImage(abstractFile);
216                         else if (abstractFile instanceof DirectoryFile)
217                                 layout.enlistDirectory(abstractFile);
218
219         }
220
221         public void initializeLayouts() {
222                 layouts = new HashSet<Layout>();
223                 layouts.add(new MixedLayout());
224
225                 for (final Layout layout : layouts)
226                         layout.init(indexingOptions.galleryTitle, pathElements, this,
227                                         new IndexingContext("", "."));
228         }
229
230         public void initializeThumbnailsDirectory() {
231                 // initialize thumbnails directory
232                 thumbnailsPath = directoryToIndex.getAbsolutePath() + "/"
233                                 + Constants.THUMBNAILS_DIRECTORY_NAME + "/";
234
235                 // ensure thumbnails directory exists
236                 final File thumbnailsDirectory = new File(thumbnailsPath);
237                 if (!thumbnailsDirectory.exists())
238                         thumbnailsDirectory.mkdirs();
239         }
240
241         public void loadOrCreateMetadata() {
242                 metadataFile = new File(thumbnailsPath + Constants.METADATA_FILE_NAME);
243
244                 metadata = MetadadaHelper.initDirectoryMetadata(metadataFile);
245         }
246
247         private void removeUnusedThumbnailFiles() {
248
249                 final File thumbnailsDirectory = new File(thumbnailsPath);
250
251                 for (final File file : thumbnailsDirectory.listFiles())
252                         if (!validMetadataFiles.contains(file.getName()))
253                                 file.delete();
254
255         }
256
257         public void updateMetadata() throws IOException, ImageFormatError {
258
259                 final File[] directoryContent = directoryToIndex.listFiles();
260
261                 for (final File file : directoryContent)
262                         if (shallFileBeIndexed(file)) {
263
264                                 metadata.ensureFileMetainfoIsUpToDate(directoryToIndex, file);
265
266                                 if (file.isDirectory())
267                                         new FilesystemIndexer(file, indexingOptions,
268                                                         getChildPath(file));
269                         }
270         }
271 }