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

it.tidalwave.geo.location.elmo.impl.ElmoGeoCoderEntityProxy 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.location.elmo.impl;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import org.openide.util.Parameters;
import org.openrdf.elmo.annotations.rdf;
import org.openrdf.elmo.Entity;
import it.tidalwave.util.logging.Logger;
import it.tidalwave.util.NotFoundException;
import it.tidalwave.semantic.LazyPropertyHolder;
import it.tidalwave.openrdf.elmo.ElmoVolatile;
import it.tidalwave.geo.Coordinate;
import it.tidalwave.geo.geocoding.GeoCoder;
import it.tidalwave.geo.geocoding.GeoCoderEntity;
import it.tidalwave.geo.geocoding.GeoCoderEntity.Type;
import it.tidalwave.geo.location.GeoSchema;
import it.tidalwave.geo.location.elmo.GeoVocabulary;
import static it.tidalwave.role.Displayable.Displayable;
import static it.tidalwave.role.MutableDisplayable.MutableDisplayable;
import static it.tidalwave.semantic.SkosConcept.SkosConcept;
import static it.tidalwave.geo.geocoding.GeoCoder.GeoCoder;

/***********************************************************************************************************************
 *
 * @author Fabrizio Giudici
 * @version $Id$
 *
 **********************************************************************************************************************/
@rdf(GeoVocabulary.URI_GEO_ENTITY)
public class ElmoGeoCoderEntityProxy extends Support implements GeoCoderEntityProxy
  {
    private final static String CLASS = ElmoGeoCoderEntityProxy.class.getName();
    private final static Logger logger = Logger.getLogger(CLASS);

    @rdf(GeoVocabulary.URI_WGS84_LATITUDE) @CheckForNull
    private Double latitude;

    @rdf(GeoVocabulary.URI_WGS84_LONGITUDE) @CheckForNull
    private Double longitude;

    @rdf(GeoVocabulary.URI_WGS84_ALTITUDE) @CheckForNull
    private Double altitude;
    
    @rdf(GeoVocabulary.URI_LATEST_CHILDREN_QUERY_TIME) @CheckForNull
    private XMLGregorianCalendar latestChildrenQueryTime;

    @rdf(GeoVocabulary.URI_ROOT) @CheckForNull
    private Boolean root; // a wrapper Boolean, so no statements for false // FIXME: use skos:topConceptOf

    @rdf(GeoVocabulary.URI_CODE) @CheckForNull
    private String code;
    
    @rdf(GeoVocabulary.URI_TYPE)
    private String typeAsString;

    @rdf(GeoVocabulary.URI_SKOS_IN_SCHEME)
    private GeoSchema geoSchema;

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @ElmoVolatile
    private final LazyPropertyHolder coordinateHolder = new LazyPropertyHolder()
      {
        @Override @CheckForNull
        protected Coordinate create()
          {
            Coordinate result = null;

            if ((latitude != null) && (longitude != null))
              {
                result = (altitude != null) ? new Coordinate(latitude, longitude, altitude)
                                            : new Coordinate(latitude, longitude);
              }

            return result;
          }
      };

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @ElmoVolatile
    private final LazyPropertyHolder geoCoderEntityHolder = new LazyPropertyHolder()
      {
        @Override @Nonnull
        protected GeoCoderEntity create()
          {
            try
              {
                final QName qName = ElmoGeoCoderEntityProxy.this.as(Entity).getQName();
                final GeoCoder geoCoder = geoSchema.getLookup().lookup(GeoCoder);
                return geoCoder.findGeoEntityById(qName.getNamespaceURI() + qName.getLocalPart());
              }
            catch (NotFoundException e)
              {
                throw new RuntimeException(e); // malfunction
              }
          }
      };

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public GeoCoderEntityProxy getParent()
      throws NotFoundException
      {
        logger.fine("getParent() - %s", this);
        //
        // The root entity has no parent - in case of offline operation, don't ask anybody.
        //
        if (Boolean.TRUE.equals(root)) // root can be null or true
          {
            throw new NotFoundException(String.format("No parent for %s", this));
          }
        //
        // First parent is searched in the local repository. This saves queries to the geocoder and fixes potential
        // geocoder bugs (for instance, at 2009-02-12 GeoNames reports that parent of
        // http://sws.geonames.org/6540563/ (Recco) is http://sws.geonames.org/3174725/ (Liguria)
        // instead of http://sws.geonames.org/3176217/ (Provincia di Genova)
        //
        try
          {
            return as(SkosConcept).findBroaders().ofType(GeoCoderEntityProxy).result();
          }
        catch (NotFoundException e)
          {
            final GeoCoderEntity gcEntity = geoCoderEntityHolder.get();
            assert gcEntity != null : "Null geoCoderEntity";
            logger.finer(">>>> getting parent from %s", gcEntity);
            final GeoCoderEntity gcParentEntity = gcEntity.getParent();
            final GeoCoderEntityProxy gcParentEntityProxy = ElmoGeoCoderEntityProxyFactory.findOrCreate(geoSchema, gcParentEntity);
            logger.finer(">>>> parent is %s", gcParentEntityProxy);
            as(SkosConcept).addBroader(gcParentEntityProxy);

            return gcParentEntityProxy;
          }
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public List getChildren()
      {
        logger.fine("getChildren() - %s", this);

        final List result = new ArrayList();

        if (latestChildrenQueryTime == null)
          {
            final GeoCoderEntity gcEntity = geoCoderEntityHolder.get();
            assert gcEntity != null : "Null geoCoderEntity for " + this;
            logger.finest(">>>> getting children from geoEntity: %s", gcEntity);

            for (final GeoCoderEntity gcEntityChild : gcEntity.findChildren().results())
              {
                final GeoCoderEntityProxy gcEntityChildProxy = ElmoGeoCoderEntityProxyFactory.findOrCreate(geoSchema, gcEntityChild);
                as(SkosConcept).addNarrower(gcEntityChildProxy);
                result.add(gcEntityChildProxy);
              }

            latestChildrenQueryTime = Support.toXMLGregorianCalendar(getTimeStamp());
            merge(this);
          }
        else
          {
            logger.finest(">>>> getting children from narrowers");
            result.addAll(as(SkosConcept).findNarrowers().ofType(GeoCoderEntityProxy).results());
          }

        logger.finer(">>>> returning: %s", result);

        return result;
      }
    
    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public GeoCoderEntityProxy findChildByName (final @Nonnull String name)
      throws NotFoundException
      {
        Parameters.notNull("name", name);
        //
        // If we have previously queried for all the children, we have the result here, so just query getChildren().
        // We can't always delegate to getChildren(), because it stores all the children in the repository, while we
        // want to be incremental.
        //
        if (latestChildrenQueryTime != null)
          {
            for (final GeoCoderEntityProxy gcEntityChildProxy : getChildren())
              {
                if (name.equals(gcEntityChildProxy.as(Displayable).getDisplayName()))
                  {
                    return gcEntityChildProxy;
                  }
              }
          }
        else
          {
            final GeoCoderEntity gcEntity = geoCoderEntityHolder.get();
            assert gcEntity != null : "Null geoCoderEntity for " + this;

            for (final GeoCoderEntity gcEntityChild : gcEntity.findChildren().results())
              {
                if (name.equals(gcEntityChild.as(Displayable).getDisplayName()))
                  {
                    final GeoCoderEntityProxy gcEntityProxyChild =
                            ElmoGeoCoderEntityProxyFactory.findOrCreate(geoSchema, gcEntityChild);
                    as(SkosConcept).addNarrower(gcEntityProxyChild);
                    return gcEntityProxyChild;
                  }
              }
          }

        throw new NotFoundException(String.format("Child not found: %s for %s", name, this));
      }
    
    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public Coordinate getCoordinate()
      throws NotFoundException
      {
        return NotFoundException.throwWhenNull(coordinateHolder.get(), "No coordinate for " + this);
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public GeoCoderEntity getGeoCoderEntity()
      {
        final GeoCoderEntity gcEntity = geoCoderEntityHolder.get();
        assert gcEntity != null : "Null geoCoderEntity for " + this;
        return gcEntity;
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public Type getType()
      {
        return geoSchema.getLookup().lookup(GeoCoder).typeFromString(typeAsString);
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public String getCode()
      {
        return (code != null) ? code : "";
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override
    public void setBindings (final @Nonnull GeoSchema geoSchema)
      {
        this.geoSchema = geoSchema;
      }
    
    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public String toString()
      {
        final QName qName = as(Entity.class).getQName();
        return String.format("ElmoGeoCoderEntityProxy@%x[%s (%s; %s; %s) root: %s code: %s type: %s lcqt: %s]",
                             System.identityHashCode(this),
                             qName.getNamespaceURI() + qName.getLocalPart(),
                             latitude, longitude, altitude,
                             root, code, typeAsString,
                             latestChildrenQueryTime);
      }

    /*******************************************************************************************************************
     *
     * 
     *
     ******************************************************************************************************************/
//    @Override
    protected void init (final @Nonnull GeoCoderEntity gcEntity)
      {
         as(MutableDisplayable).setDisplayName(gcEntity.as(Displayable).getDisplayName());
    //        SkosConceptUtils.setDisplayName(this, geoEntity.getLocalName(), Locale.???); FIXME: find the locale for the country

        try
          {
            gcEntity.getParent();
          }
        catch (NotFoundException e)
          {
            root = true; // for false, leave it null
          }

        final Coordinate coordinate = gcEntity.getCoordinate();

        if (coordinate != null)
          {
            latitude  = coordinate.getLatitude();
            longitude = coordinate.getLongitude();
            altitude  = coordinate.getAltitude();
          }

        typeAsString = gcEntity.getTypeAsString();

        final String gcEntityCode = gcEntity.getCode();
        code = "".equals(gcEntityCode) ? null : gcEntityCode; // here null is good, so no RDF statements are generated
        merge(this);
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private static Date getTimeStamp()
      {
        // FIXME: retrofit the TimestampProvider in blueMarine Metadata when it will be available in OpenBlueSky
        if (Boolean.getBoolean("it.tidalwave.geo.location.elmo.impl.FakeTimeStamp"))
          {
            return new Date(1260026377000L);
          }
        
        return new Date();
      }
  }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy