1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 or later
5    * as published by the Free Software Foundation. This program is distributed
6    * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7    * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *      http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * © CrossWire Bible Society, 2013 - 2016
18   *
19   */
20  package org.crosswire.jsword.book.sword.state;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.RandomAccessFile;
25  import java.net.URI;
26  
27  import org.crosswire.common.util.FileUtil;
28  import org.crosswire.common.util.IOUtil;
29  import org.crosswire.common.util.Reporter;
30  import org.crosswire.jsword.JSMsg;
31  import org.crosswire.jsword.book.BookException;
32  import org.crosswire.jsword.book.BookMetaData;
33  import org.crosswire.jsword.book.sword.SwordUtil;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  /**
38   * Stores the random access files required for processing the passage request.
39   * 
40   * The caller is required to close to correctly free resources and avoid File
41   * pointer leaks.
42   * 
43   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
44   * @author DM Smith
45   */
46  public class ZLDBackendState extends RawLDBackendState {
47      /**
48       * This is default package access for forcing the use of the
49       * OpenFileStateManager to manage the creation. Not doing so may result in
50       * new instances of OpenFileState being created for no reason, and as a
51       * result, if they are released to the OpenFileStateManager by mistake this
52       * would result in leakage
53       * 
54       * @param bookMetaData the appropriate metadata for the book
55       */
56       ZLDBackendState(BookMetaData bookMetaData) throws BookException {
57          super(bookMetaData);
58          zdxFile = null;
59          zdtFile = null;
60          zdxRaf = null;
61          zdtRaf = null;
62          lastBlockNum = -1;
63          lastUncompressed = EMPTY_BYTES;
64  
65          URI path = null;
66          try {
67              path = SwordUtil.getExpandedDataPath(bookMetaData);
68          } catch (BookException e) {
69              Reporter.informUser(this, e);
70              return;
71          }
72  
73          try {
74              zdxFile = new File(path.getPath() + EXTENSION_Z_INDEX);
75              zdtFile = new File(path.getPath() + EXTENSION_Z_DATA);
76  
77              if (!zdxFile.canRead()) {
78                  // TRANSLATOR: Common error condition: The file could not be read. There can be many reasons.
79                  // {0} is a placeholder for the file.
80                  Reporter.informUser(this, new BookException(JSMsg.gettext("Error reading {0}", zdtFile.getAbsolutePath())));
81                  return;
82              }
83  
84              if (!zdtFile.canRead()) {
85                  // TRANSLATOR: Common error condition: The file could not be read. There can be many reasons.
86                  // {0} is a placeholder for the file.
87                  Reporter.informUser(this, new BookException(JSMsg.gettext("Error reading {0}", zdtFile.getAbsolutePath())));
88                  return;
89              }
90  
91              // Open the files
92              zdxRaf = new RandomAccessFile(zdxFile, FileUtil.MODE_READ);
93              zdtRaf = new RandomAccessFile(zdtFile, FileUtil.MODE_READ);
94          } catch (IOException ex) {
95              //failed to open the files, so close them now
96              IOUtil.close(zdxRaf);
97              IOUtil.close(zdtRaf);
98  
99              LOGGER.error("failed to open files", ex);
100             zdxRaf = null;
101             zdtRaf = null;
102             return;
103         }
104     }
105 
106     @Override
107     public void releaseResources() {
108         super.releaseResources();
109         lastBlockNum = -1;
110         lastUncompressed = EMPTY_BYTES;
111 
112         IOUtil.close(zdxRaf);
113         IOUtil.close(zdtRaf);
114             zdxRaf = null;
115             zdtRaf = null;
116     }
117 
118     /**
119      * @return the zdxRaf
120      */
121     public RandomAccessFile getZdxRaf() {
122         return zdxRaf;
123     }
124 
125     /**
126      * @return the zdtRaf
127      */
128     public RandomAccessFile getZdtRaf() {
129         return zdtRaf;
130     }
131 
132     /**
133      * @return the lastBlockNum
134      */
135     public long getLastBlockNum() {
136         return lastBlockNum;
137     }
138 
139     /**
140      * @return the lastUncompressed
141      */
142     public byte[] getLastUncompressed() {
143         return lastUncompressed;
144     }
145 
146     /**
147      * @param lastBlockNum the lastBlockNum to set
148      */
149     public void setLastBlockNum(long lastBlockNum) {
150         this.lastBlockNum = lastBlockNum;
151     }
152 
153     /**
154      * @param lastUncompressed the lastUncompressed to set
155      */
156     public void setLastUncompressed(byte[] lastUncompressed) {
157         this.lastUncompressed = lastUncompressed;
158     }
159 
160     private static final byte[] EMPTY_BYTES = new byte[0];
161     private static final String EXTENSION_Z_INDEX = ".zdx";
162     private static final String EXTENSION_Z_DATA = ".zdt";
163 
164     /**
165      * The compressed index.
166      */
167     private File zdxFile;
168 
169     /**
170      * The compressed index random access file.
171      */
172     private RandomAccessFile zdxRaf;
173 
174     /**
175      * The compressed text.
176      */
177     private  File zdtFile;
178 
179     /**
180      * The compressed text random access file.
181      */
182     private  RandomAccessFile zdtRaf;
183 
184     /**
185      * The index of the block that is cached.
186      */
187     private  long lastBlockNum;
188 
189     /**
190      * The cache for a read of a compressed block.
191      */
192     private  byte[] lastUncompressed;
193 
194     /**
195      * The log stream
196      */
197     private static final Logger LOGGER = LoggerFactory.getLogger(ZLDBackendState.class);
198 }
199