You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

293 lines
10 KiB

  1. /*******************************************************************************
  2. * Copyright 2Fi Business Solutions Ltd.
  3. *
  4. * This code is copyrighted. Under no circumstances should any party, people,
  5. * or organization should redistribute any portions of this code in any form,
  6. * either verbatim or through electronic media, to any third parties, unless
  7. * under explicit written permission by 2Fi Business Solutions Ltd.
  8. ******************************************************************************/
  9. package com.ffii.tbms.file.service;
  10. import java.awt.image.BufferedImage;
  11. import java.io.ByteArrayInputStream;
  12. import java.io.IOException;
  13. import java.util.List;
  14. import java.util.Map;
  15. import javax.imageio.ImageIO;
  16. import org.apache.commons.lang3.RandomStringUtils;
  17. import org.springframework.beans.factory.annotation.Autowired;
  18. import org.springframework.scheduling.annotation.Scheduled;
  19. import org.springframework.stereotype.Service;
  20. import org.springframework.transaction.annotation.Isolation;
  21. import org.springframework.transaction.annotation.Transactional;
  22. import com.ffii.core.dao.JdbcDao;
  23. import com.ffii.core.utils.FileUtils;
  24. import com.ffii.core.utils.MapUtils;
  25. import com.ffii.core.web.AbstractService;
  26. import com.ffii.core.web.view.AbstractView;
  27. import com.ffii.tbms.file.File;
  28. import com.ffii.tbms.file.FileBlob;
  29. import com.ffii.tbms.file.FileRef;
  30. import com.ffii.tbms.file.dao.FileBlobDao;
  31. import com.ffii.tbms.file.dao.FileDao;
  32. import com.ffii.tbms.file.dao.FileRefDao;
  33. /**
  34. * @author Patrick
  35. */
  36. @Service
  37. public class FileService extends AbstractService {
  38. @Autowired
  39. private JdbcDao jdbcDao;
  40. @Autowired
  41. private FileDao fileDao;
  42. @Autowired
  43. private FileBlobDao fileBlobDao;
  44. @Autowired
  45. private FileRefDao fileRefDao;
  46. /**
  47. * Save File, FileBlob, and FileRef in one go
  48. *
  49. * @param filename
  50. * the filename, cannot be null
  51. * @param description
  52. * optional File description
  53. * @param refType
  54. * the File reference type, should not be empty
  55. * @param refId
  56. * mandatory, use 0 if N/A
  57. * @param refCode
  58. * optional
  59. * @param bytes
  60. * the File byte array
  61. *
  62. * @return File ID
  63. */
  64. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
  65. public Integer saveFile(String filename, String description, String refType, int refId, String refCode, byte[] bytes) {
  66. File file = new File();
  67. file.setFilename(filename);
  68. file.setDescription(description);
  69. file.setMimetype(FileUtils.guessMimetype(filename));
  70. file.setFilesize(bytes.length);
  71. file.setSkey(RandomStringUtils.randomAlphanumeric(16));
  72. FileBlob fileBlob = new FileBlob();
  73. fileBlob.setBytes(bytes);
  74. FileRef fileRef = new FileRef();
  75. fileRef.setRefId(refId);
  76. fileRef.setRefType(refType);
  77. fileRef.setRefCode(refCode);
  78. // try to get width and height if mimetype is png or jpeg
  79. if (AbstractView.CONTENT_TYPE_PNG.equals(file.getMimetype()) || AbstractView.CONTENT_TYPE_JPEG.equals(file.getMimetype())) {
  80. BufferedImage image;
  81. try {
  82. image = ImageIO.read(new ByteArrayInputStream(bytes));
  83. if (image != null) {
  84. file.setImageWidth(image.getWidth());
  85. file.setImageHeight(image.getHeight());
  86. }
  87. } catch (IOException e) {
  88. // ignore
  89. }
  90. }
  91. // save File
  92. saveFile(file);
  93. // save FileBlob
  94. fileBlob.setFileId(file.getId());
  95. saveFileBlob(fileBlob);
  96. // save FileRef
  97. fileRef.setFileId(file.getId());
  98. saveFileRef(fileRef);
  99. return file.getId();
  100. }
  101. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
  102. public Integer saveFile(File instance) {
  103. return fileDao.saveOrUpdate(instance);
  104. }
  105. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
  106. public Integer saveFileBlob(FileBlob instance) {
  107. return fileBlobDao.saveOrUpdate(instance);
  108. }
  109. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
  110. public Integer saveFileRef(FileRef instance) {
  111. return fileRefDao.saveOrUpdate(instance);
  112. }
  113. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  114. public File findFileByIdAndKey(int id, String skey) {
  115. return fileDao.findByQuery("from com.ffii.tbms.file.File f where f.id = ? and f.skey = ?", id, skey);
  116. }
  117. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  118. public File findFileById(int id) {
  119. return fileDao.findByQuery("from com.ffii.tbms.file.File f where f.id = ? ", id);
  120. }
  121. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  122. public FileRef findFileRefByTypeAndId(String refType, int refId) {
  123. return fileRefDao.findByQuery("from com.ffii.tbms.file.FileRef where refType = ? and refId = ?", refType, refId);
  124. }
  125. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  126. public FileRef findFileRefByfileId(int fileId) {
  127. return fileRefDao.findByQuery("from com.ffii.tbms.file.FileRef where fileId = ?", fileId);
  128. }
  129. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  130. public FileBlob findFileBlobByFileId(int fileId) {
  131. return fileBlobDao.findByQuery("from com.ffii.tbms.file.FileBlob fb where fb.fileId = ?", fileId);
  132. }
  133. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  134. public boolean isFileExists(int id, String skey) {
  135. String sql = "SELECT"
  136. + " COUNT(1)"
  137. + " FROM files f"
  138. + " WHERE f.deleted = 0"
  139. + " AND f.id = :id"
  140. + " AND f.skey = :skey";
  141. int count = jdbcDao.queryForInt(sql, MapUtils.toHashMap("id", id, "skey", skey));
  142. return (count > 0);
  143. }
  144. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  145. public List<Map<String, Object>> searchFiles(Map<String, Object> args) {
  146. StringBuilder sql = new StringBuilder("SELECT"
  147. + " f.id,"
  148. + " f.filename,"
  149. + " f.filesize,"
  150. + " f.mimetype, "
  151. + " f.skey,"
  152. + " fr.refId,"
  153. + " fr.refType,"
  154. + " f.created,"
  155. + " f.imageWidth,"
  156. + " f.imageHeight,"
  157. + " u.fullname AS createdByName,"
  158. + " f.description"
  159. + " FROM files f"
  160. + " LEFT JOIN files_ref fr ON f.id = fr.fileId"
  161. + " LEFT JOIN users u ON f.createdBy = u.id"
  162. + " WHERE f.deleted = 0 AND fr.deleted =0 ");
  163. if (args.containsKey("filename")) sql.append(" AND f.filename = :filename");
  164. if (args.containsKey("refType")) sql.append(" AND fr.refType = :refType");
  165. if (args.containsKey("refId")) sql.append(" AND fr.refId = :refId");
  166. if (args.containsKey("startDate")) sql.append(" AND f.created >= :startDate");
  167. if (args.containsKey("endDate")) sql.append(" AND f.created < :endDate");
  168. if (args.containsKey("fileId")) sql.append(" AND f.id = :fileId");
  169. sql.append(" ORDER BY f.created DESC");
  170. return jdbcDao.queryForList(sql.toString(), args);
  171. }
  172. @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true)
  173. public List<Map<String, Object>> searchFilesFromDocument(Map<String, Object> args) {
  174. StringBuilder sql = new StringBuilder("SELECT"
  175. + " f.id,"
  176. + " f.filename,"
  177. + " f.filesize,"
  178. + " f.mimetype,"
  179. + " f.skey,"
  180. + " fr.refId,"
  181. + " fr.refType,"
  182. + " f.created,"
  183. + " u.fullname AS createdByName,"
  184. + " f.description"
  185. + " FROM files_ref fr"
  186. + " LEFT JOIN files f ON f.id = fr.fileId"
  187. + " LEFT JOIN users u ON f.createdBy = u.id"
  188. + " LEFT JOIN document_ref dr ON dr.documentId = fr.refId AND fr.refType = 'document'"
  189. + " WHERE 1 = 1"
  190. + " AND f.deleted = 0"
  191. + " AND fr.deleted = 0"
  192. + " AND dr.deleted = 0");
  193. if (args != null) {
  194. if (args.containsKey("filename")) sql.append(" AND f.filename = :filename");
  195. if (args.containsKey("refType")) sql.append(" AND fr.refType = :refType");
  196. if (args.containsKey("refId")) sql.append(" AND fr.refId = :refId");
  197. if (args.containsKey("startDate")) sql.append(" AND f.created >= :startDate");
  198. if (args.containsKey("endDate")) sql.append(" AND f.created < :endDate");
  199. if (args.containsKey("documentRefType")) sql.append(" AND dr.refType = :documentRefType");
  200. if (args.containsKey("documentRefId")) sql.append(" AND dr.refId = :documentRefId");
  201. }
  202. sql.append(" GROUP BY f.id"
  203. + " ORDER BY f.created DESC");
  204. return jdbcDao.queryForList(sql.toString(), args);
  205. }
  206. /**
  207. * Delete <code>FileRef</code> by <code>fileId</code>, <code>refId</code>, <code>refType</code>, and <code>skey</code>
  208. */
  209. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
  210. public void deleteFile(Integer fileId, Integer refId, String refType, String skey) {
  211. Map<String, ?> args = MapUtils.toHashMap("fileId", fileId, "refId", refId, "refType", refType, "skey", skey);
  212. jdbcDao.executeUpdate("DELETE FROM files_ref"
  213. + " WHERE fileId = :fileId"
  214. + " AND refId = :refId"
  215. + " AND refType = :refType"
  216. + " AND EXISTS (SELECT 1 FROM files WHERE id = files_ref.fileId AND skey = :skey)",
  217. args);
  218. jdbcDao.executeUpdate("DELETE FROM files_blob WHERE id = :fileId ",args);
  219. }
  220. /**
  221. * Scheduled daily job
  222. *
  223. * Delete all orphan (without any <code>FileRef</code>) <code>File</code>s and <code>FileBlob</code>s
  224. */
  225. @Scheduled(cron = "0 0 0 * * ?") // everyday at 00:00:00
  226. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = false)
  227. public void deleteOrphanFiles() {
  228. jdbcDao.executeUpdate("DELETE FROM files_blob WHERE NOT EXISTS (SELECT 1 FROM files_ref WHERE deleted = 0 AND fileId = files_blob.fileId)");
  229. jdbcDao.executeUpdate("DELETE FROM files WHERE NOT EXISTS (SELECT 1 FROM files_ref WHERE deleted = 0 AND fileId = files.id)");
  230. }
  231. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = true)
  232. public List<Map<String, Object>> getCustImageList() {
  233. return jdbcDao.queryForList(" Select cp.* From cust_photo cp ", null);
  234. }
  235. @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class, readOnly = true)
  236. public List<Map<String, Object>> getOrderImageList() {
  237. return jdbcDao.queryForList(" Select op.* From order_photo cp ", null);
  238. }
  239. }