/** * VMware Continuent Tungsten Replicator * Copyright (C) 2015 VMware, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Initial developer(s): Robert Hodges * Contributor(s): */ package com.continuent.tungsten.common.file; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; /** * Implements FileIO operations for generic OS file system supported by java.io * package. */ public class JavaFileIO implements FileIO { /** * Internal filter class to select file names based on a prefix. If the * prefix value is null all names are selected. */ public class LocalFilenameFilter implements FilenameFilter { private final String prefix; public LocalFilenameFilter(String prefix) { this.prefix = prefix; } public boolean accept(File dir, String name) { if (prefix == null) return true; else return name.startsWith(prefix); } } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#exists(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean exists(FilePath path) { return new File(path.toString()).exists(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#isFile(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean isFile(FilePath path) { return new File(path.toString()).isFile(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#isDirectory(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean isDirectory(FilePath path) { return new File(path.toString()).isDirectory(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#writable(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean writable(FilePath path) { return new File(path.toString()).canWrite(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#readable(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean readable(FilePath path) { return new File(path.toString()).canRead(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#list(com.continuent.tungsten.common.file.FilePath) */ @Override public String[] list(FilePath path) { return list(path, null); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#list(com.continuent.tungsten.common.file.FilePath, * java.lang.String) */ @Override public String[] list(FilePath path, String prefix) { // Children can only exist on directories. if (isDirectory(path)) { File dir = new File(path.toString()); String[] seqnoFileNames = dir.list(new LocalFilenameFilter(prefix)); return seqnoFileNames; } else { return new String[0]; } } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#mkdir(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean mkdir(FilePath path) { return new File(path.toString()).mkdirs(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#mkdirs(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean mkdirs(FilePath path) { return new File(path.toString()).mkdirs(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#delete(com.continuent.tungsten.common.file.FilePath) */ @Override public boolean delete(FilePath path) { return delete(path, false); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#delete(com.continuent.tungsten.common.file.FilePath, * boolean) */ @Override public boolean delete(FilePath path, boolean recursive) { // If the node does not exist, return immediately. if (!exists(path)) return true; // Try to delete children if this is recursive. Otherwise, // we cannot continuent and must return. if (isDirectory(path)) { for (String child : list(path)) { if (recursive) { boolean deleted = delete(new FilePath(path, child), recursive); if (!deleted) return false; } else return false; } } // Delete the path for which we were called. File fileToDelete = new File(path.toString()); return fileToDelete.delete(); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#write(com.continuent.tungsten.common.file.FilePath, * java.lang.String) */ @Override public void write(FilePath path, String value) throws FileIOException { write(path, value, "UTF-8", false); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#write(com.continuent.tungsten.common.file.FilePath, * java.lang.String, java.lang.String) */ @Override public void write(FilePath path, String value, String charset) throws FileIOException { write(path, value, charset, false); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#write(com.continuent.tungsten.common.file.FilePath, * java.lang.String, java.lang.String, boolean) */ @Override public void write(FilePath path, String value, String charset, boolean fsync) throws FileIOException { // Write the value and flush to storage. This overwrites any // previous version. FileOutputStream fos = null; try { fos = getOutputStream(path); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, charset)); bw.write(value); bw.flush(); if (fsync) { fos.getFD().sync(); } } catch (IOException e) { throw new FileIOException("Unable to write data to file: file=" + path.toString() + " value=" + safeSynopsis(value, 20), e); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { } } } } // Print a prefix of a string value avoiding accidental index // out-of-bounds errors. private String safeSynopsis(String value, int length) { if (value.length() <= length) return value; else return value.substring(0, 10) + "..."; } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#read(com.continuent.tungsten.common.file.FilePath) */ @Override public String read(FilePath path) throws FileIOException { return read(path, "UTF-8"); } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#read(com.continuent.tungsten.common.file.FilePath, * java.lang.String) */ @Override public String read(FilePath path, String charset) throws FileIOException { // Read from storage. FileInputStream fos = null; try { fos = getInputStream(path); BufferedReader bf = new BufferedReader(new InputStreamReader(fos, charset)); StringBuffer buf = new StringBuffer(); int nextChar = 0; while ((nextChar = bf.read()) > -1) { buf.append((char) nextChar); } return buf.toString(); } catch (IOException e) { throw new FileIOException("Unable to read data from file: file=" + path.toString(), e); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { } } } } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#getInputStream(com.continuent.tungsten.common.file.FilePath) */ public FileInputStream getInputStream(FilePath path) throws FileIOException { try { File f = new File(path.toString()); return new FileInputStream(f); } catch (IOException e) { throw new FileIOException("Unable to read data from file: file=" + path.toString(), e); } } /** * {@inheritDoc} * * @see com.continuent.tungsten.common.file.FileIO#getOutputStream(com.continuent.tungsten.common.file.FilePath) */ public FileOutputStream getOutputStream(FilePath path) throws FileIOException { try { File f = new File(path.toString()); return (new FileOutputStream(f)); } catch (IOException e) { throw new FileIOException("Unable to write data to file: file=" + path.toString(), e); } } }