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 */
017package org.apache.commons.vfs2;
018
019import java.io.IOException;
020import java.util.regex.Matcher;
021import java.util.regex.Pattern;
022
023import org.apache.commons.vfs2.util.Messages;
024
025/**
026 * Thrown for file system errors.
027 */
028public class FileSystemException
029    extends IOException
030{
031    /**
032     * serialVersionUID format is YYYYMMDD for the date of the last binary change.
033     */
034    private static final long serialVersionUID = 20101208L;
035
036    /** URL pattern */
037    private static final Pattern URL_PATTERN = Pattern.compile("[a-z]+://.*");
038
039    /** Password pattern */
040    private static final Pattern PASSWORD_PATTERN = Pattern.compile(":(?:[^/]+)@");
041
042    /**
043     * Array of complementary info (context).
044     */
045    private final String[] info;
046
047    /**
048     * Constructs exception with the specified detail message.
049     *
050     * @param code the error code of the message.
051     */
052    public FileSystemException(final String code)
053    {
054        this(code, null, (Object[]) null);
055    }
056
057    /**
058     * Constructs exception with the specified detail message.
059     *
060     * @param code  the error code of the message.
061     * @param info0 one context information.
062     */
063    public FileSystemException(final String code, final Object info0)
064    {
065        this(code, null, new Object[]{info0});
066    }
067
068    /**
069     * Constructs exception with the specified detail message.
070     *
071     * @param code      the error code of the message.
072     * @param info0     one context information.
073     * @param throwable the cause.
074     */
075    public FileSystemException(final String code,
076                               final Object info0,
077                               final Throwable throwable)
078    {
079        this(code, throwable, new Object[]{info0});
080    }
081
082    /**
083     * Constructs exception with the specified detail message.
084     *
085     * @param code the error code of the message.
086     * @param info array of complementary info (context).
087     */
088    public FileSystemException(final String code, final Object... info)
089    {
090        this(code, null, info);
091    }
092
093    /**
094     * Constructs exception with the specified detail message.
095     *
096     * @param code the error code of the message.
097     * @param throwable the original cause
098     */
099    public FileSystemException(final String code, final Throwable throwable)
100    {
101        this(code, throwable, (Object[]) null);
102    }
103
104    /**
105     * Constructs exception with the specified detail message.
106     *
107     * @param code      the error code of the message.
108     * @param info      array of complementary info (context).
109     * @param throwable the cause.
110     * @deprecated Use instead {@link #FileSystemException(String, Throwable, Object[])}. Will be removed in 3.0.
111     */
112    @Deprecated
113    public FileSystemException(final String code,
114                               final Object[] info,
115                               final Throwable throwable)
116    {
117        this(code, throwable, info);
118    }
119
120    /**
121     * Constructs exception with the specified detail message.
122     *
123     * @param code      the error code of the message.
124     * @param info      array of complementary info (context).
125     * @param throwable the cause.
126     */
127    public FileSystemException(final String code,
128                               final Throwable throwable,
129                               final Object... info)
130    {
131        super(code, throwable);
132
133        if (info == null)
134        {
135            this.info = new String[0];
136        }
137        else
138        {
139            this.info = new String[info.length];
140            for (int i = 0; i < info.length; i++)
141            {
142                String value = String.valueOf(info[i]);
143                // mask passwords (VFS-169)
144                final Matcher urlMatcher = URL_PATTERN.matcher(value);
145                if (urlMatcher.find())
146                {
147                    final Matcher pwdMatcher = PASSWORD_PATTERN.matcher(value);
148                    value = pwdMatcher.replaceFirst(":***@");
149                }
150                this.info[i] = value;
151            }
152        }
153    }
154
155    /**
156     * Constructs wrapper exception.
157     *
158     * @param throwable the root cause to wrap.
159     */
160    public FileSystemException(final Throwable throwable)
161    {
162        this(throwable.getMessage(), throwable, (Object[]) null);
163    }
164
165    /**
166     * Retrieves message from bundle.
167     * @return The exception message.
168     */
169    @Override
170    public String getMessage()
171    {
172        return Messages.getString(super.getMessage(), (Object[]) getInfo());
173    }
174
175    /**
176     * Retrieves error code of the exception.
177     * Could be used as key for internationalization.
178     *
179     * @return the code.
180     */
181    public String getCode()
182    {
183        return super.getMessage();
184    }
185
186    /**
187     * Retrieves array of complementary info (context).
188     * Could be used as parameter for internationalization.
189     *
190     * @return the context info.
191     */
192    public String[] getInfo()
193    {
194        return info;
195    }
196}