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 import java.util.Set;
23
24 /**
25 * Abstract class defining the interface for classes in charge of loading
26 * materials.
27 */
28 public abstract class MaterialLoader implements Closeable {
29
30 /**
31 * Maximum allowed file size to keep cached in memory. Files exceeding this
32 * size will just be streamed.
33 */
34 public static final long DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY = 50000000;
35
36 /**
37 * Constant defining whether textures must be validated by default.
38 */
39 public static final boolean DEFAULT_TEXTURE_VALIDATION_ENABLED = true;
40
41 /**
42 * Instance in charge of reading data from file.
43 */
44 protected AbstractFileReaderAndWriter reader;
45
46 /**
47 * Boolean indicating that this instance is locked because decoding is being
48 * done.
49 */
50 protected boolean locked;
51
52 /**
53 * Listener in charge of notifying when the decoding starts, ends or
54 * progress events.
55 */
56 protected MaterialLoaderListener listener;
57
58 /**
59 * File to be read.
60 */
61 protected File file;
62
63 /**
64 * Indicates if texture images must be validated to ensure that they are
65 * valid image files.
66 */
67 protected boolean textureValidationEnabled;
68
69 /**
70 * Limit of bytes to keep mapped in memory. If provided file exceeds this
71 * value, then it is not mapped into memory.
72 */
73 private long fileSizeLimitToKeepInMemory;
74
75 /**
76 * Default Constructor.
77 */
78 protected MaterialLoader() {
79 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
80 reader = null;
81 locked = false;
82 listener = null;
83 textureValidationEnabled = DEFAULT_TEXTURE_VALIDATION_ENABLED;
84 }
85
86 /**
87 * Constructor.
88 *
89 * @param f material file to be read.
90 * @throws IOException raised if provided file does not exist or an I/O
91 * exception occurs.
92 */
93 protected MaterialLoader(final File f) throws IOException {
94 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
95 file = f;
96 if (f.length() < fileSizeLimitToKeepInMemory) {
97 reader = new MappedFileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
98 } else {
99 reader = new FileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
100 }
101 locked = false;
102 listener = null;
103 textureValidationEnabled = DEFAULT_TEXTURE_VALIDATION_ENABLED;
104 }
105
106 /**
107 * Constructor.
108 *
109 * @param listener material listener to notify start, end and progress
110 * events.
111 */
112 protected MaterialLoader(final MaterialLoaderListener listener) {
113 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
114 reader = null;
115 locked = false;
116 this.listener = listener;
117 textureValidationEnabled = DEFAULT_TEXTURE_VALIDATION_ENABLED;
118 }
119
120 /**
121 * Constructor.
122 *
123 * @param f material file to be read.
124 * @param listener material listener to notify start, end and progress
125 * events.
126 * @throws IOException raised if provided file does not exist or an I/O
127 * exception occurs.
128 */
129 protected MaterialLoader(final File f, final MaterialLoaderListener listener) throws IOException {
130 fileSizeLimitToKeepInMemory = DEFAULT_FILE_SIZE_LIMIT_TO_KEEP_IN_MEMORY;
131 file = f;
132 if (f.length() < fileSizeLimitToKeepInMemory) {
133 reader = new MappedFileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
134 } else {
135 reader = new FileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
136 }
137 locked = false;
138 this.listener = listener;
139 textureValidationEnabled = DEFAULT_TEXTURE_VALIDATION_ENABLED;
140 }
141
142 /**
143 * Returns maximum allowed file size to keep cached in memory. Files
144 * exceeding this size will just be streamed.
145 *
146 * @return maximum allowed file size to keep cached in memory.
147 */
148 public long getFileSizeLimitToKeepInMemory() {
149 return fileSizeLimitToKeepInMemory;
150 }
151
152 /**
153 * Sets maximum allowed file size to keep cached in memory. Files exceeding
154 * this size will just be streamed.
155 *
156 * @param fileSizeLimitToKeepInMemory maximum allowed file size to keep
157 * cached in memory.
158 * @throws LockedException if this instance is already loading another file.
159 */
160 public void setFileSizeLimitToKeepInMemory(final long fileSizeLimitToKeepInMemory) throws LockedException {
161 if (isLocked()) {
162 throw new LockedException();
163 }
164
165 this.fileSizeLimitToKeepInMemory = fileSizeLimitToKeepInMemory;
166 }
167
168 /**
169 * Indicates whether a material file to be loaded has already been set.
170 *
171 * @return True if material file has already been provided, false otherwise.
172 */
173 public boolean hasFile() {
174 return reader != null;
175 }
176
177 /**
178 * Sets material file to be loaded.
179 *
180 * @param f material file to be loaded.
181 * @throws LockedException raised if this instance is loaded because a file
182 * is already being loaded.
183 * @throws IOException raised if provided file does not exist or if an I/O
184 * exception occurs.
185 */
186 @SuppressWarnings("DuplicatedCode")
187 public void setFile(final File f) throws LockedException, IOException {
188 if (isLocked()) {
189 throw new LockedException();
190 }
191 file = f;
192
193 if (reader != null) {
194 // close previous file
195 reader.close();
196 }
197
198 if (f.length() < fileSizeLimitToKeepInMemory) {
199 reader = new MappedFileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
200 } else {
201 reader = new FileReaderAndWriter(f, FileChannel.MapMode.READ_ONLY);
202 }
203 }
204
205 /**
206 * Closes file provided to this loader.
207 *
208 * @throws IOException if an I/O error occurs.
209 */
210 @Override
211 public void close() throws IOException {
212 if (reader != null) {
213 reader.close();
214 reader = null;
215 }
216 }
217
218 /**
219 * Indicates if textures must be validated to ensure that image files are
220 * valid files.
221 *
222 * @return true if textures must be validated, false otherwise.
223 */
224 public boolean isTextureValidationEnabled() {
225 return textureValidationEnabled;
226 }
227
228 /**
229 * Specifies whether textures must be validated to ensure that image files
230 * are valid files.
231 *
232 * @param textureValidationEnabled true if textures must be validated, false
233 * otherwise.
234 */
235 public void setTextureValidationEnabled(final boolean textureValidationEnabled) {
236 this.textureValidationEnabled = textureValidationEnabled;
237 }
238
239 /**
240 * Determines whether this instance is locked.
241 * A material loader remains locked while decoding of a file is being done.
242 * This instance will remain locked once the loading process starts until
243 * it finishes either successfully or not.
244 * While this instance remains locked no parameters can be changed,
245 * otherwise a LockedException will be raised.
246 *
247 * @return True if instance is locked, false otherwise.
248 */
249 public synchronized boolean isLocked() {
250 return locked;
251 }
252
253 /**
254 * Sets the lock value of this instance so that no parameters cannot be
255 * changed until this instance is unlocked.
256 *
257 * @param locked value that determines whether this instance is locked or
258 * not.
259 */
260 protected synchronized void setLocked(final boolean locked) {
261 this.locked = locked;
262 }
263
264 /**
265 * Returns material listener of this instance.
266 * A material listener notifies of start, end and progress change events.
267 *
268 * @return material listener of this instance.
269 */
270 public MaterialLoaderListener getListener() {
271 return listener;
272 }
273
274 /**
275 * Sets material listener of this instance.
276 * A material listener notifies of start, end and progress change events.
277 *
278 * @param listener material listener of this instance.
279 * @throws LockedException Raised if this instance is already locked.
280 */
281 public void setListener(final MaterialLoaderListener listener) throws LockedException {
282 if (isLocked()) {
283 throw new LockedException();
284 }
285 this.listener = listener;
286 }
287
288 /**
289 * Determines whether enough parameters have been set so that the loading
290 * process can start.
291 *
292 * @return True if this instance is ready to start loading a file, false
293 * otherwise.
294 */
295 public abstract boolean isReady();
296
297 /**
298 * Starts the loading process of provided file.
299 * This method returns a set containing all the materials that have been
300 * loaded.
301 *
302 * @return a set containing all the materials that have been loaded.
303 * @throws LockedException raised if this instance is already locked.
304 * @throws NotReadyException raised if this instance is not yet ready.
305 * @throws IOException if an I/O error occurs.
306 * @throws LoaderException if file is corrupted or cannot be interpreted.
307 */
308 public abstract Set<Material> load() throws LockedException, NotReadyException, IOException, LoaderException;
309 }