001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.osm;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.List;
009import java.util.Stack;
010
011/**
012 * This is an exception that is thrown if the user attempts to upload a list of relations with a cyclic dependency in them
013 * @since 12673 (moved from {@code action.upload} package)
014 */
015public class CyclicUploadDependencyException extends Exception {
016    private final List<Relation> cycle;
017
018    /**
019     * Creates a new {@link CyclicUploadDependencyException}
020     * @param cycle The cycle that was found
021     */
022    public CyclicUploadDependencyException(Stack<Relation> cycle) {
023        this.cycle = new ArrayList<>(cycle);
024    }
025
026    protected String formatRelation(Relation r) {
027        StringBuilder sb = new StringBuilder();
028        if (r.getName() != null) {
029            sb.append('\'').append(r.getName()).append('\'');
030        } else if (!r.isNew()) {
031            sb.append(r.getId());
032        } else {
033            sb.append("relation@").append(r.hashCode());
034        }
035        return sb.toString();
036    }
037
038    @Override
039    public String getMessage() {
040        StringBuilder sb = new StringBuilder();
041        sb.append(tr("Cyclic dependency between relations:"))
042          .append('[');
043        for (int i = 0; i < cycle.size(); i++) {
044            if (i > 0) {
045                sb.append(',');
046            }
047            sb.append(formatRelation(cycle.get(i)));
048        }
049        sb.append(']');
050        return sb.toString();
051    }
052
053    /**
054     * Gets the cycle
055     * @return The cycle that was detected
056     */
057    public List<Relation> getCyclicUploadDependency() {
058        return Collections.unmodifiableList(cycle);
059    }
060}