Package org.geomajas.rest.server.mvc

Source Code of org.geomajas.rest.server.mvc.RestController$InternalFeatureComparator

/*
* 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.rest.server.mvc;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.geomajas.configuration.AttributeInfo;
import org.geomajas.configuration.VectorLayerInfo;
import org.geomajas.global.GeomajasException;
import org.geomajas.layer.LayerException;
import org.geomajas.layer.VectorLayer;
import org.geomajas.layer.VectorLayerService;
import org.geomajas.layer.feature.InternalFeature;
import org.geomajas.rest.server.RestException;
import org.geomajas.service.ConfigurationService;
import org.geomajas.service.FilterService;
import org.geomajas.service.GeoService;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;

import com.vividsolutions.jts.geom.Envelope;

/**
* Spring MVC controller that maps a REST request to vectorlayers.
*
* @author Oliver May
* @author Jan De Moerlose
*/
@Controller("/rest/**")
public class RestController {

  @Autowired
  private VectorLayerService vectorLayerService;

  @Autowired
  private FilterService filterService;

  @Autowired
  private ConfigurationService configurationService;

  @Autowired
  private GeoService geoService;

  static final String VIEW = "rest.server.mvc.GeoJsonView";

  static final String FEATURE_COLLECTION = "FeatureCollection";

  static final String VECTOR_LAYER_INFO = "VectorLayerInfo";

  static final String ATTRIBUTES = "Attrs";

  @RequestMapping(value = "/rest/{layerId}/{featureId}.json", method = RequestMethod.GET)
  public String readOneFeature(@PathVariable String layerId, @PathVariable String featureId,
      @RequestParam(value = "no_geom", required = false) boolean noGeom,
      @RequestParam(value = "attrs", required = false) List<String> attrs, Model model) throws RestException {
    List<InternalFeature> features;
    try {
      features = vectorLayerService.getFeatures(layerId, null, filterService
          .createFidFilter(new String[] { featureId }), null, getIncludes(noGeom));
    } catch (GeomajasException e) {
      throw new RestException(e, RestException.PROBLEM_READING_LAYERSERVICE, layerId);
    }
    if (features.size() != 1) {
      throw new RestException(RestException.FEATURE_NOT_FOUND, featureId, layerId);
    }
    model.addAttribute(FEATURE_COLLECTION, features.get(0));
    model.addAttribute(VECTOR_LAYER_INFO, features.get(0).getLayer().getLayerInfo());
    model.addAttribute(ATTRIBUTES, attrs);
    return VIEW;
  }

  @RequestMapping(value = "/rest/{layerId}", method = RequestMethod.GET)
  public String readFeatures(@PathVariable String layerId,
      @RequestParam(value = "no_geom", required = false) boolean noGeom,
      @RequestParam(value = "attrs", required = false) List<String> attrs,
      @RequestParam(value = "box", required = false) Envelope box,
      @RequestParam(value = "bbox", required = false) Envelope bbox,
      @RequestParam(value = "maxFeatures", required = false) Integer maxFeatures,
      @RequestParam(value = "limit", required = false) Integer limit,
      @RequestParam(value = "offset", required = false) Integer offset,
      @RequestParam(value = "order_by", required = false) String orderBy,
      @RequestParam(value = "dir", required = false) FeatureOrder dir,
      @RequestParam(value = "queryable", required = false) List<String> queryable,
      @RequestParam(value = "epsg", required = false) String epsg, WebRequest request, Model model)
      throws RestException {

    List<Filter> filters = new ArrayList<Filter>();
    filters.add(createBBoxFilter(layerId, box, bbox));
    if (queryable != null) {
      for (String attributeName : queryable) {
        String prefix = attributeName + "_";
        for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
          if (entry.getKey().startsWith(prefix)) {
            filters.add(createAttributeFilter(attributeName, entry.getKey().substring(prefix.length()),
                entry.getValue()[0]));
          }
        }
      }
    }
    List<InternalFeature> features;
    try {
      CoordinateReferenceSystem crs = null;
      if (epsg != null) {
        crs = geoService.getCrs2("EPSG:" + epsg);
      }
      features = vectorLayerService.getFeatures(layerId, crs, and(filters), null, getIncludes(noGeom),
          getOffset(offset), getLimit(maxFeatures, limit));
    } catch (Exception e) {
      throw new RestException(e, RestException.PROBLEM_READING_LAYERSERVICE, layerId);
    }
    if (features.size() > 0) {
      VectorLayerInfo info = features.get(0).getLayer().getLayerInfo();
      model.addAttribute(VECTOR_LAYER_INFO, info);
      VectorLayer layer = configurationService.getVectorLayer(layerId);
      if (orderBy != null) {
        Collections.sort(features, createComparator(layer, orderBy, dir));
      }
      model.addAttribute(FEATURE_COLLECTION, features);
      model.addAttribute(ATTRIBUTES, attrs);
    }
    return VIEW;
  }

  public ModelAndView createUpdateFeatures() {
    return new ModelAndView();
  }

  public ModelAndView updateFeature() {
    return new ModelAndView();
  }

  public ModelAndView deleteFeature() {
    return new ModelAndView();
  }

  public ModelAndView countFeatures() {
    return new ModelAndView();
  }

  @InitBinder
  public void initBinder(WebDataBinder binder) {
    binder.setConversionService(new RestParameterConversionService());
  }

  private int getIncludes(Boolean noGeom) {
    int featureIncludes = VectorLayerService.FEATURE_INCLUDE_ALL;
    if (noGeom) {
      featureIncludes = VectorLayerService.FEATURE_INCLUDE_ATTRIBUTES;
    }
    return featureIncludes;
  }

  private int getOffset(Integer offset) {
    if (offset != null && offset > 0) {
      return offset;
    } else {
      return 0;
    }
  }

  private int getLimit(Integer... limit) {
    int result = Integer.MAX_VALUE;
    for (Integer l : limit) {
      if (l != null && l >= 0) {
        result = Math.min(result, l);
      }
    }
    return result;
  }

  private Filter and(List<Filter> filters) {
    if (filters.size() == 0) {
      return null;
    } else {
      Filter result = filters.get(0);
      for (int i = 1; i < filters.size(); i++) {
        result = filterService.createAndFilter(result, filters.get(i));
      }
      return result;
    }
  }

  private Filter createBBoxFilter(String layerId, Envelope... bbox) throws RestException {
    VectorLayer layer = configurationService.getVectorLayer(layerId);
    for (Envelope envelope : bbox) {
      if (envelope != null) {
        try {
          return filterService.createBboxFilter(layer.getLayerInfo().getCrs(), envelope, layer
              .getFeatureModel().getGeometryAttributeName());
        } catch (LayerException e) {
          throw new RestException(e, RestException.PROBLEM_READING_LAYERSERVICE, layerId);
        }
      }
    }
    return filterService.createTrueFilter();
  }

  private Filter createAttributeFilter(String attributeName, String operation, String value) throws RestException {
    if ("eq".equalsIgnoreCase(operation)) {
      return filterService.createCompareFilter(attributeName, "==", value);
    } else if ("ne".equalsIgnoreCase(operation)) {
      return filterService.createCompareFilter(attributeName, "<>", value);
    } else if ("lt".equalsIgnoreCase(operation)) {
      return filterService.createCompareFilter(attributeName, "<", value);
    } else if ("lte".equalsIgnoreCase(operation)) {
      return filterService.createCompareFilter(attributeName, "<=", value);
    } else if ("gt".equalsIgnoreCase(operation)) {
      return filterService.createCompareFilter(attributeName, ">", value);
    } else if ("gte".equalsIgnoreCase(operation)) {
      return filterService.createCompareFilter(attributeName, ">=", value);
    } else if ("like".equalsIgnoreCase(operation)) {
      return filterService.createLikeFilter(attributeName, value);
    } else {
      throw new RestException(RestException.UNSUPPORTED_QUERY_OPERATION, operation);
    }
  }

  private Comparator<? super InternalFeature> createComparator(VectorLayer layer, final String attributeName,
      final FeatureOrder order) throws RestException {
    List<AttributeInfo> attributes = layer.getLayerInfo().getFeatureInfo().getAttributes();
    AttributeInfo info = null;
    for (AttributeInfo attributeInfo : attributes) {
      // be tolerant on casing
      if (attributeInfo.getName().equalsIgnoreCase(attributeName)) {
        info = attributeInfo;
      }
    }
    if (info == null) {
      throw new RestException(RestException.NO_SUCH_ATTRIBUTE, attributeName, layer.getId());
    }
    return new InternalFeatureComparator(order, attributeName);
  }

  /**
   * Compares features based on a single attribute.
   *
   * @author Jan De Moerloose
   */
  static class InternalFeatureComparator implements Comparator<InternalFeature> {

    private FeatureOrder order;

    private String attributeName;

    public InternalFeatureComparator(FeatureOrder order, String attributeName) {
      this.order = (order == null ? FeatureOrder.ASC : FeatureOrder.DESC);
      this.attributeName = attributeName;
    }

    public int compare(InternalFeature f1, InternalFeature f2) {
      Object value1 = f1.getAttributes().get(attributeName).getValue();
      Object value2 = f2.getAttributes().get(attributeName).getValue();
      if (value1 == null && value2 == null) {
        return 0;
      }
      if (value1 == null) {
        return 1;
      } else if (value2 == null) {
        return -1;
      } else {
        if (value1 instanceof Comparable && order == FeatureOrder.ASC) {
          return ((Comparable) value1).compareTo(value2);
        } else if (value2 instanceof Comparable && order == FeatureOrder.DESC) {
          return ((Comparable) value2).compareTo(value1);
        } else {
          // can this happen ?
          return 0;
        }
      }
    }
  }

}
TOP

Related Classes of org.geomajas.rest.server.mvc.RestController$InternalFeatureComparator

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.