Changeset 2168 in josm


Ignore:
Timestamp:
2009-09-20T11:46:08+02:00 (11 years ago)
Author:
Gubaer
Message:

fixed #3304: Upload failed - Placeholder Relation not found
fixed #2353: Wrong relation upload order results in 512 Precondition Failed
Warning: this is going to break plugins which register Upload Hooks. These plugins will be fixed shortly.

Location:
trunk
Files:
6 added
3 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/UploadAction.java

    r2153 r2168  
    1919
    2020import org.openstreetmap.josm.Main;
     21import org.openstreetmap.josm.actions.upload.ApiPreconditionCheckerHook;
     22import org.openstreetmap.josm.actions.upload.RelationUploadOrderHook;
     23import org.openstreetmap.josm.actions.upload.UploadHook;
     24import org.openstreetmap.josm.actions.upload.UploadParameterHook;
    2125import org.openstreetmap.josm.data.APIDataSet;
    2226import org.openstreetmap.josm.data.conflict.ConflictCollection;
     
    6771         * Checks server capabilities before upload.
    6872         */
    69         uploadHooks.add(new ApiPreconditionChecker());
     73        uploadHooks.add(new ApiPreconditionCheckerHook());
     74
     75        /**
     76         * Adjusts the upload order of new relations
     77         */
     78        uploadHooks.add(new RelationUploadOrderHook());
    7079
    7180        /**
     
    7382         * give the user the possibility to cancel the upload.
    7483         */
    75         uploadHooks.add(new UploadConfirmationHook());
     84        uploadHooks.add(new UploadParameterHook());
    7685    }
    7786
     
    99108        }
    100109    }
    101 
    102     /** Upload Hook */
    103     public interface UploadHook {
    104         /**
    105          * Checks the upload.
    106          * @param apiDataSet the data to upload
    107          */
    108         public boolean checkUpload(APIDataSet apiDataSet);
    109     }
    110 
    111110
    112111    public UploadAction() {
     
    483482    }
    484483
    485 
    486     static public class UploadConfirmationHook implements UploadHook {
    487 
    488         public boolean checkUpload(APIDataSet apiData) {
    489             final UploadDialog dialog = UploadDialog.getUploadDialog();
    490             dialog.setUploadedPrimitives(apiData.getPrimitivesToAdd(),apiData.getPrimitivesToUpdate(), apiData.getPrimitivesToDelete());
    491             dialog.setVisible(true);
    492             if (dialog.isCanceled())
    493                 return false;
    494             dialog.rememberUserInput();
    495             return true;
    496         }
    497     }
    498 
    499484    public UploadDiffTask createUploadTask(OsmDataLayer layer, Collection<OsmPrimitive> toUpload, Changeset changeset, boolean closeChangesetAfterUpload) {
    500485        return new UploadDiffTask(layer, toUpload, changeset, closeChangesetAfterUpload);
  • trunk/src/org/openstreetmap/josm/actions/upload/ApiPreconditionCheckerHook.java

    r2156 r2168  
    1 package org.openstreetmap.josm.actions;
     1package org.openstreetmap.josm.actions.upload;
    22
    33import static org.openstreetmap.josm.tools.I18n.tr;
     
    1010
    1111import org.openstreetmap.josm.Main;
    12 import org.openstreetmap.josm.actions.UploadAction.UploadHook;
    1312import org.openstreetmap.josm.data.APIDataSet;
    1413import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    1918import org.openstreetmap.josm.io.OsmApiInitializationException;
    2019
    21 public class ApiPreconditionChecker implements UploadHook {
     20public class ApiPreconditionCheckerHook implements UploadHook {
    2221
    2322    public boolean checkUpload(APIDataSet apiData) {
  • trunk/src/org/openstreetmap/josm/data/APIDataSet.java

    r2039 r2168  
    22package org.openstreetmap.josm.data;
    33
     4import java.util.ArrayList;
     5import java.util.Collection;
     6import java.util.Collections;
     7import java.util.Comparator;
     8import java.util.HashMap;
     9import java.util.HashSet;
    410import java.util.LinkedList;
    511import java.util.List;
     12import java.util.Set;
     13import java.util.Stack;
     14import java.util.logging.Logger;
    615
    716import org.openstreetmap.josm.data.osm.DataSet;
     17import org.openstreetmap.josm.data.osm.Node;
    818import org.openstreetmap.josm.data.osm.OsmPrimitive;
     19import org.openstreetmap.josm.data.osm.Relation;
     20import org.openstreetmap.josm.data.osm.RelationMember;
     21import org.openstreetmap.josm.data.osm.Way;
     22
     23import org.openstreetmap.josm.actions.upload.CyclicUploadDependencyException;
    924
    1025/**
     
    1328 * The collection is derived from the modified primitives of an {@see DataSet}.
    1429 *
    15  * FIXME: use to optimize the upload order before uploading, see various tickets in trac
    1630 *
    1731 */
     
    113127        return ret;
    114128    }
     129
     130    /**
     131     * Adjusts the upload order for new relations. Child relations are uploaded first,
     132     * parent relations second.
     133     *
     134     * This method detects cyclic dependencies in new relation. Relations with cyclic
     135     * dependencies can't be uploaded.
     136     *
     137     * @throws CyclicUploadDependencyException thrown, if a cyclic dependency is detected
     138     */
     139    public void adjustRelationUploadOrder() throws CyclicUploadDependencyException{
     140        LinkedList<OsmPrimitive> newToAdd = new LinkedList<OsmPrimitive>();
     141        newToAdd.addAll(OsmPrimitive.getFilteredList(toAdd, Node.class));
     142        newToAdd.addAll(OsmPrimitive.getFilteredList(toAdd, Way.class));
     143
     144        List<Relation> relationsToAdd = OsmPrimitive.getFilteredList(toAdd, Relation.class);
     145        List<Relation> noProblemRelations = filterRelationsNotReferringToNewRelations(relationsToAdd);
     146        newToAdd.addAll(noProblemRelations);
     147        relationsToAdd.removeAll(noProblemRelations);
     148
     149        RelationUploadDependencyGraph graph = new RelationUploadDependencyGraph(relationsToAdd);
     150        newToAdd.addAll(graph.computeUploadOrder());
     151        toAdd = newToAdd;
     152    }
     153
     154    /**
     155     * Replies the subset of relations in <code>relations</code> which are not referring to any
     156     * new relation
     157     *
     158     * @param relations a list of relations
     159     * @return the subset of relations in <code>relations</code> which are not referring to any
     160     * new relation
     161     */
     162    protected List<Relation> filterRelationsNotReferringToNewRelations(Collection<Relation> relations) {
     163        List<Relation> ret = new LinkedList<Relation>();
     164        for (Relation relation: relations) {
     165            boolean refersToNewRelation = false;
     166            for (RelationMember m : relation.getMembers()) {
     167                if (m.isRelation() && m.getMember().getId() <= 0) {
     168                    refersToNewRelation = true;
     169                    break;
     170                }
     171            }
     172            if (!refersToNewRelation) {
     173                ret.add(relation);
     174            }
     175        }
     176        return ret;
     177    }
     178
     179    /**
     180     * Utility class to sort a collection of of new relations with their dependencies
     181     * topologically.
     182     *
     183     */
     184    private class RelationUploadDependencyGraph {
     185        private final Logger logger = Logger.getLogger(RelationUploadDependencyGraph.class.getName());
     186        private HashMap<Relation, Set<Relation>> children;
     187        private Collection<Relation> relations;
     188        private Set<Relation> visited;
     189        private List<Relation> uploadOrder;
     190
     191        public RelationUploadDependencyGraph() {
     192            this.children = new HashMap<Relation, Set<Relation>>();
     193            this.visited = new HashSet<Relation>();
     194        }
     195
     196        public RelationUploadDependencyGraph(Collection<Relation> relations) {
     197            this();
     198            build(relations);
     199        }
     200
     201        public void build(Collection<Relation> relations) {
     202            this.relations = new HashSet<Relation>();
     203            for(Relation relation: relations) {
     204                if (relation.getId() > 0 ) {
     205                    continue;
     206                }
     207                this.relations.add(relation);
     208                for (RelationMember m: relation.getMembers()) {
     209                    if (m.isRelation() && m.getMember().getId() == 0) {
     210                        addDependency(relation, (Relation)m.getMember());
     211                    }
     212                }
     213            }
     214        }
     215
     216        public Set<Relation> getChildren(Relation relation) {
     217            Set<Relation> p = children.get(relation);
     218            if (p == null) {
     219                p = new HashSet<Relation>();
     220                children.put(relation, p);
     221            }
     222            return p;
     223        }
     224
     225        public void addDependency(Relation relation, Relation child) {
     226            getChildren(relation).add(child);
     227        }
     228
     229        protected void visit(Stack<Relation> path, Relation current) throws CyclicUploadDependencyException{
     230            if (path.contains(current)) {
     231                path.push(current);
     232                throw new CyclicUploadDependencyException(path);
     233            }
     234            if (!visited.contains(current)) {
     235                path.push(current);
     236                visited.add(current);
     237                for (Relation dependent : getChildren(current)) {
     238                    visit(path,dependent);
     239                }
     240                uploadOrder.add(current);
     241                path.pop();
     242            }
     243        }
     244
     245        public List<Relation> computeUploadOrder() throws CyclicUploadDependencyException {
     246            visited = new HashSet<Relation>();
     247            uploadOrder = new LinkedList<Relation>();
     248            Stack<Relation> path = new Stack<Relation>();
     249            for (Relation relation: relations) {
     250                visit(path, relation);
     251            }
     252            ArrayList<Relation> ret = new ArrayList<Relation>(relations);
     253            Collections.sort(
     254                    ret,
     255                    new Comparator<Relation>() {
     256                        public int compare(Relation o1, Relation o2) {
     257                            return new Integer(uploadOrder.indexOf(o1)).compareTo(uploadOrder.indexOf(o2));
     258                        }
     259                    }
     260            );
     261            return ret;
     262        }
     263    }
    115264}
  • trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java

    r2161 r2168  
    298298
    299299        // Ensure all required variables are available
    300         if(rememberSizePref.length() == 0 && defaultWindowGeometry != null) {
     300        if(rememberSizePref.length() != 0 && defaultWindowGeometry != null) {
    301301            if(visible) {
    302302                new WindowGeometry(rememberSizePref,
Note: See TracChangeset for help on using the changeset viewer.