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