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