View Javadoc
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 }