1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package Torello.Java;

import java.io.*;

/**
 * Used by methods that accept <CODE>'target directory'</CODE> parameters to validate that the
 * parameter's contents actually point to a <B>both</B> valid <B>and</B> writable location on disk.
 * 
 * <BR /><EMBED CLASS='external-html' DATA-FILE-ID=WRITABLE_DIR_EX>
 */
public class WritableDirectoryException extends RuntimeException
{
    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDEX>  */
    public static final long serialVersionUID = 1;

    /**
     * This boolean allows a user to decide whether the zero-length {@code String} should force an
     * exception throw when passed to this class' {@link #check(String)} method.  When this boolean
     * is set to {@code TRUE}, the class will check whether or not the directory named by the
     * {@code String} returned by a call to {@code System.getProperty("user.dir")} is writable.
     *   
     * <BR /><BR />An invocation to method {@code System.getProperty("user.dir")} returns a
     * {@code String} that contains the current user's home directory.  If this directory is
     * writable, then no exception throw shall occur when testing and passing a zero-length 
     * {@code String} to the {@code 'directory'} parameter of the {@code check(String)} method.
     * 
     * <BR /><BR />When this parameter is set to {@code FALSE}, and when a zero-length 
     * {@code String} is passed to the {@code 'directory'} parameter of the {@code 'check(String)'}
     * method.  
     * 
     * <BR /><BR /><B>DEFAULT:</B> The default behavior of method {@link #check(String)} is to
     * throw an exception whenever the zero-length {@code String} is passed.
     */
    public static boolean THROW_ON_ZERO_LENGTH_STRING = true;

    /** Constructs a {@code WritableDirectoryException} with no detail message. */
    public WritableDirectoryException()
    { super(); }

    /**
     * Constructs a {@code WritableDirectoryException} with the specified detail message.
     * @param message the detail message.
     */
    public WritableDirectoryException(String message)
    { super(message); }

    /**
     * Constructs a new exception with the specified detail message and cause.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>NOTE:</B>
     * 
     * <BR /><BR />The detail message associated with cause is not automatically incorporated into
     * this exception's detail message.
     * 
     * @param message The detail message (which is saved for later retrieval by the
     * {@code Throwable.getMessage()} method).
     * 
     * @param cause the cause (which is saved for later retrieval by the
     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
     * cause is nonexistent or unknown.)
     */
    public WritableDirectoryException(String message, Throwable cause)
    { super(message, cause); }

    /**
     * Constructs a new exception with the specified cause and a detail message of
     * {@code (cause==null ? null : cause.toString())} (which typically contains the class and
     * detail message of cause).  This constructor is useful for exceptions that are little more
     * than wrappers for other {@code Throwable's}.
     * 
     * @param cause The cause (which is saved for later retrieval by the
     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
     * cause is nonexistent or unknown.)
     */
    public WritableDirectoryException(Throwable cause)
    { super(cause); }

   /**
     * Checks that a directory-name is valid and ready for saving image files.
     * 
     * @param directory  This is the directory-name to be tested.
     * 
     * @throws WritableDirectoryException Throws under any of the following circustances:
     * 
     * <BR /><BR /><UL CLASS=JDUL>
     * 
     * <LI> Parameter {@code 'directory'} has been passed null.
     *      <BR /><BR />
     *      </LI>
     * 
     * <LI> Parameter {@code 'directory'} is a zero length {@code String}, and the configurable
     *      {@code public} and {@code static} boolean {@link #THROW_ON_ZERO_LENGTH_STRING} has
     *      been set to {@code TRUE}.
     *      <BR /><BR />
     *      </LI>
     * 
     * <LI> The directory specified by parameter {@code 'directory'} does not exist anywhere on the
     *      file-system.
     *      <BR /><BR />
     *      </LI>
     *
     * <LI> The file specified by parameter {@code 'directory'} exists, but is a file, rather than
     *      a directory.
     *      <BR /><BR />
     *      </LI>
     *
     * <LI> This method was unable to write a small, temporary file to that directory, and in 
     *      the process of attempting to do so caused a Java {@code IOException} to be thrown.
     * 
     *      <BR /><BR />Note that in this case, the {@code IOException} that was thrown (and
     *      caught) will be assigned as the {@code 'cause'} exception, and may be retrieved by
     *      calling {@code 'this'} exception's {@code getCause()} method.
     *      </LI>
     *
     * </UL>
     */
    public static void check(String directory)
    {
        if (directory == null) throw new WritableDirectoryException
            ("Parameter 'directory' was passed null");

        if (directory == "")
        {
            if (THROW_ON_ZERO_LENGTH_STRING) throw new WritableDirectoryException(
                "You have passed the zero-length String to the class " +
                "WritableDirectoryException's 'check' method.  If this is the desired behavior, " +
                "there is a configurable, static, boolean named 'THROW_ON_ZERO_LENGTH_STRING' " + 
                "in this class that should be set to FALSE.  Currently, when the zero-length " +
                "String is passed here, an exception (this one) is thrown immediately.  If this " +
                "configuration-boolean were TRUE, the directory checked would be the one " +
                "returned by a call to System.getProperty(\"user.dir\")"
            );

            directory = System.getProperty("user.dir");
        }

        check(new File(directory));
    }

   /**
     * Checks that a directory-name is valid and ready for saving image files.
     * 
     * @param directory  This is the directory-name to be tested.
     * 
     * @throws WritableDirectoryException Throws under any of the following circustances:
     * 
     * <BR /><BR /><UL CLASS=JDUL>
     * 
     * <LI> Parameter {@code 'directory'} has been passed null.
     *      <BR /><BR />
     *      </LI>
     * 
     * <LI> The directory specified by parameter {@code 'directory'} does not exist anywhere on the
     *      file-system.
     *      <BR /><BR />
     *      </LI>
     *
     * <LI> The file specified by parameter {@code 'directory'} exists, but is a file, rather than
     *      a directory.
     *      <BR /><BR />
     *      </LI>
     *
     * <LI> This method was unable to write a small, temporary file to that directory, and in 
     *      the process of attempting to do so caused a Java {@code IOException} to be thrown.
     * 
     *      <BR /><BR />Note that in this case, the {@code IOException} that was thrown (and
     *      caught) will be assigned as the {@code 'cause'} exception, and may be retrieved by
     *      calling {@code 'this'} exception's {@code getCause()} method.
     *      </LI>
     *
     * </UL>
     */
    public static void check(File directory)
    {
        if (directory == null) throw new WritableDirectoryException
            ("Parameter 'directory' was passed null");

        // Make sure that the directory name exists on the file-system.  If not throw exception
        if (! directory.exists()) throw new WritableDirectoryException(
            "The directory-name [" + directory.toString() + "], that you have passed does not " +
            "exist, or could not be found be the file-system."
        );

        // Make sure that the directory-named is actually a directory, not a file, link, etc...
        if (! directory.isDirectory()) throw new WritableDirectoryException(
            "The directory-name [" + directory.toString() + "], that you have passed was found, " +
            "but it is not a valid directory-name on the file-system."
        );

        // Make sure that the directory provided is writable, or throw an exception.
        try
        {
            File f = File.createTempFile("test", "tmp", directory);
            f.delete();
        }

        catch (IOException ioe)
        {
            throw new WritableDirectoryException(
                "There was a JavaIOException when attempting to write a file to the directory-name " +
                '[' + directory.toString() + "].  Please see this exception's getCause() " +
                "throwable for more details.",
                ioe
            );
        }
    }
}