
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 extends Taxonomy> computeResults()
{
if (id != null)
{
try
{
return Collections.singletonList(loadTaxonomy(id));
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
else
{
return loadTaxonomies();
}
}
};
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
private List extends Taxonomy> 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 extends Taxon> 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 extends Taxon> 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