Package org.neo4j.gis.spatial

Source Code of org.neo4j.gis.spatial.DynamicLayerConfig$PropertyUsageSearch

/**
* Copyright (c) 2010-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.gis.spatial;

import java.io.File;
import java.io.PrintStream;
import java.util.LinkedHashMap;

import org.geotools.filter.text.cql2.CQLException;
import org.neo4j.gis.spatial.rtree.Envelope;
import org.neo4j.gis.spatial.rtree.Listener;
import org.neo4j.gis.spatial.rtree.filter.SearchFilter;
import org.neo4j.gis.spatial.attributes.PropertyMappingManager;
import org.neo4j.gis.spatial.indexfilter.CQLIndexReader;
import org.neo4j.gis.spatial.indexfilter.DynamicIndexReader;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import com.vividsolutions.jts.geom.GeometryFactory;

public class DynamicLayerConfig implements Layer, Constants {

  private DynamicLayer parent;
  protected Node configNode;
  private String[] propertyNames;

  /**
   * Construct the layer config instance on existing config information in
   * the database.
   *
   * @param configNode
   */
  public DynamicLayerConfig(DynamicLayer parent, Node configNode) {
    this.parent = parent;
    this.configNode = configNode;
    this.propertyNames = (String[]) configNode.getProperty("propertyNames", null);
  }

  /**
   * Construct a new layer config by building the database structure to
   * support the necessary configuration
   *
   * @param name
   *            of the new dynamic layer
   * @param geometryType
   *            the geometry this layer supports
   * @param query
   *            formated query string for this dynamic layer
   */
  public DynamicLayerConfig(DynamicLayer parent, String name, int geometryType, String query) {
    this.parent = parent;
   
    GraphDatabaseService database = parent.getSpatialDatabase().getDatabase();
    Transaction tx = database.beginTx();
    try {
      Node node = database.createNode();
      node.setProperty(PROP_LAYER, name);
      node.setProperty(PROP_TYPE, geometryType);
      node.setProperty(PROP_QUERY, query);
      parent.getLayerNode().createRelationshipTo(node, SpatialRelationshipTypes.LAYER_CONFIG);
      tx.success();
      configNode = node;
    } finally {
      tx.close();
    }
  }

  public String getName() {
      try (Transaction tx = configNode.getGraphDatabase().beginTx()) {
        String name = (String) configNode.getProperty(PROP_LAYER);
        tx.success();
        return name;
      }
  }

  public String getQuery() {
      try (Transaction tx = configNode.getGraphDatabase().beginTx()) {
        String name = (String) configNode.getProperty(PROP_QUERY);
        tx.success();
        return name;
      }
  }

  public SpatialDatabaseRecord add(Node geomNode) {
    throw new SpatialDatabaseException("Cannot add nodes to dynamic layers, add the node to the base layer instead");
  }

  public void delete(Listener monitor) {
    throw new SpatialDatabaseException("Cannot delete dynamic layers, delete the base layer instead");
  }

  public CoordinateReferenceSystem getCoordinateReferenceSystem() {
    return parent.getCoordinateReferenceSystem();
  }

  public SpatialDataset getDataset() {
    return parent.getDataset();
  }

  public String[] getExtraPropertyNames() {
    if (propertyNames != null && propertyNames.length > 0) {
      return propertyNames;
    } else {
      return parent.getExtraPropertyNames();
    }
  }

  private class PropertyUsageSearch implements SearchFilter {
   
    private Layer layer;
    private LinkedHashMap<String, Integer> names = new LinkedHashMap<String, Integer>();
    private int nodeCount = 0;
    private int MAX_COUNT = 10000;

    public PropertyUsageSearch(Layer layer) {
      this.layer = layer;
    }
   
    @Override
    public boolean needsToVisit(Envelope indexNodeEnvelope) {
      return nodeCount < MAX_COUNT;
    }

    @Override
    public boolean geometryMatches(Node geomNode) {
      if (nodeCount++ < MAX_COUNT) {
        SpatialDatabaseRecord record = new SpatialDatabaseRecord(layer, geomNode);
        for (String name : record.getPropertyNames()) {
          Object value = record.getProperty(name);
          if (value != null) {
            Integer count = names.get(name);
            if (count == null)
              count = 0;
            names.put(name, count + 1);
          }
        }
      }
     
      // no need to collect nodes
      return false;
    }
   
    public String[] getNames() {
      return names.keySet().toArray(new String[] {});       
    }
   
    public int getNodeCount() {
      return nodeCount;
    }
   
    public void describeUsage(PrintStream out) {
      for (String name : names.keySet()) {
        System.out.println(name + "\t" + names.get(name));
      }
    }
  }

  /**
   * This method will scan the layer for property names that are actually
   * used, and restrict the layer properties to those
   */
  public void restrictLayerProperties() {
    if (propertyNames != null && propertyNames.length > 0) {
      System.out.println("Restricted property names already exists - will be overwritten");
    }
   
    System.out.println("Before property scan we have " + getExtraPropertyNames().length + " known attributes for layer "
        + getName());
   
    PropertyUsageSearch search = new PropertyUsageSearch(this);
    getIndex().searchIndex(search).count();
    setExtraPropertyNames(search.getNames());
   
    System.out.println("After property scan of " + search.getNodeCount() + " nodes, we have "
        + getExtraPropertyNames().length + " known attributes for layer " + getName());
    // search.describeUsage(System.out);
  }
 
  public void setExtraPropertyNames(String[] names) {
    try (Transaction tx = configNode.getGraphDatabase().beginTx()) {
      configNode.setProperty("propertyNames", names);
      propertyNames = names;
      tx.success();
    }
  }   
 
  public GeometryEncoder getGeometryEncoder() {
    return parent.getGeometryEncoder();
  }

  public GeometryFactory getGeometryFactory() {
    return parent.getGeometryFactory();
  }

  public Integer getGeometryType() {
    try (Transaction tx = configNode.getGraphDatabase().beginTx()) {
      Integer geometryType = (Integer) configNode.getProperty(PROP_TYPE);
      tx.success();
      return geometryType;
    }
  }

  public LayerIndexReader getIndex() {
    if (parent.index instanceof LayerTreeIndexReader) {
      String query = getQuery();
      if (query.startsWith("{")) {
        // Make a standard JSON based dynamic layer
        return new DynamicIndexReader((LayerTreeIndexReader) parent.index, query);
      } else {
        // Make a CQL based dynamic layer
        try {
          return new CQLIndexReader((LayerTreeIndexReader) parent.index, this, query);
        } catch (CQLException e) {
          throw new SpatialDatabaseException("Error while creating CQL based DynamicLayer", e);
        }
      }
    } else {
      throw new SpatialDatabaseException("Cannot make a DynamicLayer from a non-LayerTreeIndexReader Layer");
    }
  }

  public Node getLayerNode() {
    // TODO: Make sure that the mismatch between the name on the dynamic
    // layer node and the dynamic layer translates into the correct
    // object being returned
    return parent.getLayerNode();
  }

  public SpatialDatabaseService getSpatialDatabase() {
    return parent.getSpatialDatabase();
  }

  public void initialize(SpatialDatabaseService spatialDatabase, String name, Node layerNode) {
    throw new SpatialDatabaseException("Cannot initialize the layer config, initialize only the dynamic layer node");
  }

  public Object getStyle() {
    Object style = parent.getStyle();
    if (style != null && style instanceof File) {
      File parent = ((File) style).getParentFile();
      File newStyle = new File(parent, getName() + ".sld");
      if (newStyle.canRead()) {
        style = newStyle;
      }
    }
    return style;
  }
 
  public Layer getParent() {
    return parent;
  }
 
  public String toString() {
    return getName();
  }

  private PropertyMappingManager propertyMappingManager;

  @Override
  public PropertyMappingManager getPropertyMappingManager() {
    if (propertyMappingManager == null) {
      propertyMappingManager = new PropertyMappingManager(this);
    }
    return propertyMappingManager;
  }
}
TOP

Related Classes of org.neo4j.gis.spatial.DynamicLayerConfig$PropertyUsageSearch

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.