001/**
002 *
003 * Copyright the original author or authors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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.jivesoftware.smack.util;
018
019import java.io.BufferedReader;
020import java.io.File;
021import java.io.FileInputStream;
022import java.io.FileNotFoundException;
023import java.io.FileOutputStream;
024import java.io.FileReader;
025import java.io.FileWriter;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.InputStreamReader;
029import java.io.Reader;
030import java.net.MalformedURLException;
031import java.net.URI;
032import java.net.URL;
033import java.nio.charset.StandardCharsets;
034import java.util.ArrayList;
035import java.util.List;
036import java.util.Set;
037import java.util.logging.Level;
038import java.util.logging.Logger;
039
040public final class FileUtils {
041
042    private static final Logger LOGGER = Logger.getLogger(FileUtils.class.getName());
043
044    public static InputStream getInputStreamForClasspathFile(String path) {
045        return getInputStreamForClasspathFile(path, null);
046    }
047
048    public static InputStream getInputStreamForClasspathFile(String path, ClassLoader loader) {
049        try {
050            return getStreamForClasspathFile(path, loader);
051        } catch (IOException e) {
052            LOGGER.log(Level.FINE, "Suppressed IOException in getInputStreamForClasspathFile", e);
053            return null;
054        }
055    }
056
057    public static InputStream getStreamForClasspathFile(String path, ClassLoader loader) throws IOException {
058        // Get an array of class loaders to try loading the providers files from.
059        List<ClassLoader> classLoaders = getClassLoaders();
060        if (loader != null) {
061            classLoaders.add(0, loader);
062        }
063        for (ClassLoader classLoader : classLoaders) {
064            InputStream is = classLoader.getResourceAsStream(path);
065
066            if (is != null) {
067                return is;
068            }
069        }
070        throw new IOException("Unable to get '" + path + "' from classpath. Tried ClassLoaders:" + classLoaders);
071    }
072
073    public static InputStream getStreamForUri(URI uri, ClassLoader loader) throws IOException {
074        String protocol = uri.getScheme();
075        if (protocol.equals("classpath")) {
076            String path = uri.getSchemeSpecificPart();
077            return getStreamForClasspathFile(path, loader);
078        }
079
080        URL url = uri.toURL();
081        return url.openStream();
082    }
083
084    /**
085     * Returns default classloaders.
086     *
087     * @return a List of ClassLoader instances.
088     */
089    public static List<ClassLoader> getClassLoaders() {
090        ClassLoader[] classLoaders = new ClassLoader[2];
091        classLoaders[0] = FileUtils.class.getClassLoader();
092        classLoaders[1] = Thread.currentThread().getContextClassLoader();
093
094        // Clean up possible null values. Note that #getClassLoader may return a null value.
095        List<ClassLoader> loaders = new ArrayList<ClassLoader>(classLoaders.length);
096        for (ClassLoader classLoader : classLoaders) {
097            if (classLoader != null) {
098                loaders.add(classLoader);
099            }
100        }
101        return loaders;
102    }
103
104    public static boolean addLines(String uriString, Set<String> set) throws MalformedURLException, IOException {
105        URI uri = URI.create(uriString);
106        InputStream is = getStreamForUri(uri, null);
107        InputStreamReader sr = new InputStreamReader(is, StandardCharsets.UTF_8);
108        BufferedReader br = new BufferedReader(sr);
109        try {
110            String line;
111            while ((line = br.readLine()) != null) {
112                set.add(line);
113            }
114        }
115        finally {
116            br.close();
117        }
118        return true;
119    }
120
121    /**
122     * Reads the contents of a File.
123     *
124     * @param file TODO javadoc me please
125     * @return the content of file or null in case of an error
126     * @throws IOException if an I/O error occurred.
127     */
128    @SuppressWarnings("DefaultCharset")
129    public static String readFileOrThrow(File file) throws IOException {
130        try (Reader reader = new FileReader(file)) {
131            char[] buf = new char[8192];
132            int len;
133            StringBuilder s = new StringBuilder();
134            while ((len = reader.read(buf)) >= 0) {
135                s.append(buf, 0, len);
136            }
137            return s.toString();
138        }
139    }
140
141    public static String readFile(File file) {
142        try {
143            return readFileOrThrow(file);
144        } catch (FileNotFoundException e) {
145            LOGGER.log(Level.FINE, "readFile", e);
146        } catch (IOException e) {
147            LOGGER.log(Level.WARNING, "readFile", e);
148        }
149        return null;
150    }
151
152    @SuppressWarnings("DefaultCharset")
153    public static void writeFileOrThrow(File file, CharSequence content) throws IOException {
154        FileWriter writer = new FileWriter(file, false);
155        try {
156            writer.write(content.toString());
157        } finally {
158            writer.close();
159        }
160    }
161
162    public static boolean writeFile(File file, CharSequence content) {
163        try {
164            writeFileOrThrow(file, content);
165            return true;
166        }
167        catch (IOException e) {
168            LOGGER.log(Level.WARNING, "writeFile", e);
169            return false;
170        }
171    }
172
173    public static FileOutputStream prepareFileOutputStream(File file) throws IOException {
174        if (!file.exists()) {
175
176            // Create parent directory
177            File parent = file.getParentFile();
178            if (!parent.exists() && !parent.mkdirs()) {
179                throw new IOException("Cannot create directory " + parent.getAbsolutePath());
180            }
181
182            // Create file
183            if (!file.createNewFile()) {
184                throw new IOException("Cannot create file " + file.getAbsolutePath());
185            }
186        }
187
188        if (file.isDirectory()) {
189            throw new AssertionError("File " + file.getAbsolutePath() + " is not a file!");
190        }
191
192        return new FileOutputStream(file);
193    }
194
195    public static FileInputStream prepareFileInputStream(File file) throws IOException {
196        if (file.exists()) {
197            if (file.isFile()) {
198                return new FileInputStream(file);
199            } else {
200                throw new IOException("File " + file.getAbsolutePath() + " is not a file!");
201            }
202        } else {
203            throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found.");
204        }
205    }
206
207    public static void maybeDeleteFileOrThrow(File file) throws IOException {
208        if (!file.exists()) {
209            return;
210        }
211
212        boolean successfullyDeleted = file.delete();
213        if (!successfullyDeleted) {
214            throw new IOException("Could not delete file " + file);
215        }
216    }
217
218    public static void maybeCreateFileWithParentDirectories(File file) throws IOException {
219        File parent = file.getParentFile();
220        if (!parent.exists() && !parent.mkdirs()) {
221            throw new IOException("Cannot create directory " + parent);
222        }
223
224        if (file.isFile()) {
225            return;
226        }
227
228        if (!file.exists()) {
229            if (file.createNewFile()) {
230                return;
231            }
232            throw new IOException("Cannot create file " + file);
233        }
234
235        if (file.isDirectory()) {
236            throw new IOException("File " + file + " exists, but is a directory.");
237        } else {
238            throw new IOException("File " + file + " exists, but is neither a file nor a directory");
239        }
240    }
241}