001    package org.LiveGraph.dataFile.write;
002    
003    import java.io.File;
004    import java.io.FileNotFoundException;
005    import java.io.FileOutputStream;
006    import java.util.Calendar;
007    import java.util.GregorianCalendar;
008    
009    
010    
011    /**
012     * This class provides static convenience methods for creating dedicated data stream writers.
013     * Given just a directory on the local hard drive, this class can automatically
014     * choose a descriptive and unique name for a data file and return an appropriate
015     * {@link DataStreamWriter} object.<br />
016     * <br />
017     * An example of how to use this class can be found in
018     * {@link org.LiveGraph.demoDataSource.LiveGraphDemo}.<br />
019     * 
020     * <p style="font-size:smaller;">This product includes software developed by the
021     *    <strong>LiveGraph</strong> project and its contributors.<br />
022     *    (<a href="http://www.live-graph.org" target="_blank">http://www.live-graph.org</a>)<br />
023     *    Copyright (c) 2007 G. Paperin.<br />
024     *    All rights reserved.
025     * </p>
026     * <p style="font-size:smaller;">File: DataStreamWriterFactory.java</p> 
027     * <p style="font-size:smaller;">Redistribution and use in source and binary forms, with or
028     *    without modification, are permitted provided that the following terms and conditions are met:
029     * </p>
030     * <p style="font-size:smaller;">1. Redistributions of source code must retain the above
031     *    acknowledgement of the LiveGraph project and its web-site, the above copyright notice,
032     *    this list of conditions and the following disclaimer.<br />
033     *    2. Redistributions in binary form must reproduce the above acknowledgement of the
034     *    LiveGraph project and its web-site, the above copyright notice, this list of conditions
035     *    and the following disclaimer in the documentation and/or other materials provided with
036     *    the distribution.<br />
037     *    3. All advertising materials mentioning features or use of this software or any derived
038     *    software must display the following acknowledgement:<br />
039     *    <em>This product includes software developed by the LiveGraph project and its
040     *    contributors.<br />(http://www.live-graph.org)</em><br />
041     *    4. All advertising materials distributed in form of HTML pages or any other technology
042     *    permitting active hyper-links that mention features or use of this software or any
043     *    derived software must display the acknowledgment specified in condition 3 of this
044     *    agreement, and in addition, include a visible and working hyper-link to the LiveGraph
045     *    homepage (http://www.live-graph.org).
046     * </p>
047     * <p style="font-size:smaller;">THIS SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY
048     *    OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
049     *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL
050     *    THE AUTHORS, CONTRIBUTORS OR COPYRIGHT  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
051     *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM, OUT OF OR
052     *    IN CONNECTION WITH THE SOFTWARE OR THE USE OR  OTHER DEALINGS IN THE SOFTWARE.
053     * </p>
054     * 
055     * @author Greg Paperin (<a href="http://www.paperin.org" target="_blank">http://www.paperin.org</a>)
056     * @version {@value org.LiveGraph.LiveGraph#version}
057     */
058    public class DataStreamWriterFactory {
059    
060    /**
061     * Data file extension used if no other specified.
062     */
063    public static final String defaultFileExtension = "dat";
064    
065    
066    /**
067     * Creates a new {@link DataStreamWriter} object for a unique file located in the
068     * specified directory. The file will be named on the basis of the specified name and the
069     * current date and time.<br />
070     * The file name will be constructed according to the following pattern:<br />
071     * {@code dataFileName.YY.MM.DD-HH.MM.SS.}{@value #defaultFileExtension}
072     * 
073     * @param dataFileDir The local folder in thich the file will be located.
074     * @param dataFileName The basis for the file name.
075     * @return A {@code DataStreamWriter} for the file with the name described above.
076     */
077    public static DataStreamWriter createDataWriter(String dataFileDir, String dataFileName) {
078            return createDataWriter(dataFileDir, dataFileName, defaultFileExtension);
079    }
080    
081    /**
082     * Creates a new {@link DataStreamWriter} object for a unique file located in the
083     * specified directory. The file will be named on the basis of the specified name, the
084     * specified extension and the current date and time.<br />
085     * The file name will be constructed according to the following pattern:<br />
086     * {@code dataFileName.YY.MM.DD-HH.MM.SS.dataFileExt}
087     * 
088     * @param dataFileDir The local folder in thich the file will be located.
089     * @param dataFileName The basis for the file name.
090     * @param dataFileExt The extension for the file name.
091     * @return A {@code DataStreamWriter} for the file with the name described above.
092     */
093    public static DataStreamWriter createDataWriter(String dataFileDir, String dataFileName, String dataFileExt) {
094            File file = getUniqueDataFile(dataFileDir, dataFileName, dataFileExt);
095            final int MAX_RETRY = 5;
096            for (int retry = 0; retry < MAX_RETRY; retry++) {
097                    
098                    try {
099                            FileOutputStream outs = new FileOutputStream(file);
100                            DataStreamWriter writer = new DataStreamWriter(outs);
101                            return writer;
102                    } catch (FileNotFoundException e) {
103                            Thread.yield();
104                            try {Thread.sleep((int) (Math.random() * 1000)); }
105                            catch (InterruptedException e2) {}
106                            Thread.yield();
107                    }                               
108            }
109            throw new Error("Cannot create data writer. Something weird is happening concurrently."); 
110    }
111    
112    
113    /**
114     * Constructs a unique file name for a file located in the specified directory. The file will
115     * be named on the basis of the specified name, the specified extension and the current date
116     * and time.<br />
117     * The file name will be constructed according to the following pattern:<br />
118     * {@code dataFileName.YY.MM.DD-HH.MM.SS.dataFileExt} <br />
119     * If that file already exists, the file name will be adjusted to <br />
120     * {@code dataFileName.YY.MM.DD-HH.MM.SS(1).dataFileExt}, <br />
121     * {@code dataFileName.YY.MM.DD-HH.MM.SS(2).dataFileExt}, <br />
122     * and so on until the file does not already exist.
123     * 
124     * @param dataFileDir The local folder in thich the file will be located.
125     * @param dataFileName The basis for the file name.
126     * @param dataFileExt The extension for the file name.
127     * @return A file object describing a file with the name as specified above.
128     */
129    public static File getUniqueDataFile(String dataFileDir, String dataFileName, String dataFileExt) {
130            
131            if (null == dataFileDir)
132                    throw new NullPointerException("Data file directory cannot be null");
133            
134            if (null == dataFileName)
135                    throw new NullPointerException("Data file name basis cannot be null");
136            
137            if (null == dataFileExt)
138                    throw new NullPointerException("Data file extension cannot be null");
139            
140            if (dataFileDir.trim().length() > 0 &&  !dataFileDir.endsWith("/") && !dataFileDir.endsWith("\\"))
141                    dataFileDir = dataFileDir + "/";
142            
143            while (dataFileDir.length() > 1 && dataFileDir.startsWith("."))
144                    dataFileDir = dataFileDir.substring(1);
145            
146            Calendar date = new GregorianCalendar();
147            String fName = String.format("%s.%2$ty.%2$tm.%2$td-%2$tH.%2$tM.%2$tS.%3$s", dataFileName, date, dataFileExt);
148            File dataFile = new File(dataFileDir + fName);
149            if (dataFile.exists()) {
150                    int k = 1;
151                    while(dataFile.exists()) {
152                            fName = String.format("%1$s.%2$ty.%2$tm.%2$td-%2$tH.%2$tM.%2$tS(%4$d).%3$s",
153                                                                      dataFileName, date, dataFileExt, k);
154                            dataFile = new File(dataFileDir + fName);
155                            k++;
156                    }
157            }
158            
159            return dataFile;
160    }
161    
162    } // public class DataStreamWriterFactory