package org.kvj.lima1.pg.sync.data; import java.awt.AlphaComposite; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.imageio.ImageIO; import javax.sql.DataSource; import org.apache.commons.fileupload.FileItem; import org.codehaus.jettison.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FileStorage { private static Logger log = LoggerFactory.getLogger(FileStorage.class); private static String getDataFolderName(String app, String user) { return app + "-" + user; } private static String upload(Connection c, String app, long userID, InputStream file, File newFile, String name, long created) { try { FileOutputStream out = new FileOutputStream(newFile); DAO.copyStream(file, out); out.close(); file.close(); PreparedStatement insertFile = c .prepareStatement("insert into files " + "(id, user_id, app, name, created) " + "values (?, ?, ?, ?, ?)"); insertFile.setLong(1, DAO.nextID(c)); insertFile.setLong(2, userID); insertFile.setString(3, app); insertFile.setString(4, name); insertFile.setLong(5, created); insertFile.execute(); return null; } catch (Exception e) { log.error("Save error", e); return "Database error"; } } public static String upload(DataSource ds, String app, String user, InputStream file, String name) { Connection c = null; try { JSONObject schema = SchemaStorage.getInstance().getSchema(app); if (null == schema) { throw new Exception("Schema not found"); } c = ds.getConnection(); long userID = UserStorage.findUserByName(c, user); File newFile = new File(DAO.getUploadFolder(getDataFolderName(app, user)), name); return upload(c, app, userID, file, newFile, name, System.currentTimeMillis()); } catch (Exception e) { log.error("Save error", e); return "Database error"; } finally { DAO.closeConnection(c); } } public static File getFile(String app, String user, String name) { try { JSONObject schema = SchemaStorage.getInstance().getSchema(app); if (null == schema) { throw new Exception("Schema not found"); } File file = new File(DAO.getUploadFolder(getDataFolderName(app, user)), name); if (file.exists() && file.isFile()) { return file; } throw new Exception("File not found"); } catch (Exception e) { log.error("Download error", e); return null; } } public static String removeFile(DataSource ds, String app, String user, String name) { Connection c = null; try { JSONObject schema = SchemaStorage.getInstance().getSchema(app); if (null == schema) { throw new Exception("Schema not found"); } c = ds.getConnection(); long userID = UserStorage.findUserByName(c, user); File file = new File(DAO.getUploadFolder(getDataFolderName(app, user)), name); PreparedStatement removeFile = c .prepareStatement("delete from files where app=? and user_id=? and name=?"); removeFile.setString(1, app); removeFile.setLong(2, userID); removeFile.setString(3, name); removeFile.execute(); if (file.exists()) { try { file.delete(); } catch (Exception e) { log.error("Error removing file", e); } } return null; } catch (Exception e) { log.error("Remove file error", e); return "Database error"; } finally { DAO.closeConnection(c); } } public static int backupFiles(DataSource ds, String app, String user, long from, ZipOutputStream zip) { Connection c = null; try { JSONObject schema = SchemaStorage.getInstance().getSchema(app); if (null == schema) { throw new Exception("Schema not found"); } c = ds.getConnection(); long userID = UserStorage.findUserByName(c, user); PreparedStatement files = c .prepareStatement("select name, created from files " + "where user_id=? and app=? and created>?"); files.setLong(1, userID); files.setString(2, app); files.setLong(3, from); StringBuilder meta = new StringBuilder(); int filesAdded = 0; ResultSet filesSet = files.executeQuery(); File folder = DAO.getUploadFolder(getDataFolderName(app, user)); while (filesSet.next()) { String name = filesSet.getString(1); File file = new File(folder, name); if (!file.exists() || !file.isFile()) { log.warn("Skip file {} - not accessible", name); continue; } try { ZipEntry entry = new ZipEntry(name); zip.putNextEntry(entry); FileInputStream fis = new FileInputStream(file); DAO.copyStream(fis, zip); fis.close(); zip.closeEntry(); filesAdded++; zip.flush(); JSONObject metaObject = new JSONObject(); metaObject.put("name", name); metaObject.put("created", filesSet.getLong(2)); meta.append(metaObject.toString()); meta.append("\n"); } catch (Exception e) { log.warn("Error writing blob", e); continue; } } if (filesAdded > 0) { ZipEntry entry = new ZipEntry("meta.json"); zip.putNextEntry(entry); zip.write(meta.toString().getBytes("utf-8")); zip.closeEntry(); } return filesAdded; } catch (Exception e) { log.error("Download error", e); } finally { DAO.closeConnection(c); } return 0; } private static Dimension resize(int width, int height, int newWidth) { if (width > newWidth) { float ratio = (float) newWidth / (float) width; return new Dimension(newWidth, (int) (height * ratio)); } return null; } public static boolean resizeImageFile(File file, int width, OutputStream out) { try { BufferedImage image = ImageIO.read(file); if (null == image) { throw new Exception("Invalid image"); } int type = image.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : image.getType(); Dimension newSize = resize(image.getWidth(), image.getHeight(), width); if (null == newSize) { // Resize not necessary return false; } BufferedImage resizeImage = new BufferedImage( (int) newSize.getWidth(), (int) newSize.getHeight(), type); Graphics2D g = resizeImage.createGraphics(); g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.drawImage(image, 0, 0, resizeImage.getWidth(), resizeImage.getHeight(), null); g.dispose(); String fileType = "jpg"; int dotIndex = file.getName().lastIndexOf("."); if (dotIndex != -1) { fileType = file.getName().substring(dotIndex + 1); } ImageIO.write(resizeImage, fileType, out); return true; } catch (Exception e) { log.error("Error resizing image", e); } return false; } static void clearCache(Connection c, String app, String user) throws IOException, SQLException { File folder = DAO.getUploadFolder(getDataFolderName(app, user)); File[] files = folder.listFiles(); for (File file : files) { if (file.isFile()) { file.delete(); } } long userID = UserStorage.findUserByName(c, user); PreparedStatement st = c .prepareStatement("delete from files where user_id=? and app=?"); st.setLong(1, userID); st.setString(2, app); st.execute(); } public static String restoreFiles(DataSource ds, String app, String user, FileItem fileItem) { Connection c = null; try { List<String> files = RestoreManager.getFilesInZip(fileItem .getInputStream()); InputStream meta = RestoreManager.openFileInZip( fileItem.getInputStream(), "meta.json"); if (null == meta) { throw new Exception("meta.json not found"); } BufferedReader br = new BufferedReader(new InputStreamReader(meta, "utf-8")); String line = null; Map<String, Long> metaMap = new HashMap<String, Long>(); while ((line = br.readLine()) != null) { if (line.isEmpty()) { continue; } try { JSONObject obj = new JSONObject(line); metaMap.put(obj.getString("name"), obj.getLong("created")); } catch (Exception e) { log.warn("Error reading JSON", e); } } br.close(); c = ds.getConnection(); long userID = UserStorage.findUserByName(c, user); for (String fileName : files) { Long created = metaMap.get(fileName); if (null == created) { log.warn("Skip file {}", fileName); } else { InputStream zip = RestoreManager.openFileInZip( fileItem.getInputStream(), fileName); if (null == zip) { throw new Exception("Error in zip"); } File file = new File(DAO.getUploadFolder(getDataFolderName( app, user)), fileName); String result = upload(c, app, userID, zip, file, fileName, created); if (null != result) { return result; } } } return null; } catch (Exception e) { log.error("Error restoring files", e); } finally { DAO.closeConnection(c); } return "Restore files error"; } }