Package org.geomajas.layer.hibernate

Source Code of org.geomajas.layer.hibernate.HibernateLayer$ScrollIterator

/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2011 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/

package org.geomajas.layer.hibernate;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.commons.beanutils.ConvertUtils;
import org.geomajas.configuration.AssociationAttributeInfo;
import org.geomajas.configuration.AttributeInfo;
import org.geomajas.configuration.SortType;
import org.geomajas.configuration.VectorLayerInfo;
import org.geomajas.global.Api;
import org.geomajas.global.ExceptionCode;
import org.geomajas.global.GeomajasException;
import org.geomajas.layer.LayerException;
import org.geomajas.layer.VectorLayer;
import org.geomajas.layer.VectorLayerAssociationSupport;
import org.geomajas.layer.VectorLayerLazyFeatureConversionSupport;
import org.geomajas.layer.feature.Attribute;
import org.geomajas.layer.feature.FeatureModel;
import org.geomajas.service.DtoConverterService;
import org.geomajas.service.FilterService;
import org.geomajas.service.GeoService;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;

/**
* Hibernate layer model.
*
* @author Pieter De Graef
* @author Jan De Moerloose
* @author Kristof Heirwegh
* @since 1.7.1
*/
@Api
@Transactional(rollbackFor = { Exception.class })
public class HibernateLayer extends HibernateLayerUtil implements VectorLayer, VectorLayerAssociationSupport,
    VectorLayerLazyFeatureConversionSupport {

  private FeatureModel featureModel;

  /**
   * Should the result be retrieved as a scrollable resultset? Your database(driver) needs to support this.
   */
  private boolean scrollableResultSet;

  /**
   * When parsing dates from filters, this model must know how to parse these strings into Date objects before
   * transforming them into Hibernate criteria.
   */
  private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

  @Autowired
  private FilterService filterService;

  @Autowired
  private DtoConverterService converterService;

  @Autowired
  private GeoService geoService;

  private CoordinateReferenceSystem crs;

  private int srid;

  private String id;

  private boolean useLazyFeatureConversion = true;

  public String getId() {
    return id;
  }

  /**
   * Set the layer id.
   *
   * @param id
   *            layer id
   * @since 1.8.0
   */
  @Api
  public void setId(String id) {
    this.id = id;
  }

  public CoordinateReferenceSystem getCrs() {
    return crs;
  }

  public FeatureModel getFeatureModel() {
    return featureModel;
  }

  public boolean useLazyFeatureConversion() {
    return useLazyFeatureConversion;
  }

  /**
   * Configure whether lazy feature conversion should be enabled for this layer. Default is true.
   *
   * @param useLazyFeatureConversion
   *            use lazy feature conversion?
   * @since 1.8.0
   */
  @Api
  public void setUseLazyFeatureConversion(boolean useLazyFeatureConversion) {
    this.useLazyFeatureConversion = useLazyFeatureConversion;
  }

  /**
   * Set the layer configuration.
   *
   * @param layerInfo
   *            layer information
   * @throws LayerException
   *             oops
   * @since 1.7.1
   */
  @Api
  @Override
  public void setLayerInfo(VectorLayerInfo layerInfo) throws LayerException {
    super.setLayerInfo(layerInfo);
    if (null != featureModel) {
      featureModel.setLayerInfo(getLayerInfo());
    }
  }

  @PostConstruct
  @SuppressWarnings("unused")
  protected void postConstruct() throws GeomajasException {
    crs = geoService.getCrs2(getLayerInfo().getCrs());
    srid = geoService.getSridFromCrs(crs);
  }

  public boolean isCreateCapable() {
    return true;
  }

  public boolean isUpdateCapable() {
    return true;
  }

  public boolean isDeleteCapable() {
    return true;
  }

  /**
   * Set the featureModel.
   *
   * @param featureModel
   *            feature model
   * @throws LayerException
   *             problem setting the feature model
   * @since 1.8.0
   */
  @Api
  public void setFeatureModel(FeatureModel featureModel) throws LayerException {
    this.featureModel = featureModel;
    if (null != getLayerInfo()) {
      featureModel.setLayerInfo(getLayerInfo());
    }
    filterService.registerFeatureModel(featureModel);
  }

  /**
   * Set the session factory for creating Hibernate sessions.
   *
   * @param sessionFactory
   *            session factory
   * @throws HibernateLayerException
   *             factory could not be set
   * @since 1.8.0
   */
  @Api
  public void setSessionFactory(SessionFactory sessionFactory) throws HibernateLayerException {
    super.setSessionFactory(sessionFactory);
  }

  /**
   * This implementation does not support the 'offset' parameter. The maxResultSize parameter is not used (limiting
   * the result needs to be done after security {@link org.geomajas.internal.layer.vector.GetFeaturesEachStep}). If
   * you expect large results to be returned enable scrollableResultSet to retrieve only as many records as needed.
   */
  public Iterator<?> getElements(Filter filter, int offset, int maxResultSize) throws LayerException {
    try {
      Session session = getSessionFactory().getCurrentSession();
      Criteria criteria = session.createCriteria(getFeatureInfo().getDataSourceName());
      if (filter != null) {
        if (filter != Filter.INCLUDE) {
          CriteriaVisitor visitor = new CriteriaVisitor((HibernateFeatureModel) featureModel, dateFormat);
          Criterion c = (Criterion) filter.accept(visitor, criteria);
          if (c != null) {
            criteria.add(c);
          }
        }
      }

      // Sorting of elements.
      if (getFeatureInfo().getSortAttributeName() != null) {
        if (SortType.ASC.equals(getFeatureInfo().getSortType())) {
          criteria.addOrder(Order.asc(getFeatureInfo().getSortAttributeName()));
        } else {
          criteria.addOrder(Order.desc(getFeatureInfo().getSortAttributeName()));
        }
      }

      criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

      if (isScrollableResultSet()) {
        return (Iterator<?>) new ScrollIterator(criteria.scroll());
      } else {
        List<?> list = criteria.list();
        return list.iterator();
      }
    } catch (HibernateException he) {
      throw new HibernateLayerException(he, ExceptionCode.HIBERNATE_LOAD_FILTER_FAIL, getFeatureInfo()
          .getDataSourceName(), filter.toString());
    }
  }

  public Object create(Object feature) throws LayerException {
    // force the srid value
    enforceSrid(feature);
    Session session = getSessionFactory().getCurrentSession();
    session.save(feature);
    return feature;
  }

  public Object saveOrUpdate(Object feature) throws LayerException {
    // force the srid value
    enforceSrid(feature);
    Session session = getSessionFactory().getCurrentSession();
    // using merge to allow detached objects, although Geomajas avoids them
    return session.merge(feature);
  }

  public void delete(String featureId) throws LayerException {
    Session session = getSessionFactory().getCurrentSession();
    session.delete(getFeature(featureId));
    session.flush();
  }

  public Object read(String featureId) throws LayerException {
    Object object = getFeature(featureId);
    if (object == null) {
      throw new LayerException(ExceptionCode.LAYER_MODEL_FEATURE_NOT_FOUND, featureId);
    }
    return object;
  }

  public void update(Object feature) throws LayerException {
    Session session = getSessionFactory().getCurrentSession();
    session.update(feature);
  }

  public Envelope getBounds() throws LayerException {
    return getBounds(filterService.createTrueFilter());
  }

  /**
   * Retrieve the bounds of the specified features.
   *
   * @param filter
   *            filter which needs to be applied
   * @return the bounds of the specified features
   */
  public Envelope getBounds(Filter filter) throws LayerException {
    // Envelope bounds = getBoundsDb(filter);
    // if (bounds == null)
    // bounds = getBoundsLocal(filter);
    // return bounds;

    // @TODO getBoundsDb cannot handle hibernate Formula fields
    return getBoundsLocal(filter);
  }

  public List<Attribute<?>> getAttributes(String attributeName, Filter filter) throws LayerException {
    if (attributeName == null) {
      throw new HibernateLayerException(ExceptionCode.ATTRIBUTE_UNKNOWN, (Object) null);
    }
    AssociationAttributeInfo attributeInfo = getRecursiveAttributeInfo(attributeName, getFeatureInfo()
        .getAttributes());
    Session session = getSessionFactory().getCurrentSession();
    Criteria criteria = session.createCriteria(attributeInfo.getFeature().getDataSourceName());
    CriteriaVisitor visitor = new CriteriaVisitor((HibernateFeatureModel) getFeatureModel(), dateFormat);
    if (filter != null) {
      Criterion c = (Criterion) filter.accept(visitor, null);
      if (c != null) {
        criteria.add(c);
      }
    }
    List<Attribute<?>> attributes = new ArrayList<Attribute<?>>();
    for (Object object : criteria.list()) {
      try {
        attributes.add(converterService.toDto(object, attributeInfo));
      } catch (GeomajasException e) {
        throw new HibernateLayerException(e, ExceptionCode.HIBERNATE_ATTRIBUTE_TYPE_PROBLEM, attributeName);
      }
    }
    return attributes;
  }

  // -------------------------------------------------------------------------
  // Extra getters and setters:
  // -------------------------------------------------------------------------

  public DateFormat getDateFormat() {
    return dateFormat;
  }

  public void setDateFormat(DateFormat dateFormat) {
    this.dateFormat = dateFormat;
  }

  public boolean isScrollableResultSet() {
    return scrollableResultSet;
  }

  /**
   * <p>
   * Should the result be retrieved as a scrollable resultset? Your database(driver) needs to support this.
   * </p>
   *
   * @param scrollableResultSet
   *            true when a scrollable resultset should be used
   * @since 1.8.0
   */
  @Api
  public void setScrollableResultSet(boolean scrollableResultSet) {
    this.scrollableResultSet = scrollableResultSet;
  }

  // -------------------------------------------------------------------------
  // Private functions:
  // -------------------------------------------------------------------------

  /**
   * A wrapper around a Hibernate {@link ScrollableResults}
   *
   * ScrollableResults are annoying they run 1 step behind an iterator...
   */
  @SuppressWarnings("rawtypes")
  private static class ScrollIterator implements Iterator {

    private final ScrollableResults sr;

    private boolean hasNext;

    public ScrollIterator(ScrollableResults sr) {
      this.sr = sr;
      hasNext = sr.first();
    }

    public boolean hasNext() {
      return hasNext;
    }

    public Object next() {
      Object o = sr.get(0);
      hasNext = sr.next();
      return o;
    }

    public void remove() {
      // TODO the alternative (default) version with list allows remove(),
      // but this will
      // only remove it from the list, not from db, so maybe we should
      // just ignore instead of throwing an exception
      throw new HibernateException("Unsupported operation: You cannot remove records this way.");
    }
  }

  /**
   * Enforces the correct srid on incoming features.
   *
   * @param feature
   *            object to enforce srid on
   * @throws LayerException
   *             problem getting or setting srid
   */
  private void enforceSrid(Object feature) throws LayerException {
    Geometry geom = getFeatureModel().getGeometry(feature);
    if (null != geom) {
      geom.setSRID(srid);
      getFeatureModel().setGeometry(feature, geom);
    }
  }

  /**
   * Bounds are calculated locally, can use any filter, but slower than native.
   *
   * @param filter
   *            filter which needs to be applied
   * @return the bounds of the specified features
   * @throws LayerException
   *             oops
   */
  private Envelope getBoundsLocal(Filter filter) throws LayerException {
    try {
      Session session = getSessionFactory().getCurrentSession();
      Criteria criteria = session.createCriteria(getFeatureInfo().getDataSourceName());
      CriteriaVisitor visitor = new CriteriaVisitor((HibernateFeatureModel) getFeatureModel(), dateFormat);
      Criterion c = (Criterion) filter.accept(visitor, criteria);
      if (c != null) {
        criteria.add(c);
      }
      criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
      List<?> features = criteria.list();
      Envelope bounds = new Envelope();
      for (Object f : features) {
        Envelope geomBounds = getFeatureModel().getGeometry(f).getEnvelopeInternal();
        if (!geomBounds.isNull()) {
          bounds.expandToInclude(geomBounds);
        }
      }
      return bounds;
    } catch (HibernateException he) {
      throw new HibernateLayerException(he, ExceptionCode.HIBERNATE_LOAD_FILTER_FAIL, getFeatureInfo()
          .getDataSourceName(), filter.toString());
    }
  }

  private Object getFeature(String featureId) throws HibernateLayerException {
    Session session = getSessionFactory().getCurrentSession();
    return session.get(getFeatureInfo().getDataSourceName(), (Serializable) ConvertUtils.convert(featureId,
        getEntityMetadata().getIdentifierType().getReturnedClass()));
  }
 
 
  private AssociationAttributeInfo getRecursiveAttributeInfo(String name, List<AttributeInfo> infos) {
    for (AttributeInfo attributeInfo : infos) {
      if (attributeInfo instanceof AssociationAttributeInfo) {
        AssociationAttributeInfo associationAttributeInfo = (AssociationAttributeInfo) attributeInfo;
        if (name.equals(attributeInfo.getName())) {
          return associationAttributeInfo;
        } else if (name.startsWith(attributeInfo.getName())) {
          String childName = name.substring(attributeInfo.getName().length() + 1);
          return getRecursiveAttributeInfo(childName, associationAttributeInfo.getFeature().getAttributes());
        }
      }
    }
    return null;
  }

}
TOP

Related Classes of org.geomajas.layer.hibernate.HibernateLayer$ScrollIterator

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.