View Javadoc
1   /******************************************************************************
2    * PicImporterImpl.java - Implement the Picture Importer interface
3    * 
4    * PicMan - The BuckoSoft Picture Manager in Java
5    * Copyright(c) 2005 - Dick Balaska
6    * 
7    */
8   package com.buckosoft.PicMan.business;
9   
10  import java.io.File;
11  import java.text.ParseException;
12  import java.text.SimpleDateFormat;
13  import java.util.Date;
14  import java.util.LinkedList;
15  import java.util.List;
16  
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  import org.dom4j.Document;
20  
21  import com.buckosoft.PicMan.business.util.CopyFile;
22  import com.buckosoft.PicMan.business.util.MD5SumUpdater;
23  import com.buckosoft.PicMan.dom.ImportAnalyzeDom;
24  import com.buckosoft.PicMan.dom.ImportPicsDom;
25  import com.buckosoft.PicMan.domain.Pic;
26  import com.buckosoft.PicMan.domain.Root;
27  import com.buckosoft.PicMan.image.PicReader;
28  import com.drew.imaging.ImageMetadataReader;
29  import com.drew.metadata.Metadata;
30  import com.drew.metadata.exif.ExifIFD0Directory;
31  
32  /** Import unknown pictures from an alien directory into our structure.
33   * @author Dick Balaska
34   * @since 2008/01/30
35   * @see <a href="http://cvs.buckosoft.com/Projects/java/PicMan/PicMan/src/com/buckosoft/PicMan/business/PicImporterImpl.java">PicImporterImpl.java</a>
36   */
37  public class PicImporterImpl implements PicImporter {
38  	protected final Log log = LogFactory.getLog(getClass());
39  
40  	private	PicManFacade	pmf;
41  	private	List<String>	picExtensions;
42  	private byte[] buf = new byte[4096];
43  
44  	
45  	/** Set the reference to the PicMan API.
46  	 * @param pmf The PicManFacade
47  	 */
48  	public	void setPicMan(PicManFacade pmf) {
49  		this.pmf = pmf;
50  	}
51  
52  	/* (non-Javadoc)
53  	 * @see com.buckosoft.PicMan.business.PicImporter#getPicNamesToImport()
54  	 */
55  	public List<File> getPicNamesToImport() {
56  		
57  		picExtensions = pmf.getDB().getPicExtensions();
58  		LinkedList<File> list = new LinkedList<File>();
59  		File f = new File(pmf.getDB().getSystem().getImportDirectory());
60  		File[] files = f.listFiles();
61  		if (files == null) {
62  			return(list);
63  		}
64  		for (int i=0; i<files.length; i++) {
65  			File file = files[i];
66  			String	s = file.getName();
67  			if (s.length() < 4)
68  				continue;
69  			String t = s.substring(s.length()-3);
70  			boolean match = false;
71  			for (String pe : picExtensions) {
72  				if (t.compareToIgnoreCase(pe) == 0) {
73  					match = true;
74  					break;
75  				}
76  			}
77  			if (match) {
78  				list.add(file);
79  				log.info("Add: " + s);
80  			}
81  		}
82  		return list;
83  	}
84  
85  	/* (non-Javadoc)
86  	 * @see com.buckosoft.PicMan.business.PicImporter#importPic(int, java.lang.String, java.lang.String, java.lang.String)
87  	 */
88  	public Document importPic(int rid, String odir, String iname, String oname) {
89  		boolean success = false;
90  		String is;
91  		if (rid == -1) {
92  			is = pmf.getDB().getSystem().getImportDirectory() + "/" + iname;
93  			File fromFile = new File(is);
94  			try {
95  				success = fromFile.delete();
96  			} catch (Exception e) {
97  				return(ImportPicsDom.createDocument(iname, 1, "Failed to delete file: " + e.getLocalizedMessage()));		
98  			}
99  			return(ImportPicsDom.createDocument(iname, 0, "success"));
100 		}
101 		Root root = pmf.getDB().getRoot(rid);
102 		is = pmf.getDB().getSystem().getImportDirectory() + "/" + iname;
103 		File fromFile = new File(is);
104 		File toFile = new File(root.getPath() + "/" + odir + "/" + oname + ".jpg");
105 		if (!fromFile.canRead())
106 			return(ImportPicsDom.createDocument(iname, 1, "Input file doesn't exist"));
107 		if (toFile.exists())
108 			return(ImportPicsDom.createDocument(iname, 1, "Output file exists"));
109 		File toDir = new File(root.getPath() + "/" + odir);
110 		if (!toDir.isDirectory()) {
111 			try {
112 				toDir.mkdirs();
113 			} catch (Exception e) {
114 				return(ImportPicsDom.createDocument(iname, 1, "Failed to make output directory: " + e.getLocalizedMessage()));
115 			}
116 		}
117 		try {
118 			CopyFile.copyFile(fromFile, toFile, buf);
119 		} catch(Exception e) {
120 			return(ImportPicsDom.createDocument(iname, 1, "Failed to copy file: " + e.getLocalizedMessage()));			
121 		}
122 		toFile.setReadOnly();
123 		Pic pic = pmf.getDB().getPic(oname);
124 		if (pic == null) {
125 			log.error("Can't find newly imported pic '" + oname + "'");
126 		} else {
127 			MD5SumUpdater.calculateMD5Sum(pmf, pic);
128 			log.debug("md5sum for " + pic.getName() + " = " + pic.getMd5());
129 			pmf.getDB().updatePic(pic);
130 		}
131 		try {
132 			success = fromFile.delete();
133 		} catch (Exception e) {
134 			return(ImportPicsDom.createDocument(iname, 1, "Failed to delete file: " + e.getLocalizedMessage()));			
135 			
136 		}
137 		if (!success) {
138 			try {
139 				Thread.sleep(1000);
140 				success = fromFile.delete();
141 			} catch (Exception e) {
142 				return(ImportPicsDom.createDocument(iname, 1, "Failed to delete file: " + e.getLocalizedMessage()));
143 			}
144 			
145 		}
146 		if (!success) {
147 			try {
148 				Thread.sleep(3000);
149 				success = fromFile.delete();
150 				if (!success) {
151 					fromFile = null;
152 					success = new File(is).delete();
153 				}
154 			} catch (Exception e) {
155 				return(ImportPicsDom.createDocument(iname, 1, "Failed to delete file: " + e.getLocalizedMessage()));
156 			}
157 			
158 		}
159 		if (!success)
160 			return(ImportPicsDom.createDocument(iname, 1, "Failed to delete file."));
161 		
162 		return(ImportPicsDom.createDocument(iname, 0, "success"));
163 	}
164 
165 	@Override
166 	public Document analyzePic(String fname, String customDate) {
167 		Pic iPic = new Pic(true, fname);
168 		List<Pic>	pics = checkForDuplicatePics(fname);
169 		PossibleDates pds = getPossibleDates(iPic, customDate);
170 		return(ImportAnalyzeDom.createDocument(pics, pds));
171 	}
172 
173 	private	List<Pic> checkForDuplicatePics(String fname) {
174 		Pic pic = new Pic(true, fname);
175 		MD5SumUpdater.calculateMD5Sum(pmf, pic);
176 		log.info("checkForDups: " + fname + " -- " + pic.getMd5());
177 		List<Pic> dups = pmf.getDB().getPicsByMD5Sum(pic.getMd5());
178 		return(dups);
179 	}
180 
181 	private	SimpleDateFormat sdf = new SimpleDateFormat();
182 	
183 	private	PossibleDates getPossibleDates(Pic iPic, String customDate) {
184 		PossibleDates pds = new PossibleDates();
185 		if (customDate != null) {
186 			try {
187 				pds.setCustomDate(sdf.parse(customDate));
188 			} catch (ParseException e) {
189 				log.warn("Failed to parse customDate", e);
190 			}
191 		}
192 		File f;
193 		f = new File(PicReader.getFullPath(pmf, iPic));
194 		if (f == null) {
195 			log.warn("Can't find file " + PicReader.getFullPath(pmf, iPic));
196 			return(pds);
197 		} else {
198 			pds.setFileDate(new Date(f.lastModified()));
199 		}
200 		
201 		Metadata metadata = null;
202 		try {
203 			metadata = ImageMetadataReader.readMetadata(f);
204 //		} catch (ImageProcessingException | IOException e) {
205 		} catch (Throwable t) {
206 			t.printStackTrace();
207 		}
208 		String s = null;
209 		if (metadata != null) {
210 			ExifIFD0Directory directory = metadata.getDirectory(ExifIFD0Directory.class);
211 			try {
212 				s = directory.getString(ExifIFD0Directory.TAG_DATETIME);
213 			} catch (Exception e) {}
214 /*			int d = -1;
215  			try {
216 				d = directory.getInt(ExifIFD0Directory.TAG_DATETIME);
217 			} catch (Exception e) {
218 				log.warn("failed directory.getInt(ExifIFD0Directory.TAG_DATETIME) " + e.getLocalizedMessage());
219 			}
220 			if (d != -1) {
221 				Date date = new Date(d);
222 				log.info("date = " + date.toString());
223 			}
224 */		}
225 		log.info("s = " + s);
226 		if (s != null) {
227 			SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
228 			try {
229 				pds.setTakenDate(sdf.parse(s));
230 				log.info("Taken date: " + pds.getTakenDate());
231 			} catch (ParseException e) {
232 				log.warn("Failed to parse date", e);
233 			}
234 		}
235 		return(pds);
236 	}
237 
238 	public class PossibleDates {
239 		Date	takenDate = null;
240 		Date	fileDate = null;
241 		Date	customDate = null;
242 		/**
243 		 * @return the takenDate
244 		 */
245 		public Date getTakenDate() {
246 			return takenDate;
247 		}
248 		/**
249 		 * @param takenDate the date the pic was taken. From the jpeg tag.
250 		 */
251 		public void setTakenDate(Date takenDate) {
252 			this.takenDate = takenDate;
253 		}
254 		/**
255 		 * @return the fileDate
256 		 */
257 		public Date getFileDate() {
258 			return fileDate;
259 		}
260 		/**
261 		 * @param fileDate the fileDate to set
262 		 */
263 		public void setFileDate(Date fileDate) {
264 			this.fileDate = fileDate;
265 		}
266 		/**
267 		 * @return the customDate
268 		 */
269 		public Date getCustomDate() {
270 			return customDate;
271 		}
272 		/**
273 		 * @param customDate the customDate to set
274 		 */
275 		public void setCustomDate(Date customDate) {
276 			this.customDate = customDate;
277 		}
278 		
279 	}
280 	
281 }