Index: ZipExplorerPlugin.java =================================================================== --- ZipExplorerPlugin.java (revision 1903) +++ ZipExplorerPlugin.java (working copy) @@ -24,6 +24,8 @@ import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.cache.api.XWikiCache; +import com.xpn.xwiki.cache.api.XWikiCacheNeedsRefreshException; import com.xpn.xwiki.api.Api; import com.xpn.xwiki.api.Attachment; import com.xpn.xwiki.api.Document; @@ -32,14 +34,12 @@ import com.xpn.xwiki.plugin.XWikiDefaultPlugin; import com.xpn.xwiki.plugin.XWikiPluginInterface; import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -50,9 +50,16 @@ */ public class ZipExplorerPlugin extends XWikiDefaultPlugin { + private static final Log log = LogFactory.getLog(ZipExplorerPlugin.class); + private static final int TYPE_ZIP = 4; + private static final int TYPE_FILE = 5; + private static String name = "zipexplorer"; + private XWikiCache zipExplorerCache; + private int capacity = 50; + /** * Path separators for URL. - * @todo Define this somewhere else as this is not specific to this plugin + * @todo Define this somewhere else as this is not specific to this plugin */ private static final String URL_SEPARATOR = "/"; @@ -74,10 +81,45 @@ */ public String getName() { - return "zipexplorer"; + return name; } + public void init(XWikiContext context) { + super.init(context); + initCache(context); + } + /** + * Initializing the cache with setting the properties of meemory use or disk use or combining two of the them and + * setting the path of the cache. + * @param context the XWiki context, used to get the default capacity. + */ + public void initCache(XWikiContext context) { + String capacityParam = ""; + try { + capacityParam = context.getWiki().Param("xwiki.plugin.zipexplorer.cache.capacity"); + if ((capacityParam!=null)&&(!capacityParam.equals(""))) + capacity = Integer.parseInt(capacityParam); + } catch (NumberFormatException e) { + if (log.isErrorEnabled()) + log.error("Error in ImagePlugin reading capacity: " + capacityParam, e); + } + + Properties props = new Properties(); + props.put("cache.memory", "true"); + props.put("cache.unlimited.disk", "true"); + props.put("cache.persistence.overflow.only", "false"); + props.put("cache.blocking", "false"); + + props.put("cache.persistence.class", "com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener"); + props.put("cache.path", "temp/zipExplorerCache"); + + try { + zipExplorerCache = context.getWiki().getCacheService().newLocalCache(props, capacity); + } catch (XWikiException e) { + } + } + /** * {@inheritDoc} * * @see com.xpn.xwiki.plugin.XWikiDefaultPlugin#getPluginApi @@ -89,9 +131,9 @@ /** * For ZIP URLs of the format http://[...]/zipfile.zip/SomeDirectory/SomeFile.txt - * return a new attachment containing the file pointed to inside the ZIP. If the original - * attachment does not point to a ZIP file or if it doesn't specify a location inside the ZIP - * then do nothing and return the original attachment. + * return a attachment if it exists in cache otherwise, a new attachment containing the file pointed to + * inside the ZIP. If the original attachment does not point to a ZIP file or if it doesn't specify a + * location inside the ZIP then do nothing and return the original attachment. * * @param attachment the original attachment * @param context the XWiki context, used to get the request URL corresponding to the download @@ -111,46 +153,69 @@ { return attachment; } + // initializing the cache if is it not. + if (zipExplorerCache==null) + initCache(context); String filename = getFileLocationFromZipURL(url, context.getAction().trim()); - - // Create the new attachment pointing to the file inside the ZIP - XWikiAttachment newAttachment = new XWikiAttachment(); + // building unique name to place in cache + String key = attachment.getDoc() + "-" + attachment.getId() + "-" + attachment.getVersion() + "-" + TYPE_FILE + "-" + attachment.getFilename() + "-" + filename; + //String key = attachment.getDoc().getFullName() + "-" + attachment.getFilename() + "-" + attachment.getVersion(); + XWikiAttachment newAttachment = new XWikiAttachment(); newAttachment.setDoc(attachment.getDoc()); newAttachment.setAuthor(attachment.getAuthor()); newAttachment.setDate(attachment.getDate()); - try { - byte[] stream = attachment.getContent(context); - ByteArrayInputStream bais = new ByteArrayInputStream(stream); - ZipInputStream zis = new ZipInputStream(bais); - ZipEntry entry; + // checking cache is initialised or not. + if(zipExplorerCache != null){ + try{ + // if the key found in cache then it will take from here , otherwise it will raise the exception + byte[] data = (byte[])zipExplorerCache.getFromCache(key); + newAttachment.setFilesize(data.length); + newAttachment.setContent(data); + newAttachment.setFilename(filename); + }catch(XWikiCacheNeedsRefreshException ex) { + // if attachment does not exists in cache , then it will create new one. + // Create the new attachment pointing to the file inside the ZIP + try { + byte[] stream = attachment.getContent(context); + ByteArrayInputStream bais = new ByteArrayInputStream(stream); + ZipInputStream zis = new ZipInputStream(bais); + ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - String entryName = entry.getName(); + while ((entry = zis.getNextEntry()) != null) { + String entryName = entry.getName(); - if (entryName.equals(filename)) { - newAttachment.setFilename(entryName); + if (entryName.equals(filename)) { + newAttachment.setFilename(entryName); - // Note: We're copying the content of the file in the ZIP in memory. This is - // potentially going to cause an error if the file's size is greater than the - // maximum size of a byte[] array in Java or if there's not enough memomry. - byte[] data = IOUtils.toByteArray(zis); + // Note: We're copying the content of the file in the ZIP in memory. This is + // potentially going to cause an error if the file's size is greater than the + // maximum size of a byte[] array in Java or if there's not enough memomry. + byte[] data = IOUtils.toByteArray(zis); - newAttachment.setFilesize(data.length); - newAttachment.setContent(data); - break; - } - } - } catch (XWikiException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } + newAttachment.setFilesize(data.length); + newAttachment.setContent(data); + break; + } + } + // putting the new one into cache + zipExplorerCache.putInCache(key, newAttachment.getContent(context)); + } catch (XWikiException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } return newAttachment; } /** + * Ftirst It will check the cache if the file exists with the name attachmentName. If it is then it will return + * the list of file entries in the zip file with attachementName.Otherwise the it will return list of file entries + * in the ZIP file attached under the passed attachment name inside the passed document. + * * @param document the document containing the ZIP file as an attachment * @param attachmentName the name under which the ZIP file is attached in the document * @param context not used @@ -162,21 +227,39 @@ { List zipList = null; if (isZipFile(attachmentName)) { + // initializing the cache if is it not. + if (zipExplorerCache==null) + initCache(context); + Attachment attachment = document.getAttachment(attachmentName); zipList = new ArrayList(); - try { - byte[] stream = attachment.getContent(); - ByteArrayInputStream bais = new ByteArrayInputStream(stream); - ZipInputStream zis = new ZipInputStream(bais); - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - zipList.add(entry.getName()); - } - } catch (XWikiException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + // building unique name to place in cache + String key = document.getFullName() + "-" + attachment.getId() + "-" + attachment.getVersion() + "-" + TYPE_ZIP + attachmentName; + // checking cache is initialised or not. + if(zipExplorerCache != null){ + try{ + // if the key found in cache then it will take from here , otherwise it will raise the exception + zipList = (ArrayList)zipExplorerCache.getFromCache(key); + }catch(XWikiCacheNeedsRefreshException ex) { + // if attachment does not exists in cache , then it will create new one. + try { + byte[] stream = attachment.getContent(); + ByteArrayInputStream bais = new ByteArrayInputStream(stream); + ZipInputStream zis = new ZipInputStream(bais); + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + zipList.add(entry.getName()); + } + // putting the new one into cache + zipExplorerCache.putInCache(key, zipList); + } catch (XWikiException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } } + } return zipList; }