Coverage Report - ca.uhn.hl7v2.util.idgenerator.FileBasedGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
FileBasedGenerator
87%
64/73
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  5
         private static final Logger LOG = LoggerFactory.getLogger(FileBasedGenerator.class.getName());
 54  
 
 55  5555
         private String directory = Home.getHomeDirectory().getAbsolutePath();
 56  5555
         private String fileName = "id_file";
 57  5555
         private boolean neverFail = true;
 58  5555
         private boolean used = false;
 59  5555
         private boolean minimizeReads = false;
 60  5555
         private ReentrantLock lock = new ReentrantLock();
 61  
 
 62  
         public FileBasedGenerator() {
 63  35
                 this(1L);
 64  35
         }
 65  
 
 66  
         FileBasedGenerator(long increment) {
 67  5555
                 super(increment);
 68  5555
         }
 69  
 
 70  
         public String getID() throws IOException {
 71  
                 try {
 72  6855
                         lock.lock();
 73  
                         
 74  
                         // If ID is 0, read initial value from file if possible
 75  6855
                         if (!minimizeReads || !used) {
 76  6855
                                 long readInitialValue = readInitialValue(getFilePath());
 77  6850
                                 if (readInitialValue >= 0) {
 78  6835
                                         set(readInitialValue);
 79  
                                 }
 80  6850
                                 used = true;
 81  
                         }
 82  
                         
 83  6850
                         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  6850
                         writeNextValue(Long.parseLong(id) + getIncrement());
 87  13700
                         return id;
 88  
                 } finally {
 89  6855
                         lock.unlock();
 90  
                 }
 91  
         }
 92  
 
 93  
 
 94  
         private void writeNextValue(long id) throws IOException {
 95  6885
                 PrintWriter pw = null;
 96  
                 try {
 97  6885
                         pw = new PrintWriter(new FileOutputStream(getFilePath(), false));
 98  6875
                         pw.println(Long.toString(id));
 99  10
                 } catch (IOException e) {
 100  10
                         if (neverFail) {
 101  20
                                 LOG.warn("Could not write ID to file {}, going to use internal ID generator. {}",
 102  10
                                                 getFilePath(), e.getMessage());
 103  10
                                 return;
 104  
                         }
 105  0
                         throw e;
 106  
                 } finally {
 107  6885
                         if (pw != null)
 108  6875
                                 pw.close();
 109  
                 }
 110  6875
         }
 111  
 
 112  
         private long readInitialValue(String path) throws IOException {
 113  6855
                 BufferedReader br = null;
 114  6855
                 String id = null;
 115  
                 try {
 116  6855
                         br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
 117  6835
                         id = br.readLine();
 118  13670
                         return Long.parseLong(id);
 119  20
                 } catch (IOException e) {
 120  20
                         LOG.info("Could not read ID file {} ", path);
 121  20
                         if (!neverFail) {
 122  5
                                 throw e;
 123  
                         }
 124  30
                         return -1;
 125  0
                 } catch (NumberFormatException e) {
 126  0
                         LOG.info("ID {} read from file is not a number", id);
 127  0
                         return -1;
 128  
                 } finally {
 129  6855
                         if (br != null)
 130  
                                 try {
 131  6835
                                         br.close();
 132  0
                                 } catch (IOException e) {
 133  6840
                                 }
 134  
                 }
 135  
         }
 136  
 
 137  
         private String getFilePath() {
 138  13750
                 return new File(directory, fileName).getAbsolutePath();
 139  
         }
 140  
 
 141  
         public void setDirectory(String directory) {
 142  
                 try {
 143  15
                         lock.lock();
 144  15
                         this.directory = directory;
 145  
                 } finally {
 146  15
                         lock.unlock();
 147  15
                 }
 148  15
         }
 149  
 
 150  
         public void setFileName(String fileName) {
 151  
                 try {
 152  15
                         lock.lock();
 153  15
                         this.fileName = fileName;
 154  
                 } finally {
 155  15
                         lock.unlock();
 156  15
                 }
 157  15
         }
 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  10
                 this.neverFail = neverFail;
 178  10
         }
 179  
 
 180  
         public void reset() {
 181  
                 try {
 182  35
                         lock.lock();
 183  35
                         super.reset();
 184  35
                         writeNextValue(0l);
 185  0
                 } catch (IOException e) {
 186  0
                         throw new IllegalStateException("Cannot initialize persistent ID generator", e);
 187  
                 } finally {
 188  35
                         lock.unlock();
 189  35
                 }
 190  35
         }
 191  
 
 192  
 }