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.tools;
028 import org.opends.messages.Message;
029
030
031
032 import java.io.File;
033 import java.io.RandomAccessFile;
034
035 import org.opends.server.util.args.ArgumentException;
036 import org.opends.server.util.args.ArgumentParser;
037 import org.opends.server.util.args.BooleanArgument;
038 import org.opends.server.util.args.IntegerArgument;
039 import org.opends.server.util.args.StringArgument;
040
041 import static org.opends.messages.ToolMessages.*;
042 import static org.opends.server.util.ServerConstants.*;
043 import static org.opends.server.util.StaticUtils.*;
044
045
046
047 /**
048 * This program provides a simple tool that will wait for a specified file to be
049 * deleted before exiting. It can be used in the process of confirming that the
050 * server has completed its startup or shutdown process.
051 */
052 public class WaitForFileDelete
053 {
054 /**
055 * The fully-qualified name of this class.
056 */
057 private static final String CLASS_NAME =
058 "org.opends.server.tools.WaitForFileDelete";
059
060
061
062 /**
063 * The exit code value that will be used if the target file is deleted
064 * successfully.
065 */
066 public static final int EXIT_CODE_SUCCESS = 0;
067
068
069
070 /**
071 * The exit code value that will be used if an internal error occurs within
072 * this program.
073 */
074 public static final int EXIT_CODE_INTERNAL_ERROR = 1;
075
076
077
078 /**
079 * The exit code value that will be used if a timeout occurs while waiting for
080 * the file to be removed.
081 */
082 public static final int EXIT_CODE_TIMEOUT = 2;
083
084
085
086 /**
087 * Processes the command-line arguments and initiates the process of waiting
088 * for the file to be removed.
089 *
090 * @param args The command-line arguments provided to this program.
091 */
092 public static void main(String[] args)
093 {
094 try
095 {
096 int exitCode = mainWait(args);
097 if (exitCode != EXIT_CODE_SUCCESS)
098 {
099 System.exit(filterExitCode(exitCode));
100 }
101 }
102 catch (Exception e)
103 {
104 e.printStackTrace();
105 System.exit(EXIT_CODE_INTERNAL_ERROR);
106 }
107 }
108
109
110
111 /**
112 * Processes the command-line arguments and then waits for the specified file
113 * to be removed.
114 *
115 * @param args The command-line arguments provided to this program.
116 *
117 * @return An integer value of zero if the file was deleted successfully, or
118 * some other value if a problem occurred.
119 */
120 public static int mainWait(String[] args)
121 {
122 // Create all of the command-line arguments for this program.
123 BooleanArgument showUsage = null;
124 IntegerArgument timeout = null;
125 StringArgument logFilePath = null;
126 StringArgument targetFilePath = null;
127 StringArgument outputFilePath = null;
128
129 Message toolDescription = INFO_WAIT4DEL_TOOL_DESCRIPTION.get();
130 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription,
131 false);
132
133 try
134 {
135 targetFilePath =
136 new StringArgument("targetfile", 'f', "targetFile", true, false,
137 true, INFO_PATH_PLACEHOLDER.get(), null, null,
138 INFO_WAIT4DEL_DESCRIPTION_TARGET_FILE.get());
139 argParser.addArgument(targetFilePath);
140
141
142 logFilePath = new StringArgument(
143 "logfile", 'l', "logFile", false, false,
144 true, INFO_PATH_PLACEHOLDER.get(), null, null,
145 INFO_WAIT4DEL_DESCRIPTION_LOG_FILE.get());
146 argParser.addArgument(logFilePath);
147
148
149 outputFilePath = new StringArgument(
150 "outputfile", 'o', "outputFile",
151 false, false,
152 true, INFO_PATH_PLACEHOLDER.get(), null, null,
153 INFO_WAIT4DEL_DESCRIPTION_OUTPUT_FILE.get());
154 argParser.addArgument(outputFilePath);
155
156
157 timeout = new IntegerArgument("timeout", 't', "timeout", true, false,
158 true, INFO_SECONDS_PLACEHOLDER.get(), 60,
159 null, true, 0, false,
160 0, INFO_WAIT4DEL_DESCRIPTION_TIMEOUT.get());
161 argParser.addArgument(timeout);
162
163
164 showUsage = new BooleanArgument("help", 'H', "help",
165 INFO_WAIT4DEL_DESCRIPTION_HELP.get());
166 argParser.addArgument(showUsage);
167 argParser.setUsageArgument(showUsage);
168 }
169 catch (ArgumentException ae)
170 {
171 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
172 System.err.println(wrapText(message, MAX_LINE_WIDTH));
173 return EXIT_CODE_INTERNAL_ERROR;
174 }
175
176
177 // Parse the command-line arguments provided to the program.
178 try
179 {
180 argParser.parseArguments(args);
181 }
182 catch (ArgumentException ae)
183 {
184 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
185
186 System.err.println(wrapText(message, MAX_LINE_WIDTH));
187 System.err.println(argParser.getUsage());
188 return EXIT_CODE_INTERNAL_ERROR;
189 }
190
191
192 // If we should just display usage or version information,
193 // then print it and exit.
194 if (argParser.usageOrVersionDisplayed())
195 {
196 return EXIT_CODE_SUCCESS;
197 }
198
199
200 // Get the file to watch. If it doesn't exist now, then exit immediately.
201 File targetFile = new File(targetFilePath.getValue());
202 if (! targetFile.exists())
203 {
204 return EXIT_CODE_SUCCESS;
205 }
206
207
208 // If a log file was specified, then open it.
209 long logFileOffset = 0L;
210 RandomAccessFile logFile = null;
211 if (logFilePath.isPresent())
212 {
213 try
214 {
215 File f = new File(logFilePath.getValue());
216 if (f.exists())
217 {
218 logFile = new RandomAccessFile(f, "r");
219 logFileOffset = logFile.length();
220 logFile.seek(logFileOffset);
221 }
222 }
223 catch (Exception e)
224 {
225 Message message = WARN_WAIT4DEL_CANNOT_OPEN_LOG_FILE.get(
226 logFilePath.getValue(), String.valueOf(e));
227 System.err.println(wrapText(message, MAX_LINE_WIDTH));
228
229 logFile = null;
230 }
231 }
232
233
234 // If an output file was specified and we could open the log file, open it
235 // and append data to it.
236 RandomAccessFile outputFile = null;
237 long outputFileOffset = 0L;
238 if (logFile != null)
239 {
240 if (outputFilePath.isPresent())
241 {
242 try
243 {
244 File f = new File(outputFilePath.getValue());
245 if (f.exists())
246 {
247 outputFile = new RandomAccessFile(f, "rw");
248 outputFileOffset = outputFile.length();
249 outputFile.seek(outputFileOffset);
250 }
251 }
252 catch (Exception e)
253 {
254 Message message = WARN_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE.get(
255 outputFilePath.getValue(), String.valueOf(e));
256 System.err.println(wrapText(message, MAX_LINE_WIDTH));
257
258 outputFile = null;
259 }
260 }
261 }
262 // Figure out when to stop waiting.
263 long stopWaitingTime;
264 try
265 {
266 long timeoutMillis = 1000L * Integer.parseInt(timeout.getValue());
267 if (timeoutMillis > 0)
268 {
269 stopWaitingTime = System.currentTimeMillis() + timeoutMillis;
270 }
271 else
272 {
273 stopWaitingTime = Long.MAX_VALUE;
274 }
275 }
276 catch (Exception e)
277 {
278 // This shouldn't happen, but if it does then ignore it.
279 stopWaitingTime = System.currentTimeMillis() + 60000;
280 }
281
282
283 // Operate in a loop, printing out any applicable log messages and waiting
284 // for the target file to be removed.
285 byte[] logBuffer = new byte[8192];
286 while (System.currentTimeMillis() < stopWaitingTime)
287 {
288 if (logFile != null)
289 {
290 try
291 {
292 while (logFile.length() > logFileOffset)
293 {
294 int bytesRead = logFile.read(logBuffer);
295 if (bytesRead > 0)
296 {
297 if (outputFile == null)
298 {
299 System.out.write(logBuffer, 0, bytesRead);
300 System.out.flush();
301 }
302 else
303 {
304 // Write on the file.
305 // TODO
306 outputFile.write(logBuffer, 0, bytesRead);
307
308 }
309 logFileOffset += bytesRead;
310 }
311 }
312 }
313 catch (Exception e)
314 {
315 // We'll just ignore this.
316 }
317 }
318
319
320 if (! targetFile.exists())
321 {
322 break;
323 }
324 else
325 {
326 try
327 {
328 Thread.sleep(10);
329 } catch (InterruptedException ie) {}
330 }
331 }
332
333 if (outputFile != null)
334 {
335 try
336 {
337 outputFile.close();
338 }
339 catch (Throwable t) {}
340 }
341
342 if (targetFile.exists())
343 {
344 return EXIT_CODE_TIMEOUT;
345 }
346 else
347 {
348 return EXIT_CODE_SUCCESS;
349 }
350 }
351 }
352