001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
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.spongepowered.configurate;
018
019import org.checkerframework.checker.nullness.qual.Nullable;
020
021import java.io.IOException;
022import java.util.function.Supplier;
023
024/**
025 * Any sort of error thrown within Configurate.
026 *
027 * <p>Configurate's errors are designed to provide a view of as
028 * many errors as possible within one configuration tree, through the
029 * {@link Throwable#getSuppressed() suppressed exceptions}</p>
030 *
031 * @since 4.0.0
032 */
033public class ConfigurateException extends IOException {
034
035    private static final long serialVersionUID = 1635526451813128733L;
036
037    private @Nullable Supplier<NodePath> path;
038
039    /**
040     * Given an unknown {@link IOException}, return it as a Configurate type.
041     *
042     * <p>If the input {@code ex} is already a {@link ConfigurateException},
043     * this method returns the input value.</p>
044     *
045     * @param source node where the source exception was thrown
046     * @param ex the source exception
047     * @return an exception, either casted or wrapped
048     * @since 4.0.0
049     */
050    public static ConfigurateException wrap(final ConfigurationNode source, final IOException ex) {
051        if (ex instanceof ConfigurateException) {
052            return (ConfigurateException) ex;
053        } else {
054            return new ConfigurateException(source, ex);
055        }
056    }
057
058    /**
059     * Create a new unknown exception.
060     *
061     * @since 4.0.0
062     */
063    public ConfigurateException() {
064    }
065
066    /**
067     * Create a new exception at unknown path with provided
068     * informational message.
069     *
070     * @param message informational message
071     * @since 4.0.0
072     */
073    public ConfigurateException(final String message) {
074        super(message);
075    }
076
077    /**
078     * Create a new exception with a cause and unknown message.
079     *
080     * @param cause the cause of this exception
081     * @since 4.0.0
082     */
083    public ConfigurateException(final Throwable cause) {
084        super(cause);
085    }
086
087    /**
088     * Create a new exception with informational message and cause.
089     *
090     * @param message the informational message
091     * @param cause the cause of the exception
092     * @since 4.0.0
093     */
094    public ConfigurateException(final @Nullable String message, final @Nullable Throwable cause) {
095        super(message, cause);
096    }
097
098    /**
099     * Create a new exception pre-initialized with path and message.
100     *
101     * @param pos node where the error occurred
102     * @param message message describing the error
103     * @since 4.0.0
104     */
105    public ConfigurateException(final ConfigurationNode pos, final String message) {
106        super(message);
107        this.path = pos::path;
108    }
109
110    /**
111     * Create a new exception pre-initialized with path and cause.
112     *
113     * @param pos node where the error occurred
114     * @param cause direct cause of this exception
115     * @since 4.0.0
116     */
117    public ConfigurateException(final ConfigurationNode pos, final Throwable cause) {
118        super(cause);
119        this.path = pos::path;
120    }
121
122    /**
123     * Create a new exception pre-initialized with path, message, and cause.
124     *
125     * @param pos node where the error occurred
126     * @param message message describing the error
127     * @param cause direct cause of this exception
128     * @since 4.0.0
129     */
130    public ConfigurateException(final ConfigurationNode pos, final @Nullable String message, final @Nullable Throwable cause) {
131        super(message, cause);
132        this.path = pos::path;
133    }
134
135    /**
136     * Create a new exception pre-initialized with path, message, and cause.
137     *
138     * @param path path to the node where the error occurred
139     * @param message message describing the error
140     * @param cause direct cause of this exception
141     * @since 4.0.0
142     */
143    public ConfigurateException(final NodePath path, final @Nullable String message, final @Nullable Throwable cause) {
144        super(message, cause);
145        this.path = () -> path;
146    }
147
148    /**
149     * Get the path associated with this failure.
150     *
151     * @return the path
152     * @since 4.0.0
153     */
154    public NodePath path() {
155        final @Nullable Supplier<NodePath> path = this.path;
156        return path == null ? NodePath.path() : path.get();
157    }
158
159    /**
160     * Initialize path if none has been set.
161     *
162     * @param path new path
163     * @since 4.0.0
164     */
165    public void initPath(final Supplier<NodePath> path) {
166        if (this.path == null) {
167            this.path = path;
168        }
169    }
170
171    /**
172     * Get the exception's message without any extra formatting.
173     *
174     * @return the raw message
175     * @since 4.0.0
176     */
177    public @Nullable String rawMessage() {
178        return super.getMessage();
179    }
180
181    /**
182     * Get a description of the location of this error, with path included.
183     *
184     * @return message
185     * @since 4.0.0
186     */
187    @Override
188    public @Nullable String getMessage() {
189        return this.path().toString() + ": " + super.getMessage();
190    }
191
192}