Ignore:
Timestamp:
28.12.2009 00:15:22 (2 years ago)
Author:
Gubaer
Message:

Partial commit due to issue described in #4137
Breaks the build

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/ChangesetQuery.java

    r2512 r2688  
    22package org.openstreetmap.josm.io; 
    33 
     4import static org.openstreetmap.josm.tools.I18n.tr; 
     5 
     6import java.text.DateFormat; 
     7import java.text.ParseException; 
     8import java.text.SimpleDateFormat; 
    49import java.util.Date; 
    5  
    6 import org.openstreetmap.josm.data.coor.CoordinateFormat; 
     10import java.util.HashMap; 
     11import java.util.Map; 
     12 
     13import org.openstreetmap.josm.data.Bounds; 
    714import org.openstreetmap.josm.data.coor.LatLon; 
    8 import org.openstreetmap.josm.tools.DateUtils; 
    9  
    10 import static org.openstreetmap.josm.tools.I18n.tr; 
     15import org.openstreetmap.josm.tools.CheckParameterUtil; 
    1116 
    1217public class ChangesetQuery { 
    13     private Long user = null; 
    14     private LatLon min = null; 
    15     private LatLon max = null; 
     18 
     19    /** 
     20     * Replies a changeset query object from the query part of a OSM API URL for querying 
     21     * changesets. 
     22     *  
     23     * @param query the query part 
     24     * @return the query object 
     25     * @throws ChangesetQueryUrlException thrown if query doesn't consist of valid query parameters 
     26     *  
     27     */ 
     28    static public ChangesetQuery buildFromUrlQuery(String query) throws ChangesetQueryUrlException{ 
     29        return new ChangesetQueryUrlParser().parse(query); 
     30    } 
     31 
     32    /** the user id this query is restricted to. null, if no restriction to a user id applies */ 
     33    private Integer uid = null; 
     34    /** the user name this query is restricted to. null, if no restriction to a user name applies */ 
     35    private String userName = null; 
     36    /** the bounding box this query is restricted to. null, if no restriction to a bounding box applies */ 
     37    private Bounds bounds = null; 
     38 
    1639    private Date closedAfter = null; 
    1740    private Date createdBefore = null; 
     41    /** indicates whether only open changesets are queried. null, if no restrictions regarding open changesets apply */ 
    1842    private Boolean open = null; 
     43    /** indicates whether only closed changesets are queried. null, if no restrictions regarding open changesets apply */ 
    1944    private Boolean closed = null; 
    2045 
    2146    public ChangesetQuery() {} 
    2247 
    23     public ChangesetQuery forUser(long uid) { 
     48    /** 
     49     * Restricts the query to changesets owned by the user with id <code>uid</code>. 
     50     *  
     51     * @param uid the uid of the user. >0 expected. 
     52     * @return the query object with the applied restriction 
     53     * @throws IllegalArgumentException thrown if uid <= 0 
     54     * @see #forUser(String) 
     55     */ 
     56    public ChangesetQuery forUser(int uid) throws IllegalArgumentException{ 
    2457        if (uid <= 0) 
    2558            throw new IllegalArgumentException(tr("Parameter ''{0}'' > 0 expected. Got ''{1}''.", "uid", uid)); 
    26         this.user = uid; 
    27         return this; 
    28     } 
    29  
    30     public ChangesetQuery inBbox(double minLon, double minLat, double maxLon, double maxLat) { 
     59        this.uid = uid; 
     60        this.userName = null; 
     61        return this; 
     62    } 
     63 
     64    /** 
     65     * Restricts the query to changesets owned by the user with user name <code>username</code>. 
     66     *  
     67     * Caveat: for historical reasons the username might not be unique! It is recommended to use 
     68     * {@see #forUser(int)} to restrict the query to a specific user. 
     69     *  
     70     * @param username the username. Must not be null. 
     71     * @return the query object with the applied restriction 
     72     * @throws IllegalArgumentException thrown if username is null. 
     73     * @see #forUser(int) 
     74     */ 
     75    public ChangesetQuery forUser(String username) { 
     76        CheckParameterUtil.ensureParameterNotNull(username, "username"); 
     77        this.userName = username; 
     78        this.uid = 0; 
     79        return this; 
     80    } 
     81 
     82    /** 
     83     * Replies true if this query is restricted to user whom we only know the user name 
     84     * for. 
     85     *  
     86     * @return true if this query is restricted to user whom we only know the user name 
     87     * for 
     88     */ 
     89    public boolean isRestrictedToPartiallyIdentifiedUser() { 
     90        return userName != null; 
     91    } 
     92 
     93    /** 
     94     * Replies the user name which this query is restricted to. null, if this query isn't 
     95     * restricted to a user name, i.e. if {@see #isRestrictedToPartiallyIdentifiedUser()} is false. 
     96     *  
     97     * @return the user name which this query is restricted to 
     98     */ 
     99    public String getUserName() { 
     100        return userName; 
     101    } 
     102 
     103    /** 
     104     * Replies true if this query is restricted to user whom know the user id for. 
     105     *  
     106     * @return true if this query is restricted to user whom know the user id for 
     107     */ 
     108    public boolean isRestrictedToFullyIdentifiedUser() { 
     109        return uid > 0; 
     110    } 
     111 
     112    /** 
     113     * Replies a query which is restricted to a bounding box. 
     114     *  
     115     * @param minLon  min longitude of the bounding box. Valid longitude value expected. 
     116     * @param minLat  min latitude of the bounding box. Valid latitude value expected. 
     117     * @param maxLon  max longitude of the bounding box. Valid longitude value expected. 
     118     * @param maxLat  max latitude of the bounding box.  Valid latitude value expected. 
     119     *  
     120     * @return the restricted changeset query 
     121     * @throws IllegalArgumentException thrown if either of the parameters isn't a valid longitude or 
     122     * latitude value 
     123     */ 
     124    public ChangesetQuery inBbox(double minLon, double minLat, double maxLon, double maxLat) throws IllegalArgumentException{ 
     125        if (!LatLon.isValidLon(minLon)) 
     126            throw new IllegalArgumentException(tr("Illegal longitude value for parameter ''{0}'', got {1}", "minLon", minLon)); 
     127        if (!LatLon.isValidLon(maxLon)) 
     128            throw new IllegalArgumentException(tr("Illegal longitude value for parameter ''{0}'', got {1}", "maxLon", maxLon)); 
     129        if (!LatLon.isValidLat(minLat)) 
     130            throw new IllegalArgumentException(tr("Illegal latitude value for parameter ''{0}'', got {1}", "minLat", minLat)); 
     131        if (!LatLon.isValidLat(maxLat)) 
     132            throw new IllegalArgumentException(tr("Illegal longitude value for parameter ''{0}'', got {1}", "maxLat", maxLat)); 
     133 
    31134        return inBbox(new LatLon(minLon, minLat), new LatLon(maxLon, maxLat)); 
    32135    } 
    33136 
     137    /** 
     138     * Replies a query which is restricted to a bounding box. 
     139     *  
     140     * @param min the min lat/lon coordinates of the bounding box. Must not be null. 
     141     * @param max the max lat/lon coordiantes of the bounding box. Must not be null. 
     142     *  
     143     * @return the restricted changeset query 
     144     * @throws IllegalArgumentException thrown if min is null 
     145     * @throws IllegalArgumentException thrown if max is null 
     146     */ 
    34147    public ChangesetQuery inBbox(LatLon min, LatLon max) { 
    35         this.min = min; 
    36         this.max = max; 
    37         return this; 
    38     } 
    39  
    40     public ChangesetQuery closedAfter(Date d) { 
     148        CheckParameterUtil.ensureParameterNotNull(min, "min"); 
     149        CheckParameterUtil.ensureParameterNotNull(max, "max"); 
     150        this.bounds  = new Bounds(min,max); 
     151        return this; 
     152    } 
     153 
     154    /** 
     155     *  Replies a query which is restricted to a bounding box given by <code>bbox</code>. 
     156     *  
     157     * @param bbox the bounding box. Must not be null. 
     158     * @return the changeset query 
     159     * @throws IllegalArgumentException thrown if bbox is null. 
     160     */ 
     161    public ChangesetQuery inBbox(Bounds bbox) throws IllegalArgumentException { 
     162        CheckParameterUtil.ensureParameterNotNull(bbox, "bbox"); 
     163        this.bounds = bbox; 
     164        return this; 
     165    } 
     166 
     167    /** 
     168     * Restricts the result to changesets which have been closed after the date given by <code>d</code>. 
     169     * <code>d</code> d is a date relative to the current time zone. 
     170     *  
     171     * @param d the date . Must not be null. 
     172     * @return the restricted changeset query 
     173     * @throws IllegalArgumentException thrown if d is null 
     174     */ 
     175    public ChangesetQuery closedAfter(Date d) throws IllegalArgumentException{ 
     176        CheckParameterUtil.ensureParameterNotNull(d, "d"); 
    41177        this.closedAfter = d; 
    42178        return this; 
    43179    } 
    44180 
    45     public ChangesetQuery between(Date closedAfter, Date createdBefore ) { 
     181    /** 
     182     * Restricts the result to changesets which have been closed after <code>closedAfter</code> and which 
     183     * habe been created before <code>createdBefore</code>. Both dates are expressed relative to the current 
     184     * time zone. 
     185     *  
     186     * @param closedAfter only reply changesets closed after this date. Must not be null. 
     187     * @param createdBefore only reply changesets created before this date. Must not be null. 
     188     * @return the restricted changeset query 
     189     * @throws IllegalArgumentException thrown if closedAfter is null 
     190     * @throws IllegalArgumentException thrown if createdBefore is null 
     191     */ 
     192    public ChangesetQuery closedAfterAndCreatedBefore(Date closedAfter, Date createdBefore ) throws IllegalArgumentException{ 
     193        CheckParameterUtil.ensureParameterNotNull(closedAfter, "closedAfter"); 
     194        CheckParameterUtil.ensureParameterNotNull(createdBefore, "createdBefore"); 
    46195        this.closedAfter = closedAfter; 
    47196        this.createdBefore = createdBefore; 
     
    49198    } 
    50199 
    51     public ChangesetQuery beingOpen() { 
    52         this.open =  true; 
    53         this.closed = null; 
    54         return this; 
    55     } 
    56  
    57     public ChangesetQuery beingClosed() { 
    58         this.open =  null; 
    59         this.closed = true; 
    60         return this; 
    61     } 
    62  
     200    /** 
     201     * Restricts the result to changesets which are or aren't open, depending on the value of 
     202     * <code>isOpen</code> 
     203     *  
     204     * @param isOpen whether changesets should or should not be open 
     205     * @return the restricted changeset query 
     206     */ 
     207    public ChangesetQuery beingOpen(boolean isOpen) { 
     208        this.open =  isOpen; 
     209        return this; 
     210    } 
     211 
     212    /** 
     213     * Restricts the result to changesets which are or aren't closed, depending on the value of 
     214     * <code>isClosed</code> 
     215     *  
     216     * @param isClosed whether changesets should or should not be open 
     217     * @return the restricted changeset query 
     218     */ 
     219    public ChangesetQuery beingClosed(boolean isClosed) { 
     220        this.closed = isClosed; 
     221        return this; 
     222    } 
     223 
     224    /** 
     225     * Replies the query string to be used in a query URL for the OSM API. 
     226     *  
     227     * @return the query string 
     228     */ 
    63229    public String getQueryString() { 
    64230        StringBuffer sb = new StringBuffer(); 
    65         if (user != null) { 
    66             sb.append("user").append("=").append(user); 
    67         } 
    68         if (min!=null && max != null) { 
     231        if (uid != null) { 
     232            sb.append("user").append("=").append(uid); 
     233        } else if (userName != null) { 
     234            sb.append("display_name").append("=").append(userName); 
     235        } 
     236        if (bounds != null) { 
    69237            if (sb.length() > 0) { 
    70238                sb.append("&"); 
    71239            } 
    72             sb.append("min_lon").append("=").append(min.lonToString(CoordinateFormat.DECIMAL_DEGREES)); 
    73             sb.append("&"); 
    74             sb.append("min_lat").append("=").append(min.latToString(CoordinateFormat.DECIMAL_DEGREES)); 
    75             sb.append("&"); 
    76             sb.append("max_lon").append("=").append(max.lonToString(CoordinateFormat.DECIMAL_DEGREES)); 
    77             sb.append("&"); 
    78             sb.append("max_lat").append("=").append(max.latToString(CoordinateFormat.DECIMAL_DEGREES)); 
     240            sb.append("bbox=").append(bounds.encodeAsString(",")); 
    79241        } 
    80242        if (closedAfter != null && createdBefore != null) { 
     
    82244                sb.append("&"); 
    83245            } 
    84             sb.append("time").append("=").append(DateUtils.fromDate(closedAfter)) 
    85             .append(",").append(DateUtils.fromDate(createdBefore)); 
     246            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"); 
     247            sb.append("time").append("=").append(df.format(closedAfter)); 
     248            sb.append(",").append(df.format(createdBefore)); 
    86249        } else if (closedAfter != null) { 
    87250            if (sb.length() > 0) { 
    88251                sb.append("&"); 
    89252            } 
    90             sb.append("time").append("=").append(DateUtils.fromDate(closedAfter)); 
     253            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"); 
     254            sb.append("time").append("=").append(df.format(closedAfter)); 
    91255        } 
    92256 
     
    95259                sb.append("&"); 
    96260            } 
    97             sb.append("open=true"); 
     261            sb.append("open=").append(Boolean.toString(open)); 
    98262        } else if (closed != null) { 
    99263            if (sb.length() > 0) { 
    100264                sb.append("&"); 
    101265            } 
    102             sb.append("closed=true"); 
     266            sb.append("closed=").append(Boolean.toString(closed)); 
    103267        } 
    104268        return sb.toString(); 
    105269    } 
     270 
     271 
     272    public static class ChangesetQueryUrlException extends Exception { 
     273 
     274        public ChangesetQueryUrlException() { 
     275            super(); 
     276        } 
     277 
     278        public ChangesetQueryUrlException(String arg0, Throwable arg1) { 
     279            super(arg0, arg1); 
     280        } 
     281 
     282        public ChangesetQueryUrlException(String arg0) { 
     283            super(arg0); 
     284        } 
     285 
     286        public ChangesetQueryUrlException(Throwable arg0) { 
     287            super(arg0); 
     288        } 
     289    } 
     290 
     291    public static class ChangesetQueryUrlParser { 
     292        protected int parseUid(String value) throws ChangesetQueryUrlException { 
     293            if (value == null || value.trim().equals("")) 
     294                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", "uid",value)); 
     295            int id; 
     296            try { 
     297                id = Integer.parseInt(value); 
     298                if (id <= 0) 
     299                    throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", "uid",value)); 
     300            } catch(NumberFormatException e) { 
     301                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", "uid",value)); 
     302            } 
     303            return id; 
     304        } 
     305 
     306        protected boolean parseOpen(String value) throws ChangesetQueryUrlException { 
     307            if (value == null || value.trim().equals("")) 
     308                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", "open",value)); 
     309            if (value.equals("true")) 
     310                return true; 
     311            else if (value.equals("false")) 
     312                return false; 
     313            else 
     314                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", "open",value)); 
     315        } 
     316 
     317        protected boolean parseBoolean(String value, String parameter) throws ChangesetQueryUrlException { 
     318            if (value == null || value.trim().equals("")) 
     319                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", parameter,value)); 
     320            if (value.equals("true")) 
     321                return true; 
     322            else if (value.equals("false")) 
     323                return false; 
     324            else 
     325                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", parameter,value)); 
     326        } 
     327 
     328        protected Date parseDate(String value, String parameter) throws ChangesetQueryUrlException { 
     329            if (value == null || value.trim().equals("")) 
     330                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", parameter,value)); 
     331            if (value.endsWith("Z")) { 
     332                // OSM API generates date strings we time zone abbreviation "Z" which Java SimpleDateFormat 
     333                // doesn't understand. Convert into GMT time zone before parsing. 
     334                // 
     335                value = value.substring(0,value.length() - 1) + "GMT+00:00"; 
     336            } 
     337            DateFormat formatter = new SimpleDateFormat("MM/dd/yy"); 
     338            formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"); 
     339            try { 
     340                return formatter.parse(value); 
     341            } catch(ParseException e) { 
     342                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", parameter,value)); 
     343            } 
     344        } 
     345 
     346        protected Date[] parseTime(String value) throws ChangesetQueryUrlException { 
     347            String[] dates = value.split(","); 
     348            if (dates == null || dates.length == 0 || dates.length > 2) 
     349                throw new ChangesetQueryUrlException(tr("Unexpected value for ''{0}'' in changeset query url, got {1}", "time", value)); 
     350            if (dates.length == 1) 
     351                return new Date[]{parseDate(dates[0], "time")}; 
     352            else if (dates.length == 2) 
     353                return new Date[]{parseDate(dates[0], "time"),parseDate(dates[1], "time")}; 
     354            return null; 
     355        } 
     356 
     357        protected ChangesetQuery crateFromMap(Map<String,String> queryParams) throws ChangesetQueryUrlException { 
     358            ChangesetQuery csQuery = new ChangesetQuery(); 
     359 
     360            for (String k: queryParams.keySet()) { 
     361                if (k.equals("uid")) { 
     362                    if (queryParams.containsKey("display_name")) 
     363                        throw new ChangesetQueryUrlException(tr("Can''t create a changeset query including both the query parameters ''uid'' and ''display_name''")); 
     364                    csQuery.forUser(parseUid(queryParams.get("uid"))); 
     365                } else if (k.equals("display_name")) { 
     366                    if (queryParams.containsKey("uid")) 
     367                        throw new ChangesetQueryUrlException(tr("Can''t create a changeset query including both the query parameters ''uid'' and ''display_name''")); 
     368                    csQuery.forUser(queryParams.get("display_name")); 
     369                } else if (k.equals("open")) { 
     370                    boolean b = parseBoolean(queryParams.get(k), "open"); 
     371                    csQuery.beingOpen(b); 
     372                } else if (k.equals("closed")) { 
     373                    boolean b = parseBoolean(queryParams.get(k), "closed"); 
     374                    csQuery.beingClosed(b); 
     375                } else if (k.equals("time")) { 
     376                    Date[] dates = parseTime(queryParams.get(k)); 
     377                    switch(dates.length) { 
     378                    case 1: 
     379                        csQuery.closedAfter(dates[0]); 
     380                        break; 
     381                    case 2: 
     382                        csQuery.closedAfterAndCreatedBefore(dates[0], dates[1]); 
     383                        break; 
     384                    } 
     385                } else if (k.equals("bbox")) { 
     386                    try { 
     387                        csQuery.inBbox(new Bounds(queryParams.get(k), ",")); 
     388                    } catch(IllegalArgumentException e) { 
     389                        throw new ChangesetQueryUrlException(e); 
     390                    } 
     391                } else 
     392                    throw new ChangesetQueryUrlException(tr("Unsupported parameter ''{0}'' in changeset query string",k )); 
     393            } 
     394            return csQuery; 
     395        } 
     396 
     397        protected Map<String,String> createMapFromQueryString(String query) { 
     398            Map<String,String> queryParams  = new HashMap<String, String>(); 
     399            String[] keyValuePairs = query.split("&"); 
     400            for (String keyValuePair: keyValuePairs) { 
     401                String[] kv = keyValuePair.split("="); 
     402                queryParams.put(kv[0], kv[1]); 
     403            } 
     404            return queryParams; 
     405        } 
     406 
     407        /** 
     408         * Parses the changeset query given as URL query parameters and replies a 
     409         * {@see ChangesetQuery} 
     410         *  
     411         * <code>query</code> is the query part of a API url for querying changesets, 
     412         * see <a href="http://wiki.openstreetmap.org/wiki/API_v0.6#Query:_GET_.2Fapi.2F0.6.2Fchangesets">OSM API</a>. 
     413         *  
     414         * Example for an query string:<br> 
     415         * <pre> 
     416         *    uid=1234&open=true 
     417         * </pre> 
     418         *  
     419         * @param query the query string. If null, an empty query (identical to a query for all changesets) is 
     420         * assumed 
     421         * @return the changeset query 
     422         * @throws ChangesetQueryUrlException if the query string doesn't represent a legal query for changesets 
     423         */ 
     424        public ChangesetQuery parse(String query) throws  ChangesetQueryUrlException{ 
     425            if (query == null) 
     426                return new ChangesetQuery(); 
     427            query = query.trim(); 
     428            if (query.equals("")) 
     429                return new ChangesetQuery(); 
     430            Map<String,String> queryParams  = createMapFromQueryString(query); 
     431            return crateFromMap(queryParams); 
     432        } 
     433    } 
    106434} 
Note: See TracChangeset for help on using the changeset viewer.