com.tangosol.engarde.DirectoryStorage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.engarde;
import com.tangosol.util.Base;
import com.tangosol.util.NullImplementation;
import com.tangosol.util.StringTable;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.jar.JarFile;
/**
* Directory tree that contains a Java application components.
*
* @version 1.00 10/08/01
* @author gg
*/
public class DirectoryStorage
extends Base
implements ApplicationReader, ApplicationWriter
{
/**
* Construct a new DirectoryStorage
*
* @param dirRoot root directory
* @param iAccess access mode could be one of of the following values:
* ACCESS_READ, ACCESS_WRITE or ACCESS_READ | ACCESS_WRITE
*/
public DirectoryStorage(File dirRoot, int iAccess)
throws IOException
{
azzert((iAccess & (ACCESS_READ | ACCESS_WRITE)) != 0, "Illegal access mode: " + iAccess);
if (dirRoot == null || !dirRoot.isDirectory())
{
throw new IOException("Not a directory: " + dirRoot);
}
m_dirRoot = dirRoot.getCanonicalFile();
m_fAllowRead = (iAccess & ACCESS_READ) != 0;
m_fAllowWrite = (iAccess & ACCESS_WRITE) != 0;
}
/**
* Get the root directory
*/
public File getRoot()
{
return m_dirRoot;
}
/**
* Provide a human-readable description of the storage.
*
* @return a string describing the property
*/
public String toString()
{
return CLASS + ": " + m_dirRoot;
}
// ---- ApplicationReader interface ---------------------------------------
/**
* Return an input stream for reading the content of the specified
* application entry.
*
* @param entry the application entry
*
* @return an input stream for reading the content of the specified
* application entry or null if not found
*
* @exception IOException if an I/O error has occurred
*/
public InputStream getInputStream(ApplicationEntry entry)
throws IOException
{
if (!m_fAllowRead)
{
throw new IllegalStateException(
"ApplicationReader operation is not allowed");
}
File file = new File(m_dirRoot, entry.getName());
return file.isFile() ? (InputStream)
new FileInputStream(file) : new ByteArrayInputStream(new byte[0]);
}
/**
* Return an ApplicationReader that represents an application contained
* within this application as a specified application entry
*
* @param sName name of the application entry
*
* @return an ApplicationReader object for reading the content of
* the contained application or null if not found
*
* @exception IOException if an I/O error has occurred
*/
public ApplicationReader extractApplication(String sName)
throws IOException
{
if (!m_fAllowRead)
{
throw new IllegalStateException(
"ApplicationReader operation is not allowed");
}
File file = new File(m_dirRoot, sName);
if (file.exists())
{
return file.isDirectory() ? (ApplicationReader)
new DirectoryStorage(file,
m_fAllowWrite ? ACCESS_READ | ACCESS_WRITE : ACCESS_READ) :
new JarStorage(new JarFile(file.getCanonicalFile()));
}
return null;
}
/**
* Return an ApplicationEntry object for the given name
*
* @param sName name of the application entry
*
* @return ApplicationEntry object for the given entry name or
* null if not found
*/
public ApplicationEntry getEntry(String sName)
{
if (!m_fAllowRead)
{
throw new IllegalStateException(
"ApplicationReader operation is not allowed");
}
File file = new File(m_dirRoot, sName);
return file.exists() ? new Entry(sName, file.isDirectory()) : null;
}
/**
* Return an enumeration of the application entries
*
* @return Enumeration of ApplicationEntry objects
*/
public Enumeration entries()
{
if (!m_fAllowRead)
{
throw new IllegalStateException(
"ApplicationReader operation is not allowed");
}
StringTable tbl = new StringTable();
collectEntries(m_dirRoot, tbl);
return tbl.elements();
}
private void collectEntries(File dir, StringTable tbl)
{
File[] aFile = dir.listFiles();
if (aFile != null)
{
String sRoot = m_dirRoot.getPath() + File.separatorChar;
int cchRoot = sRoot.length();
for (int i = 0, c = aFile.length; i < c; i++)
{
File file = aFile[i];
String sPath = file.getPath();
azzert(sPath.startsWith(sRoot));
sPath = sPath.substring(cchRoot).replace(File.separatorChar, '/');
if (file.isFile())
{
tbl.put(sPath, new Entry(sPath, false));
}
else if (file.isDirectory())
{
tbl.put(sPath, new Entry(sPath, true));
collectEntries(file, tbl);
}
}
}
}
/**
* Close the application reader and release all used resources
*/
public void close()
{
m_fAllowRead = false;
if (m_fAllowWrite)
{
try
{
closeEntry();
}
catch (IOException e) {}
m_fAllowWrite = false;
}
}
// ---- ApplicationWriter interface ---------------------------------------
/**
* Create a new application entry with all attributes of the specified
* entry and prepare to start writing the entry data.
* Close the current entry if still active.
*
* @param entry an application entry
*
* @return a newly created AppplicationEntry
*
* @exception IOException if an I/O error has occurred
*/
public ApplicationEntry createEntry(ApplicationEntry entry)
throws IOException
{
if (!m_fAllowWrite)
{
throw new IllegalStateException(
"ApplicationWriter operation is not allowed");
}
Entry entryCurr = m_currEntry;
if (entryCurr != null)
{
closeEntry();
}
entryCurr = ensureEntry(entry.getName(),
entry instanceof Entry && ((Entry) entry).isDirectory());
entryCurr.setTime(entry.getTime());
return entryCurr;
}
/**
* Create a new application entry with a given name and prepare to start
* writing the entry data. Close the current entry if still active.
*
* @param sName the application entry name
*
* @return a newly created AppplicationEntry
*
* @exception IOException if an I/O error has occurred
*/
public ApplicationEntry createEntry(String sName)
throws IOException
{
if (!m_fAllowWrite)
{
throw new IllegalStateException(
"ApplicationWriter operation is not allowed");
}
Entry entry = m_currEntry;
if (entry != null)
{
closeEntry();
}
return ensureEntry(sName, sName.endsWith("/"));
}
private Entry ensureEntry(String sName, boolean fDir)
throws IOException
{
// the entry could refer to a symbolic link; resolve the actual
// (canonical) file before attempting to create parent directories
File file = new File(m_dirRoot, sName).getCanonicalFile();
File dir = file.getParentFile();
if (!dir.exists() && !dir.mkdirs())
{
throw new IOException(CLASS +
": Failure to create directory: " + dir);
}
m_currOut = fDir ? NullImplementation.getOutputStream() :
new FileOutputStream(file);
m_currEntry = new Entry(sName, fDir);
return m_currEntry;
}
/**
* Write an array of bytes to the current application entry data.
* This method will block until all the bytes are written.
*
* @param ab the data to be written
* @param of the offset into the array
* @param cb the number of bytes to write
*
* @exception IOException if an I/O error has occurred
*/
public void writeEntryData(byte[] ab, int of, int cb)
throws IOException
{
if (!m_fAllowWrite)
{
throw new IllegalStateException(
"ApplicationWriter operation is not allowed");
}
if (m_currOut == null)
{
throw new IllegalStateException("Request is out of sequence");
}
if (m_currEntry.isDirectory() && cb > 0)
{
throw new IllegalStateException(
"Illegal write operation to a directory: " + m_currEntry);
}
if (cb > 0)
{
m_currOut.write(ab, of, cb);
}
}
/**
* Close the current application entry.
*
* @exception IOException if an I/O error has occurred
*/
public void closeEntry()
throws IOException
{
if (!m_fAllowWrite)
{
throw new IllegalStateException(
"ApplicationWriter operation is not allowed");
}
Entry entry = m_currEntry;
if (entry != null)
{
m_currOut.close();
entry.getFile().setLastModified(entry.getTime());
m_currOut = null;
m_currEntry = null;
}
}
// ---- data fields and constants ----------------------------------------
/**
* Specifies whether or not the "read" operations are allowed
*/
private boolean m_fAllowRead;
/**
* Specifies whether or not the "write" operations are allowed
*/
private boolean m_fAllowWrite;
/**
* Specifies the root directory of this storage
*/
private File m_dirRoot;
/**
* Specifies the currently "active" entry
*/
private Entry m_currEntry;
/**
* Specifies the currently "active" file output stream
*/
private OutputStream m_currOut;
/**
* ACCESS_READ denotes the read only mode of operations
*/
public static final int ACCESS_READ = 1;
/**
* ACCESS_WRITE denotes the read only mode of operations
*/
public static final int ACCESS_WRITE = 2;
/**
* The name of this class.
*/
private static final String CLASS = "DirectoryStorage";
// ---- inner class -------------------------------------------------------
public class Entry
implements ApplicationEntry
{
/**
* Construct a new entry for the specified path
*/
protected Entry(String sPath, boolean fDir)
{
azzert(sPath != null);
m_sPath = sPath;
m_fDir = fDir;
}
/**
* Return the file object for this entry.
*
* @return the name of the entry
*/
public File getFile()
{
return new File(m_dirRoot, m_sPath);
}
/**
* Check whether or not this entry represents a directory.
*
* @return true iff this entry represents a directory
*/
public boolean isDirectory()
{
return m_fDir;
}
// ---- ApplicationEntry interface ------------------------------------
/**
* Return the name of the entry.
*
* @return the name of the entry
*/
public String getName()
{
return m_sPath;
}
/**
* Return the modification time of the entry, or -1 if not specified.
*
* @return the modification time of the entry, or -1 if not specified
*/
public long getTime()
{
return m_lTime == 0 ? getFile().lastModified() : m_lTime;
}
/**
* Set the modification time of the entry.
*
* @param lTime the entry modification time in number of milliseconds
* since the epoch
*/
public void setTime(long lTime)
{
m_lTime = lTime;
}
/**
* Return the [uncompressed] size of the entry data, or -1 if not known.
*
* @return the size of the entry data, or -1 if not known
*/
public long getSize()
{
return getFile().length();
}
/**
* Set the [uncompressed] size of the entry data.
*
* @param lSize the size in bytes
*/
public void setSize(long lSize)
{
// no op
}
// ----- Object methods -------------------------------------------
/**
* Provide a human-readable description of the storage.
*
* @return a string describing the property
*/
public String toString()
{
return "DirectoryStorage$Entry: " + getFile();
}
// ---- data fields --------------------------------------------------
/**
* Path relative to the storage root representing this Entry
*/
private String m_sPath;
/**
* Directory indicator.
*/
private boolean m_fDir;
/**
* Cached value of time attribute
*/
private long m_lTime;
}
}