|
1 |
| package photospace.meta; |
|
2 |
| |
|
3 |
| import java.io.*; |
|
4 |
| import java.net.*; |
|
5 |
| import java.text.*; |
|
6 |
| import java.util.*; |
|
7 |
| import org.apache.commons.io.*; |
|
8 |
| import org.apache.commons.logging.*; |
|
9 |
| import org.w3c.tools.jpeg.*; |
|
10 |
| import com.drew.imaging.jpeg.*; |
|
11 |
| import com.drew.metadata.*; |
|
12 |
| import com.drew.metadata.jpeg.*; |
|
13 |
| import com.hp.hpl.jena.rdf.model.*; |
|
14 |
| import photospace.beans.*; |
|
15 |
| import photospace.meta.rdf.*; |
|
16 |
| import photospace.vfs.*; |
|
17 |
| |
|
18 |
| public class PersisterImpl |
|
19 |
| implements java.io.Serializable, Persister |
|
20 |
| { |
|
21 |
| private static final Log log = LogFactory.getLog(PersisterImpl.class); |
|
22 |
| |
|
23 |
| public static final String RDF_EXT = ".rdf"; |
|
24 |
| |
|
25 |
| private FileSystem filesystem; |
|
26 |
| private Translator translator; |
|
27 |
| |
|
28 |
| private boolean storingInJpeg = false; |
|
29 |
| |
|
30 |
4
| public Meta getMeta(String path)
|
|
31 |
| throws IOException, JpegProcessingException, MetadataException, ParseException |
|
32 |
| { |
|
33 |
4
| Meta meta = getMeta(filesystem.getFile(path));
|
|
34 |
4
| meta.setPath(path);
|
|
35 |
4
| return meta;
|
|
36 |
| } |
|
37 |
| |
|
38 |
14
| public Meta getMeta(File file)
|
|
39 |
| throws IOException, JpegProcessingException, MetadataException, ParseException |
|
40 |
| { |
|
41 |
14
| file = getMetaFile(file.getCanonicalFile());
|
|
42 |
| |
|
43 |
14
| Meta meta;
|
|
44 |
| |
|
45 |
14
| try
|
|
46 |
| { |
|
47 |
14
| if (rdfIsInJpeg(file))
|
|
48 |
| { |
|
49 |
0
| Metadata exif = getExif(file);
|
|
50 |
| |
|
51 |
0
| String comments = getRdfComments(exif);
|
|
52 |
| |
|
53 |
0
| if (comments == null)
|
|
54 |
| { |
|
55 |
0
| meta = translator.fromExif(exif);
|
|
56 |
| } |
|
57 |
| else |
|
58 |
| { |
|
59 |
0
| meta = translator.fromRdf(getRdf(comments));
|
|
60 |
0
| if (new Date(file.lastModified()).after(meta.getUpdated()))
|
|
61 |
| { |
|
62 |
0
| Meta fromExif = translator.fromExif(exif);
|
|
63 |
0
| Beans.merge(fromExif, meta);
|
|
64 |
0
| if (!meta.getHasPosition() && fromExif.getHasPosition()) meta.setPosition(fromExif.getPosition());
|
|
65 |
| } |
|
66 |
| } |
|
67 |
| } |
|
68 |
| else |
|
69 |
| { |
|
70 |
14
| Model rdf = getRdfFromFile(file);
|
|
71 |
14
| if (rdf == null)
|
|
72 |
| { |
|
73 |
10
| if (isJpeg(file))
|
|
74 |
| { |
|
75 |
4
| Metadata exif = getExif(file);
|
|
76 |
4
| meta = translator.fromExif(exif);
|
|
77 |
| } |
|
78 |
6
| else if (file.isDirectory())
|
|
79 |
| { |
|
80 |
6
| meta = new FolderMeta();
|
|
81 |
| } |
|
82 |
| else |
|
83 |
| { |
|
84 |
0
| throw new IllegalStateException("Not sure what to do with " + file);
|
|
85 |
| } |
|
86 |
| } |
|
87 |
| else |
|
88 |
| { |
|
89 |
4
| meta = translator.fromRdf(rdf);
|
|
90 |
| } |
|
91 |
| } |
|
92 |
| } |
|
93 |
| catch (MetadataException e) |
|
94 |
| { |
|
95 |
0
| throw new MetadataException("Exception getting EXIF metadata for " + file, e);
|
|
96 |
| } |
|
97 |
| |
|
98 |
14
| meta.setName(file.getName());
|
|
99 |
14
| meta.setPath(getPath(file));
|
|
100 |
| |
|
101 |
14
| return meta;
|
|
102 |
| } |
|
103 |
| |
|
104 |
29
| private File getMetaFile(File file)
|
|
105 |
| { |
|
106 |
29
| if (file.getName().equals("folder" + RDF_EXT))
|
|
107 |
0
| return file.getParentFile();
|
|
108 |
29
| else if (file.getName().endsWith(RDF_EXT))
|
|
109 |
0
| return new File(file.getPath().substring(0, file.getPath().length() - RDF_EXT.length()));
|
|
110 |
| else |
|
111 |
29
| return file;
|
|
112 |
| } |
|
113 |
| |
|
114 |
15
| public String getPath(File file)
|
|
115 |
| { |
|
116 |
15
| return filesystem.getPath(getMetaFile(file));
|
|
117 |
| } |
|
118 |
| |
|
119 |
2
| public void saveMeta(String path, Meta meta)
|
|
120 |
| throws IOException, FileNotFoundException |
|
121 |
| { |
|
122 |
2
| saveMeta(filesystem.getFile(path), meta);
|
|
123 |
| } |
|
124 |
| |
|
125 |
4
| public void saveMeta(File file, Meta meta)
|
|
126 |
| throws IOException, FileNotFoundException |
|
127 |
| { |
|
128 |
4
| meta.setUpdated(new Date());
|
|
129 |
| |
|
130 |
1
| if (meta.getPath() == null) meta.setPath(getPath(file.getAbsoluteFile()));
|
|
131 |
| |
|
132 |
4
| log.info(("Saving " + meta));
|
|
133 |
| |
|
134 |
4
| ByteArrayOutputStream rdf = new ByteArrayOutputStream();
|
|
135 |
4
| translator.toRdf(meta).write(rdf);
|
|
136 |
| |
|
137 |
4
| if (rdfIsInJpeg(file))
|
|
138 |
| { |
|
139 |
0
| saveRdfToJpeg(file, rdf.toString());
|
|
140 |
| } |
|
141 |
| else |
|
142 |
| { |
|
143 |
4
| saveRdfToFile(file, rdf.toString());
|
|
144 |
| } |
|
145 |
| } |
|
146 |
| |
|
147 |
4
| private void saveRdfToFile(File file, String rdf)
|
|
148 |
| throws IOException |
|
149 |
| { |
|
150 |
4
| FileWriter writer = new FileWriter(getRdfFile(file));
|
|
151 |
4
| try
|
|
152 |
| { |
|
153 |
4
| writer.write(rdf);
|
|
154 |
| } |
|
155 |
| finally |
|
156 |
| { |
|
157 |
4
| writer.close();
|
|
158 |
| } |
|
159 |
| } |
|
160 |
| |
|
161 |
0
| private void saveRdfToJpeg(File jpeg, String rdf)
|
|
162 |
| throws IOException |
|
163 |
| { |
|
164 |
0
| writeJpegComment(jpeg, rdf);
|
|
165 |
| |
|
166 |
| } |
|
167 |
| |
|
168 |
0
| public void writeJpegComment(File jpeg, String rdf)
|
|
169 |
| throws IOException |
|
170 |
| { |
|
171 |
0
| ByteArrayOutputStream jpegOS = new ByteArrayOutputStream();
|
|
172 |
0
| JpegCommentWriter jcw = new JpegCommentWriter(jpegOS, new FileInputStream(jpeg));
|
|
173 |
0
| try
|
|
174 |
| { |
|
175 |
0
| jcw.write(rdf);
|
|
176 |
| } |
|
177 |
| finally |
|
178 |
| { |
|
179 |
0
| jcw.close();
|
|
180 |
| } |
|
181 |
| |
|
182 |
0
| FileOutputStream fos = new FileOutputStream(jpeg);
|
|
183 |
0
| try
|
|
184 |
| { |
|
185 |
0
| fos.write(jpegOS.toByteArray());
|
|
186 |
| } |
|
187 |
| finally |
|
188 |
| { |
|
189 |
0
| fos.close();
|
|
190 |
| } |
|
191 |
| } |
|
192 |
| |
|
193 |
21
| private File getRdfFile(File file)
|
|
194 |
| { |
|
195 |
6
| if (file.isDirectory()) return new File(file.getPath(), "folder" + RDF_EXT);
|
|
196 |
| |
|
197 |
0
| if (file.getName().toLowerCase().endsWith(RDF_EXT)) return file;
|
|
198 |
| |
|
199 |
15
| return new File(file.getPath() + RDF_EXT);
|
|
200 |
| } |
|
201 |
| |
|
202 |
8
| public Metadata getExif(File jpeg)
|
|
203 |
| throws FileNotFoundException, IOException, JpegProcessingException |
|
204 |
| { |
|
205 |
8
| InputStream in = new FileInputStream(jpeg);
|
|
206 |
8
| try
|
|
207 |
| { |
|
208 |
8
| return getExif(in);
|
|
209 |
| } |
|
210 |
| finally |
|
211 |
| { |
|
212 |
8
| in.close();
|
|
213 |
| } |
|
214 |
| } |
|
215 |
| |
|
216 |
8
| public Metadata getExif(InputStream in)
|
|
217 |
| throws JpegProcessingException |
|
218 |
| { |
|
219 |
8
| return JpegMetadataReader.readMetadata(in);
|
|
220 |
| } |
|
221 |
| |
|
222 |
0
| public void remove(Meta meta)
|
|
223 |
| throws IOException, JpegProcessingException |
|
224 |
| { |
|
225 |
0
| File file = filesystem.getFile(meta.getPath());
|
|
226 |
| |
|
227 |
0
| removeRdf(file);
|
|
228 |
| |
|
229 |
0
| FileUtils.forceDelete(file);
|
|
230 |
| } |
|
231 |
| |
|
232 |
0
| public void removeRdf(File file)
|
|
233 |
| throws IOException, JpegProcessingException |
|
234 |
| { |
|
235 |
0
| if (rdfIsInJpeg(file))
|
|
236 |
| { |
|
237 |
0
| writeJpegComment(file, "");
|
|
238 |
| } |
|
239 |
| else |
|
240 |
| { |
|
241 |
0
| File rdf = getRdfFile(file);
|
|
242 |
0
| if (rdf.exists()) FileUtils.forceDelete(rdf);
|
|
243 |
| } |
|
244 |
| } |
|
245 |
| |
|
246 |
3
| public Model getRdf(File file)
|
|
247 |
| throws IOException, JpegProcessingException |
|
248 |
| { |
|
249 |
3
| if (rdfIsInJpeg(file))
|
|
250 |
| { |
|
251 |
0
| return getRdfFromJpeg(file);
|
|
252 |
| } |
|
253 |
| else |
|
254 |
| { |
|
255 |
3
| return getRdfFromFile(file);
|
|
256 |
| } |
|
257 |
| } |
|
258 |
| |
|
259 |
17
| private Model getRdfFromFile(File file)
|
|
260 |
| throws MalformedURLException |
|
261 |
| { |
|
262 |
17
| File rdfFile = getRdfFile(file);
|
|
263 |
12
| if (!rdfFile.exists()) return null;
|
|
264 |
5
| Model rdf = ModelFactory.createDefaultModel();
|
|
265 |
5
| rdf.read(rdfFile.toURL().toString());
|
|
266 |
5
| return rdf;
|
|
267 |
| } |
|
268 |
| |
|
269 |
0
| private Model getRdfFromJpeg(File jpeg)
|
|
270 |
| throws JpegProcessingException, IOException |
|
271 |
| { |
|
272 |
0
| InputStream in = new FileInputStream(jpeg);
|
|
273 |
0
| Metadata exif;
|
|
274 |
0
| try
|
|
275 |
| { |
|
276 |
0
| exif = getExif(in);
|
|
277 |
| } |
|
278 |
| finally |
|
279 |
| { |
|
280 |
0
| in.close();
|
|
281 |
| } |
|
282 |
| |
|
283 |
0
| String comments = getRdfComments(exif);
|
|
284 |
0
| if (comments == null) return null;
|
|
285 |
| |
|
286 |
0
| return getRdf(comments);
|
|
287 |
| } |
|
288 |
| |
|
289 |
21
| private boolean rdfIsInJpeg(File file)
|
|
290 |
| { |
|
291 |
21
| return isStoringInJpeg() && isJpeg(file);
|
|
292 |
| } |
|
293 |
| |
|
294 |
10
| private boolean isJpeg(File file)
|
|
295 |
| { |
|
296 |
10
| return file.getName().toLowerCase().endsWith(".jpg")
|
|
297 |
| || file.getName().toLowerCase().endsWith(".jpeg"); |
|
298 |
| } |
|
299 |
| |
|
300 |
0
| private String getRdfComments(Metadata exif)
|
|
301 |
| { |
|
302 |
0
| return RdfTools.getRdfString(exif.getDirectory(JpegCommentDirectory.class).getString(JpegCommentDirectory.TAG_JPEG_COMMENT));
|
|
303 |
| } |
|
304 |
| |
|
305 |
0
| private Model getRdf(String str)
|
|
306 |
| { |
|
307 |
0
| Model rdf = ModelFactory.createDefaultModel();
|
|
308 |
0
| rdf.read(new StringReader(str), "");
|
|
309 |
0
| return rdf;
|
|
310 |
| } |
|
311 |
| |
|
312 |
21
| private boolean isStoringInJpeg()
|
|
313 |
| { |
|
314 |
21
| return storingInJpeg;
|
|
315 |
| } |
|
316 |
| |
|
317 |
2
| public void setStoringInJpeg(boolean storingInJpeg)
|
|
318 |
| { |
|
319 |
2
| this.storingInJpeg = storingInJpeg;
|
|
320 |
| } |
|
321 |
| |
|
322 |
7
| public void setFilesystem(FileSystem filesystem)
|
|
323 |
| { |
|
324 |
7
| this.filesystem = filesystem;
|
|
325 |
| } |
|
326 |
| |
|
327 |
8
| public void setTranslator(Translator translator)
|
|
328 |
| { |
|
329 |
8
| this.translator = translator;
|
|
330 |
| } |
|
331 |
| |
|
332 |
| } |