/** * DataCleaner (community edition) * Copyright (C) 2014 Neopost - Customer Information Management * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.datacleaner.repository.file; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.metamodel.util.Action; import org.apache.metamodel.util.FileHelper; import org.apache.metamodel.util.FileResource; import org.apache.metamodel.util.Func; import org.apache.metamodel.util.Resource; import org.datacleaner.repository.AbstractRepositoryNode; import org.datacleaner.repository.RepositoryFile; import org.datacleaner.repository.RepositoryFolder; import org.datacleaner.util.FileFilters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@link RepositoryFile} implementation based on a local file. */ public final class FileRepositoryFile extends AbstractRepositoryNode implements RepositoryFile { private static final Logger logger = LoggerFactory.getLogger(FileRepositoryFile.class); private static final long serialVersionUID = 1L; private final ReadWriteLock _lock; private final FileRepositoryFolder _parent; private final File _file; public FileRepositoryFile(final FileRepositoryFolder parent, final File file) { _parent = parent; _file = file; _lock = new ReentrantReadWriteLock(); } /** * Gets the physical {@link File} that is backing this * {@link RepositoryFile} instance. * * @return */ public File getFile() { return _file; } @Override public RepositoryFolder getParent() { return _parent; } @Override public String getName() { return _file.getName(); } @Override public long getSize() { return _file.length(); } /** * {@inheritDoc} */ @Override @Deprecated public InputStream readFile() { try { final FileInputStream in = new FileInputStream(_file); return new BufferedInputStream(in); } catch (final FileNotFoundException e) { throw new IllegalStateException(e); } } @Override public void readFile(final Action<InputStream> readCallback) { final Lock readLock = _lock.readLock(); readLock.lock(); try { final FileInputStream fileInputStream; final InputStream inputStream; try { fileInputStream = new FileInputStream(_file); inputStream = new BufferedInputStream(fileInputStream); } catch (final FileNotFoundException e) { throw new IllegalStateException(e); } try { readCallback.run(inputStream); } catch (final Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new IllegalStateException("Error occurred while reading from file", e); } finally { FileHelper.safeClose(inputStream, fileInputStream); } } finally { readLock.unlock(); } } @Override public <E> E readFile(final Func<InputStream, E> readCallback) { final Lock readLock = _lock.readLock(); readLock.lock(); try { final FileInputStream fileInputStream; final InputStream inputStream; try { fileInputStream = new FileInputStream(_file); inputStream = new BufferedInputStream(fileInputStream); } catch (final FileNotFoundException e) { throw new IllegalStateException(e); } try { return readCallback.eval(inputStream); } catch (final Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new IllegalStateException("Error occurred while writing to file", e); } finally { FileHelper.safeClose(inputStream, fileInputStream); } } finally { readLock.unlock(); } } @Override public OutputStream writeFile(final boolean append) { try { return new FileOutputStream(_file, append); } catch (final FileNotFoundException e) { throw new IllegalStateException(e); } } @Override public void writeFile(final Action<OutputStream> writeCallback) { writeFile(writeCallback, false); } @Override public void writeFile(final Action<OutputStream> writeCallback, final boolean append) { final Lock writeLock = _lock.writeLock(); writeLock.lock(); try { final FileOutputStream fileOutputStream; final OutputStream outputStream; try { fileOutputStream = new FileOutputStream(_file, append); outputStream = new BufferedOutputStream(fileOutputStream); } catch (final FileNotFoundException e) { throw new IllegalStateException(e); } try { if (writeCallback != null) { writeCallback.run(outputStream); } } catch (final Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new IllegalStateException("Error occurred while writing to file", e); } finally { FileHelper.safeClose(outputStream, fileOutputStream); } } finally { writeLock.unlock(); } } @Override public Type getType() { if (getName().endsWith(FileFilters.ANALYSIS_XML.getExtension())) { return Type.ANALYSIS_JOB; } else if (getName().endsWith(FileFilters.ANALYSIS_RESULT_SER.getExtension())) { return Type.ANALYSIS_RESULT; } else if (getName().endsWith(FileFilters.ANALYSIS_TIMELINE_XML.getExtension())) { return Type.TIMELINE_SPEC; } return Type.OTHER; } @Override public void delete() throws IllegalStateException { final boolean success = _file.delete(); if (!success) { throw new IllegalStateException("Could not delete file: " + _file); } _parent.onDeleted(_file); } @Override public long getLastModified() { final long lastModified = _file.lastModified(); if (lastModified == 0) { if (logger.isWarnEnabled()) { logger.warn("File.lastModified() return 0. File.exists()={}, File.getPath()={}", Boolean.valueOf(_file.exists()), _file.getPath()); } return -1; } return lastModified; } @Override public Resource toResource() { return new FileResource(_file); } }