001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.cli2.validation;
018
019import java.io.File;
020import java.util.List;
021import java.util.ListIterator;
022
023/**
024 * The <code>FileValidator</code> validates the string argument
025 * values are files.  If the value is a file, the string value in
026 * the {@link java.util.List} of values is replaced with the
027 * {@link java.io.File} instance.
028 *
029 * The following attributes can also be specified using the
030 * appropriate settors:
031 * <ul>
032 *  <li>writable</li>
033 *  <li>readable</li>
034 *  <li>hidden</li>
035 *  <li>existing</li>
036 *  <li>is a file</li>
037 *  <li>is a directory</li>
038 * </ul>
039 *
040 * The following example shows how to limit the valid values
041 * for the config attribute to files that are readable, writeable,
042 * and that already existing.
043 *
044 * <pre>
045 * ...
046 * ArgumentBuilder builder = new ArgumentBuilder();
047 * FileValidator validator = FileValidator.getExistingFileInstance();
048 * validator.setReadable(true);
049 * validator.setWritable(true);
050 *
051 * Argument age =
052 *     builder.withName("config");
053 *            .withValidator(validator);
054 * </pre>
055 *
056 * @author Rob Oxspring
057 * @author John Keyes
058 */
059public class FileValidator implements Validator {
060
061    /**
062     * Returns a <code>FileValidator</code> for existing files/directories.
063     *
064     * @return a <code>FileValidator</code> for existing files/directories.
065     */
066    public static FileValidator getExistingInstance() {
067        final FileValidator validator = new FileValidator();
068        validator.setExisting(true);
069        return validator;
070    }
071
072    /**
073     * Returns a <code>FileValidator</code> for existing files.
074     *
075     * @return a <code>FileValidator</code> for existing files.
076     */
077    public static FileValidator getExistingFileInstance() {
078        final FileValidator validator = new FileValidator();
079        validator.setExisting(true);
080        validator.setFile(true);
081        return validator;
082    }
083
084    /**
085     * Returns a <code>FileValidator</code> for existing directories.
086     *
087     * @return a <code>FileValidator</code> for existing directories.
088     */
089    public static FileValidator getExistingDirectoryInstance() {
090        final FileValidator validator = new FileValidator();
091        validator.setExisting(true);
092        validator.setDirectory(true);
093        return validator;
094    }
095
096    /** whether the argument value is readable */
097    private boolean readable = false;
098
099    /** whether the argument value is writable */
100    private boolean writable = false;
101
102    /** whether the argument value exists */
103    private boolean existing = false;
104
105    /** whether the argument value is a directory */
106    private boolean directory = false;
107
108    /** whether the argument value is a file */
109    private boolean file = false;
110
111    /** whether the argument value is a hidden file or directory */
112    private boolean hidden = false;
113
114    /**
115     * Validate the list of values against the list of permitted values.
116     * If a value is valid, replace the string in the <code>values</code>
117     * {@link java.util.List} with the {@link java.io.File} instance.
118     *
119     * @see org.apache.commons.cli2.validation.Validator#validate(java.util.List)
120     */
121    public void validate(final List values) throws InvalidArgumentException {
122        for (final ListIterator i = values.listIterator(); i.hasNext();) {
123            final String name = (String)i.next();
124            final File f = new File(name);
125
126            if ((existing && !f.exists())
127                || (file && !f.isFile())
128                || (directory && !f.isDirectory())
129                || (hidden && !f.isHidden())
130                || (readable && !f.canRead())
131                || (writable && !f.canWrite())) {
132
133                throw new InvalidArgumentException(name);
134            }
135
136            i.set(f);
137        }
138    }
139
140    /**
141     * Returns whether the argument values must represent directories.
142     *
143     * @return whether the argument values must represent directories.
144     */
145    public boolean isDirectory() {
146        return directory;
147    }
148
149    /**
150     * Specifies whether the argument values must represent directories.
151     *
152     * @param directory specifies whether the argument values must
153     * represent directories.
154     */
155    public void setDirectory(boolean directory) {
156        this.directory = directory;
157    }
158
159    /**
160     * Returns whether the argument values must represent existing
161     * files/directories.
162     *
163     * @return whether the argument values must represent existing
164     * files/directories.
165     */
166    public boolean isExisting() {
167        return existing;
168    }
169
170    /**
171     * Specifies whether the argument values must represent existing
172     * files/directories.
173     *
174     * @param existing specifies whether the argument values must
175     * represent existing files/directories.
176     */
177    public void setExisting(boolean existing) {
178        this.existing = existing;
179    }
180
181    /**
182     * Returns whether the argument values must represent directories.
183     *
184     * @return whether the argument values must represent directories.
185     */
186    public boolean isFile() {
187        return file;
188    }
189
190    /**
191     * Specifies whether the argument values must represent files.
192     *
193     * @param file specifies whether the argument values must
194     * represent files.
195     */
196    public void setFile(boolean file) {
197        this.file = file;
198    }
199
200    /**
201     * Returns whether the argument values must represent hidden
202     * files/directories.
203     *
204     * @return whether the argument values must represent hidden
205     * files/directories.
206     */
207    public boolean isHidden() {
208        return hidden;
209    }
210
211    /**
212     * Specifies whether the argument values must represent hidden
213     * files/directories.
214     *
215     * @param hidden specifies whether the argument values must
216     * represent hidden files/directories.
217     */
218    public void setHidden(boolean hidden) {
219        this.hidden = hidden;
220    }
221
222    /**
223     * Returns whether the argument values must represent readable
224     * files/directories.
225     *
226     * @return whether the argument values must represent readable
227     * files/directories.
228     */
229    public boolean isReadable() {
230        return readable;
231    }
232
233    /**
234     * Specifies whether the argument values must represent readable
235     * files/directories.
236     *
237     * @param readable specifies whether the argument values must
238     * represent readable files/directories.
239     */
240    public void setReadable(boolean readable) {
241        this.readable = readable;
242    }
243
244    /**
245     * Returns whether the argument values must represent writable
246     * files/directories.
247     *
248     * @return whether the argument values must represent writable
249     * files/directories.
250     */
251    public boolean isWritable() {
252        return writable;
253    }
254
255    /**
256     * Specifies whether the argument values must represent writable
257     * files/directories.
258     *
259     * @param writable specifies whether the argument values must
260     * represent writable files/directories.
261     */
262    public void setWritable(boolean writable) {
263        this.writable = writable;
264    }
265}