001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.util.args;
028 import org.opends.messages.Message;
029
030
031
032 import java.io.BufferedReader;
033 import java.io.File;
034 import java.io.FileReader;
035 import java.util.LinkedHashMap;
036
037 import static org.opends.messages.UtilityMessages.*;
038 import org.opends.messages.MessageBuilder;
039 import static org.opends.server.util.StaticUtils.*;
040
041
042
043 /**
044 * This class defines an argument whose value will be read from a file rather
045 * than actually specified on the command-line. When a value is specified on
046 * the command line, it will be treated as the path to the file containing the
047 * actual value rather than the value itself.
048 * <BR><BR>
049 * Note that if if no filename is provided on the command line but a default
050 * value is specified programatically or if the default value is read from a
051 * specified property, then that default value will be taken as the actual value
052 * rather than a filename.
053 * <BR><BR>
054 * Also note that this argument type assumes that the entire value for the
055 * argument is on a single line in the specified file. If the file contains
056 * multiple lines, then only the first line will be read.
057 */
058 public class FileBasedArgument
059 extends Argument
060 {
061 // The mapping between filenames specified and the first lines read from those
062 // files.
063 private LinkedHashMap<String,String> namesToValues;
064
065
066
067 /**
068 * Creates a new file-based argument with the provided information.
069 *
070 * @param name The generic name that should be used to refer to
071 * this argument.
072 * @param shortIdentifier The single-character identifier for this
073 * argument, or <CODE>null</CODE> if there is none.
074 * @param longIdentifier The long identifier for this argument, or
075 * <CODE>null</CODE> if there is none.
076 * @param isRequired Indicates whether this argument must be specified
077 * on the command line.
078 * @param valuePlaceholder The placeholder for the argument value that will
079 * be displayed in usage information, or
080 * <CODE>null</CODE> if this argument does not
081 * require a value.
082 * @param description Message for the description of this
083 * argument.
084 *
085 * @throws ArgumentException If there is a problem with any of the
086 * parameters used to create this argument.
087 */
088 public FileBasedArgument(String name, Character shortIdentifier,
089 String longIdentifier, boolean isRequired,
090 Message valuePlaceholder,
091 Message description)
092 throws ArgumentException
093 {
094 super(name, shortIdentifier, longIdentifier, isRequired, false, true,
095 valuePlaceholder, null, null, description);
096
097
098 namesToValues = new LinkedHashMap<String,String>();
099 }
100
101
102
103 /**
104 * Creates a new file-based argument with the provided information.
105 *
106 * @param name The generic name that should be used to refer to
107 * this argument.
108 * @param shortIdentifier The single-character identifier for this
109 * argument, or <CODE>null</CODE> if there is none.
110 * @param longIdentifier The long identifier for this argument, or
111 * <CODE>null</CODE> if there is none.
112 * @param isRequired Indicates whether this argument must be specified
113 * on the command line.
114 * @param isMultiValued Indicates whether this argument may be specified
115 * more than once to provide multiple values.
116 * @param valuePlaceholder The placeholder for the argument value that will
117 * be displayed in usage information, or
118 * <CODE>null</CODE> if this argument does not
119 * require a value.
120 * @param defaultValue The default value that should be used for this
121 * argument if none is provided in a properties file
122 * or on the command line. This may be
123 * <CODE>null</CODE> if there is no generic default.
124 * @param propertyName The name of the property in a property file that
125 * may be used to override the default value but
126 * will be overridden by a command-line argument.
127 * @param description Message for the description of this
128 * argument.
129 *
130 * @throws ArgumentException If there is a problem with any of the
131 * parameters used to create this argument.
132 */
133 public FileBasedArgument(String name, Character shortIdentifier,
134 String longIdentifier, boolean isRequired,
135 boolean isMultiValued, Message valuePlaceholder,
136 String defaultValue, String propertyName,
137 Message description)
138 throws ArgumentException
139 {
140 super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
141 true, valuePlaceholder, defaultValue, propertyName,
142 description);
143
144 namesToValues = new LinkedHashMap<String,String>();
145 }
146
147
148
149 /**
150 * Retrieves a map between the filenames specified on the command line and the
151 * first lines read from those files.
152 *
153 * @return A map between the filenames specified on the command line and the
154 * first lines read from those files.
155 */
156 public LinkedHashMap<String,String> getNameToValueMap()
157 {
158 return namesToValues;
159 }
160
161
162
163 /**
164 * Indicates whether the provided value is acceptable for use in this
165 * argument.
166 *
167 * @param valueString The value for which to make the determination.
168 * @param invalidReason A buffer into which the invalid reason may be
169 * written if the value is not acceptable.
170 *
171 * @return <CODE>true</CODE> if the value is acceptable, or
172 * <CODE>false</CODE> if it is not.
173 */
174 public boolean valueIsAcceptable(String valueString,
175 MessageBuilder invalidReason)
176 {
177 // First, make sure that the specified file exists.
178 File valueFile;
179 try
180 {
181 valueFile = new File(valueString);
182 if (! valueFile.exists())
183 {
184 invalidReason.append(ERR_FILEARG_NO_SUCH_FILE.get(
185 valueString, getName()));
186 return false;
187 }
188 }
189 catch (Exception e)
190 {
191 invalidReason.append(ERR_FILEARG_CANNOT_VERIFY_FILE_EXISTENCE.get(
192 valueString, getName(),
193 getExceptionMessage(e)));
194 return false;
195 }
196
197
198 // Open the file for reading.
199 BufferedReader reader;
200 try
201 {
202 reader = new BufferedReader(new FileReader(valueFile));
203 }
204 catch (Exception e)
205 {
206 invalidReason.append(ERR_FILEARG_CANNOT_OPEN_FILE.get(
207 valueString, getName(),
208 getExceptionMessage(e)));
209 return false;
210 }
211
212
213 // Read the first line and close the file.
214 String line;
215 try
216 {
217 line = reader.readLine();
218 }
219 catch (Exception e)
220 {
221 invalidReason.append(ERR_FILEARG_CANNOT_READ_FILE.get(
222 valueString, getName(),
223 getExceptionMessage(e)));
224 return false;
225 }
226 finally
227 {
228 try
229 {
230 reader.close();
231 } catch (Exception e) {}
232 }
233
234
235 // If the line read is null, then that means the file was empty.
236 if (line == null)
237 {
238
239 invalidReason.append(ERR_FILEARG_EMPTY_FILE.get(valueString, getName()));
240 return false;
241 }
242
243
244 // Store the value in the hash so it will be available for addValue. We
245 // won't do any validation on the value itself, so anything that we read
246 // will be considered acceptable.
247 namesToValues.put(valueString, line);
248 return true;
249 }
250
251
252
253 /**
254 * Adds a value to the set of values for this argument. This should only be
255 * called if the value is allowed by the <CODE>valueIsAcceptable</CODE>
256 * method. Note that in this case, correct behavior depends on a previous
257 * successful call to <CODE>valueIsAcceptable</CODE> so that the value read
258 * from the file may be stored in the name-to-value hash and used in place of
259 * the filename here.
260 *
261 * @param valueString The string representation of the value to add to this
262 * argument.
263 */
264 public void addValue(String valueString)
265 {
266 String actualValue = namesToValues.get(valueString);
267 if (actualValue != null)
268 {
269 super.addValue(actualValue);
270 }
271 }
272 }
273