001    package sears.file.exception.io;
002    
003    import java.io.File;
004    import java.io.IOException;
005    
006    import sears.file.FileSystemAccess;
007    import sears.tools.Utils;
008    
009    /**
010     * A <tt>FileConversionException</tt> is throw when an error occurs during a file access
011     * and conversion to subtitle file
012     * <br>This class provides <tt>static</tt> methods to create generic objects using
013     * the class constants.
014     * <p>
015     * Two distinct categories of constants:
016     * <br>- file access exception ( read and write access )
017     * <br>- malformed subtitle file exception
018     * </p>
019     */
020    public abstract class FileConversionException extends IOException {
021    
022            /** Default Serial UID */
023            private static final long serialVersionUID = 1L;
024            // FILE ACCESS EXCEPTION :
025            // +++++++++++++++++++++
026            //
027            /** FILE ACCESS EXCEPTION: Read access exception */
028            public static final int READ_ACCESS                             = 0;
029            /** FILE ACCESS EXCEPTION: Write access exception */
030            public static final int WRITE_ACCESS                            = 1;
031            /** FILE ACCESS EXCEPTION: unsupported file size exception */
032            public static final int UNSUPPORTED_FILE_SIZE           = 2;
033    
034            // MALFORMED SUBTITLE FILE EXCEPTION :
035            // +++++++++++++++++++++++++++++++++
036            //
037            // + NUMBER - MALFORMED SUBTITLE FILE EXCEPTION
038            /** MALFORMED SUBTITLE FILE EXCEPTION: no subtitle number exception */
039            public static final int NO_SUBTITLE_NUMBER                      = 3;
040            /** MALFORMED SUBTITLE FILE EXCEPTION: malformed subtitle number exception */
041            public static final int MALFORMED_SUBTITLE_NUMBER       = 4;
042    
043            // + TIME - MALFORMED SUBTITLE FILE EXCEPTION
044            /** MALFORMED SUBTITLE FILE EXCEPTION: no subtitle time exception */
045            public static final int NO_SUBTITLE_TIME                        = 5;
046            /** MALFORMED SUBTITLE FILE EXCEPTION: malformed subtitle time line exception */
047            public static final int MALFORMED_TIME_LINE             = 6;
048            /** MALFORMED SUBTITLE FILE EXCEPTION: malformed subtitle start time exception */
049            public static final int MALFORMED_START_TIME            = 7;
050            /** MALFORMED SUBTITLE FILE EXCEPTION: malformed subtitle end time exception */
051            public static final int MALFORMED_END_TIME                      = 8;
052    
053            // + TEXT - MALFORMED SUBTITLE FILE EXCEPTION
054            /** MALFORMED SUBTITLE FILE EXCEPTION: no subtitle text exception */
055            public static final int NO_SUBTITLE_TEXT                        = 9;
056            /** MALFORMED SUBTITLE FILE EXCEPTION: malformed subtitle text exception */
057            public static final int MALFORMED_SUBTITLE_TEXT         = 10;
058    
059            // + GENERIC MALFORMED SUBTITLE FILE EXCEPTION
060            /** MALFORMED SUBTITLE FILE EXCEPTION: generic subtitle file exception */
061            public static final int MALFORMED_SUBTITLE_FILE         = 11;
062    
063            // + SPECIAL MALFORMED SUBTITLE FILE EXCEPTION
064            /** MALFORMED SUBTITLE FILE EXCEPTION: unexpected end of file exception */
065            public static final int UNEXPECTED_END_OF_FILE          = 12;
066            /** MALFORMED SUBTITLE FILE EXCEPTION: empty subtitle file exception */
067            public static final int EMPTY_SUBTITLE_FILE                     = 13;
068    
069            /**
070             * Returns the error message
071             * @return the error message
072             */
073            public abstract String getMessage();
074    
075            /**
076             * Returns the detail error message
077             * @return the detail error message
078             */
079            public abstract String getDetail();
080    
081            /**
082             * Returns a <tt>boolean</tt> which indicates if the error could have
083             * appeared because of a bad encoding/decoding
084             * @return      true if the error could be appear because a bad encoding/decoding
085             *                      false if not
086             */
087            public abstract boolean couldBeABadEncoding();
088    
089            // returns a formatted message by analyze <tt>file</tt> parameter
090            private static String fileDetail(File file) {
091                    String detail = "";
092                    try {
093                            detail = file.getPath() + Utils.LINE_SEPARATOR;
094                    } catch( NullPointerException e ) {
095                            detail = "";
096                    }
097                    return detail;
098            }
099    
100            // READ ERROR
101            // returns a formatted error message by testing <tt>file</tt> parameter
102            private static String iOExceptionDetailWhenReading(File file) {
103                    String message = null;
104                    if( file != null ) {
105                            try {
106                                    if( file.exists() ) {
107                                            if( !file.canRead() ) {
108                                                    message = "File read access is denied";
109                                            } else {
110                                                    message = "Unknow error, the file seems to be readable";
111                                            }
112                                    } else {
113                                            message = "File does not exist";
114                                    }
115                            } catch (SecurityException e) {
116                                    message = "There's a security restriction on this file";
117                            }
118                    } else {
119                            message = "Unknow error";
120                    }
121                    return message;
122            }
123    
124            // WRITE ERROR
125            // returns a formatted error message by testing <tt>file</tt> parameter
126            private static String iOExceptionDetailWhenWriting(File file) {
127                    String message = null;
128                    if( file != null ) {
129                            try {
130                                    if( file.exists() ) {
131                                            if( !file.canWrite() ) {
132                                                    message = "File write access is denied";
133                                            } else {
134                                                    message = "Unknow error, the file seems to be writable";
135                                            }
136                                    } else {
137                                            message = "File does not exist";
138                                    }
139                            } catch (SecurityException e) {
140                                    message = "There's a security restriction on this file";
141                            }
142                    } else {
143                            message = "Unknow error";
144                    }
145                    return message;
146            }
147    
148            // LENGTH ERROR
149            // returns a formatted error message by testing <tt>file</tt> parameter
150            private static String getFileLengthMessage(File file) {
151                    String message = "";
152                    try {
153                            message = file.length() + " octets is too big"
154                            + Utils.LINE_SEPARATOR 
155                            + "SEARS do not support file bigger than " 
156                            + FileSystemAccess.MAX_SUBTITLE_FILE_SIZE + " octets";  
157                    } catch (SecurityException e) {
158                            message = "SEARS do not support file bigger than " 
159                                    + FileSystemAccess.MAX_SUBTITLE_FILE_SIZE + " octets";  
160                    } catch (NullPointerException e) {
161                            // DEVELOPPER:
162                            // ????
163                            // file is null !!!!
164                            message = "Unknow error"; 
165                    }
166                    return message;
167            }
168    
169            /**
170             * Get a new <tt>FileConversionException</tt> instance
171             * @param type  <tt>READ_ACCESS</tt>, <tt>WRITE_ACCESS</tt>, <tt>UNSUPPORTED_FILE_SIZE</tt>
172             * @param file  the file where the error is encountered
173             * @return              a new read access exception
174             */
175            public static FileConversionException getAccessException(int type, File file) {
176                    String message = "";
177                    String detail = "";
178                    switch ( type ) {
179                    case READ_ACCESS:
180                            message = "Read access error";
181                            detail  = fileDetail(file) + iOExceptionDetailWhenReading(file) + ", "
182                            + Utils.LINE_SEPARATOR + "please checks your authorisation on this file";
183                            break;
184                    case WRITE_ACCESS:
185                            message = "Write access error";
186                            detail  = fileDetail(file) + iOExceptionDetailWhenWriting(file) + ", "
187                            + Utils.LINE_SEPARATOR + "please checks your authorisation on this file";
188                            break;
189                    case UNSUPPORTED_FILE_SIZE:
190                            message = "Unsupported file size";
191                            detail  = fileDetail(file) + getFileLengthMessage(file);
192                            break;
193                    default:
194                            throw new IllegalArgumentException(type + " is not a valid identifier for an exception type");
195                    }
196                    return new Bean(message, detail, false);
197            }
198    
199            /**
200             * Get a new <tt>FileConversionException</tt> instance
201             * @param type  <tt>UNEXPECTED_END_OF_FILE</tt>, <tt>EMPTY_SUBTITLE_FILE</tt>
202             * @param file  the file on which the error occurs
203             * @return              a new malformed subtitle file exception
204             */
205            public static FileConversionException getMalformedSubtitleFileException(int type, File file) {
206                    String message = "";
207                    String detail = "";
208                    switch ( type ) {
209                    case UNEXPECTED_END_OF_FILE:
210                            message = "Subtitle file seems to be corrupted";
211                            detail  = fileDetail(file) + "unexpected end of file";
212                            break;
213                    case EMPTY_SUBTITLE_FILE:
214                            message = "file is empty";
215                            detail  = fileDetail(file) + "Sears can't read empty subtitle file";
216                            break;
217                    default:
218                            throw new IllegalArgumentException(type + " is not a valid identifier for an exception type");
219                    }
220                    return new Bean(message, detail, false);
221            }
222    
223            /**
224             * Get a new <tt>FileConversionException</tt> instance
225             * @param type                  <tt>MALFORMED_SUBTITLE_NUMBER <br>NO_SUBTITLE_TIME
226             *                                              <br>MALFORMED_TIME_LINE<br>MALFORMED_START_TIME
227             *                                              <br>MALFORMED_END_TIME<br>NO_SUBTITLE_TEXT
228             *                                              <br>MALFORMED_SUBTITLE_TEXT<br>MALFORMED_SUBTITLE_FILE</tt>
229             * @param file                  the file on which the error occurrs
230             * @param lineNumber    the line number where the error is encountered
231             * @param line                  the line where the error is encountered
232             * @return                              a new <tt>FileConversionException</tt> instance
233             */
234            public static FileConversionException getMalformedSubtitleFileException(int type, File file, int lineNumber, String line) {
235                    String message = "Subtitle file seems to be corrupted";
236                    String detail = "";
237                    switch ( type ) {
238                    case NO_SUBTITLE_NUMBER:
239                            detail = fileDetail(file) 
240                            + "no subtitle number at line " + lineNumber;   
241                            break;
242                    case MALFORMED_SUBTITLE_NUMBER:
243                            detail = fileDetail(file) 
244                            + "no subtitle number at line " + lineNumber 
245                            + Utils.LINE_SEPARATOR + line;
246                            break;
247                    case NO_SUBTITLE_TIME:
248                            detail = fileDetail(file) 
249                            + "no time at line " + lineNumber;
250                            break;
251                    case MALFORMED_TIME_LINE:
252                            detail = fileDetail(file) 
253                            + "malformed time at line " + lineNumber
254                            + Utils.LINE_SEPARATOR + line;          
255                            break;
256                    case MALFORMED_START_TIME:
257                            detail = fileDetail(file) 
258                            + "malformed start time at line " + lineNumber 
259                            + Utils.LINE_SEPARATOR + line;          
260                            break;
261                    case MALFORMED_END_TIME:
262                            detail = fileDetail(file) 
263                            + "malformed end time at line " + lineNumber 
264                            + Utils.LINE_SEPARATOR + line;
265                            break;
266                    case NO_SUBTITLE_TEXT:
267                            detail = fileDetail(file) 
268                            + "no subtitle text at line " + lineNumber;
269                            break;
270                    case MALFORMED_SUBTITLE_TEXT:
271                            detail = fileDetail(file) 
272                            + "no subtitle text at line " + lineNumber;
273                            break;
274                    case MALFORMED_SUBTITLE_FILE:
275                            detail = fileDetail(file) 
276                            + "unknow error " + Utils.LINE_SEPARATOR
277                            + "malformed subtitle file at line " + lineNumber;
278                            break;
279                    default:
280                            throw new IllegalArgumentException(type + " is not a valid identifier for an exception type");
281                    }
282                    return new Bean(message, detail, true);
283            }
284    
285            /**
286             * Get a new <tt>FileConversionException</tt> instance
287             * @param file                  the file in cause
288             * @param extension             the <tt>file</tt> extension
289             * @return                              a unsupported file format exception
290             */
291            public static FileConversionException getUnsupportedFileFormatException(File file, String extension) {
292                    return new Bean(
293                                    // MESSAGE
294                                    "unsupported file format",
295                                    // DETAIL
296                                    fileDetail(file) 
297                                    + extension + " file is not supported by Sears",
298                                    // COULD BE THE RESULT OF A BAD ENCODING
299                                    false
300                    );
301            }
302    }
303    
304    /**
305     * This class provides a way to create a basic FileConversion object
306     * <br> Used by the <tt>static</tt> methods of the abstract class that <tt>Bean</tt> extends
307     */
308    class Bean extends FileConversionException {
309    
310            private static final long serialVersionUID = 75866932870197914L;
311    
312            private String message;
313            private String detail;
314            private Boolean couldBeABadEncoding;
315    
316            /**
317             * Constructs a new object with an error message,
318             * detail for this error and a <tt>boolean</tt>
319             * to know if the error could be occur because a bad encoding/decoding
320             * @param message                               the error message
321             * @param detail                                the detail of the error
322             * @param couldBeABadEncoding   if the error may cause by a bad decoding/encoding value is true, false if not
323             */
324            public Bean(String message, String detail, boolean couldBeABadEncoding) {
325                    this.message = message;
326                    this.detail = detail;
327                    this.couldBeABadEncoding = couldBeABadEncoding;
328            }
329    
330            /*
331             * (non-Javadoc)
332             * @see sears.file.exception.io.FileConversionException#couldBeABadEncoding()
333             */
334            public boolean couldBeABadEncoding() {
335                    return couldBeABadEncoding;
336            }
337    
338            /*
339             * (non-Javadoc)
340             * @see sears.file.exception.io.FileConversionException#getDetail()
341             */
342            public String getDetail() {
343                    return detail;
344            }
345    
346            /*
347             * (non-Javadoc)
348             * @see sears.file.exception.io.FileConversionException#getMessage()
349             */
350            public String getMessage() {
351                    return message;
352            }
353    }