All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.tidalwave.geo.geocoding.geonamesprovider.GeoNames Maven / Gradle / Ivy

/***********************************************************************************************************************
 *
 * forceTen - open source geography
 * Copyright (C) 2007-2012 by Tidalwave s.a.s. (http://www.tidalwave.it)
 *
 ***********************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 *
 ***********************************************************************************************************************
 *
 * WWW: http://forceten.tidalwave.it
 * SCM: https://bitbucket.org/tidalwave/forceten-src
 *
 **********************************************************************************************************************/
package it.tidalwave.geo.geocoding.geonamesprovider;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import it.tidalwave.util.logging.Logger;
import it.tidalwave.netbeans.util.Locator;
import it.tidalwave.netbeans.workspacemanager.WorkspaceManager;
import org.apache.commons.io.FileUtils;

/***********************************************************************************************************************
 *
 * @author  Fabrizio Giudici
 * @version $Id$
 *
 **********************************************************************************************************************/
final class GeoNames
  {
    private static final String CLASS = GeoNames.class.getName();
    private static final Logger logger = Logger.getLogger(CLASS);

    private static final File cacheFolder;

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    static
      {
        try
          {
            File folder = null;

            try
              {
                final WorkspaceManager workspaceManager = Locator.find(WorkspaceManager.class);
                folder = workspaceManager.getCacheFolder("GeoData/GeoNames");
              }
            catch (RuntimeException e)
              {
                folder = new File(System.getProperty("java.io.tmpdir"));
                folder = new File(folder, "GeoData/GeoNames");
                logger.warning("Can't find WorkspaceManager: using %s as cache folder", folder.getAbsolutePath());
                logger.throwing("static", CLASS, e);
              }

            cacheFolder = folder;

            if (!cacheFolder.mkdirs() && (!cacheFolder.exists() || !cacheFolder.isDirectory()))
              {
                throw new IOException("Can't create cache folder: " + cacheFolder);
              }
          }
        catch (Exception e)
          {
            throw new ExceptionInInitializerError(e);
          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    public static Document retrieveDocument (final @Nonnull String command, final @Nonnull Object... args)
      {
        InputStream is = null;
        URL url = null;

        try
          {
            logger.finer("retrieveDocument(%s, %s)", command, Arrays.toString(args));
            url = createURL(args, command);
            logger.finest(">>>> url: %s", url);
            is = openCachedStream(url);
            final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            final DocumentBuilder docBuilder = factory.newDocumentBuilder();
            final Document document = docBuilder.parse(is);
            
            // TODO: if contains a geonames/status, it's an error message -> throw new IOException
            return document;
          }
        catch (RuntimeException e)
          {
            throw e;
          }
        catch (Exception e)
          {
            logger.throwing(CLASS, "retrieveDocument()", e);
            logger.warning("Cannot retrieve document: %s", url);
            throw new RuntimeException(e);
          }
        finally
          {
            IOUtils.closeQuietly(is);
          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @CheckForNull
    public static Icon retrieveIcon (final @Nonnull URL url)
      {
        InputStream is = null;

        try
          {
            logger.finer("retrieveIcon(%s)", url);
            is = openCachedStream(url);
            return new ImageIcon(IOUtils.toByteArray(is));
          }
        catch (FileNotFoundException e)
          {
            return null;
          }
        catch (Exception e)
          {
            logger.throwing(CLASS, "retrieveDocument()", e);
            logger.warning("Cannot retrieve document: %s", url);
            throw new RuntimeException(e);
          }
        finally
          {
            IOUtils.closeQuietly(is);
          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    public static String retrieveString (final @Nonnull String command, final @Nonnull Object... args)
      {
        BufferedReader br = null;

        try
          {
            logger.finer("retrieveString(%s, %s)", command, Arrays.toString(args));
            final URL url = createURL(args, command);
            logger.finest(">>>> url: %s", url);
            br = new BufferedReader(new InputStreamReader(openCachedStream(url)));
            final String result = br.readLine();
            assert result != null : "Read null for " + url;
            return result;
          }
        catch (RuntimeException e)
          {
            throw e;
          }
        catch (Exception e)
          {
            logger.throwing(CLASS, "retrieveString()", e);
            logger.warning("Cannot retrieve string");
            throw new RuntimeException(e);
          }
        finally
          {
            IOUtils.closeQuietly(br);
          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public static void clearCache()
      throws IOException
      {
        FileUtils.cleanDirectory(cacheFolder);
        //        final File[] cachedFiles = cacheFolder.listFiles();
        //
        //        if (cachedFiles != null)
        //          {
        //            for (final File file : cachedFiles)
        //              {
        //                file.delete();
        //              }
        //          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private static URL createURL (final @Nonnull Object[] args, final @Nonnull String command)
      throws MalformedURLException
      {
        final StringBuilder builder = new StringBuilder();
        builder.append("http://ws.geonames.org/");
        builder.append(command);
        builder.append("?");

        for (int i = 0; i < args.length; i += 2)
          {
            builder.append(args[i]);
            builder.append("=");
            builder.append(args[i + 1].toString());
            builder.append("&");
          }

        final URL url = new URL(builder.toString());
        return url;
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private static String cleaned (final @Nonnull URL url)
      {
        final StringBuilder builder = new StringBuilder();
        final String urlString = url.toExternalForm();

        for (int i = 0; i < urlString.length(); i++)
          {
            char ch = urlString.charAt(i);

            if (!Character.isLetterOrDigit(ch))
              {
                ch = '_';
              }

            builder.append(ch);
          }

        return builder.toString();
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private static InputStream openCachedStream (final @Nonnull URL url)
      throws IOException
      {
        logger.finer("openCachedStream(%s)", url);
        final File cache = new File(cacheFolder, cleaned(url));

        // TODO: the correct logic is: 1) try the file 2) use the file if not older than one day 3) otherwise try to get the
        // network timestamp 4) if network is more recent, use it 5) if network fails use the file
        if (cache.exists())
          {
            logger.finest(">>>>  cached: %s", cache);
            return new FileInputStream(cache);
          }
        else
          {
            logger.finest(">>>> not cached, retrieving: %s", cache);
            final InputStream is = url.openStream();
            final OutputStream os = new FileOutputStream(cache);

            return new InputStream()
              {
                @Override
                public int read()
                  throws IOException
                  {
                    int r = is.read();

                    if (r >= 0)
                      {
                        os.write(r);
                      }

                    return r;
                  }

                //TODO: override also read(byte[], int, int)

                @Override
                public void close()
                  throws IOException
                  {
                    try
                      {
                        os.close();
                      }
                    catch (IOException e)
                      {
                        e.printStackTrace();
                      }
                    is.close();
                  }
              };
          }
      }
  }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy