001/* 002 * Copyright 2008-2012 Marc Wick, geonames.org 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 */ 017package org.geonames; 018 019import java.io.BufferedReader; 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.InputStreamReader; 023import java.lang.reflect.Field; 024import java.net.HttpURLConnection; 025import java.net.MalformedURLException; 026import java.net.Proxy; 027import java.net.URL; 028import java.net.URLConnection; 029import java.net.URLEncoder; 030import java.text.ParseException; 031import java.text.SimpleDateFormat; 032import java.util.ArrayList; 033import java.util.List; 034import java.util.TimeZone; 035import java.util.logging.Level; 036import java.util.logging.Logger; 037 038import org.jdom.Document; 039import org.jdom.Element; 040import org.jdom.JDOMException; 041import org.jdom.input.SAXBuilder; 042 043/** 044 * provides static methods to access the 045 * <a href="http://www.geonames.org/export/ws-overview.html">GeoNames web 046 * services</a>. 047 * <p> 048 * Note : values for some fields are only returned with sufficient {@link Style} 049 * . Accessing these fields (admin codes and admin names, elevation,population) 050 * will throw an {@link InsufficientStyleException} if the {@link Style} was not 051 * sufficient. 052 * 053 * @author marc@geonames 054 * 055 */ 056public class WebService { 057 058 private static Logger logger = Logger.getLogger("org.geonames"); 059 060 private static String USER_AGENT = "gnwsc/1.1.15"; 061 062 private static boolean isAndroid = false; 063 064 private static String geoNamesServer = "http://api.geonames.org"; 065 066 private static String geoNamesServerFailover = "http://api.geonames.org"; 067 068 private static long timeOfLastFailureMainServer; 069 070 private static long averageConnectTime; 071 072 private static long averageSampleSize = 20; 073 074 private static Style defaultStyle = Style.MEDIUM; 075 076 private static int readTimeOut = 120000; 077 078 private static int connectTimeOut = 10000; 079 080 private static String DATEFMT = "yyyy-MM-dd HH:mm:ss"; 081 082 private static Proxy proxy; 083 084 static { 085 USER_AGENT += " ("; 086 String os = System.getProperty("os.name"); 087 if (os != null) { 088 USER_AGENT += os + ","; 089 } 090 String osVersion = System.getProperty("os.version"); 091 if (osVersion != null) { 092 USER_AGENT += osVersion; 093 } 094 USER_AGENT += ")"; 095 096 // android version 097 try { 098 Class aClass = Class.forName("android.os.Build"); 099 if (aClass != null) { 100 isAndroid = true; 101 Field[] fields = aClass.getFields(); 102 if (fields != null) { 103 for (Field field : fields) { 104 if ("MODEL".equalsIgnoreCase(field.getName())) { 105 USER_AGENT += "(" + field.get(aClass) + ", "; 106 } 107 } 108 } 109 aClass = Class.forName("android.os.Build$VERSION"); 110 if (aClass != null) { 111 fields = aClass.getFields(); 112 if (fields != null) { 113 for (Field field : fields) { 114 if ("RELEASE".equalsIgnoreCase(field.getName())) { 115 USER_AGENT += field.get(aClass); 116 } 117 } 118 } 119 } 120 USER_AGENT += ")"; 121 } 122 } catch (Throwable t) { 123 } 124 } 125 126 /** 127 * user name to pass to commercial web services for authentication and 128 * authorization 129 */ 130 private static String userName; 131 132 /** 133 * token to pass to as optional authentication parameter to the commercial web 134 * services. 135 */ 136 private static String token; 137 138 /** 139 * adds the username stored in a static variable to the url. It also adds a 140 * token if one has been set with the static setter previously. 141 * 142 * @param url 143 * @return url with the username appended 144 */ 145 private static String addUserName(String url) { 146 if (userName != null) { 147 url = url + "&username=" + userName; 148 } 149 if (token != null) { 150 url = url + "&token=" + token; 151 } 152 return url; 153 } 154 155 /** 156 * adds the default style to the url. The default style can be set with the 157 * static setter. It is 'MEDIUM' if not set. 158 * 159 * @param url 160 * @return url with the style parameter appended 161 */ 162 private static String addDefaultStyle(String url) { 163 if (defaultStyle != Style.MEDIUM) { 164 url = url + "&style=" + defaultStyle.name(); 165 } 166 return url; 167 } 168 169 /** 170 * returns the currently active server. Normally this is the main server, if the 171 * main server recently failed then the failover server is returned. If the main 172 * server is not available we don't want to try with every request whether it is 173 * available again. We switch to the failover server and try from time to time 174 * whether the main server is again accessible. 175 * 176 * @return 177 */ 178 private static String getCurrentlyActiveServer() { 179 if (timeOfLastFailureMainServer == 0) { 180 // no problems with main server 181 return geoNamesServer; 182 } 183 // we had problems with main server 184 if (System.currentTimeMillis() - timeOfLastFailureMainServer > 1000l * 60l * 10l) { 185 // but is was some time ago and we switch back to the main server to 186 // retry. The problem may have been solved in the mean time. 187 timeOfLastFailureMainServer = 0; 188 return geoNamesServer; 189 } 190 if (System.currentTimeMillis() < timeOfLastFailureMainServer) { 191 throw new Error("time of last failure cannot be in future."); 192 } 193 // the problems have been very recent and we continue with failover 194 // server 195 if (geoNamesServerFailover != null) { 196 return geoNamesServerFailover; 197 } 198 return geoNamesServer; 199 } 200 201 /** 202 * @return the isAndroid 203 */ 204 public static boolean isAndroid() { 205 return isAndroid; 206 } 207 208 /** 209 * opens the connection to the url and sets the user agent. In case of an 210 * IOException it checks whether a failover server is set and connects to the 211 * failover server if it has been defined and if it is different from the normal 212 * server. 213 * 214 * @param url the url to connect to 215 * @return returns the inputstream for the connection 216 * @throws IOException 217 */ 218 private static InputStream connect(String url) throws IOException { 219 int status = 0; 220 String currentlyActiveServer = getCurrentlyActiveServer(); 221 try { 222 long begin = System.currentTimeMillis(); 223 HttpURLConnection httpConnection = null; 224 if (proxy == null) { 225 httpConnection = (HttpURLConnection) new URL(currentlyActiveServer + url).openConnection(); 226 } else { 227 httpConnection = (HttpURLConnection) new URL(currentlyActiveServer + url).openConnection(proxy); 228 } 229 httpConnection.setConnectTimeout(connectTimeOut); 230 httpConnection.setReadTimeout(readTimeOut); 231 httpConnection.setRequestProperty("User-Agent", USER_AGENT); 232 InputStream in = httpConnection.getInputStream(); 233 status = httpConnection.getResponseCode(); 234 235 if (status == 200) { 236 long elapsedTime = System.currentTimeMillis() - begin; 237 averageConnectTime = (averageConnectTime * (averageSampleSize - 1) + elapsedTime) / averageSampleSize; 238 // if the average elapsed time is too long we switch server 239 if (geoNamesServerFailover != null && averageConnectTime > 5000 240 && !currentlyActiveServer.equals(geoNamesServerFailover)) { 241 timeOfLastFailureMainServer = System.currentTimeMillis(); 242 } 243 return in; 244 } 245 } catch (IOException e) { 246 return tryFailoverServer(url, currentlyActiveServer, 0, e); 247 } 248 // we only get here if we had a statuscode <> 200 249 IOException ioException = new IOException("status code " + status + " for " + url); 250 return tryFailoverServer(url, currentlyActiveServer, status, ioException); 251 } 252 253 private static synchronized InputStream tryFailoverServer(String url, String currentlyActiveServer, int status, 254 IOException e) throws MalformedURLException, IOException { 255 // we cannot reach the server 256 logger.log(Level.WARNING, "problems connecting to geonames server " + currentlyActiveServer, e); 257 // is a failover server defined? 258 if (geoNamesServerFailover == null 259 // is it different from the one we are using? 260 || currentlyActiveServer.equals(geoNamesServerFailover)) { 261 if (currentlyActiveServer.equals(geoNamesServerFailover)) { 262 // failover server is not accessible, we throw exception 263 // and switch back to main server. 264 timeOfLastFailureMainServer = 0; 265 } 266 throw e; 267 } 268 timeOfLastFailureMainServer = System.currentTimeMillis(); 269 logger.info("trying to connect to failover server " + geoNamesServerFailover); 270 // try failover server 271 URLConnection conn = null; 272 if (proxy == null) { 273 conn = new URL(geoNamesServerFailover + url).openConnection(); 274 } else { 275 conn = new URL(geoNamesServerFailover + url).openConnection(proxy); 276 } 277 278 String userAgent = USER_AGENT + " failover from " + geoNamesServer; 279 if (status != 0) { 280 userAgent += " " + status; 281 } 282 conn.setRequestProperty("User-Agent", userAgent); 283 InputStream in = conn.getInputStream(); 284 return in; 285 } 286 287 private static Element connectAndParse(String url) throws GeoNamesException, IOException, JDOMException { 288 SAXBuilder parser = new SAXBuilder(); 289 Document doc = parser.build(connect(url)); 290 try { 291 Element root = rootAndCheckException(doc); 292 return root; 293 } catch (GeoNamesException geoNamesException) { 294 if (geoNamesException.getExceptionCode() == 13 || (geoNamesException.getMessage() != null 295 && geoNamesException.getMessage().indexOf("canceling statement due to statement timeout") > -1)) { 296 String currentlyActiveServer = getCurrentlyActiveServer(); 297 if (geoNamesServerFailover != null && !currentlyActiveServer.equals(geoNamesServerFailover)) { 298 timeOfLastFailureMainServer = System.currentTimeMillis(); 299 doc = parser.build(connect(url)); 300 Element root = rootAndCheckException(doc); 301 return root; 302 } 303 } 304 throw geoNamesException; 305 } 306 } 307 308 private static Element rootAndCheckException(Document doc) throws GeoNamesException { 309 Element root = doc.getRootElement(); 310 checkException(root); 311 return root; 312 } 313 314 private static void checkException(Element root) throws GeoNamesException { 315 Element message = root.getChild("status"); 316 if (message != null) { 317 int code = 0; 318 try { 319 code = Integer.parseInt(message.getAttributeValue("value")); 320 } catch (NumberFormatException numberFormatException) { 321 } 322 throw new GeoNamesException(code, message.getAttributeValue("message")); 323 } 324 } 325 326 /** 327 * check whether we can parse an exception and throw it if we can 328 * 329 * if the line starts with ERR: then we have a geonames exception. 330 * 331 * @param line 332 * @throws GeoNamesException 333 */ 334 private static void checkException(String line) throws GeoNamesException { 335 if (line.startsWith("ERR:")) { 336 String[] terms = line.split(":"); 337 if (terms.length == 3) { 338 throw new GeoNamesException(Integer.parseInt(terms[1]), terms[2]); 339 } 340 throw new GeoNamesException("unhandled exception"); 341 } 342 } 343 344 private static Toponym getToponymFromElement(Element toponymElement) { 345 Toponym toponym = new Toponym(); 346 347 toponym.setName(toponymElement.getChildText("name")); 348 toponym.setAlternateNames(toponymElement.getChildText("alternateNames")); 349 toponym.setLatitude(Double.parseDouble(toponymElement.getChildText("lat"))); 350 toponym.setLongitude(Double.parseDouble(toponymElement.getChildText("lng"))); 351 352 String geonameId = toponymElement.getChildText("geonameId"); 353 if (geonameId != null) { 354 toponym.setGeoNameId(Integer.parseInt(geonameId)); 355 } 356 357 toponym.setContinentCode(toponymElement.getChildText("continentCode")); 358 toponym.setCountryCode(toponymElement.getChildText("countryCode")); 359 toponym.setCountryName(toponymElement.getChildText("countryName")); 360 361 toponym.setFeatureClass(FeatureClass.fromValue(toponymElement.getChildText("fcl"))); 362 toponym.setFeatureCode(toponymElement.getChildText("fcode")); 363 364 toponym.setFeatureClassName(toponymElement.getChildText("fclName")); 365 toponym.setFeatureCodeName(toponymElement.getChildText("fCodeName")); 366 367 String population = toponymElement.getChildText("population"); 368 if (population != null && !"".equals(population)) { 369 toponym.setPopulation(Long.parseLong(population)); 370 } 371 String elevation = toponymElement.getChildText("elevation"); 372 if (elevation != null && !"".equals(elevation)) { 373 toponym.setElevation(Integer.parseInt(elevation)); 374 } 375 376 toponym.setAdminCode1(toponymElement.getChildText("adminCode1")); 377 toponym.setAdminName1(toponymElement.getChildText("adminName1")); 378 toponym.setAdminCode2(toponymElement.getChildText("adminCode2")); 379 toponym.setAdminName2(toponymElement.getChildText("adminName2")); 380 toponym.setAdminCode3(toponymElement.getChildText("adminCode3")); 381 toponym.setAdminName3(toponymElement.getChildText("adminName3")); 382 toponym.setAdminCode4(toponymElement.getChildText("adminCode4")); 383 toponym.setAdminName4(toponymElement.getChildText("adminName4")); 384 toponym.setAdminCode5(toponymElement.getChildText("adminCode5")); 385 toponym.setAdminName5(toponymElement.getChildText("adminName5")); 386 387 Element timezoneElement = toponymElement.getChild("timezone"); 388 if (timezoneElement != null) { 389 Timezone timezone = new Timezone(); 390 timezone.setTimezoneId(timezoneElement.getValue()); 391 timezone.setDstOffset(Double.parseDouble(timezoneElement.getAttributeValue("dstOffset"))); 392 timezone.setGmtOffset(Double.parseDouble(timezoneElement.getAttributeValue("gmtOffset"))); 393 toponym.setTimezone(timezone); 394 } 395 396 Element bboxElement = toponymElement.getChild("bbox"); 397 if (bboxElement != null) { 398 BoundingBox boundingBox = new BoundingBox(Double.parseDouble(bboxElement.getChildText("west")), 399 Double.parseDouble(bboxElement.getChildText("east")), 400 Double.parseDouble(bboxElement.getChildText("south")), 401 Double.parseDouble(bboxElement.getChildText("north"))); 402 toponym.setBoundingBox(boundingBox); 403 } 404 405 return toponym; 406 } 407 408 private static WikipediaArticle getWikipediaArticleFromElement(Element wikipediaArticleElement) { 409 WikipediaArticle wikipediaArticle = new WikipediaArticle(); 410 wikipediaArticle.setLanguage(wikipediaArticleElement.getChildText("lang")); 411 wikipediaArticle.setTitle(wikipediaArticleElement.getChildText("title")); 412 wikipediaArticle.setSummary(wikipediaArticleElement.getChildText("summary")); 413 wikipediaArticle.setFeature(wikipediaArticleElement.getChildText("feature")); 414 wikipediaArticle.setWikipediaUrl(wikipediaArticleElement.getChildText("wikipediaUrl")); 415 wikipediaArticle.setThumbnailImg(wikipediaArticleElement.getChildText("thumbnailImg")); 416 417 wikipediaArticle.setLatitude(Double.parseDouble(wikipediaArticleElement.getChildText("lat"))); 418 wikipediaArticle.setLongitude(Double.parseDouble(wikipediaArticleElement.getChildText("lng"))); 419 420 wikipediaArticle.setRank(Integer.parseInt(wikipediaArticleElement.getChildText("rank"))); 421 422 String population = wikipediaArticleElement.getChildText("population"); 423 if (population != null && !"".equals(population)) { 424 wikipediaArticle.setPopulation(Integer.parseInt(population)); 425 } 426 427 String elevation = wikipediaArticleElement.getChildText("elevation"); 428 if (elevation != null && !"".equals(elevation)) { 429 wikipediaArticle.setElevation(Integer.parseInt(elevation)); 430 } 431 return wikipediaArticle; 432 } 433 434 private static TimeZone utc = TimeZone.getTimeZone("UTC"); 435 436 private static WeatherObservation getWeatherObservationFromElement(Element weatherObservationElement) 437 throws ParseException { 438 WeatherObservation weatherObservation = new WeatherObservation(); 439 weatherObservation.setObservation(weatherObservationElement.getChildText("observation")); 440 SimpleDateFormat df = new SimpleDateFormat(DATEFMT); 441 df.setTimeZone(utc); 442 weatherObservation.setObservationTime(df.parse(weatherObservationElement.getChildText("observationTime"))); 443 weatherObservation.setStationName(weatherObservationElement.getChildText("stationName")); 444 weatherObservation.setIcaoCode(weatherObservationElement.getChildText("ICAO")); 445 weatherObservation.setCountryCode(weatherObservationElement.getChildText("countryCode")); 446 String elevation = weatherObservationElement.getChildText("elevation"); 447 if (elevation != null && !"".equals(elevation)) { 448 weatherObservation.setElevation(Integer.parseInt(elevation)); 449 } 450 weatherObservation.setLatitude(Double.parseDouble(weatherObservationElement.getChildText("lat"))); 451 weatherObservation.setLongitude(Double.parseDouble(weatherObservationElement.getChildText("lng"))); 452 String temperature = weatherObservationElement.getChildText("temperature"); 453 if (temperature != null && !"".equals(temperature)) { 454 weatherObservation.setTemperature(Double.parseDouble(temperature)); 455 } 456 String dewPoint = weatherObservationElement.getChildText("dewPoint"); 457 if (dewPoint != null && !"".equals(dewPoint)) { 458 weatherObservation.setDewPoint(Double.parseDouble(dewPoint)); 459 } 460 String humidity = weatherObservationElement.getChildText("humidity"); 461 if (humidity != null && !"".equals(humidity)) { 462 weatherObservation.setHumidity(Double.parseDouble(humidity)); 463 } 464 weatherObservation.setClouds(weatherObservationElement.getChildText("clouds")); 465 weatherObservation.setWeatherCondition(weatherObservationElement.getChildText("weatherCondition")); 466 weatherObservation.setWindSpeed(weatherObservationElement.getChildText("windSpeed")); 467 return weatherObservation; 468 469 } 470 471 /** 472 * returns a list of postal codes for the given parameters. This method is for 473 * convenience. 474 * 475 * @param postalCode 476 * @param placeName 477 * @param countryCode 478 * @return 479 * @throws Exception 480 */ 481 public static List<PostalCode> postalCodeSearch(String postalCode, String placeName, String countryCode) 482 throws Exception { 483 PostalCodeSearchCriteria postalCodeSearchCriteria = new PostalCodeSearchCriteria(); 484 postalCodeSearchCriteria.setPostalCode(postalCode); 485 postalCodeSearchCriteria.setPlaceName(placeName); 486 postalCodeSearchCriteria.setCountryCode(countryCode); 487 return postalCodeSearch(postalCodeSearchCriteria); 488 } 489 490 /** 491 * returns a list of postal codes for the given search criteria matching a full 492 * text search on the GeoNames postal codes database. 493 * 494 * @param postalCodeSearchCriteria 495 * @return 496 * @throws Exception 497 */ 498 public static List<PostalCode> postalCodeSearch(PostalCodeSearchCriteria postalCodeSearchCriteria) 499 throws Exception { 500 List<PostalCode> postalCodes = new ArrayList<PostalCode>(); 501 502 String url = "/postalCodeSearch?"; 503 if (postalCodeSearchCriteria.getPostalCode() != null) { 504 url = url + "postalcode=" + URLEncoder.encode(postalCodeSearchCriteria.getPostalCode(), "UTF8"); 505 } 506 if (postalCodeSearchCriteria.getPlaceName() != null) { 507 if (!url.endsWith("&")) { 508 url = url + "&"; 509 } 510 url = url + "placename=" + URLEncoder.encode(postalCodeSearchCriteria.getPlaceName(), "UTF8"); 511 } 512 if (postalCodeSearchCriteria.getAdminCode1() != null) { 513 url = url + "&adminCode1=" + URLEncoder.encode(postalCodeSearchCriteria.getAdminCode1(), "UTF8"); 514 } 515 516 if (postalCodeSearchCriteria.getCountryCode() != null) { 517 if (!url.endsWith("&")) { 518 url = url + "&"; 519 } 520 url = url + "country=" + postalCodeSearchCriteria.getCountryCode(); 521 } 522 if (postalCodeSearchCriteria.getCountryBias() != null) { 523 if (!url.endsWith("&")) { 524 url = url + "&"; 525 } 526 url = url + "countryBias=" + postalCodeSearchCriteria.getCountryBias(); 527 } 528 if (postalCodeSearchCriteria.getMaxRows() > 0) { 529 url = url + "&maxRows=" + postalCodeSearchCriteria.getMaxRows(); 530 } 531 if (postalCodeSearchCriteria.getStartRow() > 0) { 532 url = url + "&startRow=" + postalCodeSearchCriteria.getStartRow(); 533 } 534 if (postalCodeSearchCriteria.isOROperator()) { 535 url = url + "&operator=OR"; 536 } 537 if (postalCodeSearchCriteria.isReduced() != null) { 538 url = url + "&isReduced=" + postalCodeSearchCriteria.isReduced().toString(); 539 } 540 if (postalCodeSearchCriteria.getBoundingBox() != null) { 541 url = url + "&east=" + postalCodeSearchCriteria.getBoundingBox().getEast(); 542 url = url + "&west=" + postalCodeSearchCriteria.getBoundingBox().getWest(); 543 url = url + "&north=" + postalCodeSearchCriteria.getBoundingBox().getNorth(); 544 url = url + "&south=" + postalCodeSearchCriteria.getBoundingBox().getSouth(); 545 } 546 547 url = addUserName(url); 548 549 Element root = connectAndParse(url); 550 for (Object obj : root.getChildren("code")) { 551 Element codeElement = (Element) obj; 552 PostalCode code = getPostalCodeFromElement(codeElement); 553 postalCodes.add(code); 554 } 555 556 return postalCodes; 557 } 558 559 /** 560 * returns a list of postal codes 561 * 562 * @param postalCodeSearchCriteria 563 * @return 564 * @throws Exception 565 */ 566 public static List<PostalCode> findNearbyPostalCodes(PostalCodeSearchCriteria postalCodeSearchCriteria) 567 throws Exception { 568 569 List<PostalCode> postalCodes = new ArrayList<PostalCode>(); 570 571 String url = "/findNearbyPostalCodes?"; 572 if (postalCodeSearchCriteria.getPostalCode() != null) { 573 url = url + "&postalcode=" + URLEncoder.encode(postalCodeSearchCriteria.getPostalCode(), "UTF8"); 574 } 575 if (postalCodeSearchCriteria.getPlaceName() != null) { 576 url = url + "&placename=" + URLEncoder.encode(postalCodeSearchCriteria.getPlaceName(), "UTF8"); 577 } 578 if (postalCodeSearchCriteria.getCountryCode() != null) { 579 url = url + "&country=" + postalCodeSearchCriteria.getCountryCode(); 580 } 581 582 if (postalCodeSearchCriteria.getLatitude() != null) { 583 url = url + "&lat=" + postalCodeSearchCriteria.getLatitude(); 584 } 585 if (postalCodeSearchCriteria.getLongitude() != null) { 586 url = url + "&lng=" + postalCodeSearchCriteria.getLongitude(); 587 } 588 if (postalCodeSearchCriteria.getStyle() != null) { 589 url = url + "&style=" + postalCodeSearchCriteria.getStyle(); 590 } 591 if (postalCodeSearchCriteria.getMaxRows() > 0) { 592 url = url + "&maxRows=" + postalCodeSearchCriteria.getMaxRows(); 593 } 594 595 if (postalCodeSearchCriteria.getRadius() > 0) { 596 url = url + "&radius=" + postalCodeSearchCriteria.getRadius(); 597 } 598 url = addUserName(url); 599 600 Element root = connectAndParse(url); 601 for (Object obj : root.getChildren("code")) { 602 Element codeElement = (Element) obj; 603 PostalCode code = getPostalCodeFromElement(codeElement); 604 if (codeElement.getChildText("distance") != null) { 605 code.setDistance(Double.parseDouble(codeElement.getChildText("distance"))); 606 } 607 postalCodes.add(code); 608 } 609 610 return postalCodes; 611 } 612 613 private static PostalCode getPostalCodeFromElement(Element codeElement) throws ParseException { 614 PostalCode code = new PostalCode(); 615 code.setPostalCode(codeElement.getChildText("postalcode")); 616 code.setPlaceName(codeElement.getChildText("name")); 617 code.setCountryCode(codeElement.getChildText("countryCode")); 618 619 code.setLatitude(Double.parseDouble(codeElement.getChildText("lat"))); 620 code.setLongitude(Double.parseDouble(codeElement.getChildText("lng"))); 621 622 code.setAdminName1(codeElement.getChildText("adminName1")); 623 code.setAdminCode1(codeElement.getChildText("adminCode1")); 624 code.setAdminName2(codeElement.getChildText("adminName2")); 625 code.setAdminCode2(codeElement.getChildText("adminCode2")); 626 code.setAdminName3(codeElement.getChildText("adminName3")); 627 code.setAdminCode3(codeElement.getChildText("adminCode3")); 628 return code; 629 } 630 631 /** 632 * convenience method for {@link #findNearbyPlaceName(double,double,double,int)} 633 * 634 * @param latitude 635 * @param longitude 636 * @return 637 * @throws IOException 638 * @throws Exception 639 */ 640 public static List<Toponym> findNearbyPlaceName(double latitude, double longitude) throws IOException, Exception { 641 return findNearbyPlaceName(latitude, longitude, 0, 0); 642 } 643 644 public static List<Toponym> findNearbyPlaceName(double latitude, double longitude, double radius, int maxRows) 645 throws IOException, Exception { 646 List<Toponym> places = new ArrayList<Toponym>(); 647 648 String url = "/findNearbyPlaceName?"; 649 650 url = url + "&lat=" + latitude; 651 url = url + "&lng=" + longitude; 652 if (radius > 0) { 653 url = url + "&radius=" + radius; 654 } 655 if (maxRows > 0) { 656 url = url + "&maxRows=" + maxRows; 657 } 658 url = addUserName(url); 659 url = addDefaultStyle(url); 660 661 Element root = connectAndParse(url); 662 for (Object obj : root.getChildren("geoname")) { 663 Element toponymElement = (Element) obj; 664 Toponym toponym = getToponymFromElement(toponymElement); 665 places.add(toponym); 666 } 667 668 return places; 669 } 670 671 public static List<Toponym> findNearby(double latitude, double longitude, FeatureClass featureClass, 672 String[] featureCodes) throws IOException, Exception { 673 return findNearby(latitude, longitude, 0, featureClass, featureCodes, null, 0); 674 } 675 676 /* Overload function to allow backward compatibility */ 677 /** 678 * Based on the following inforamtion: Webservice Type : REST 679 * api.geonames.org/findNearbyWikipedia? Parameters : lang : language code 680 * (around 240 languages) (default = en) lat,lng, radius (in km), maxRows 681 * (default = 10) featureClass featureCode Example: 682 * http://api.geonames.org/findNearby?lat=47.3&lng=9 683 * 684 * @param: latitude 685 * @param: longitude 686 * @param: radius 687 * @param: feature Class 688 * @param: feature Codes 689 * @param: language 690 * @param: maxRows 691 * @return: list of wikipedia articles 692 * @throws: Exception 693 */ 694 public static List<Toponym> findNearby(double latitude, double longitude, double radius, FeatureClass featureClass, 695 String[] featureCodes, String language, int maxRows) throws IOException, Exception { 696 List<Toponym> places = new ArrayList<Toponym>(); 697 698 String url = "/findNearby?"; 699 700 url += "&lat=" + latitude; 701 url += "&lng=" + longitude; 702 if (radius > 0) { 703 url = url + "&radius=" + radius; 704 } 705 if (maxRows > 0) { 706 url = url + "&maxRows=" + maxRows; 707 } 708 709 if (language != null) { 710 url = url + "&lang=" + language; 711 } 712 713 if (featureClass != null) { 714 url += "&featureClass=" + featureClass; 715 } 716 if (featureCodes != null && featureCodes.length > 0) { 717 for (String featureCode : featureCodes) { 718 url += "&featureCode=" + featureCode; 719 } 720 } 721 722 url = addUserName(url); 723 url = addDefaultStyle(url); 724 725 Element root = connectAndParse(url); 726 for (Object obj : root.getChildren("geoname")) { 727 Element toponymElement = (Element) obj; 728 Toponym toponym = getToponymFromElement(toponymElement); 729 places.add(toponym); 730 } 731 732 return places; 733 } 734 735 /** 736 * 737 * @param geoNameId 738 * @param language - optional 739 * @param style - optional 740 * @return the toponym for the geoNameId 741 * @throws IOException 742 * @throws Exception 743 */ 744 public static Toponym get(int geoNameId, String language, String style) throws IOException, Exception { 745 String url = "/get?"; 746 747 url += "geonameId=" + geoNameId; 748 749 if (language != null) { 750 url = url + "&lang=" + language; 751 } 752 753 if (style != null) { 754 url = url + "&style=" + style; 755 } else { 756 url = addDefaultStyle(url); 757 } 758 url = addUserName(url); 759 760 Element root = connectAndParse(url); 761 Toponym toponym = getToponymFromElement(root); 762 return toponym; 763 } 764 765 /** 766 * for US only 767 * 768 * @param latitude 769 * @param longitude 770 * @return 771 * @throws IOException 772 * @throws Exception 773 */ 774 public static Address findNearestAddress(double latitude, double longitude) throws IOException, Exception { 775 776 String url = "/findNearestAddress?"; 777 778 url = url + "&lat=" + latitude; 779 url = url + "&lng=" + longitude; 780 url = addUserName(url); 781 782 Element root = connectAndParse(url); 783 for (Object obj : root.getChildren("address")) { 784 Element codeElement = (Element) obj; 785 Address address = new Address(); 786 address.setStreet(codeElement.getChildText("street")); 787 address.setStreetNumber(codeElement.getChildText("streetNumber")); 788 address.setMtfcc(codeElement.getChildText("mtfcc")); 789 790 address.setPostalCode(codeElement.getChildText("postalcode")); 791 address.setPlaceName(codeElement.getChildText("placename")); 792 address.setCountryCode(codeElement.getChildText("countryCode")); 793 794 address.setLatitude(Double.parseDouble(codeElement.getChildText("lat"))); 795 address.setLongitude(Double.parseDouble(codeElement.getChildText("lng"))); 796 797 address.setAdminName1(codeElement.getChildText("adminName1")); 798 address.setAdminCode1(codeElement.getChildText("adminCode1")); 799 address.setAdminName2(codeElement.getChildText("adminName2")); 800 address.setAdminCode2(codeElement.getChildText("adminCode2")); 801 address.setAdminName3(codeElement.getChildText("adminName3")); 802 address.setAdminCode3(codeElement.getChildText("adminCode3")); 803 address.setAdminName4(codeElement.getChildText("adminName4")); 804 address.setAdminCode4(codeElement.getChildText("adminCode4")); 805 806 address.setDistance(Double.parseDouble(codeElement.getChildText("distance"))); 807 808 return address; 809 } 810 811 return null; 812 } 813 814 public static Intersection findNearestIntersection(double latitude, double longitude) throws Exception { 815 return findNearestIntersection(latitude, longitude, 0); 816 } 817 818 public static Intersection findNearestIntersection(double latitude, double longitude, double radius) 819 throws Exception { 820 821 String url = "/findNearestIntersection?"; 822 823 url = url + "&lat=" + latitude; 824 url = url + "&lng=" + longitude; 825 if (radius > 0) { 826 url = url + "&radius=" + radius; 827 } 828 url = addUserName(url); 829 830 Element root = connectAndParse(url); 831 for (Object obj : root.getChildren("intersection")) { 832 Element e = (Element) obj; 833 Intersection intersection = new Intersection(); 834 intersection.setStreet1(e.getChildText("street1")); 835 intersection.setStreet2(e.getChildText("street2")); 836 intersection.setLatitude(Double.parseDouble(e.getChildText("lat"))); 837 intersection.setLongitude(Double.parseDouble(e.getChildText("lng"))); 838 intersection.setDistance(Double.parseDouble(e.getChildText("distance"))); 839 intersection.setPostalCode(e.getChildText("postalcode")); 840 intersection.setPlaceName(e.getChildText("placename")); 841 intersection.setCountryCode(e.getChildText("countryCode")); 842 intersection.setAdminName2(e.getChildText("adminName2")); 843 intersection.setAdminCode1(e.getChildText("adminCode1")); 844 intersection.setAdminName1(e.getChildText("adminName1")); 845 return intersection; 846 } 847 return null; 848 } 849 850 /** 851 * 852 * @see <a * href= 853 * "http://www.geonames.org/maps/reverse-geocoder.html#findNearbyStreets" > 854 * web service documentation</a> 855 * 856 * @param latitude 857 * @param longitude 858 * @param radius 859 * @return 860 * @throws Exception 861 */ 862 public static List<StreetSegment> findNearbyStreets(double latitude, double longitude, double radius) 863 throws Exception { 864 865 String url = "/findNearbyStreets?"; 866 867 url = url + "&lat=" + latitude; 868 url = url + "&lng=" + longitude; 869 if (radius > 0) { 870 url = url + "&radius=" + radius; 871 } 872 url = addUserName(url); 873 874 List<StreetSegment> segments = new ArrayList<StreetSegment>(); 875 876 Element root = connectAndParse(url); 877 for (Object obj : root.getChildren("streetSegment")) { 878 Element e = (Element) obj; 879 StreetSegment streetSegment = new StreetSegment(); 880 String line = e.getChildText("line"); 881 String[] points = line.split(","); 882 double[] latArray = new double[points.length]; 883 double[] lngArray = new double[points.length]; 884 for (int i = 0; i < points.length; i++) { 885 String[] coords = points[i].split(" "); 886 lngArray[i] = Double.parseDouble(coords[0]); 887 latArray[i] = Double.parseDouble(coords[1]); 888 } 889 890 streetSegment.setCfcc(e.getChildText("cfcc")); 891 streetSegment.setName(e.getChildText("name")); 892 streetSegment.setFraddl(e.getChildText("fraddl")); 893 streetSegment.setFraddr(e.getChildText("fraddr")); 894 streetSegment.setToaddl(e.getChildText("toaddl")); 895 streetSegment.setToaddr(e.getChildText("toaddr")); 896 streetSegment.setPostalCode(e.getChildText("postalcode")); 897 streetSegment.setPlaceName(e.getChildText("placename")); 898 streetSegment.setCountryCode(e.getChildText("countryCode")); 899 streetSegment.setAdminName2(e.getChildText("adminName2")); 900 streetSegment.setAdminCode1(e.getChildText("adminCode1")); 901 streetSegment.setAdminName1(e.getChildText("adminName1")); 902 segments.add(streetSegment); 903 } 904 return segments; 905 } 906 907 public static List<StreetSegment> findNearbyStreetsOSM(double latitude, double longitude, double radius) 908 throws Exception { 909 910 String url = "/findNearbyStreetsOSM?"; 911 912 url = url + "&lat=" + latitude; 913 url = url + "&lng=" + longitude; 914 if (radius > 0) { 915 url = url + "&radius=" + radius; 916 } 917 url = addUserName(url); 918 919 List<StreetSegment> segments = new ArrayList<StreetSegment>(); 920 921 Element root = connectAndParse(url); 922 for (Object obj : root.getChildren("streetSegment")) { 923 Element e = (Element) obj; 924 StreetSegment streetSegment = new StreetSegment(); 925 String line = e.getChildText("line"); 926 String[] points = line.split(","); 927 double[] latArray = new double[points.length]; 928 double[] lngArray = new double[points.length]; 929 for (int i = 0; i < points.length; i++) { 930 String[] coords = points[i].split(" "); 931 lngArray[i] = Double.parseDouble(coords[0]); 932 latArray[i] = Double.parseDouble(coords[1]); 933 } 934 935 streetSegment.setName(e.getChildText("name")); 936 segments.add(streetSegment); 937 } 938 return segments; 939 } 940 941 public static Address address(double latitude, double longitude) throws IOException, Exception { 942 943 String url = "/address?"; 944 945 url = url + "&lat=" + latitude; 946 url = url + "&lng=" + longitude; 947 url = addUserName(url); 948 949 Element root = connectAndParse(url); 950 for (Object obj : root.getChildren("address")) { 951 Element codeElement = (Element) obj; 952 Address address = new Address(); 953 address.setStreet(codeElement.getChildText("street")); 954 address.setStreetNumber(codeElement.getChildText("houseNumber")); 955 956 address.setPostalCode(codeElement.getChildText("postalcode")); 957 address.setPlaceName(codeElement.getChildText("locality")); 958 address.setCountryCode(codeElement.getChildText("countryCode")); 959 960 address.setLatitude(Double.parseDouble(codeElement.getChildText("lat"))); 961 address.setLongitude(Double.parseDouble(codeElement.getChildText("lng"))); 962 963 address.setAdminName1(codeElement.getChildText("adminName1")); 964 address.setAdminCode1(codeElement.getChildText("adminCode1")); 965 address.setAdminName2(codeElement.getChildText("adminName2")); 966 address.setAdminCode2(codeElement.getChildText("adminCode2")); 967 address.setAdminName3(codeElement.getChildText("adminName3")); 968 address.setAdminCode3(codeElement.getChildText("adminCode3")); 969 970 address.setSourceId(codeElement.getChildText("sourceId")); 971 972 address.setDistance(Double.parseDouble(codeElement.getChildText("distance"))); 973 974 return address; 975 } 976 977 return null; 978 } 979 980 public static Address geoCodeAddress(String q, String country, String postalcode) throws IOException, Exception { 981 982 String url = "/geoCodeAddress?"; 983 984 url = url + "&q=" + URLEncoder.encode(q, "UTF8"); 985 if (country != null && !country.isEmpty()) { 986 url = url + "&country=" + country; 987 } 988 if (postalcode != null && !postalcode.isEmpty()) { 989 url = url + "&postalcode=" + URLEncoder.encode(postalcode, "UTF8"); 990 } 991 url = addUserName(url); 992 993 Element root = connectAndParse(url); 994 for (Object obj : root.getChildren("address")) { 995 Element codeElement = (Element) obj; 996 Address address = new Address(); 997 address.setSourceId(codeElement.getChildText("sourceId")); 998 address.setStreet(codeElement.getChildText("street")); 999 address.setStreetNumber(codeElement.getChildText("houseNumber")); 1000 1001 address.setPostalCode(codeElement.getChildText("postalcode")); 1002 address.setPlaceName(codeElement.getChildText("locality")); 1003 address.setCountryCode(codeElement.getChildText("countryCode")); 1004 1005 address.setLatitude(Double.parseDouble(codeElement.getChildText("lat"))); 1006 address.setLongitude(Double.parseDouble(codeElement.getChildText("lng"))); 1007 1008 address.setAdminName1(codeElement.getChildText("adminName1")); 1009 address.setAdminCode1(codeElement.getChildText("adminCode1")); 1010 address.setAdminName2(codeElement.getChildText("adminName2")); 1011 address.setAdminCode2(codeElement.getChildText("adminCode2")); 1012 address.setAdminName3(codeElement.getChildText("adminName3")); 1013 address.setAdminCode3(codeElement.getChildText("adminCode3")); 1014 address.setAdminName4(codeElement.getChildText("adminName4")); 1015 address.setAdminCode4(codeElement.getChildText("adminCode4")); 1016 1017 return address; 1018 } 1019 1020 return null; 1021 } 1022 1023 /** 1024 * convenience method for {@link #search(ToponymSearchCriteria)} 1025 * 1026 * @see <a href="http://www.geonames.org/export/geonames-search.html">search web 1027 * service documentation</a> 1028 * 1029 * @param q 1030 * @param countryCode 1031 * @param name 1032 * @param featureCodes 1033 * @param startRow 1034 * @return 1035 * @throws Exception 1036 */ 1037 public static ToponymSearchResult search(String q, String countryCode, String name, String[] featureCodes, 1038 int startRow) throws Exception { 1039 return search(q, countryCode, name, featureCodes, startRow, null, null, null); 1040 } 1041 1042 /** 1043 * convenience method for {@link #search(ToponymSearchCriteria)} 1044 * 1045 * The string fields will be transparently utf8 encoded within the call. 1046 * 1047 * @see <a href="http://www.geonames.org/export/geonames-search.html">search web 1048 * service documentation</a> 1049 * 1050 * @param q search over all fields 1051 * @param countryCode 1052 * @param name search over name only 1053 * @param featureCodes 1054 * @param startRow 1055 * @param language 1056 * @param style 1057 * @param exactName 1058 * @return 1059 * @throws Exception 1060 */ 1061 public static ToponymSearchResult search(String q, String countryCode, String name, String[] featureCodes, 1062 int startRow, String language, Style style, String exactName) throws Exception { 1063 ToponymSearchCriteria searchCriteria = new ToponymSearchCriteria(); 1064 searchCriteria.setQ(q); 1065 searchCriteria.setCountryCode(countryCode); 1066 searchCriteria.setName(name); 1067 searchCriteria.setFeatureCodes(featureCodes); 1068 searchCriteria.setStartRow(startRow); 1069 searchCriteria.setLanguage(language); 1070 searchCriteria.setStyle(style); 1071 searchCriteria.setNameEquals(exactName); 1072 return search(searchCriteria); 1073 } 1074 1075 /** 1076 * full text search on the GeoNames database. 1077 * 1078 * This service gets the number of toponyms defined by the 'maxRows' parameter. 1079 * The parameter 'style' determines which fields are returned by the service. 1080 * 1081 * @see <a href="http://www.geonames.org/export/geonames-search.html">search web 1082 * service documentation</a> 1083 * 1084 * <br> 1085 * 1086 * <pre> 1087 * ToponymSearchCriteria searchCriteria = new ToponymSearchCriteria(); 1088 * searchCriteria.setQ("z&uumlrich"); 1089 * ToponymSearchResult searchResult = WebService.search(searchCriteria); 1090 * for (Toponym toponym : searchResult.toponyms) { 1091 * System.out.println(toponym.getName() + " " + toponym.getCountryName()); 1092 * } 1093 * </pre> 1094 * 1095 * 1096 * @param searchCriteria 1097 * @return 1098 * @throws Exception 1099 */ 1100 public static ToponymSearchResult search(ToponymSearchCriteria searchCriteria) throws Exception { 1101 ToponymSearchResult searchResult = new ToponymSearchResult(); 1102 1103 String url = "/search?"; 1104 1105 if (searchCriteria.getQ() != null) { 1106 url = url + "q=" + URLEncoder.encode(searchCriteria.getQ(), "UTF8"); 1107 } 1108 if (searchCriteria.getNameEquals() != null) { 1109 url = url + "&name_equals=" + URLEncoder.encode(searchCriteria.getNameEquals(), "UTF8"); 1110 } 1111 if (searchCriteria.getNameStartsWith() != null) { 1112 url = url + "&name_startsWith=" + URLEncoder.encode(searchCriteria.getNameStartsWith(), "UTF8"); 1113 } 1114 1115 if (searchCriteria.getName() != null) { 1116 url = url + "&name=" + URLEncoder.encode(searchCriteria.getName(), "UTF8"); 1117 } 1118 1119 if (searchCriteria.getTag() != null) { 1120 url = url + "&tag=" + URLEncoder.encode(searchCriteria.getTag(), "UTF8"); 1121 } 1122 1123 if (searchCriteria.getCountryCode() != null) { 1124 url = url + "&country=" + searchCriteria.getCountryCode(); 1125 } 1126 if (searchCriteria.getCountryCodes() != null) { 1127 for (String countryCode : searchCriteria.getCountryCodes()) { 1128 url = url + "&country=" + countryCode; 1129 } 1130 } 1131 if (searchCriteria.getCountryBias() != null) { 1132 if (!url.endsWith("&")) { 1133 url = url + "&"; 1134 } 1135 url = url + "countryBias=" + searchCriteria.getCountryBias(); 1136 } 1137 if (searchCriteria.getContinentCode() != null) { 1138 url = url + "&continentCode=" + searchCriteria.getContinentCode(); 1139 } 1140 1141 if (searchCriteria.getAdminCode1() != null) { 1142 url = url + "&adminCode1=" + URLEncoder.encode(searchCriteria.getAdminCode1(), "UTF8"); 1143 } 1144 if (searchCriteria.getAdminCode2() != null) { 1145 url = url + "&adminCode2=" + URLEncoder.encode(searchCriteria.getAdminCode2(), "UTF8"); 1146 } 1147 if (searchCriteria.getAdminCode3() != null) { 1148 url = url + "&adminCode3=" + URLEncoder.encode(searchCriteria.getAdminCode3(), "UTF8"); 1149 } 1150 if (searchCriteria.getAdminCode4() != null) { 1151 url = url + "&adminCode4=" + URLEncoder.encode(searchCriteria.getAdminCode4(), "UTF8"); 1152 } 1153 1154 if (searchCriteria.getLanguage() != null) { 1155 url = url + "&lang=" + searchCriteria.getLanguage(); 1156 } 1157 1158 if (searchCriteria.getFeatureClass() != null) { 1159 url = url + "&featureClass=" + searchCriteria.getFeatureClass(); 1160 } 1161 1162 if (searchCriteria.getFeatureCodes() != null) { 1163 for (String featureCode : searchCriteria.getFeatureCodes()) { 1164 url = url + "&fcode=" + featureCode; 1165 } 1166 } 1167 if (searchCriteria.getMaxRows() > 0) { 1168 url = url + "&maxRows=" + searchCriteria.getMaxRows(); 1169 } 1170 if (searchCriteria.getStartRow() > 0) { 1171 url = url + "&startRow=" + searchCriteria.getStartRow(); 1172 } 1173 if (searchCriteria.getFuzzy() != 1.0) { 1174 url = url + "&fuzzy=" + searchCriteria.getFuzzy(); 1175 } 1176 1177 if (searchCriteria.getBoundingBox() != null) { 1178 url = url + "&east=" + searchCriteria.getBoundingBox().getEast(); 1179 url = url + "&west=" + searchCriteria.getBoundingBox().getWest(); 1180 url = url + "&north=" + searchCriteria.getBoundingBox().getNorth(); 1181 url = url + "&south=" + searchCriteria.getBoundingBox().getSouth(); 1182 } 1183 1184 if (searchCriteria.getStyle() != null) { 1185 url = url + "&style=" + searchCriteria.getStyle(); 1186 } else { 1187 url = addDefaultStyle(url); 1188 } 1189 url = addUserName(url); 1190 1191 Element root = connectAndParse(url); 1192 searchResult.totalResultsCount = Integer.parseInt(root.getChildText("totalResultsCount")); 1193 searchResult.setStyle(Style.valueOf(root.getAttributeValue("style"))); 1194 1195 for (Object obj : root.getChildren("geoname")) { 1196 Element toponymElement = (Element) obj; 1197 Toponym toponym = getToponymFromElement(toponymElement); 1198 toponym.setStyle(searchResult.getStyle()); 1199 searchResult.toponyms.add(toponym); 1200 } 1201 1202 return searchResult; 1203 } 1204 1205 /** 1206 * returns the children in the administrative hierarchy of a toponym. With 1207 * default maxRows. 1208 * 1209 * @param geonameId 1210 * @param language 1211 * @param style 1212 * @return 1213 * @throws Exception 1214 */ 1215 public static ToponymSearchResult children(int geonameId, String language, Style style) throws Exception { 1216 return children(geonameId, language, style, 0); 1217 } 1218 1219 /** 1220 * 1221 * @param geonameId 1222 * @param language 1223 * @param style 1224 * @param maxRows 1225 * @return 1226 * @throws Exception 1227 */ 1228 public static ToponymSearchResult children(int geonameId, String language, Style style, int maxRows) 1229 throws Exception { 1230 1231 ToponymSearchResult searchResult = new ToponymSearchResult(); 1232 1233 String url = "/children?"; 1234 1235 url = url + "geonameId=" + geonameId; 1236 1237 if (language != null) { 1238 url = url + "&lang=" + language; 1239 } 1240 if (maxRows != 0) { 1241 url += "&maxRows=" + maxRows; 1242 } 1243 1244 if (style != null) { 1245 url = url + "&style=" + style; 1246 } else { 1247 url = addDefaultStyle(url); 1248 } 1249 url = addUserName(url); 1250 1251 Element root = connectAndParse(url); 1252 searchResult.totalResultsCount = Integer.parseInt(root.getChildText("totalResultsCount")); 1253 searchResult.setStyle(Style.valueOf(root.getAttributeValue("style"))); 1254 1255 for (Object obj : root.getChildren("geoname")) { 1256 Element toponymElement = (Element) obj; 1257 Toponym toponym = getToponymFromElement(toponymElement); 1258 searchResult.toponyms.add(toponym); 1259 } 1260 1261 return searchResult; 1262 } 1263 1264 /** 1265 * returns the neighbours of a toponym. 1266 * 1267 * @param geonameId 1268 * @param language 1269 * @param style 1270 * @return 1271 * @throws Exception 1272 */ 1273 public static ToponymSearchResult neighbours(int geonameId, String language, Style style) throws Exception { 1274 ToponymSearchResult searchResult = new ToponymSearchResult(); 1275 1276 String url = "/neighbours?"; 1277 1278 url = url + "geonameId=" + geonameId; 1279 1280 if (language != null) { 1281 url = url + "&lang=" + language; 1282 } 1283 1284 if (style != null) { 1285 url = url + "&style=" + style; 1286 } else { 1287 url = addDefaultStyle(url); 1288 } 1289 url = addUserName(url); 1290 1291 Element root = connectAndParse(url); 1292 searchResult.totalResultsCount = Integer.parseInt(root.getChildText("totalResultsCount")); 1293 searchResult.setStyle(Style.valueOf(root.getAttributeValue("style"))); 1294 1295 for (Object obj : root.getChildren("geoname")) { 1296 Element toponymElement = (Element) obj; 1297 Toponym toponym = getToponymFromElement(toponymElement); 1298 searchResult.toponyms.add(toponym); 1299 } 1300 1301 return searchResult; 1302 } 1303 1304 /** 1305 * returns the hierarchy for a geonameId 1306 * 1307 * @see <a href= 1308 * "http://www.geonames.org/export/place-hierarchy.html#hierarchy">Hierarchy 1309 * service description</a> 1310 * 1311 * @param geonameId 1312 * @param language 1313 * @param style 1314 * @return 1315 * @throws Exception 1316 */ 1317 public static List<Toponym> hierarchy(int geonameId, String language, Style style) throws Exception { 1318 1319 String url = "/hierarchy?"; 1320 1321 url = url + "geonameId=" + geonameId; 1322 1323 if (language != null) { 1324 url = url + "&lang=" + language; 1325 } 1326 1327 if (style != null) { 1328 url = url + "&style=" + style; 1329 } else { 1330 url = addDefaultStyle(url); 1331 } 1332 url = addUserName(url); 1333 1334 Element root = connectAndParse(url); 1335 List<Toponym> toponyms = new ArrayList<Toponym>(); 1336 for (Object obj : root.getChildren("geoname")) { 1337 Element toponymElement = (Element) obj; 1338 Toponym toponym = getToponymFromElement(toponymElement); 1339 toponyms.add(toponym); 1340 } 1341 1342 return toponyms; 1343 } 1344 1345 public static void saveTags(String[] tags, Toponym toponym, String username, String password) throws Exception { 1346 if (toponym.getGeoNameId() == 0) { 1347 throw new Error("no geonameid specified"); 1348 } 1349 1350 // FIXME proper url 1351 String url = "/servlet/geonames?srv=61"; 1352 1353 url = url + "&geonameId=" + toponym.getGeoNameId(); 1354 url = addUserName(url); 1355 1356 StringBuilder tagsCommaseparated = new StringBuilder(); 1357 for (String tag : tags) { 1358 tagsCommaseparated.append(tag + ","); 1359 } 1360 url = url + "&tag=" + tagsCommaseparated; 1361 1362 Element root = connectAndParse(url); 1363 } 1364 1365 /** 1366 * full text search on geolocated wikipedia articles. 1367 * 1368 * @param q 1369 * @param language 1370 * @return 1371 * @throws Exception 1372 */ 1373 public static List<WikipediaArticle> wikipediaSearch(String q, String language) throws Exception { 1374 List<WikipediaArticle> articles = new ArrayList<WikipediaArticle>(); 1375 1376 String url = "/wikipediaSearch?"; 1377 1378 url = url + "q=" + URLEncoder.encode(q, "UTF8"); 1379 1380 if (language != null) { 1381 url = url + "&lang=" + language; 1382 } 1383 url = addUserName(url); 1384 1385 Element root = connectAndParse(url); 1386 for (Object obj : root.getChildren("entry")) { 1387 Element wikipediaArticleElement = (Element) obj; 1388 WikipediaArticle wikipediaArticle = getWikipediaArticleFromElement(wikipediaArticleElement); 1389 articles.add(wikipediaArticle); 1390 } 1391 1392 return articles; 1393 } 1394 1395 /** 1396 * full text search on geolocated wikipedia articles. 1397 * 1398 * @param title 1399 * @param language 1400 * @return 1401 * @throws Exception 1402 */ 1403 public static List<WikipediaArticle> wikipediaSearchForTitle(String title, String language) throws Exception { 1404 List<WikipediaArticle> articles = new ArrayList<WikipediaArticle>(); 1405 1406 String url = "/wikipediaSearch?"; 1407 1408 url = url + "title=" + URLEncoder.encode(title, "UTF8"); 1409 1410 if (language != null) { 1411 url = url + "&lang=" + language; 1412 } 1413 url = addUserName(url); 1414 1415 Element root = connectAndParse(url); 1416 for (Object obj : root.getChildren("entry")) { 1417 Element wikipediaArticleElement = (Element) obj; 1418 WikipediaArticle wikipediaArticle = getWikipediaArticleFromElement(wikipediaArticleElement); 1419 articles.add(wikipediaArticle); 1420 } 1421 1422 return articles; 1423 } 1424 1425 public static List<WikipediaArticle> findNearbyWikipedia(double latitude, double longitude, String language) 1426 throws Exception { 1427 return findNearbyWikipedia(latitude, longitude, 0, language, 0); 1428 } 1429 1430 /* Overload function to allow backward compatibility */ 1431 /** 1432 * Based on the following inform: Webservice Type : REST 1433 * api.geonames.org/findNearbyWikipedia? Parameters : lang : language code 1434 * (around 240 languages) (default = en) lat,lng, radius (in km), maxRows 1435 * (default = 5) Example: 1436 * http://api.geonames.org/findNearbyWikipedia?lat=47&lng=9 1437 * 1438 * @param: latitude 1439 * @param: longitude 1440 * @param: radius 1441 * @param: language 1442 * @param: maxRows 1443 * @return: list of wikipedia articles 1444 * @throws: Exception 1445 */ 1446 public static List<WikipediaArticle> findNearbyWikipedia(double latitude, double longitude, double radius, 1447 String language, int maxRows) throws Exception { 1448 1449 List<WikipediaArticle> articles = new ArrayList<WikipediaArticle>(); 1450 1451 String url = "/findNearbyWikipedia?"; 1452 1453 url = url + "lat=" + latitude; 1454 url = url + "&lng=" + longitude; 1455 if (radius > 0) { 1456 url = url + "&radius=" + radius; 1457 } 1458 if (maxRows > 0) { 1459 url = url + "&maxRows=" + maxRows; 1460 } 1461 1462 if (language != null) { 1463 url = url + "&lang=" + language; 1464 } 1465 url = addUserName(url); 1466 1467 Element root = connectAndParse(url); 1468 for (Object obj : root.getChildren("entry")) { 1469 Element wikipediaArticleElement = (Element) obj; 1470 WikipediaArticle wikipediaArticle = getWikipediaArticleFromElement(wikipediaArticleElement); 1471 articles.add(wikipediaArticle); 1472 } 1473 1474 return articles; 1475 } 1476 1477 /** 1478 * GTOPO30 is a global digital elevation model (DEM) with a horizontal grid 1479 * spacing of 30 arc seconds (approximately 1 kilometer). GTOPO30 was derived 1480 * from several raster and vector sources of topographic information. 1481 * 1482 * @param latitude 1483 * @param longitude 1484 * @return a single number giving the elevation in meters according to gtopo30, 1485 * ocean areas have been masked as "no data" and have been assigned a 1486 * value of -9999 1487 * @throws IOException 1488 * @throws GeoNamesException 1489 */ 1490 public static int gtopo30(double latitude, double longitude) throws IOException, GeoNamesException { 1491 String url = "/gtopo30?lat=" + latitude + "&lng=" + longitude; 1492 url = addUserName(url); 1493 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1494 String gtopo30 = in.readLine(); 1495 in.close(); 1496 checkException(gtopo30); 1497 return Integer.parseInt(gtopo30); 1498 } 1499 1500 /** 1501 * Shuttle Radar Topography Mission (SRTM) elevation data. SRTM consisted of a 1502 * specially modified radar system that flew onboard the Space Shuttle Endeavour 1503 * during an 11-day mission in February of 2000. The dataset covers land areas 1504 * between 60 degrees north and 56 degrees south. This web service is using 1505 * SRTM3 data with data points located every 3-arc-second (approximately 90 1506 * meters) on a latitude/longitude grid. 1507 * 1508 * @param latitude 1509 * @param longitude 1510 * @return elevation or -32768 if unknown 1511 * @throws IOException 1512 * @throws GeoNamesException 1513 */ 1514 public static int srtm3(double latitude, double longitude) throws IOException, GeoNamesException { 1515 String url = "/srtm3?lat=" + latitude + "&lng=" + longitude; 1516 url = addUserName(url); 1517 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1518 String srtm3 = in.readLine(); 1519 in.close(); 1520 checkException(srtm3); 1521 return Integer.parseInt(srtm3); 1522 } 1523 1524 public static int[] srtm3(double[] latitude, double[] longitude) throws IOException { 1525 if (latitude.length != longitude.length) { 1526 throw new Error("number of lats and longs must be equal"); 1527 } 1528 int[] elevation = new int[latitude.length]; 1529 String lats = ""; 1530 String lngs = ""; 1531 for (int i = 0; i < elevation.length; i++) { 1532 lats += latitude[i] + ","; 1533 lngs += longitude[i] + ","; 1534 } 1535 String url = "/srtm3?lats=" + lats + "&lngs=" + lngs; 1536 url = addUserName(url); 1537 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1538 for (int i = 0; i < elevation.length; i++) { 1539 String srtm3 = in.readLine(); 1540 elevation[i] = Integer.parseInt(srtm3); 1541 } 1542 in.close(); 1543 return elevation; 1544 } 1545 1546 public static int srtm1(double latitude, double longitude) throws IOException, GeoNamesException { 1547 String url = "/srtm1?lat=" + latitude + "&lng=" + longitude; 1548 url = addUserName(url); 1549 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1550 String srtm1 = in.readLine(); 1551 in.close(); 1552 checkException(srtm1); 1553 return Integer.parseInt(srtm1); 1554 } 1555 1556 public static int[] srtm1(double[] latitude, double[] longitude) throws IOException { 1557 if (latitude.length != longitude.length) { 1558 throw new Error("number of lats and longs must be equal"); 1559 } 1560 int[] elevation = new int[latitude.length]; 1561 String lats = ""; 1562 String lngs = ""; 1563 for (int i = 0; i < elevation.length; i++) { 1564 lats += latitude[i] + ","; 1565 lngs += longitude[i] + ","; 1566 } 1567 String url = "/srtm1?lats=" + lats + "&lngs=" + lngs; 1568 url = addUserName(url); 1569 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1570 for (int i = 0; i < elevation.length; i++) { 1571 String srtm1 = in.readLine(); 1572 elevation[i] = Integer.parseInt(srtm1); 1573 } 1574 in.close(); 1575 return elevation; 1576 } 1577 1578 public static int astergdem(double latitude, double longitude) throws IOException, GeoNamesException { 1579 String url = "/astergdem?lat=" + latitude + "&lng=" + longitude; 1580 url = addUserName(url); 1581 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1582 String astergdem = in.readLine(); 1583 in.close(); 1584 checkException(astergdem); 1585 return Integer.parseInt(astergdem); 1586 } 1587 1588 public static int[] astergdem(double[] latitude, double[] longitude) throws IOException { 1589 if (latitude.length != longitude.length) { 1590 throw new Error("number of lats and longs must be equal"); 1591 } 1592 int[] elevation = new int[latitude.length]; 1593 String lats = ""; 1594 String lngs = ""; 1595 for (int i = 0; i < elevation.length; i++) { 1596 lats += latitude[i] + ","; 1597 lngs += longitude[i] + ","; 1598 } 1599 String url = "/astergdem?lats=" + lats + "&lngs=" + lngs; 1600 url = addUserName(url); 1601 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1602 for (int i = 0; i < elevation.length; i++) { 1603 String astergdem = in.readLine(); 1604 elevation[i] = Integer.parseInt(astergdem); 1605 } 1606 in.close(); 1607 return elevation; 1608 } 1609 1610 /** 1611 * The iso country code of any given point. It is calling 1612 * {@link #countryCode(double, double, double)} with radius=0.0 1613 * 1614 * @param latitude 1615 * @param longitude 1616 * @return 1617 * @throws IOException 1618 * @throws GeoNamesException 1619 */ 1620 public static String countryCode(double latitude, double longitude) throws IOException, GeoNamesException { 1621 return countryCode(latitude, longitude, 0); 1622 } 1623 1624 /** 1625 * The iso country code of any given point with radius for coastal areas. 1626 * 1627 * @param latitude 1628 * @param longitude 1629 * @param radius (optional) 1630 * 1631 * @return iso country code for the given latitude/longitude 1632 * @throws IOException 1633 * @throws GeoNamesException 1634 */ 1635 public static String countryCode(double latitude, double longitude, double radius) 1636 throws IOException, GeoNamesException { 1637 String url = "/countryCode?lat=" + latitude + "&lng=" + longitude; 1638 if (radius != 0) { 1639 url += "&radius=" + radius; 1640 } 1641 url = addUserName(url); 1642 BufferedReader in = new BufferedReader(new InputStreamReader(connect(url))); 1643 String cc = in.readLine(); 1644 in.close(); 1645 if (cc != null && cc.length() == 2) { 1646 return cc; 1647 } 1648 if (cc == null || cc.length() == 0) { 1649 // nothing found return null 1650 return null; 1651 } 1652 // check whether we can parse an exception and throw it if we can 1653 checkException(cc); 1654 // something else was wrong, through generic exception 1655 throw new GeoNamesException("unhandled exception"); 1656 } 1657 1658 /** 1659 * 1660 * @param latitude 1661 * @param longitude 1662 * @param radius (optional) 1663 * @param level (optional) 1664 * @param lang (optional) 1665 * @return 1666 * @throws IOException 1667 * @throws Exception 1668 */ 1669 public static CountrySubdivision countrySubdivision(double latitude, double longitude, double radius, int level, String lang) 1670 throws IOException, Exception { 1671 String url = "/countrySubdivision?lat=" + latitude + "&lng=" + longitude; 1672 if (radius != 0) { 1673 url += "&radius=" + radius; 1674 } 1675 if (level != 0) { 1676 url += "&level=" + level; 1677 } 1678 if (lang!=null) { 1679 url += "&lang=" + level; 1680 } 1681 url = addUserName(url); 1682 Element root = connectAndParse(url); 1683 for (Object obj : root.getChildren("countrySubdivision")) { 1684 Element codeElement = (Element) obj; 1685 CountrySubdivision countrySubdivision = new CountrySubdivision(); 1686 1687 countrySubdivision.setCountryCode(codeElement.getChildText("countryCode")); 1688 countrySubdivision.setCountryName(codeElement.getChildText("countryName")); 1689 1690 countrySubdivision.setAdminName1(codeElement.getChildText("adminName1")); 1691 countrySubdivision.setAdminCode1(codeElement.getChildText("adminCode1")); 1692 countrySubdivision.setAdminName2(codeElement.getChildText("adminName2")); 1693 countrySubdivision.setAdminCode2(codeElement.getChildText("adminCode2")); 1694 countrySubdivision.setAdminName3(codeElement.getChildText("adminName3")); 1695 countrySubdivision.setAdminCode3(codeElement.getChildText("adminCode3")); 1696 countrySubdivision.setAdminName4(codeElement.getChildText("adminName4")); 1697 countrySubdivision.setAdminCode4(codeElement.getChildText("adminCode4")); 1698 countrySubdivision.setAdminName5(codeElement.getChildText("adminName5")); 1699 countrySubdivision.setAdminCode5(codeElement.getChildText("adminCode5")); 1700 1701 countrySubdivision.setDistance(Double.parseDouble(codeElement.getChildText("distance"))); 1702 1703 return countrySubdivision; 1704 } 1705 1706 return null; 1707 } 1708 1709 /** 1710 * get the timezone for a given location 1711 * 1712 * @param latitude 1713 * @param longitude 1714 * @return timezone at the given location 1715 * @throws IOException 1716 * @throws Exception 1717 */ 1718 public static Timezone timezone(double latitude, double longitude) throws IOException, Exception { 1719 1720 String url = "/timezone?"; 1721 double radius = 0; 1722 1723 url = url + "&lat=" + latitude; 1724 url = url + "&lng=" + longitude; 1725 if (radius > 0) { 1726 url = url + "&radius=" + radius; 1727 } 1728 url = addUserName(url); 1729 1730 Element root = connectAndParse(url); 1731 for (Object obj : root.getChildren("timezone")) { 1732 Element codeElement = (Element) obj; 1733 Timezone timezone = new Timezone(); 1734 timezone.setTimezoneId(codeElement.getChildText("timezoneId")); 1735 timezone.setCountryCode(codeElement.getChildText("countryCode")); 1736 1737 if (codeElement.getChildText("time") != null) { 1738 String minuteDateFmt = "yyyy-MM-dd HH:mm"; 1739 SimpleDateFormat df = null; 1740 if (codeElement.getChildText("time").length() == minuteDateFmt.length()) { 1741 df = new SimpleDateFormat(minuteDateFmt); 1742 } else { 1743 df = new SimpleDateFormat(DATEFMT); 1744 } 1745 timezone.setTime(df.parse(codeElement.getChildText("time"))); 1746 if (codeElement.getChildText("sunrise") != null) { 1747 timezone.setSunrise(df.parse(codeElement.getChildText("sunrise"))); 1748 } 1749 if (codeElement.getChildText("sunset") != null) { 1750 timezone.setSunset(df.parse(codeElement.getChildText("sunset"))); 1751 } 1752 timezone.setGmtOffset(Double.parseDouble(codeElement.getChildText("gmtOffset"))); 1753 timezone.setDstOffset(Double.parseDouble(codeElement.getChildText("dstOffset"))); 1754 } 1755 return timezone; 1756 } 1757 1758 return null; 1759 } 1760 1761 // FIXME implement and test 1762 public static String ocean(double latitude, double longitude) throws IOException, Exception { 1763 1764 String url = "/ocean?"; 1765 double radius = 0; 1766 1767 url = url + "&lat=" + latitude; 1768 url = url + "&lng=" + longitude; 1769 if (radius > 0) { 1770 url = url + "&radius=" + radius; 1771 } 1772 url = addUserName(url); 1773 1774 Element root = connectAndParse(url); 1775 for (Object obj : root.getChildren("ocean")) { 1776 Element oceanElement = (Element) obj; 1777 if (oceanElement != null) { 1778 return oceanElement.getChildText("name"); 1779 } 1780 } 1781 1782 return null; 1783 } 1784 1785 /** 1786 * 1787 * @param latitude 1788 * @param longitude 1789 * @return 1790 * @throws IOException 1791 * @throws Exception 1792 */ 1793 public static WeatherObservation findNearByWeather(double latitude, double longitude) 1794 throws IOException, Exception { 1795 1796 String url = "/findNearByWeatherXML?"; 1797 1798 url = url + "&lat=" + latitude; 1799 url = url + "&lng=" + longitude; 1800 url = addUserName(url); 1801 1802 Element root = connectAndParse(url); 1803 for (Object obj : root.getChildren("observation")) { 1804 Element weatherObservationElement = (Element) obj; 1805 WeatherObservation weatherObservation = getWeatherObservationFromElement(weatherObservationElement); 1806 return weatherObservation; 1807 } 1808 1809 return null; 1810 } 1811 1812 public static WeatherObservation weatherIcao(String icaoCode) throws IOException, Exception { 1813 1814 String url = "/weatherIcaoXML?"; 1815 1816 url = url + "&ICAO=" + icaoCode; 1817 url = addUserName(url); 1818 1819 Element root = connectAndParse(url); 1820 for (Object obj : root.getChildren("observation")) { 1821 Element weatherObservationElement = (Element) obj; 1822 WeatherObservation weatherObservation = getWeatherObservationFromElement(weatherObservationElement); 1823 return weatherObservation; 1824 } 1825 1826 return null; 1827 } 1828 1829 /** 1830 * @return the geoNamesServer, default is http://api.geonames.org 1831 */ 1832 public static String getGeoNamesServer() { 1833 return geoNamesServer; 1834 } 1835 1836 /** 1837 * @return the geoNamesServerFailover 1838 */ 1839 public static String getGeoNamesServerFailover() { 1840 return geoNamesServerFailover; 1841 } 1842 1843 /** 1844 * sets the server name for the GeoNames server to be used for the requests. 1845 * Default is api.geonames.org 1846 * 1847 * @param geoNamesServer the geonamesServer to set 1848 */ 1849 public static void setGeoNamesServer(String pGeoNamesServer) { 1850 if (pGeoNamesServer == null) { 1851 throw new Error(); 1852 } 1853 pGeoNamesServer = pGeoNamesServer.trim().toLowerCase(); 1854 // add default http protocol if it is missing 1855 if (!pGeoNamesServer.startsWith("http://") && !pGeoNamesServer.startsWith("https://")) { 1856 pGeoNamesServer = "http://" + pGeoNamesServer; 1857 } 1858 WebService.geoNamesServer = pGeoNamesServer; 1859 } 1860 1861 /** 1862 * sets the default failover server for requests in case the main server is not 1863 * accessible. Default is api.geonames.org<br> 1864 * The failover server is only called if it is different from the main 1865 * server.<br> 1866 * The failover server is used for commercial GeoNames web service users. 1867 * 1868 * @param geoNamesServerFailover the geoNamesServerFailover to set 1869 */ 1870 public static void setGeoNamesServerFailover(String geoNamesServerFailover) { 1871 if (geoNamesServerFailover != null) { 1872 geoNamesServerFailover = geoNamesServerFailover.trim().toLowerCase(); 1873 if (!geoNamesServerFailover.startsWith("http://") && !geoNamesServerFailover.startsWith("https://")) { 1874 geoNamesServerFailover = "http://" + geoNamesServerFailover; 1875 } 1876 } 1877 WebService.geoNamesServerFailover = geoNamesServerFailover; 1878 } 1879 1880 /** 1881 * @return the proxy 1882 */ 1883 public static Proxy getProxy() { 1884 return proxy; 1885 } 1886 1887 /** 1888 * @param proxy the proxy to set 1889 * 1890 * If you are behind a proxy and cannot change the java system 1891 * properties, you can use this method to set a proxy. You define 1892 * it like this: 1893 * 1894 * <pre> 1895 * <code> 1896 * java.net.SocketAddress sa = new java.net.InetSocketAddress("myproxyserver", 8080); 1897 * java.net.Proxy proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, sa); 1898 * </code> 1899 * </pre> 1900 */ 1901 public static void setProxy(Proxy proxy) { 1902 WebService.proxy = proxy; 1903 } 1904 1905 /** 1906 * @return the userName 1907 */ 1908 public static String getUserName() { 1909 return userName; 1910 } 1911 1912 /** 1913 * Sets the user name to be used for the requests. Needed to access the 1914 * commercial GeoNames web services. 1915 * 1916 * @param userName the userName to set 1917 */ 1918 public static void setUserName(String userName) { 1919 WebService.userName = userName; 1920 } 1921 1922 /** 1923 * @return the token 1924 */ 1925 public static String getToken() { 1926 return token; 1927 } 1928 1929 /** 1930 * sets the token to be used to authenticate the requests. This is an optional 1931 * parameter for the commercial version of the GeoNames web services. 1932 * 1933 * @param token the token to set 1934 */ 1935 public static void setToken(String token) { 1936 WebService.token = token; 1937 } 1938 1939 /** 1940 * @return the defaultStyle 1941 */ 1942 public static Style getDefaultStyle() { 1943 return defaultStyle; 1944 } 1945 1946 /** 1947 * @param defaultStyle the defaultStyle to set 1948 */ 1949 public static void setDefaultStyle(Style defaultStyle) { 1950 WebService.defaultStyle = defaultStyle; 1951 } 1952 1953 /** 1954 * @return the readTimeOut 1955 */ 1956 public static int getReadTimeOut() { 1957 return readTimeOut; 1958 } 1959 1960 /** 1961 * @param readTimeOut the readTimeOut to set 1962 */ 1963 public static void setReadTimeOut(int readTimeOut) { 1964 WebService.readTimeOut = readTimeOut; 1965 } 1966 1967 /** 1968 * @return the connectTimeOut 1969 */ 1970 public static int getConnectTimeOut() { 1971 return connectTimeOut; 1972 } 1973 1974 /** 1975 * @param connectTimeOut the connectTimeOut to set 1976 */ 1977 public static void setConnectTimeOut(int connectTimeOut) { 1978 WebService.connectTimeOut = connectTimeOut; 1979 } 1980 1981}