/* * 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. */ package com.addthis.hydra.task.output; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.zip.GZIPOutputStream; import com.addthis.bundle.core.Bundle; import com.addthis.hydra.store.compress.CompressionType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractOutputWrapper implements OutputWrapper{ private static final Logger log = LoggerFactory.getLogger(AbstractOutputWrapper.class); private OutputStream rawout; private OutputStreamEmitter lineout; private boolean compress; private CompressionType compressType; private final AtomicLong lineCount = new AtomicLong(); private long lastAccessTime; private String rawTarget; private final Lock wrapperLock = new ReentrantLock(); private boolean closed = false; public AbstractOutputWrapper(OutputStream out, OutputStreamEmitter lineout, boolean compress, CompressionType compressType, String rawTarget) { this.rawout = out; this.lineout = lineout; this.compress = compress; this.compressType = compressType; this.rawTarget = rawTarget; } @Override public String getRawTarget() { return rawTarget; } @Override public void incrementLineCount() { lineCount.incrementAndGet(); } @Override public long getLastAccessTime() { return lastAccessTime; } @Override public void setLastAccessTime(long lastAccessTime) { this.lastAccessTime = lastAccessTime; } @Override public long getLineCount() { return lineCount.get(); } @Override public void close() { wrapperLock.lock(); try { if (closed) { return; } closed = true; if (lineout != null) { try { lineout.flush(rawout); } catch (Exception ex) { log.warn("", ex); } } if (rawout != null) { if (compress && compressType == CompressionType.GZIP) { try { ((GZIPOutputStream) rawout).finish(); } catch (Exception ex) { log.warn("", ex); } } else if (compress && compressType == CompressionType.SNAPPY) { try { rawout.flush(); } catch (IOException e) { log.warn("", e); } } else if (compress && compressType == CompressionType.BZIP2) { try { rawout.flush(); } catch (IOException e) { log.warn("", e); } } closeStream(rawout); } renameTempTargetFile(); } finally { wrapperLock.unlock(); } } protected abstract void renameTempTargetFile(); private void closeStream(OutputStream outputStream) { try { outputStream.flush(); } catch (Exception ex) { log.warn("", ex); } finally { try { outputStream.close(); } catch (Exception ex) { log.warn("", ex); } } } @Override public void write(ByteArrayOutputStream bufOut, Bundle row) throws IOException { wrapperLock.lock(); try { if (!closed) { lineout.write(bufOut, row); } else { throw new IOException("output wrapper for file: " + getFileName() + " was closed"); } } finally { wrapperLock.unlock(); } } @Override public void write(byte[] bytes) throws IOException { wrapperLock.lock(); try { if (!closed) { rawout.write(bytes); } else { throw new IOException("output wrapper for file: " + getFileName() + " was closed"); } } finally { wrapperLock.unlock(); } } @Override public boolean isClosed() { return closed; } @Override public void lock() { wrapperLock.lock(); } @Override public void unlock() { wrapperLock.unlock(); } }