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

it.tidalwave.bluebill.taxonomy.mobile.impl.SimpleTaxonomyManager Maven / Gradle / Ivy

The newest version!
/***********************************************************************************************************************
 *
 * blueBill Mobile - Android - open source birding
 * Copyright (C) 2009-2011 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://bluebill.tidalwave.it/mobile
 * SCM: https://java.net/hg/bluebill-mobile~android-src
 *
 **********************************************************************************************************************/
package it.tidalwave.bluebill.taxonomy.mobile.impl;

import it.tidalwave.bluebill.taxonomy.mobile.TaxonomyFinder;
import java.io.InputStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.text.Collator;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.io.BufferedReader;
import java.io.Reader;
import org.json.me.JSONArray;
import org.json.me.JSONException;
import org.json.me.JSONObject;
import it.tidalwave.util.Id;
import it.tidalwave.bluebill.taxonomy.mobile.Taxon;
import it.tidalwave.bluebill.taxonomy.mobile.Taxonomy;
import it.tidalwave.bluebill.taxonomy.mobile.Taxon.Rank;
import it.tidalwave.bluebill.taxonomy.mobile.TaxonomyManager;
import it.tidalwave.bluebill.taxonomy.mobile.impl.io.TaxonomyUnmarshallerFactory;
import it.tidalwave.role.spi.DefaultDisplayable;
import it.tidalwave.role.spi.DefaultIdentifiable;
import it.tidalwave.semantic.Type;
import it.tidalwave.semantic.io.GraphDeserializer;
import it.tidalwave.semantic.io.GraphUnmarshaller;
import it.tidalwave.semantic.io.MimeTypes;
import it.tidalwave.semantic.io.impl.DefaultGraphDeserializer;
import it.tidalwave.semantic.io.impl.GraphUnmarshallerImpl;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import lombok.Cleanup;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.openrdf.model.Graph;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFParseException;

/***********************************************************************************************************************
 *
 * @author  Fabrizio Giudici
 * @version $Id$
 *
 **********************************************************************************************************************/
@RequiredArgsConstructor @Slf4j
public class SimpleTaxonomyManager implements TaxonomyManager 
  {
    // FIXME: use a vocabulary
    private static final Type TYPE_TAXONOMY = new Type("http://bluebill.tidalwave.it/rdf/taxo/2010/08/28#TaxonomyScheme");
    
    private static final Map NAME_MAP_BY_RANK = new HashMap();

    /* package */ static final SortedMap LOCALE_MAP_BY_CODE = new TreeMap();

    private final Map> nameBagsByLanguage = new HashMap>();

    private final List taxonomies = new ArrayList();
    
    private final String resourceBasePath;

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    static
      {
        NAME_MAP_BY_RANK.put(Rank.CLASS, "Class");
        NAME_MAP_BY_RANK.put(Rank.ORDER, "Order");
        NAME_MAP_BY_RANK.put(Rank.FAMILY, "Family");
        NAME_MAP_BY_RANK.put(Rank.GENUS, "Genus");
        NAME_MAP_BY_RANK.put(Rank.SPECIES, "Species");
        NAME_MAP_BY_RANK.put(Rank.SUBSPECIES, "Subspecies");

        final String[] languageCodes = { "af", "en", "en_us", "it", "de", "da", "no", "fi", "sv", "fr", "fr_ca", "es", "nl" };

        for (final String languageCode : languageCodes)
          {
            LOCALE_MAP_BY_CODE.put(languageCode, new Locale(languageCode));
          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    private final Comparator taxonComparator = new Comparator()
      {
        final Collator collator = Collator.getInstance();

        public int compare (final @Nonnull Taxon taxon1, final @Nonnull Taxon taxon2)
          {
            return collator.compare(taxon1.getScientificName(), taxon2.getScientificName());
          }
      };

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public SimpleTaxonomyManager()
      {
        this("");   
      }
    
    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public TaxonomyFinder findTaxonomies() 
      {
        log.info("findTaxonomies()");
        
        return new SimpleTaxonomyFinderSupport() 
          {
            @Override @Nonnull
            protected List computeResults()
              {
                if (id != null)
                  {
                    try  
                      {
                        return Collections.singletonList(loadTaxonomy(id));
                      }
                    catch (Exception e) 
                      {
                        throw new RuntimeException(e);
                      }
                  }
                        
                else
                  {
                    return loadTaxonomies();  
                  }
              }
          };
      }
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private List loadTaxonomies() 
      {
        if (taxonomies.isEmpty())
          {
            try
              {
                final GraphDeserializer deserializer = new DefaultGraphDeserializer();
                @Cleanup final InputStream is = openResourceStream(getResourcePath("taxonomies.n3"));
                final Graph graph = deserializer.read(is, MimeTypes.MIME_N3);
                is.close();

                final GraphUnmarshaller unmarshaller = new GraphUnmarshallerImpl();
                unmarshaller.registerStatementUnmarshallerFactory(new TaxonomyUnmarshallerFactory());
                final List t = unmarshaller.unmarshalAll(graph, TYPE_TAXONOMY);
                taxonomies.addAll(t);
              }
            catch (RDFParseException e)
              {
                throw new RuntimeException(e);  
              } 
            catch (RDFHandlerException e)
              {
                throw new RuntimeException(e);  
              } 
            catch (IOException e)
              {
                throw new RuntimeException(e);  
              } 
          }

        return taxonomies;
      }
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private Taxonomy loadTaxonomy (final @Nonnull Id id)
      throws Exception
      {
        log.info("loadTaxonomy({})", id);
 
        final String resourceName = id.stringValue().replaceAll("[:/]", "_");
        @Cleanup final Reader r = new InputStreamReader(openResourceStream(getResourcePath(resourceName + ".json")), "UTF-8");        
        final BufferedReader br = new BufferedReader(r);
        final StringBuilder builder = new StringBuilder();

        for (;;)
          {
            final String line = br.readLine();

            if (line == null)
              {
                break;
              }

            builder.append(line);
          }

        r.close();
        
        final String string = builder.toString();
        final JSONObject rootObject = new JSONObject(string);
        final JSONObject jsonTaxonomy = rootObject.getJSONObject("Taxonomy");
        final SimpleTaxonomy taxonomy = new SimpleTaxonomy(new DefaultIdentifiable(id), new DefaultDisplayable(jsonTaxonomy.getString("name")));
        scan(taxonomy, null, jsonTaxonomy, 0);

        final Set ranks = new HashSet(taxonomy.taxonListMapByRank.keySet());
        ranks.remove(Rank.SPECIES);
        ranks.remove(Rank.SUBSPECIES);

        for (final Rank rank : ranks)
          {
            final List taxa = taxonomy.taxonListMapByRank.get(rank);
            Collections.sort(taxa, taxonComparator);
          }

        log.info(">>>> languages: {}", nameBagsByLanguage.keySet());
        
        for (final Entry> entry : nameBagsByLanguage.entrySet())
          {
            final Locale locale = new Locale(entry.getKey());
            taxonomy.namesBagByLocale.put(locale, new LocalizedNamesBag(locale, entry.getValue()));
          }

        nameBagsByLanguage.clear();

        return taxonomy;
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private List scan (final @Nonnull SimpleTaxonomy taxonomy,
                                        final @Nonnull SimpleTaxon parent,
                                        final @Nullable JSONObject jsonParent,
                                        final @Nonnull int rankLevel)
      throws JSONException
      {
        final Rank rank = Rank.values()[rankLevel];
        final List children = new ArrayList();
        final String childName = NAME_MAP_BY_RANK.get(rank);
        final JSONArray jsonChildren = jsonParent.optJSONArray(childName);

        if (jsonChildren != null)
          {
            for (int i = 0; i < jsonChildren.length(); i++)
              {
                final JSONObject jsonChild = jsonChildren.getJSONObject(i);
                // FIXME: id should be mandatory, but unfortunately Aves hasn't in EBNItalia 2003
                final Id id = new Id(jsonChild.optString("id"));
                final SimpleTaxon child = new SimpleTaxon(taxonomy, id, jsonChild.getString("name"), rank, parent);

                for (final Locale locale : LOCALE_MAP_BY_CODE.values())
                  {
                    addDisplayName(jsonChild, child, locale);
                  }

                children.add(child);
                taxonomy.taxonMapById.put(id, child);

                if (rankLevel < Rank.values().length - 1)
                  {
//                    final List scan = scan(taxonomy, child, jsonChild, level + 1);
                    final List scan = scan(taxonomy, child, jsonChild, rankLevel + 1);
                    child.children.addAll(scan);
                  }
              }
          }
        
        List taxa = taxonomy.taxonListMapByRank.get(rank);
        
        if (taxa == null)
          {
            taxa = children;
          }
        else
          {
            taxa.addAll(children);
          }

        taxonomy.taxonListMapByRank.put(rank, taxa);

        return children;
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    private void addDisplayName (final @Nonnull JSONObject jsonObject,
                                 final @Nonnull Taxon taxon,
                                 final @Nonnull Locale locale)
      {
        final String languageCode = "lang_" + locale.getLanguage();
        final String displayName = jsonObject.optString(languageCode);

        if ((displayName != null) && !displayName.equals(""))
          {
            final String language = locale.getLanguage();
            Map nameBag = nameBagsByLanguage.get(language);

            if (nameBag == null)
              {
                nameBag = new HashMap();
                nameBagsByLanguage.put(language, nameBag);
              }

            nameBag.put(taxon.getId(), displayName);
          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    protected InputStream openResourceStream (final @Nonnull String resourcePath)
      throws IOException
      {
        return new FileInputStream(resourcePath);
      }  
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private String getResourcePath (final @Nonnull String resourceName) 
      {
        log.debug(">>>> getResourcePath() for {}", resourceName);
        final String path =  "".equals(resourceBasePath) ? resourceName 
                                                         : resourceBasePath + "/" + resourceName;
        log.debug(">>>> resourceBasePath: {}", resourceBasePath);
        log.debug(">>>> path:             {}", path);
        
        return path;
      }
  }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy