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 |
| } |