1 /*
2 * Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.geometry.io;
17
18 import java.io.Closeable;
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.channels.FileChannel;
22
23 /**
24 * Abstract class defining the interface for file loaders.
25 * Specific implementations must be done for each file format to be supported.
26 */
27 public abstract class Loader implements Closeable {
28
29 /**
30 * Default limit of bytes to keep mapped in memory.
31 */
32 public static final long DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY = 50000000;
33
34 /**
35 * Instance in charge of reading data from file.
36 */
37 protected AbstractFileReaderAndWriter reader;
38
39 /**
40 * Boolean indicating that this instance is locked because decoding is being
41 * done.
42 */
43 protected boolean locked;
44
45 /**
46 * Listener in charge of notifying when the decoding starts, ends or
47 * progress events.
48 */
49 protected LoaderListener listener;
50
51 /**
52 * File to be read.
53 */
54 protected File file;
55
56 /**
57 * Limit of bytes to keep mapped in memory. If provided file exceeds this
58 * value, then it is not mapped into memory.
59 */
60 private long fileSizeLimitToKeepInMemory;
61
62 /**
63 * Default Constructor.
64 */
65 protected Loader() {
66 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
67 reader = null;
68 locked = false;
69 listener = null;
70 }
71
72 /**
73 * Constructor.
74 *
75 * @param f file to be read.
76 * @throws IOException raised if provided file does not exist or an I/O
77 * exception occurs.
78 */
79 protected Loader(final File f) throws IOException {
80 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
81 file = f;
82 if (f.length() < fileSizeLimitToKeepInMemory) {
83 reader = new MappedFileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
84 } else {
85 reader = new FileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
86 }
87 locked = false;
88 listener = null;
89 }
90
91 /**
92 * Constructor.
93 *
94 * @param listener listener to notify start, end and progress events.
95 */
96 protected Loader(final LoaderListener listener) {
97 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
98 reader = null;
99 locked = false;
100 this.listener = listener;
101 }
102
103 /**
104 * Constructor.
105 *
106 * @param f file to be read.
107 * @param listener listener to notify start, end and progress events.
108 * @throws IOException raised if provided file does not exist or an I/O
109 * exception occurs.
110 */
111 protected Loader(final File f, final LoaderListener listener) throws IOException {
112 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
113 file = f;
114 if (f.length() < fileSizeLimitToKeepInMemory) {
115 reader = new MappedFileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
116 } else {
117 reader = new FileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
118 }
119 locked = false;
120 this.listener = listener;
121 }
122
123 /**
124 * Get maximum size (in bytes) to determine whether a file is completely
125 * cached in memory (if lower than maximum size), or if it is just streamed
126 * (if greater than maximum size).
127 *
128 * @return Maximum size to determine whether file is cached in memory or not.
129 */
130 public long getFileSizeLimitToKeepInMemory() {
131 return fileSizeLimitToKeepInMemory;
132 }
133
134 /**
135 * Sets maximum size (in bytes) to determine whether a file is completely
136 * cached in memory (if lower than maximum size), or if it is just streamed
137 * (if greater than maximum size).
138 *
139 * @param fileSizeLimitToKeepInMemory maximum size to determine whether file
140 * is cached in memory or not.
141 * @throws LockedException if loader is locked because it is currently
142 * processing a file.
143 */
144 public void setFileSizeLimitToKeepInMemory(final long fileSizeLimitToKeepInMemory) throws LockedException {
145 if (isLocked()) {
146 throw new LockedException();
147 }
148
149 this.fileSizeLimitToKeepInMemory = fileSizeLimitToKeepInMemory;
150 }
151
152 /**
153 * Indicates whether a file to be loaded has already been set.
154 *
155 * @return True if file has already been provided, false otherwise.
156 */
157 public boolean hasFile() {
158 return reader != null;
159 }
160
161 /**
162 * Sets file to be loaded.
163 *
164 * @param f file to be loaded.
165 * @throws LockedException raised if this instance is loaded because a file
166 * is already being loaded.
167 * @throws IOException raised if provided file does not exist or if an I/O
168 * exception occurs.
169 */
170 @SuppressWarnings("DuplicatedCode")
171 public void setFile(final File f) throws LockedException, IOException {
172 if (isLocked()) {
173 throw new LockedException();
174 }
175 file = f;
176
177 if (reader != null) {
178 // close previous file
179 reader.close();
180 }
181
182 if (f.length() < fileSizeLimitToKeepInMemory) {
183 reader = new MappedFileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
184 } else {
185 reader = new FileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
186 }
187 }
188
189 /**
190 * Closes file provided to this loader.
191 *
192 * @throws IOException if an I/O error occurs.
193 */
194 @Override
195 public void close() throws IOException {
196 if (reader != null) {
197 reader.close();
198 reader = null;
199 }
200 }
201
202 /**
203 * Determines whether this instance is locked.
204 * A loader remains locked while decoding of a file is being done.
205 * This instance will remain locked once the loading process starts until
206 * it finishes either successfully or not.
207 * While this instance remains locked no parameters can be changed,
208 * otherwise a LockedException will be raised.
209 *
210 * @return True if instance is locked, false otherwise.
211 */
212 public synchronized boolean isLocked() {
213 return locked;
214 }
215
216 /**
217 * Sets the lock value of this instance so that no parameters cannot be
218 * changed until this instance is unlocked.
219 *
220 * @param locked value that determines whether this instance is locked or
221 * not.
222 */
223 protected synchronized void setLocked(final boolean locked) {
224 this.locked = locked;
225 }
226
227 /**
228 * Returns listener of this instance.
229 * A listener notifies of start, end and progress change events.
230 *
231 * @return listener of this instance.
232 */
233 public LoaderListener getListener() {
234 return listener;
235 }
236
237 /**
238 * Sets listener of this instance.
239 * A listener notifies of start, end and progress change events.
240 *
241 * @param listener listener of this instance.
242 * @throws LockedException Raised if this instance is already locked.
243 */
244 public void setListener(final LoaderListener listener) throws LockedException {
245 if (isLocked()) {
246 throw new LockedException();
247 }
248 this.listener = listener;
249 }
250
251 /**
252 * Determines whether enough parameters have been set so that the loading
253 * process can start.
254 *
255 * @return True if this instance is ready to start loading a file, false
256 * otherwise.
257 */
258 public abstract boolean isReady();
259
260 /**
261 * Returns mesh format this instance is capable of loading.
262 *
263 * @return Mesh format.
264 */
265 public abstract MeshFormat getMeshFormat();
266
267 /**
268 * Determines if provided file is a valid file that can be read by this
269 * loader.
270 *
271 * @return true if file is valid, false otherwise.
272 * @throws LockedException raised if this instance is already locked.
273 * @throws IOException if an I/O error occurs.
274 */
275 public abstract boolean isValidFile() throws LockedException, IOException;
276
277 /**
278 * Starts the loading process of provided file.
279 * This method returns a LoaderIterator to start the iterative process to
280 * load a file in small chunks of data.
281 *
282 * @return a loader iterator to read the file in a step-by-step process.
283 * @throws LockedException raised if this instance is already locked.
284 * @throws NotReadyException raised if this instance is not yet ready.
285 * @throws IOException if an I/O error occurs.
286 * @throws LoaderException if file is corrupted or cannot be interpreted.
287 */
288 public abstract LoaderIterator load() throws LockedException, NotReadyException, IOException, LoaderException;
289 }