Coverage Report - ca.uhn.hl7v2.util.idgenerator.FileBasedGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
FileBasedGenerator
91%
65/71
71%
10/14
2.818
 
 1  
 /**
 2  
 The contents of this file are subject to the Mozilla Public License Version 1.1 
 3  
 (the "License"); you may not use this file except in compliance with the License. 
 4  
 You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
 5  
 Software distributed under the License is distributed on an "AS IS" basis, 
 6  
 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 
 7  
 specific language governing rights and limitations under the License. 
 8  
 
 9  
 The Original Code is "FileBasedGenerator.java".  Description: 
 10  
 "Replacement for the legagy MessageIDGenerator class" 
 11  
 
 12  
 The Initial Developer of the Original Code is University Health Network. Copyright (C) 
 13  
 2001.  All Rights Reserved. 
 14  
 
 15  
 Contributor(s): ______________________________________. 
 16  
 
 17  
 Alternatively, the contents of this file may be used under the terms of the 
 18  
 GNU General Public License (the  "GPL"), in which case the provisions of the GPL are 
 19  
 applicable instead of those above.  If you wish to allow use of your version of this 
 20  
 file only under the terms of the GPL and not to allow others to use your version 
 21  
 of this file under the MPL, indicate your decision by deleting  the provisions above 
 22  
 and replace  them with the notice and other provisions required by the GPL License.  
 23  
 If you do not delete the provisions above, a recipient may use your version of 
 24  
 this file under either the MPL or the GPL. 
 25  
  */
 26  
 package ca.uhn.hl7v2.util.idgenerator;
 27  
 
 28  
 import java.io.BufferedReader;
 29  
 import java.io.File;
 30  
 import java.io.FileInputStream;
 31  
 import java.io.FileOutputStream;
 32  
 import java.io.IOException;
 33  
 import java.io.InputStreamReader;
 34  
 import java.io.PrintWriter;
 35  
 import java.util.concurrent.locks.ReentrantLock;
 36  
 
 37  
 import org.slf4j.Logger;
 38  
 import org.slf4j.LoggerFactory;
 39  
 
 40  
 import ca.uhn.hl7v2.util.Home;
 41  
 
 42  
 /**
 43  
  * Replacement for {@link ca.uhn.hl7v2.util.MessageIDGenerator}. You should not use this class
 44  
  * directly, however, but wrap it into a {@link DelegatingHiLoGenerator} generator. Its primary
 45  
  * improvement over {@link ca.uhn.hl7v2.util.MessageIDGenerator} is that you can set path and file
 46  
  * name.
 47  
  * <p>
 48  
  * Reading and writing to the file is thread-safe, however, you should not use the same file from
 49  
  * different Java processes because no read/write locks are being checked.
 50  
  */
 51  
 public class FileBasedGenerator extends InMemoryIDGenerator {
 52  
 
 53  1
         private static final Logger LOG = LoggerFactory.getLogger(FileBasedGenerator.class.getName());
 54  
 
 55  469
         private String directory = Home.getHomeDirectory().getAbsolutePath();
 56  469
         private String fileName = "id_file";
 57  469
         private boolean neverFail = true;
 58  469
         private boolean used = false;
 59  469
         private boolean minimizeReads = false;
 60  469
         private ReentrantLock lock = new ReentrantLock();
 61  
 
 62  
         public FileBasedGenerator() {
 63  7
                 this(1);
 64  7
         }
 65  
 
 66  
         FileBasedGenerator(int increment) {
 67  469
                 super(increment);
 68  469
         }
 69  
 
 70  
         public String getID() throws IOException {
 71  
                 try {
 72  1316
                         lock.lock();
 73  
                         
 74  
                         // If ID is 0, read initial value from file if possible
 75  1316
                         if (!minimizeReads || !used) {
 76  1316
                                 long readInitialValue = readInitialValue(getFilePath());
 77  1315
                                 if (readInitialValue >= 0) {
 78  1309
                                         set(readInitialValue);
 79  
                                 }
 80  1315
                                 used = true;
 81  
                         }
 82  
                         
 83  1315
                         String id = super.getID();
 84  
                         // The id held in the file is always <increment> larger so that
 85  
                         // the ID is still unique after a restart.
 86  1315
                         writeNextValue(Long.parseLong(id) + getIncrement());
 87  1315
                         return id;
 88  
                 } finally {
 89  1315
                         lock.unlock();
 90  
                 }
 91  
         }
 92  
 
 93  
 
 94  
         private void writeNextValue(long id) throws IOException {
 95  1324
                 PrintWriter pw = null;
 96  
                 try {
 97  1324
                         pw = new PrintWriter(new FileOutputStream(getFilePath(), false));
 98  1320
                         pw.println(Long.toString(id));
 99  4
                 } catch (IOException e) {
 100  4
                         if (neverFail) {
 101  4
                                 LOG.warn("Could not write ID to file {}, going to use internal ID generator. {}",
 102  
                                                 getFilePath(), e.getMessage());
 103  
                                 return;
 104  
                         }
 105  0
                         throw e;
 106  
                 } finally {
 107  1324
                         if (pw != null)
 108  1320
                                 pw.close();
 109  
                 }
 110  1320
         }
 111  
 
 112  
         private long readInitialValue(String path) throws IOException {
 113  1316
                 BufferedReader br = null;
 114  1316
                 String id = null;
 115  
                 try {
 116  1316
                         br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
 117  1311
                         id = br.readLine();
 118  1311
                         return Long.parseLong(id);
 119  5
                 } catch (IOException e) {
 120  5
                         LOG.info("Could not read ID file {} ", path);
 121  5
                         if (!neverFail) {
 122  1
                                 throw e;
 123  
                         }
 124  4
                         return -1;
 125  2
                 } catch (NumberFormatException e) {
 126  2
                         LOG.info("ID {} read from file is not a number", id);
 127  2
                         return -1;
 128  
                 } finally {
 129  1316
                         if (br != null)
 130  
                                 try {
 131  1311
                                         br.close();
 132  0
                                 } catch (IOException e) {
 133  2627
                                 }
 134  
                 }
 135  
         }
 136  
 
 137  
         private String getFilePath() {
 138  2644
                 return new File(directory, fileName).getAbsolutePath();
 139  
         }
 140  
 
 141  
         public void setDirectory(String directory) {
 142  
                 try {
 143  3
                         lock.lock();
 144  3
                         this.directory = directory;
 145  
                 } finally {
 146  3
                         lock.unlock();
 147  3
                 }
 148  3
         }
 149  
 
 150  
         public void setFileName(String fileName) {
 151  
                 try {
 152  3
                         lock.lock();
 153  3
                         this.fileName = fileName;
 154  
                 } finally {
 155  3
                         lock.unlock();
 156  3
                 }
 157  3
         }
 158  
 
 159  
         /**
 160  
          * If set to <code>true</code> (default is <code>false</code>) the generator
 161  
          * minimizes the number of disk reads by caching the last read value. This means
 162  
          * one less disk read per X number of IDs generated, but also means that multiple
 163  
          * instances of this generator may clobber each other's values.
 164  
          */
 165  
         public void setMinimizeReads(boolean theMinimizeReads) {
 166  0
                 minimizeReads = theMinimizeReads;
 167  0
         }
 168  
 
 169  
         /**
 170  
          * If set to <code>false</code> (default is <code>true</code>),
 171  
          * retrieving a new ID may fail if the ID file in the home
 172  
          * directory can not be written/read. If set to true, failures
 173  
          * will be ignored, which means that IDs may be repeated after
 174  
          * a JVM restart.
 175  
          */
 176  
         public void setNeverFail(boolean neverFail) {
 177  2
                 this.neverFail = neverFail;
 178  2
         }
 179  
 
 180  
         public void reset() {
 181  
                 try {
 182  9
                         lock.lock();
 183  9
                         super.reset();
 184  9
                         writeNextValue(0l);
 185  0
                 } catch (IOException e) {
 186  0
                         throw new IllegalStateException("Cannot initialize persistent ID generator", e);
 187  
                 } finally {
 188  9
                         lock.unlock();
 189  9
                 }
 190  9
         }
 191  
 
 192  
 }