package com.yahoo.dtf.storage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import com.yahoo.dtf.storage.Storage;
import com.yahoo.dtf.actions.Action;
import com.yahoo.dtf.exception.StorageException;
import com.yahoo.dtf.logger.DTFLogger;
import com.yahoo.dtf.util.MultiMemberGZIPInputStream;
import com.yahoo.dtf.util.SystemUtil;
public class Storage extends StorageIntf {
private static DTFLogger _logger = DTFLogger.getLogger(Storage.class);
private File _fpath = null;
private HashMap<String, ModifiedOptions> _modified = null;
private static class ModifiedOptions {
public boolean append = false;
public long modified = 0;
public long offset = 0;
public ModifiedOptions(long modified,
boolean append,
long offset) {
this.modified = modified;
this.append = append;
this.offset = offset;
}
}
public Storage(String id, String path, boolean export) throws StorageException {
super(id,path,export);
_fpath = new File(path);
if ( !_fpath.exists() ) {
if ( _logger.isDebugEnabled() )
_logger.debug("Storage path does not exist [" + path +
"] will create.");
if ( !_fpath.mkdirs() )
throw new StorageException("Unable to create storage path [" +
path + "], check folder permissions/ownership");
}
_fpath = new File(getPath());
_modified = new HashMap<String, ModifiedOptions>();
}
public boolean exists(String filename) {
return new File(_fpath.getAbsolutePath() +
File.separatorChar + filename).exists();
}
public OutputStream getOutputStream(String filename, boolean append)
throws StorageException {
try {
File file = new File(_fpath.getAbsolutePath() +
File.separatorChar + filename);
if (!append && file.isDirectory()) {
if ( _logger.isDebugEnabled() )
_logger.debug("Wiping " + file);
SystemUtil.deleteDirectory(file);
}
FileOutputStream fos = new FileOutputStream(file, append);
modifiedUpdate(file.getName(), append, file.length());
return fos;
} catch (IOException e) {
throw new StorageException("Unable to retrieve OutputStream for storage: " + getId(),e);
}
}
public InputStream getInputStream(String filename,
boolean checkForCompression)
throws StorageException {
try {
if (new File(_fpath.getAbsolutePath() + File.separatorChar +
filename + ".gz").exists()) {
filename += ".gz";
}
if (filename.endsWith(".gz")) {
return new MultiMemberGZIPInputStream(filename,this);
} else {
return getInputStream(filename);
}
} catch (IOException e) {
throw new StorageException("Unable to retrieve InputStream for storage: " + getId(),e);
}
}
public InputStream getInputStream(String filename)
throws StorageException {
try {
return new FileInputStream(_fpath.getAbsolutePath() +
File.separatorChar + filename);
} catch (FileNotFoundException e) {
throw new StorageException("Unable to retrieve InputStream for storage: " + getId(),e);
}
}
@Override
public void createPath(String path) throws StorageException {
File aux = new File(_fpath, path);
if ( !aux.mkdirs() )
throw new StorageException("Unable to create [" +
aux.getAbsolutePath() + "]");
}
@Override
public void wipe() throws StorageException {
wipe(_fpath);
}
/**
* This just wipes the directories for any files that shouldn't be there.
* Nothing is done to the directory structure itself and .nfs files are
* avoided since they sometimes refuse to be deleted.
*/
private void wipe(File path) throws StorageException {
String[] files = path.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
return !name.startsWith(".nfs");
}
}
);
if (files != null) {
for (int i = 0; i < files.length; i++) {
File file = new File(path.getAbsolutePath() + File.separatorChar + files[i]);
if (file.isFile()) {
if ( !file.delete() ) {
throw new StorageException("Unable to delete file [" + file +
"]");
}
} else {
wipe(file);
}
}
}
}
@Override
public boolean isDirectory(String path) {
return new File(_fpath, path).isDirectory();
}
@Override
public String getFullPath() {
return _fpath.getPath();
}
@Override
public String[] getFiles() {
return _fpath.list();
}
@Override
public String[] getFiles(String path) {
return new File(_fpath, path).list();
}
@Override
public Long getLastModified(String filename) {
ModifiedOptions mo = _modified.get(filename);
if ( mo == null ) {
return 0L;
}
return mo.modified;
}
@Override
public boolean openedAsAppend(String filename) {
ModifiedOptions mo = _modified.get(filename);
if ( mo == null )
return false;
else
return mo.append;
}
@Override
public long lastOpenedOffset(String filename) {
ModifiedOptions mo = _modified.get(filename);
if ( mo == null )
return 0;
else
return mo.offset;
}
private void modifiedUpdate(String filename, boolean append, long offset) {
ModifiedOptions mo = _modified.get(filename);
if ( mo == null ) {
mo = new ModifiedOptions(0, append, offset);
_modified.put(filename, mo);
}
if ( append == false || (mo.offset == 0 && !mo.append) )
mo.offset = offset;
mo.append = append;
mo.modified++;
}
@Override
public void delete(String filename) throws StorageException {
File file = new File(_fpath, filename);
if ( !file.exists() ) {
throw new StorageException("File [" + filename + "] does not exist");
}
if ( !file.delete() ) {
throw new StorageException("Unable to delete [" + filename + "]");
}
}
@Override
public void move(String src, String dst) throws StorageException {
File srcFile = new File(_fpath,src);
File dstFile = new File(_fpath,dst);
if ( !srcFile.renameTo(dstFile) ) {
throw new StorageException("Unable to rename [" + srcFile +
"] to [" + dstFile + "]");
}
}
}