14fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/*
24fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Licensed to the Apache Software Foundation (ASF) under one or more
34fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * contributor license agreements.  See the NOTICE file distributed with
44fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * this work for additional information regarding copyright ownership.
54fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The ASF licenses this file to You under the Apache License, Version 2.0
64fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * (the "License"); you may not use this file except in compliance with
74fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * the License.  You may obtain a copy of the License at
84fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
94fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      http://www.apache.org/licenses/LICENSE-2.0
104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Unless required by applicable law or agreed to in writing, software
124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * distributed under the License is distributed on an "AS IS" BASIS,
134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * See the License for the specific language governing permissions and
154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * limitations under the License.
164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */
174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypackage org.apache.commons.io.output;
184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.File;
204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.FileOutputStream;
214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.FileWriter;
224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.IOException;
234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.OutputStream;
244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.OutputStreamWriter;
254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.Writer;
264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.commons.io.FileUtils;
284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.commons.io.IOUtils;
294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/**
314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * FileWriter that will create and honor lock files to allow simple
324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * cross thread file lock handling.
334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This class provides a simple alternative to <code>FileWriter</code>
354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * that will use a lock file to prevent duplicate writes.
364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * By default, the file will be overwritten, but this may be changed to append.
384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The lock directory may be specified, but defaults to the system property
394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <code>java.io.tmpdir</code>.
404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The encoding may also be specified, and defaults to the platform default.
414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author <a href="mailto:ms@collab.net">Michael Salmon</a>
444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author Stephen Colebourne
474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author Andy Lehane
484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @version $Id: LockableFileWriter.java 610010 2008-01-08 14:50:59Z niallp $
494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */
504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypublic class LockableFileWriter extends Writer {
514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    // Cannot extend ProxyWriter, as requires writer to be
524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    // known when super() is called
534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The extension for the lock file. */
554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private static final String LCK = ".lck";
564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The writer to decorate. */
584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private final Writer out;
594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The lock file. */
604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private final File lockFile;
614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter.
644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * If the file exists, it is overwritten.
654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param fileName  the file to write to, not null
674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(String fileName) throws IOException {
714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(fileName, false, null);
724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter.
764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param fileName  file to write to, not null
784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param append  true if content should be appended, false to overwrite
794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(String fileName, boolean append) throws IOException {
834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(fileName, append, null);
844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter.
884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param fileName  the file to write to, not null
904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param append  true if content should be appended, false to overwrite
914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param lockDir  the directory in which the lock file should be held
924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(String fileName, boolean append, String lockDir) throws IOException {
964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(new File(fileName), append, lockDir);
974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter.
1014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * If the file exists, it is overwritten.
1024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the file to write to, not null
1044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
1054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
1064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(File file) throws IOException {
1084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(file, false, null);
1094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter.
1134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the file to write to, not null
1154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param append  true if content should be appended, false to overwrite
1164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
1174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
1184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(File file, boolean append) throws IOException {
1204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(file, append, null);
1214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter.
1254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the file to write to, not null
1274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param append  true if content should be appended, false to overwrite
1284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param lockDir  the directory in which the lock file should be held
1294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
1304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
1314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(File file, boolean append, String lockDir) throws IOException {
1334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(file, null, append, lockDir);
1344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter with a file encoding.
1384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the file to write to, not null
1404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param encoding  the encoding to use, null means platform default
1414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
1424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
1434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(File file, String encoding) throws IOException {
1454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(file, encoding, false, null);
1464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Constructs a LockableFileWriter with a file encoding.
1504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the file to write to, not null
1524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param encoding  the encoding to use, null means platform default
1534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param append  true if content should be appended, false to overwrite
1544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param lockDir  the directory in which the lock file should be held
1554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws NullPointerException if the file is null
1564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException in case of an I/O error
1574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public LockableFileWriter(File file, String encoding, boolean append,
1594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            String lockDir) throws IOException {
1604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        super();
1614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // init file to create/append
1624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        file = file.getAbsoluteFile();
1634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (file.getParentFile() != null) {
1644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            FileUtils.forceMkdir(file.getParentFile());
1654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (file.isDirectory()) {
1674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw new IOException("File specified is a directory");
1684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // init lock file
1714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (lockDir == null) {
1724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            lockDir = System.getProperty("java.io.tmpdir");
1734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        File lockDirFile = new File(lockDir);
1754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        FileUtils.forceMkdir(lockDirFile);
1764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        testLockDir(lockDirFile);
1774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        lockFile = new File(lockDirFile, file.getName() + LCK);
1784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // check if locked
1804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        createLock();
1814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        // init wrapped writer
1834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        out = initWriter(file, encoding, append);
1844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    //-----------------------------------------------------------------------
1874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Tests that we can write to the lock directory.
1894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param lockDir  the File representing the lock directory
1914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if we cannot write to the lock directory
1924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if we cannot find the lock file
1934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private void testLockDir(File lockDir) throws IOException {
1954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (!lockDir.exists()) {
1964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw new IOException(
1974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    "Could not find lockDir: " + lockDir.getAbsolutePath());
1984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (!lockDir.canWrite()) {
2004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw new IOException(
2014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    "Could not write to lockDir: " + lockDir.getAbsolutePath());
2024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Creates the lock file.
2074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if we cannot create the file
2094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private void createLock() throws IOException {
2114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        synchronized (LockableFileWriter.class) {
2124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (!lockFile.createNewFile()) {
2134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                throw new IOException("Can't write file, lock " +
2144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                        lockFile.getAbsolutePath() + " exists");
2154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
2164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            lockFile.deleteOnExit();
2174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Initialise the wrapped file writer.
2224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Ensure that a cleanup occurs if the writer creation fails.
2234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param file  the file to be accessed
2254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param encoding  the encoding to use
2264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param append  true to append
2274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return The initialised writer
2284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an error occurs
2294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private Writer initWriter(File file, String encoding, boolean append) throws IOException {
2314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        boolean fileExistedAlready = file.exists();
2324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        OutputStream stream = null;
2334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        Writer writer = null;
2344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        try {
2354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (encoding == null) {
2364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                writer = new FileWriter(file.getAbsolutePath(), append);
2374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            } else {
2384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                stream = new FileOutputStream(file.getAbsolutePath(), append);
2394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                writer = new OutputStreamWriter(stream, encoding);
2404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
2414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        } catch (IOException ex) {
2424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            IOUtils.closeQuietly(writer);
2434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            IOUtils.closeQuietly(stream);
2444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            lockFile.delete();
2454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (fileExistedAlready == false) {
2464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                file.delete();
2474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
2484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw ex;
2494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        } catch (RuntimeException ex) {
2504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            IOUtils.closeQuietly(writer);
2514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            IOUtils.closeQuietly(stream);
2524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            lockFile.delete();
2534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (fileExistedAlready == false) {
2544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                file.delete();
2554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
2564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw ex;
2574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return writer;
2594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    //-----------------------------------------------------------------------
2624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Closes the file writer.
2644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs
2664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void close() throws IOException {
2684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        try {
2694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            out.close();
2704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        } finally {
2714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            lockFile.delete();
2724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    //-----------------------------------------------------------------------
2764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Write a character.
2784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param idx the character to write
2794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs
2804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void write(int idx) throws IOException {
2824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        out.write(idx);
2834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Write the characters from an array.
2874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param chr the characters to write
2884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs
2894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void write(char[] chr) throws IOException {
2914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        out.write(chr);
2924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Write the specified characters from an array.
2964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param chr the characters to write
2974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param st The start offset
2984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param end The number of characters to write
2994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs
3004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void write(char[] chr, int st, int end) throws IOException {
3024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        out.write(chr, st, end);
3034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
3064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Write the characters from a string.
3074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param str the string to write
3084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs
3094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void write(String str) throws IOException {
3114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        out.write(str);
3124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
3154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Write the specified characters from a string.
3164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param str the string to write
3174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param st The start offset
3184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param end The number of characters to write
3194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs
3204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void write(String str, int st, int end) throws IOException {
3224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        out.write(str, st, end);
3234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
3264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Flush the stream.
3274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs
3284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void flush() throws IOException {
3304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        out.flush();
3314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy}
334