From dae3f4c27b423fb04632aacd1d4a5de6c8c1d311 Mon Sep 17 00:00:00 2001 From: Carlos Ruiz Date: Thu, 29 Nov 2012 16:35:56 -0500 Subject: [PATCH] IDEMPIERE-390 Attachments/archives on load balancer scenario / Implemente deletion of attachment entries for filesystem method --- .../compiere/model/AttachmentDBSystem.java | 15 +- .../compiere/model/AttachmentFileSystem.java | 61 ++- .../org/compiere/model/IAttachmentStore.java | 6 + .../src/org/compiere/model/MAttachment.java | 450 ++---------------- .../org/compiere/model/MStorageProvider.java | 23 +- 5 files changed, 125 insertions(+), 430 deletions(-) diff --git a/org.adempiere.base/src/org/compiere/model/AttachmentDBSystem.java b/org.adempiere.base/src/org/compiere/model/AttachmentDBSystem.java index 324005b78b..31426df03c 100644 --- a/org.adempiere.base/src/org/compiere/model/AttachmentDBSystem.java +++ b/org.adempiere.base/src/org/compiere/model/AttachmentDBSystem.java @@ -44,7 +44,7 @@ public class AttachmentDBSystem implements IAttachmentStore log.fine("ZipSize=" + data.length); if (data.length == 0) return true; - + // Old Format - single file if (!ZIP.equals(attach.getTitle())) { @@ -122,6 +122,7 @@ public class AttachmentDBSystem implements IAttachmentStore byte[] zipData = out.toByteArray(); log.fine("Length=" + zipData.length); attach.setBinaryData(zipData); + attach.setTitle(MAttachment.ZIP); return true; } catch (Exception e) @@ -132,4 +133,16 @@ public class AttachmentDBSystem implements IAttachmentStore return false; } + @Override + public boolean delete(MAttachment attach, MStorageProvider prov) { + // nothing todo - deleting the db record deletes the items + return true; + } + + @Override + public boolean deleteEntry(MAttachment attach, MStorageProvider provider, int index) { + attach.m_items.remove(index); + return true; + } + } diff --git a/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java b/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java index f23f07da86..ca45f68490 100644 --- a/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java +++ b/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java @@ -17,29 +17,29 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.FileNotFoundException; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.logging.Level; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import javax.xml.parsers.ParserConfigurationException; import org.compiere.util.CLogger; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.w3c.dom.NamedNodeMap; import org.xml.sax.SAXException; /** @@ -92,7 +92,7 @@ public class AttachmentFileSystem implements IAttachmentStore { FileChannel out = null; try { //create destination folder - StringBuilder msgfile = new StringBuilder().append(attach.m_attachmentPathRoot).append(File.separator).append(attach.getAttachmentPathSnippet()); + StringBuilder msgfile = new StringBuilder().append(attach.m_attachmentPathRoot).append(File.separator).append(getAttachmentPathSnippet(attach)); final File destFolder = new File(msgfile.toString()); if(!destFolder.exists()){ if(!destFolder.mkdirs()){ @@ -100,7 +100,7 @@ public class AttachmentFileSystem implements IAttachmentStore { } } msgfile = new StringBuilder().append(attach.m_attachmentPathRoot).append(File.separator) - .append(attach.getAttachmentPathSnippet()).append(File.separator).append(entryFile.getName()); + .append(getAttachmentPathSnippet(attach)).append(File.separator).append(entryFile.getName()); final File destFile = new File(msgfile.toString()); in = new FileInputStream(entryFile).getChannel(); out = new FileOutputStream(destFile).getChannel(); @@ -118,7 +118,7 @@ public class AttachmentFileSystem implements IAttachmentStore { e.printStackTrace(); log.severe("unable to copy file " + entryFile.getAbsolutePath() + " to " + attach.m_attachmentPathRoot + File.separator + - attach.getAttachmentPathSnippet() + File.separator + entryFile.getName()); + getAttachmentPathSnippet(attach) + File.separator + entryFile.getName()); } finally { if (in != null && in.isOpen()) { in.close(); @@ -146,6 +146,7 @@ public class AttachmentFileSystem implements IAttachmentStore { final byte[] xmlData = bos.toByteArray(); log.fine(bos.toString()); attach.setBinaryData(xmlData); + attach.setTitle(MAttachment.XML); return true; } catch (Exception e) { log.log(Level.SEVERE, "saveLOBData", e); @@ -246,5 +247,53 @@ public class AttachmentFileSystem implements IAttachmentStore { return true; } + /** + * Returns a path snippet, containing client, org, table and record id. + * @return String + */ + private String getAttachmentPathSnippet(MAttachment attach){ + + StringBuilder msgreturn = new StringBuilder().append(attach.getAD_Client_ID()).append(File.separator) + .append(attach.getAD_Org_ID()).append(File.separator) + .append(attach.getAD_Table_ID()).append(File.separator).append(attach.getRecord_ID()); + return msgreturn.toString(); + } + + @Override + public boolean delete(MAttachment attach, MStorageProvider prov) { + //delete all attachment files and folder + for (int i=0; i < attach.m_items.size(); i++) { + final MAttachmentEntry entry = attach.m_items.get(i); + final File file = entry.getFile(); + if (file !=null && file.exists()) { + if (!file.delete()) { + log.warning("unable to delete " + file.getAbsolutePath()); + } + } + } + final File folder = new File(m_attachmentPathRoot + getAttachmentPathSnippet(attach)); + if (folder.exists()) { + if (!folder.delete()) { + log.warning("unable to delete " + folder.getAbsolutePath()); + } + } + return true; + } + + @Override + public boolean deleteEntry(MAttachment attach, MStorageProvider provider, int index) { + //remove files + final MAttachmentEntry entry = attach.m_items.get(index); + final File file = entry.getFile(); + log.fine("delete: " + file.getAbsolutePath()); + if (file != null && file.exists()) { + if (!file.delete()) { + log.warning("unable to delete " + file.getAbsolutePath()); + } + } + attach.m_items.remove(index); + log.config("Index=" + index + " - NewSize=" + attach.m_items.size()); + return true; + } } diff --git a/org.adempiere.base/src/org/compiere/model/IAttachmentStore.java b/org.adempiere.base/src/org/compiere/model/IAttachmentStore.java index 6d1f287a28..2d53832bce 100644 --- a/org.adempiere.base/src/org/compiere/model/IAttachmentStore.java +++ b/org.adempiere.base/src/org/compiere/model/IAttachmentStore.java @@ -18,9 +18,15 @@ package org.compiere.model; + public interface IAttachmentStore { public boolean loadLOBData(MAttachment attach,MStorageProvider prov); boolean save(MAttachment attach, MStorageProvider prov); + + public boolean delete(MAttachment attach, MStorageProvider prov); + + public boolean deleteEntry(MAttachment mAttachment, MStorageProvider provider, int index); + } diff --git a/org.adempiere.base/src/org/compiere/model/MAttachment.java b/org.adempiere.base/src/org/compiere/model/MAttachment.java index c6108199b1..58dc840b1b 100644 --- a/org.adempiere.base/src/org/compiere/model/MAttachment.java +++ b/org.adempiere.base/src/org/compiere/model/MAttachment.java @@ -16,45 +16,18 @@ *****************************************************************************/ package org.compiere.model; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.nio.channels.FileChannel; import java.sql.ResultSet; import java.util.ArrayList; -import java.util.List; import java.util.Properties; import java.util.logging.Level; -import java.util.zip.Deflater; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.adempiere.base.Service; -import org.adempiere.base.ServiceQuery; import org.compiere.util.CLogger; import org.compiere.util.Env; import org.compiere.util.MimeType; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; /** @@ -74,7 +47,7 @@ public class MAttachment extends X_AD_Attachment /** * */ - private static final long serialVersionUID = 1415801644995116959L; + private static final long serialVersionUID = -4443388991706555942L; /** * Get Attachment (if there are more than one attachment it gets the first in no specific order) @@ -151,10 +124,6 @@ public class MAttachment extends X_AD_Attachment /** List of Entry Data */ public ArrayList m_items = null; - - /** is this client using the file system for attachments */ - private boolean isStoreAttachmentsOnFileSystem = false; - /** attachment (root) path - if file system is used */ public String m_attachmentPathRoot = ""; @@ -389,21 +358,13 @@ public class MAttachment extends X_AD_Attachment * @return true if deleted */ public boolean deleteEntry(int index) { + if (m_items == null) + loadLOBData(); if (index >= 0 && index < m_items.size()) { - if(isStoreAttachmentsOnFileSystem){ - //remove files - final MAttachmentEntry entry = m_items.get(index); - final File file = entry.getFile(); - log.fine("delete: " + file.getAbsolutePath()); - if(file !=null && file.exists()){ - if(!file.delete()){ - log.warning("unable to delete " + file.getAbsolutePath()); - } - } - } - m_items.remove(index); - log.config("Index=" + index + " - NewSize=" + m_items.size()); - return true; + IAttachmentStore prov = provider.getAttachmentStore(); + if (prov != null) + return prov.deleteEntry(this,provider,index); + return false; } log.warning("Not deleted Index=" + index + " - Size=" + m_items.size()); return false; @@ -505,176 +466,16 @@ public class MAttachment extends X_AD_Attachment return null; } // getEntryFile - /** * Save Entry Data in Zip File format * @return true if saved */ private boolean saveLOBData() { - ServiceQuery query=new ServiceQuery(); - String method=provider.getMethod(); - if(method == null) - method="DB"; - query.put("method", method); - List storelist = Service.locator().list(IAttachmentStore.class, query).getServices(); - - if(storelist != null){ - for(IAttachmentStore prov:storelist){ - return prov.save(this,provider); - } - } + IAttachmentStore prov = provider.getAttachmentStore(); + if (prov != null) + return prov.save(this,provider); return false; - - /*if(isStoreAttachmentsOnFileSystem){ - return saveLOBDataToFileSystem(); - } - return saveLOBDataToDB();*/ - } - - /** - * Save Entry Data in Zip File format into the database. - * @return true if saved - */ - private boolean saveLOBDataToDB() - { - if (m_items == null || m_items.size() == 0) - { - setBinaryData(null); - return true; - } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ZipOutputStream zip = new ZipOutputStream(out); - zip.setMethod(ZipOutputStream.DEFLATED); - zip.setLevel(Deflater.BEST_COMPRESSION); - zip.setComment("adempiere"); - // - try - { - for (int i = 0; i < m_items.size(); i++) - { - MAttachmentEntry item = getEntry(i); - ZipEntry entry = new ZipEntry(item.getName()); - entry.setTime(System.currentTimeMillis()); - entry.setMethod(ZipEntry.DEFLATED); - zip.putNextEntry(entry); - byte[] data = item.getData(); - zip.write (data, 0, data.length); - zip.closeEntry(); - log.fine(entry.getName() + " - " - + entry.getCompressedSize() + " (" + entry.getSize() + ") " - + (entry.getCompressedSize()*100/entry.getSize())+ "%"); - } - // zip.finish(); - zip.close(); - byte[] zipData = out.toByteArray(); - log.fine("Length=" + zipData.length); - setBinaryData(zipData); - return true; - } - catch (Exception e) - { - log.log(Level.SEVERE, "saveLOBData", e); - } - setBinaryData(null); - return false; - } // saveLOBData - - /** - * Save Entry Data to the file system. - * @return true if saved - */ - private boolean saveLOBDataToFileSystem() - { - if("".equals(m_attachmentPathRoot)){ - log.severe("no attachmentPath defined"); - return false; - } - if (m_items == null || m_items.size() == 0) { - setBinaryData(null); - return true; - } - final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - try { - final DocumentBuilder builder = factory.newDocumentBuilder(); - final Document document = builder.newDocument(); - final Element root = document.createElement("attachments"); - document.appendChild(root); - document.setXmlStandalone(true); - // create xml entries - for (int i = 0; i < m_items.size(); i++) { - log.fine(m_items.get(i).toString()); - File entryFile = m_items.get(i).getFile(); - final String path = entryFile.getAbsolutePath(); - // if local file - copy to central attachment folder - log.fine(path + " - " + m_attachmentPathRoot); - if (!path.startsWith(m_attachmentPathRoot)) { - log.fine("move file: " + path); - FileChannel in = null; - FileChannel out = null; - try { - //create destination folder - StringBuilder msgfile = new StringBuilder().append(m_attachmentPathRoot).append(File.separator).append(getAttachmentPathSnippet()); - final File destFolder = new File(msgfile.toString()); - if(!destFolder.exists()){ - if(!destFolder.mkdirs()){ - log.warning("unable to create folder: " + destFolder.getPath()); - } - } - msgfile = new StringBuilder().append(m_attachmentPathRoot).append(File.separator) - .append(getAttachmentPathSnippet()).append(File.separator).append(entryFile.getName()); - final File destFile = new File(msgfile.toString()); - in = new FileInputStream(entryFile).getChannel(); - out = new FileOutputStream(destFile).getChannel(); - in.transferTo(0, in.size(), out); - in.close(); - out.close(); - if(entryFile.exists()){ - if(!entryFile.delete()){ - entryFile.deleteOnExit(); - } - } - entryFile = destFile; - - } catch (IOException e) { - e.printStackTrace(); - log.severe("unable to copy file " + entryFile.getAbsolutePath() + " to " - + m_attachmentPathRoot + File.separator + - getAttachmentPathSnippet() + File.separator + entryFile.getName()); - } finally { - if (in != null && in.isOpen()) { - in.close(); - } - if (out != null && out.isOpen()) { - out.close(); - } - } - } - final Element entry = document.createElement("entry"); - //entry.setAttribute("name", m_items.get(i).getName()); - entry.setAttribute("name", getEntryName(i)); - String filePathToStore = entryFile.getAbsolutePath(); - filePathToStore = filePathToStore.replaceFirst(m_attachmentPathRoot.replaceAll("\\\\","\\\\\\\\"), ATTACHMENT_FOLDER_PLACEHOLDER); - log.fine(filePathToStore); - entry.setAttribute("file", filePathToStore); - root.appendChild(entry); - } - - final Source source = new DOMSource(document); - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - final Result result = new StreamResult(bos); - final Transformer xformer = TransformerFactory.newInstance().newTransformer(); - xformer.transform(source, result); - final byte[] xmlData = bos.toByteArray(); - log.fine(bos.toString()); - setBinaryData(xmlData); - return true; - } catch (Exception e) { - log.log(Level.SEVERE, "saveLOBData", e); - } - setBinaryData(null); - return false; - } /** @@ -683,193 +484,12 @@ public class MAttachment extends X_AD_Attachment */ private boolean loadLOBData () { - - ServiceQuery query=new ServiceQuery(); - String method=provider.getMethod(); - if(method == null) - method="DB"; - query.put("method", method); - - List storelist = Service.locator().list(IAttachmentStore.class, query).getServices(); - - if(storelist != null){ - for(IAttachmentStore prov:storelist){ - return prov.loadLOBData(this,provider); - } - } + IAttachmentStore prov = provider.getAttachmentStore(); + if (prov != null) + return prov.loadLOBData(this,provider); return false; - /*if(isStoreAttachmentsOnFileSystem){ - return loadLOBDataFromFileSystem(); - } - return loadLOBDataFromDB();*/ } - - /** - * Load Data from database - * @return true if success - */ - private boolean loadLOBDataFromDB () - { - // Reset - m_items = new ArrayList(); - // - byte[] data = getBinaryData(); - if (data == null) - return true; - log.fine("ZipSize=" + data.length); - if (data.length == 0) - return true; - - // Old Format - single file - if (!ZIP.equals(getTitle())) - { - m_items.add (new MAttachmentEntry(getTitle(), data, 1)); - return true; - } - try - { - ByteArrayInputStream in = new ByteArrayInputStream(data); - ZipInputStream zip = new ZipInputStream (in); - ZipEntry entry = zip.getNextEntry(); - while (entry != null) - { - String name = entry.getName(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] buffer = new byte[2048]; - int length = zip.read(buffer); - while (length != -1) - { - out.write(buffer, 0, length); - length = zip.read(buffer); - } - // - byte[] dataEntry = out.toByteArray(); - log.fine(name - + " - size=" + dataEntry.length + " - zip=" - + entry.getCompressedSize() + "(" + entry.getSize() + ") " - + (entry.getCompressedSize()*100/entry.getSize())+ "%"); - // - m_items.add (new MAttachmentEntry (name, dataEntry, m_items.size()+1)); - entry = zip.getNextEntry(); - } - } - catch (Exception e) - { - log.log(Level.SEVERE, "loadLOBData", e); - m_items = null; - return false; - } - return true; - } // loadLOBData - - /** - * Load Data from file system - * @return true if success - */ - public boolean loadLOBDataFromFileSystem(){ - if("".equals(m_attachmentPathRoot)){ - log.severe("no attachmentPath defined"); - return false; - } - // Reset - m_items = new ArrayList(); - // - byte[] data = getBinaryData(); - if (data == null) - return true; - log.fine("TextFileSize=" + data.length); - if (data.length == 0) - return true; - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - - try { - final DocumentBuilder builder = factory.newDocumentBuilder(); - final Document document = builder.parse(new ByteArrayInputStream(data)); - final NodeList entries = document.getElementsByTagName("entry"); - for (int i = 0; i < entries.getLength(); i++) { - final Node entryNode = entries.item(i); - final NamedNodeMap attributes = entryNode.getAttributes(); - final Node fileNode = attributes.getNamedItem("file"); - final Node nameNode = attributes.getNamedItem("name"); - if(fileNode==null || nameNode==null){ - log.severe("no filename for entry " + i); - m_items = null; - return false; - } - log.fine("name: " + nameNode.getNodeValue()); - String filePath = fileNode.getNodeValue(); - log.fine("filePath: " + filePath); - if(filePath!=null){ - filePath = filePath.replaceFirst(ATTACHMENT_FOLDER_PLACEHOLDER, m_attachmentPathRoot.replaceAll("\\\\","\\\\\\\\")); - //just to be shure... - String replaceSeparator = File.separator; - if(!replaceSeparator.equals("/")){ - replaceSeparator = "\\\\"; - } - filePath = filePath.replaceAll("/", replaceSeparator); - filePath = filePath.replaceAll("\\\\", replaceSeparator); - } - log.fine("filePath: " + filePath); - final File file = new File(filePath); - if (file.exists()) { - // read files into byte[] - final byte[] dataEntry = new byte[(int) file.length()]; - try { - final FileInputStream fileInputStream = new FileInputStream(file); - fileInputStream.read(dataEntry); - fileInputStream.close(); - } catch (FileNotFoundException e) { - log.severe("File Not Found."); - e.printStackTrace(); - } catch (IOException e1) { - log.severe("Error Reading The File."); - e1.printStackTrace(); - } - final MAttachmentEntry entry = new MAttachmentEntry(filePath, - dataEntry, m_items.size() + 1); - m_items.add(entry); - } else { - log.severe("file not found: " + file.getAbsolutePath()); - } - } - - } catch (SAXException sxe) { - // Error generated during parsing) - Exception x = sxe; - if (sxe.getException() != null) - x = sxe.getException(); - x.printStackTrace(); - log.severe(x.getMessage()); - - } catch (ParserConfigurationException pce) { - // Parser with specified options can't be built - pce.printStackTrace(); - log.severe(pce.getMessage()); - - } catch (IOException ioe) { - // I/O error - ioe.printStackTrace(); - log.severe(ioe.getMessage()); - } - - return true; - - } - - /** - * Returns a path snippet, containing client, org, table and record id. - * @return String - */ - public String getAttachmentPathSnippet(){ - - StringBuilder msgreturn = new StringBuilder().append(this.getAD_Client_ID()).append(File.separator) - .append(this.getAD_Org_ID()).append(File.separator) - .append(this.getAD_Table_ID()).append(File.separator).append(this.getRecord_ID()); - return msgreturn.toString(); - } - /** * Before Save * @param newRecord new @@ -877,15 +497,6 @@ public class MAttachment extends X_AD_Attachment */ protected boolean beforeSave (boolean newRecord) { - if(isStoreAttachmentsOnFileSystem){ - if (getTitle() == null || !getTitle().equals(XML)) { - setTitle (XML); - } - } else { - if (getTitle() == null || !getTitle().equals(ZIP)) { - setTitle (ZIP); - } - } return saveLOBData(); // save in BinaryData } // beforeSave @@ -895,25 +506,21 @@ public class MAttachment extends X_AD_Attachment */ protected boolean beforeDelete () { - if (isStoreAttachmentsOnFileSystem) { - //delete all attachment files and folder - for (int i=0; i storelist = Service.locator().list(IAttachmentStore.class, query).getServices(); + + IAttachmentStore store = null; + if (storelist == null) { + log.saveError("Error", "No storage provider found"); + } else { + store = storelist.get(0); + } + return store; + } }