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

it.tidalwave.geo.location.elmo.impl.ElmoGeoLocation 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.List;
import org.openide.util.Parameters;
import org.openrdf.elmo.annotations.rdf;
import it.tidalwave.util.logging.Logger;
import it.tidalwave.util.DuplicateException;
import it.tidalwave.util.NotFoundException;
import it.tidalwave.semantic.LazyPropertyHolder;
import it.tidalwave.semantic.Wrapper;
import it.tidalwave.openrdf.elmo.ElmoUtils;
import it.tidalwave.openrdf.elmo.ElmoVolatile;
import it.tidalwave.geo.Coordinate;
import it.tidalwave.geo.geocoding.GeoCoderEntity.Type;
import it.tidalwave.geo.location.GeoLocation;
import it.tidalwave.geo.location.GeoPath;
import it.tidalwave.geo.location.GeoSchema;
import it.tidalwave.geo.location.elmo.GeoVocabulary;
import static it.tidalwave.semantic.SkosConcept.SkosConcept;
import static it.tidalwave.geo.location.GeoLocation.GeoLocation;
import static it.tidalwave.role.MutableDisplayable.MutableDisplayable;

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

    /** Only used by instances not backed by a {@link GeoCoderEntityProxy}, otherwise delegates to it. */
    
    @CheckForNull @rdf(GeoVocabulary.URI_WGS84_LATITUDE)
    private Double latitude;

    /** Only used by instances not backed by a {@link GeoCoderEntityProxy}, otherwise delegates to it. */
    @CheckForNull @rdf(GeoVocabulary.URI_WGS84_LONGITUDE)
    private Double longitude;

    /** Only used by instances not backed by a {@link GeoCoderEntityProxy}, otherwise delegates to it. */
    @CheckForNull @rdf(GeoVocabulary.URI_WGS84_ALTITUDE)
    private Double altitude;

    /** Only used by instances not backed by a {@link GeoCoderEntityProxy}, otherwise delegates to it. */    
    @CheckForNull @rdf(GeoVocabulary.URI_CODE)
    private String code;

    /*******************************************************************************************************************
     *
     * Only used by instances not backed by a {@link GeoCoderEntityProxy}, otherwise delegates to it. 
     *
     ******************************************************************************************************************/
    @ElmoVolatile
    private final LazyPropertyHolder coordinateHolder = new LazyPropertyHolder()
      {
        @Override @CheckForNull
        protected Coordinate create()
          {
            if ((latitude != null) && (longitude != null))
              {
                return (altitude != null) ? new Coordinate(latitude, longitude, altitude)
                                          : new Coordinate(latitude, longitude);
              }

            return null;
          }
      };

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public Object findType (final @Nonnull GeoSchema geoSchema)
      {
        try
          {
            Parameters.notNull("geoSchema", geoSchema);
            logger.fine("findType(%s) - %s", geoSchema, this);
            return findGeoCoderEntityProxy(geoSchema).getType();
          }
        catch (NotFoundException e)
          {
            return Type.UNKNOWN;
          }
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public String findCode (final @Nonnull GeoSchema geoSchema)
      {
        try
          {
            Parameters.notNull("geoSchema", geoSchema);
            logger.fine("findCode(%s) - %s", geoSchema, this);
            return findGeoCoderEntityProxy(geoSchema).getCode();
          }
        catch (NotFoundException e)
          {
            return (code != null) ? code : "";
          }
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public Coordinate findCoordinate (final @Nonnull GeoSchema geoSchema)
      throws NotFoundException
      {
        try
          {
            Parameters.notNull("geoSchema", geoSchema);
            logger.fine("findCoordinate(%s) - %s", geoSchema, this);
            return findGeoCoderEntityProxy(geoSchema).getCoordinate();
          }
        catch (NotFoundException e)
          {
            return NotFoundException.throwWhenNull(coordinateHolder.get(), "No coordinates for " + this);
          }
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public GeoLocation findParent (final @Nonnull GeoSchema geoSchema)
      throws NotFoundException
      {
        Parameters.notNull("geoSchema", geoSchema);
        logger.fine("findParent(%s) - %s", geoSchema, this);
        GeoCoderEntityProxy gcEntityProxy = null;

        try
          {
            gcEntityProxy = findGeoCoderEntityProxy(geoSchema);
            // Don't put geoNode.getParent() from the last return line here, since it can throw NotFoundException as
            // well and that must be thrown. Here we must catch NotFoundException only from findGeoNode()
          }
        catch (NotFoundException e)
          {
            return as(SkosConcept).findBroaders().ofType(GeoLocation).result();
          }

        return ElmoGeoLocationFactory.findOrCreate(geoSchema, gcEntityProxy.getParent());
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public Finder findChildren (final @Nonnull GeoSchema geoSchema)
      {
        Parameters.notNull("geoSchema", geoSchema);
        logger.fine("findChildren(%s) - %s", geoSchema, this);

        return new FinderSupport(String.format("findChildren(%s)", geoSchema))
          {
            @Override
            @Nonnull
            protected List computeResults()
              {
                final List gcEntityProxyChildren = new ArrayList();

                try
                  {
                    final GeoCoderEntityProxy gcEntityProxy = findGeoCoderEntityProxy(geoSchema);
                    //
                    // Different strategies because when a condition is specified we don't want to bring all the
                    // children into the repository.
                    //
                    if (displayName == null)
                      {
                        gcEntityProxyChildren.addAll(gcEntityProxy.getChildren());
                      }
                    else
                      {
                        gcEntityProxyChildren.add(gcEntityProxy.findChildByName(displayName));
                      }
                  }
                catch (NotFoundException e)
                  {
                    doNothing(); // just return an empty list
                  }

                final List result = new ArrayList();
                
                for (final GeoCoderEntityProxy gcEntityProxy : gcEntityProxyChildren)
                  {
                    result.add(ElmoGeoLocationFactory.findOrCreate(geoSchema, gcEntityProxy));
                  }

                // FIXME: add children in the local repo (e.g. Polanesi in the test)
                return Wrapper.wrap(result);
              }
          };
      }
    
   /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public Builder createChild()
      {
        return new Builder()
          {
            @Override
            public GeoLocation build()
              throws DuplicateException
              {
                final GeoLocation child = ElmoGeoLocationFactory.findOrCreate(null, null);
                child.as(MutableDisplayable).setDisplayNames(displayNames);

                if (coordinate != null)
                  {
                    child.setCoordinate(coordinate);
                  }

                if (code != null)
                  {
                    child.setCode(code);
                  }
                // TODO: type

                merge(child);
                ElmoGeoLocation.this.as(SkosConcept).addNarrower(child);

                return child;
              }
          };
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public GeoPath findPath (@Nonnull GeoSchema geoSchema)
      {
        Parameters.notNull("geoSchema", geoSchema);
        logger.fine("findPath(%s)", geoSchema);
        final List result = new ArrayList();

        try
          {
            result.addAll(findParent(geoSchema).findPath(geoSchema).asList());
          }
        catch (NotFoundException e)
          {
            doNothing(); // ok, reached the root
          }

        // GeoPath is not automatically proxied, so we must manually wrap
        // We could perhaps annotate non-entity classes for having them auto-wrapped?
        result.add(Wrapper.wrap(this)); 
        final ElmoGeoPath path = new ElmoGeoPath(result);
        logger.finer(">>>> returning %s", path);
        return path;
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override
    public void setCoordinate (final @Nonnull Coordinate coordinate)
      {
        Parameters.notNull("coordinate", coordinate);

        // FIXME: throw IllegalStateException if this object is bound to a GeoCoderEntityProxy.
        this.latitude  = coordinate.getLatitude();
        this.longitude = coordinate.getLongitude();
        this.altitude  = coordinate.getAltitude();
        this.coordinateHolder.invalidate();
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override
    public void setCode (final @Nonnull String code)
      {
        Parameters.notNull("code", code);

        // FIXME: throw IllegalStateException if this object is bound to a GeoCoderEntityProxy.
        this.code = code;
      }

    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public String toString()
      {
        return String.format("ElmoGeoLocation@%x[%s (%s; %s; %s) code: %s]",
                             System.identityHashCode(this),
                             ElmoUtils.toString(this),
                             latitude, longitude, altitude,
                             code);
      }

    /*******************************************************************************************************************
     *
     * Finds or creates a GeoCoderEntityProxy bound to the current Location according to the given GeoSchema.
     *
     ******************************************************************************************************************/
    @Nonnull
    private GeoCoderEntityProxy findGeoCoderEntityProxy (final @Nonnull GeoSchema geoSchema)
      throws NotFoundException
      {
        assert geoSchema != null : "null geoSchema";

        logger.fine("findGeoCoderEntityProxy(%s)", geoSchema);
        // TODO: cache it for the current transaction?

        final GeoCoderEntityProxy gcEntityProxy = ElmoGeoCoderEntityProxyFactory.findSame(this, geoSchema);
        logger.finer(">>>> returning %s", gcEntityProxy);

        return gcEntityProxy;
      }
  }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy