001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.internal;
014
015import static org.apache.juneau.internal.ThrowableUtils.*;
016
017import java.io.*;
018
019import org.apache.juneau.*;
020
021/**
022 * File utilities.
023 */
024public class FileUtils {
025
026   /**
027    * Same as {@link File#mkdirs()} except throws a RuntimeExeption if directory could not be created.
028    *
029    * @param f The directory to create.  Must not be <jk>null</jk>.
030    * @param clean If <jk>true</jk>, deletes the contents of the directory if it already exists.
031    * @return The same file.
032    * @throws RuntimeException if directory could not be created.
033    */
034   public static File mkdirs(File f, boolean clean) {
035      assertFieldNotNull(f, "f");
036      if (f.exists()) {
037         if (clean) {
038            if (! delete(f))
039               throw new FormattedRuntimeException("Could not clean directory ''{0}''", f.getAbsolutePath());
040         } else {
041            return f;
042         }
043      }
044      if (! f.mkdirs())
045         throw new FormattedRuntimeException("Could not create directory ''{0}''", f.getAbsolutePath());
046      return f;
047   }
048
049   /**
050    * Same as {@link #mkdirs(String, boolean)} but uses String path.
051    *
052    * @param path The path of the directory to create.  Must not be <jk>null</jk>
053    * @param clean If <jk>true</jk>, deletes the contents of the directory if it already exists.
054    * @return The directory.
055    */
056   public static File mkdirs(String path, boolean clean) {
057      assertFieldNotNull(path, "path");
058      return mkdirs(new File(path), clean);
059   }
060
061   /**
062    * Recursively deletes a file or directory.
063    *
064    * @param f The file or directory to delete.
065    * @return <jk>true</jk> if file or directory was successfully deleted.
066    */
067   public static boolean delete(File f) {
068      if (f == null)
069         return true;
070      if (f.isDirectory()) {
071         File[] cf = f.listFiles();
072         if (cf != null)
073            for (File c : cf)
074               delete(c);
075      }
076      return f.delete();
077   }
078
079   /**
080    * Creates a file if it doesn't already exist using {@link File#createNewFile()}.
081    *
082    * <p>
083    * Throws a {@link RuntimeException} if the file could not be created.
084    *
085    * @param f The file to create.
086    */
087   public static void create(File f) {
088      if (f.exists())
089         return;
090      try {
091         if (! f.createNewFile())
092            throw new FormattedRuntimeException("Could not create file ''{0}''", f.getAbsolutePath());
093      } catch (IOException e) {
094         throw new RuntimeException(e);
095      }
096   }
097
098   /**
099    * Updates the modified timestamp on the specified file.
100    *
101    * <p>
102    * Method ensures that the timestamp changes even if it's been modified within the past millisecond.
103    *
104    * @param f The file to modify the modified timestamp on.
105    */
106   public static void modifyTimestamp(File f) {
107      long lm = f.lastModified();
108      long l = System.currentTimeMillis();
109      if (lm == l)
110         l++;
111      if (! f.setLastModified(l))
112         throw new FormattedRuntimeException("Could not modify timestamp on file ''{0}''", f.getAbsolutePath());
113
114      // Linux only gives 1s precision, so set the date 1s into the future.
115      if (lm == f.lastModified()) {
116         l += 1000;
117         if (! f.setLastModified(l))
118            throw new FormattedRuntimeException("Could not modify timestamp on file ''{0}''", f.getAbsolutePath());
119      }
120   }
121
122   /**
123    * Create a temporary file with the specified name.
124    *
125    * <p>
126    * The name is broken into file name and suffix, and the parts are passed to
127    * {@link File#createTempFile(String, String)}.
128    *
129    * <p>
130    * {@link File#deleteOnExit()} is called on the resulting file before being returned by this method.
131    *
132    * @param name The file name
133    * @return A newly-created temporary file.
134    * @throws IOException
135    */
136   public static File createTempFile(String name) throws IOException {
137      String[] parts = name.split("\\.");
138      File f = File.createTempFile(parts[0], "." + parts[1]);
139      f.deleteOnExit();
140      return f;
141   }
142
143   /**
144    * Strips the extension from a file name.
145    *
146    * @param name The file name.
147    * @return The file name without the extension, or <jk>null</jk> if name was <jk>null</jk>.
148    */
149   public static String getBaseName(String name) {
150      if (name == null)
151         return null;
152      int i = name.lastIndexOf('.');
153      if (i == -1)
154         return name;
155      return name.substring(0, i);
156   }
157
158   /**
159    * Returns the extension from a file name.
160    *
161    * @param name The file name.
162    * @return The the extension, or <jk>null</jk> if name was <jk>null</jk>.
163    */
164   public static String getExtension(String name) {
165      if (name == null)
166         return null;
167      int i = name.lastIndexOf('.');
168      if (i == -1)
169         return "";
170      return name.substring(i+1);
171   }
172}