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     */
017    package org.apache.commons.configuration;
018    
019    import org.apache.commons.logging.Log;
020    import org.apache.commons.logging.LogFactory;
021    
022    import java.io.InputStream;
023    import java.io.File;
024    import java.io.IOException;
025    import java.io.OutputStream;
026    import java.io.FileOutputStream;
027    import java.io.FileNotFoundException;
028    import java.net.URL;
029    import java.net.URLConnection;
030    import java.net.HttpURLConnection;
031    import java.net.MalformedURLException;
032    
033    /**
034     * FileSystem that uses java.io.File or HttpClient
035     * @since 1.7
036     * @author <a
037     * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
038     */
039    public class DefaultFileSystem extends FileSystem
040    {
041        /**
042         * The Log for diagnostic messages.
043         */
044        private Log log = LogFactory.getLog(DefaultFileSystem.class);
045    
046        public InputStream getInputStream(String basePath, String fileName)
047            throws ConfigurationException
048        {
049            try
050            {
051                URL url = ConfigurationUtils.locate(this, basePath, fileName);
052    
053                if (url == null)
054                {
055                    throw new ConfigurationException("Cannot locate configuration source " + fileName);
056                }
057                return getInputStream(url);
058            }
059            catch (ConfigurationException e)
060            {
061                throw e;
062            }
063            catch (Exception e)
064            {
065                throw new ConfigurationException("Unable to load the configuration file " + fileName, e);
066            }
067        }
068    
069        public InputStream getInputStream(URL url) throws ConfigurationException
070        {
071            // throw an exception if the target URL is a directory
072            File file = ConfigurationUtils.fileFromURL(url);
073            if (file != null && file.isDirectory())
074            {
075                throw new ConfigurationException("Cannot load a configuration from a directory");
076            }
077    
078            try
079            {
080                return url.openStream();
081            }
082            catch (Exception e)
083            {
084                throw new ConfigurationException("Unable to load the configuration from the URL " + url, e);
085            }
086        }
087    
088        public OutputStream getOutputStream(URL url) throws ConfigurationException
089        {
090            // file URLs have to be converted to Files since FileURLConnection is
091            // read only (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4191800)
092            File file = ConfigurationUtils.fileFromURL(url);
093            if (file != null)
094            {
095                return getOutputStream(file);
096            }
097            else
098            {
099                // for non file URLs save through an URLConnection
100                OutputStream out;
101                try
102                {
103                    URLConnection connection = url.openConnection();
104                    connection.setDoOutput(true);
105    
106                    // use the PUT method for http URLs
107                    if (connection instanceof HttpURLConnection)
108                    {
109                        HttpURLConnection conn = (HttpURLConnection) connection;
110                        conn.setRequestMethod("PUT");
111                    }
112    
113                    out = connection.getOutputStream();
114    
115                    // check the response code for http URLs and throw an exception if an error occured
116                    if (connection instanceof HttpURLConnection)
117                    {
118                        out = new HttpOutputStream(out, (HttpURLConnection) connection);
119                    }
120                    return out;
121                }
122                catch (IOException e)
123                {
124                    throw new ConfigurationException("Could not save to URL " + url, e);
125                }
126            }
127        }
128    
129        public OutputStream getOutputStream(File file) throws ConfigurationException
130        {
131            try
132            {
133                // create the file if necessary
134                createPath(file);
135                return new FileOutputStream(file);
136            }
137            catch (FileNotFoundException e)
138            {
139                throw new ConfigurationException("Unable to save to file " + file, e);
140            }
141        }
142    
143        public String getPath(File file, URL url, String basePath, String fileName)
144        {
145            String path = null;
146            // if resource was loaded from jar file may be null
147            if (file != null)
148            {
149                path = file.getAbsolutePath();
150            }
151    
152            // try to see if file was loaded from a jar
153            if (path == null)
154            {
155                if (url != null)
156                {
157                    path = url.getPath();
158                }
159                else
160                {
161                    try
162                    {
163                        path = getURL(basePath, fileName).getPath();
164                    }
165                    catch (Exception e)
166                    {
167                        // simply ignore it and return null
168                        ;
169                    }
170                }
171            }
172    
173            return path;
174        }
175    
176        public String getBasePath(String path)
177        {
178            URL url;
179            try
180            {
181                url = getURL(null, path);
182                return ConfigurationUtils.getBasePath(url);
183            }
184            catch (Exception e)
185            {
186                return null;
187            }
188        }
189    
190        public String getFileName(String path)
191        {
192            URL url;
193            try
194            {
195                url = getURL(null, path);
196                return ConfigurationUtils.getFileName(url);
197            }
198            catch (Exception e)
199            {
200                return null;
201            }
202        }
203    
204    
205        public URL getURL(String basePath, String file) throws MalformedURLException
206        {
207            File f = new File(file);
208            if (f.isAbsolute()) // already absolute?
209            {
210                return ConfigurationUtils.toURL(f);
211            }
212    
213            try
214            {
215                if (basePath == null)
216                {
217                    return new URL(file);
218                }
219                else
220                {
221                    URL base = new URL(basePath);
222                    return new URL(base, file);
223                }
224            }
225            catch (MalformedURLException uex)
226            {
227                return ConfigurationUtils.toURL(ConfigurationUtils.constructFile(basePath, file));
228            }
229        }
230    
231    
232        public URL locateFromURL(String basePath, String fileName)
233        {
234            try
235            {
236                URL url;
237                if (basePath == null)
238                {
239                    return new URL(fileName);
240                    //url = new URL(name);
241                }
242                else
243                {
244                    URL baseURL = new URL(basePath);
245                    url = new URL(baseURL, fileName);
246    
247                    // check if the file exists
248                    InputStream in = null;
249                    try
250                    {
251                        in = url.openStream();
252                    }
253                    finally
254                    {
255                        if (in != null)
256                        {
257                            in.close();
258                        }
259                    }
260                    return url;
261                }
262            }
263            catch (IOException e)
264            {
265                if (log.isDebugEnabled())
266                {
267                    log.debug("Could not locate file " + fileName + " at " + basePath + ": " + e.getMessage());
268                }
269                return null;
270            }
271        }
272    
273        /**
274         * Create the path to the specified file.
275         *
276         * @param file the target file
277         */
278        private void createPath(File file)
279        {
280            if (file != null)
281            {
282                // create the path to the file if the file doesn't exist
283                if (!file.exists())
284                {
285                    File parent = file.getParentFile();
286                    if (parent != null && !parent.exists())
287                    {
288                        parent.mkdirs();
289                    }
290                }
291            }
292        }
293        /**
294         * Wraps the output stream so errors can be detected in the HTTP response.
295         * @since 1.7
296         * @author <a
297         * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
298         */
299        private static class HttpOutputStream extends VerifiableOutputStream
300        {
301            /** The wrapped OutputStream */
302            private final OutputStream stream;
303    
304            /** The HttpURLConnection */
305            private final HttpURLConnection connection;
306    
307            public HttpOutputStream(OutputStream stream, HttpURLConnection connection)
308            {
309                this.stream = stream;
310                this.connection = connection;
311            }
312    
313            public void write(byte[] bytes) throws IOException
314            {
315                stream.write(bytes);
316            }
317    
318            public void write(byte[] bytes, int i, int i1) throws IOException
319            {
320                stream.write(bytes, i, i1);
321            }
322    
323            public void flush() throws IOException
324            {
325                stream.flush();
326            }
327    
328            public void close() throws IOException
329            {
330                stream.close();
331            }
332    
333            public void write(int i) throws IOException
334            {
335                stream.write(i);
336            }
337    
338            public String toString()
339            {
340                return stream.toString();
341            }
342    
343            public void verify() throws IOException
344            {
345                if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST)
346                {
347                    throw new IOException("HTTP Error " + connection.getResponseCode()
348                            + " " + connection.getResponseMessage());
349                }
350            }
351        }
352    }