Beispiel #1
0
  private Class[] getSortByAttributeClasses(LiteFeatureTypeStyle style) {
    SortBy[] sb = style.sortBy;
    FeatureType schema = style.layer.getFeatureSource().getSchema();
    Class[] classes = new Class[sb.length];
    for (int i = 0; i < classes.length; i++) {
      PropertyName property = sb[i].getPropertyName();
      if (property == null) {
        // natural sorts
        classes[i] = String.class;
      } else {
        PropertyDescriptor pd = property.evaluate(schema, null);
        if (pd == null) {
          throw new IllegalArgumentException(
              "Property "
                  + property
                  + " could not be found in feature type "
                  + schema.getName()
                  + " in layer "
                  + style.layer.getTitle());
        }
        classes[i] = pd.getType().getBinding();
      }
    }

    return classes;
  }
  protected void createTableViewer(Composite parent) {
    viewer =
        new FeatureTableViewer(
            parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);

    contentProvider = new LazyFeatureContentProvider();
    contentProvider.filter(featureLayer.filter());
    viewer.setContentProvider(contentProvider);

    // add columns
    DefaultFeatureTableColumn first = null;
    for (PropertyDescriptor prop : fs.getSchema().getDescriptors()) {
      if (Geometry.class.isAssignableFrom(prop.getType().getBinding())) {
        // skip Geometry
      } else {
        DefaultFeatureTableColumn column = new DefaultFeatureTableColumn(prop);
        // disable default sorting behaviour
        // column.setSortable( false );
        viewer.addColumn(column);
        first = first != null ? first : column;

        //                column.getViewerColumn().getColumn().addSelectionListener( new
        // SelectionAdapter() {
        //                    private SortOrder currentOrder = SortOrder.ASCENDING;
        //                    @Override
        //                    public void widgetSelected( SelectionEvent ev ) {
        //                        // with selection RAP produces huge JS which fails in browser
        //                        viewer.setSelection( StructuredSelection.EMPTY );
        //                        currentOrder = currentOrder.equals( ASCENDING ) ? DESCENDING :
        // ASCENDING;
        //                        contentProvider.sort( column, currentOrder );
        //                    }
        //                });
      }
    }

    // it is important to sort any column; otherwise preserving selection during refresh()
    // always selects a new element, which causes an event, which causes a refresh() ...
    first.sort(SWT.UP);

    //
    viewer.setInput(fs);

    // selection -> FeaturePanel
    viewer.addSelectionChangedListener(
        ev -> {
          on(ev.getSelection())
              .first(IFeatureTableElement.class)
              .ifPresent(
                  elm -> {
                    log.info("selection: " + elm);
                    featureLayer.setClicked(elm.unwrap(Feature.class).get());

                    BatikApplication.instance()
                        .getContext()
                        .openPanel(panel.site().path(), FeaturePanel.ID);
                  });
        });
  }
 private void printAttributeDescriptor(Writer w, PropertyDescriptor attrib)
     throws IOException {
   print(w, attrib.getName().toString());
   print(w, "\t");
   print(w, FieldType.forBinding(attrib.getType().getBinding()).name());
   print(w, "\t");
   print(w, Integer.toString(attrib.getMinOccurs()));
   print(w, "\t");
   print(w, Integer.toString(attrib.getMaxOccurs()));
   print(w, "\t");
   print(w, Boolean.toString(attrib.isNillable()));
   PropertyType attrType = attrib.getType();
   if (attrType instanceof GeometryType) {
     GeometryType gt = (GeometryType) attrType;
     CoordinateReferenceSystem crs = gt.getCoordinateReferenceSystem();
     String crsText = CrsTextSerializer.serialize(crs);
     print(w, "\t");
     println(w, crsText);
   } else {
     println(w, "");
   }
 }
  /**
   * This is a 'suitable replacement for extracting the expected field length of an attribute absed
   * on its "facets" (ie Filter describing type restrictions);
   *
   * <p>This code is copied from the ShapefileDataStore where it was written (probably by dzwiers).
   * Cholmes is providing documentation.
   *
   * @param type the AttributeType
   * @return an int indicating the max length of field in characters, or ANY_LENGTH
   */
  public static int getFieldLength(PropertyDescriptor descriptor) {
    PropertyType type = descriptor.getType();
    Integer length = null;
    while (type != null) {
      // TODO: We should really go through all the restrictions and find
      // the minimum of all the length restrictions; for now we assume an
      // override behavior.
      for (Filter f : type.getRestrictions()) {
        Integer filterLength = null;
        try {
          if (f == null) {
            continue;
          }
          if (f instanceof PropertyIsLessThan) {
            BinaryComparisonOperator cf = (BinaryComparisonOperator) f;
            if (cf.getExpression1() instanceof LengthFunction) {
              filterLength = cf.getExpression2().evaluate(null, Integer.class) - 1;
            }
          } else if (f instanceof PropertyIsLessThanOrEqualTo) {
            BinaryComparisonOperator cf = (BinaryComparisonOperator) f;
            if (cf.getExpression1() instanceof LengthFunction) {
              filterLength = cf.getExpression2().evaluate(null, Integer.class);
            }
          } else if (f instanceof PropertyIsGreaterThan) {
            BinaryComparisonOperator cf = (BinaryComparisonOperator) f;
            if (cf.getExpression2() instanceof LengthFunction) {
              filterLength = cf.getExpression1().evaluate(null, Integer.class) - 1;
            }
          } else if (f instanceof PropertyIsGreaterThanOrEqualTo) {
            BinaryComparisonOperator cf = (BinaryComparisonOperator) f;
            if (cf.getExpression2() instanceof LengthFunction) {
              filterLength = cf.getExpression1().evaluate(null, Integer.class);
            }
          }
        } catch (NullPointerException e) {
          // was not an integer eh? Continue, worst case we'll return ANY_LENGTH
        }

        if (filterLength != null) {
          if (length == null || filterLength < length) {
            length = filterLength;
          }
        }
      }
      type = type.getSuper();
    }

    return length != null ? length : ANY_LENGTH;
  }
  /**
   * Check if the given map layer contains a grid coverage or a grid coverage reader.
   *
   * <p>Implementation note: we avoid referencing org.geotools.coverage.grid classes directly here
   * so that applications dealing only with other data types are not forced to have JAI in the
   * classpath.
   *
   * @param layer the map layer
   * @return true if this is a grid layer; false otherwise
   */
  public static boolean isGridLayer(MapLayer layer) {

    Collection<PropertyDescriptor> descriptors =
        layer.getFeatureSource().getSchema().getDescriptors();
    for (PropertyDescriptor desc : descriptors) {
      Class<?> binding = desc.getType().getBinding();

      if (BASE_GRID_CLASS.isAssignableFrom(binding)
          || BASE_READER_CLASS.isAssignableFrom(binding)) {
        return true;
      }
    }

    return false;
  }
  private static void descriptorToJson(PropertyDescriptor desc, JSONBuilder json) {
    String name = desc.getName().getLocalPart();
    FieldTypeEnum type = FieldTypeEnum.forClass(desc.getType().getBinding());
    String alias = name;
    // TODO: For text fields we are expected to include a "length" field.

    json.object()
        .key("name")
        .value(name)
        .key("type")
        .value(type.getFieldType())
        .key("alias")
        .value(alias)
        .endObject();
  }
Beispiel #7
0
 private static void addDifference(
     String s,
     Map<PropertyDescriptor, AttributeDiff> map,
     RevFeatureType oldRevFeatureType,
     RevFeatureType newRevFeatureType) {
   String[] tokens = s.split("\t");
   PropertyDescriptor descriptor = oldRevFeatureType.type().getDescriptor(tokens[0]);
   if (descriptor == null) {
     descriptor = newRevFeatureType.type().getDescriptor(tokens[0]);
   }
   AttributeDiff ad =
       AttributeDiffFactory.attributeDiffFromText(
           descriptor.getType().getBinding(), s.substring(s.indexOf("\t") + 1));
   map.put(descriptor, ad);
 }
  public static String getGridAttributeName(MapLayer layer) {
    String attrName = null;

    Collection<PropertyDescriptor> descriptors =
        layer.getFeatureSource().getSchema().getDescriptors();
    for (PropertyDescriptor desc : descriptors) {
      Class<?> binding = desc.getType().getBinding();

      if (BASE_GRID_CLASS.isAssignableFrom(binding)
          || BASE_READER_CLASS.isAssignableFrom(binding)) {
        attrName = desc.getName().getLocalPart();
        break;
      }
    }

    return attrName;
  }
 protected void doSearch() {
   Filter filter = featureLayer.filter();
   String s = searchText.getText().getText();
   if (!StringUtils.isBlank(s)) {
     if (!s.contains("*") && !s.contains("?")) {
       s = s + "*";
     }
     for (PropertyDescriptor prop : fs.getSchema().getDescriptors()) {
       if (String.class.isAssignableFrom(prop.getType().getBinding())) {
         PropertyIsLike isLike = ff.like(ff.property(prop.getName()), s, "*", "?", "\\");
         filter = filter == Filter.INCLUDE ? isLike : ff.or(filter, isLike);
       }
     }
   }
   viewer.setSelection(StructuredSelection.EMPTY);
   log.info("FILTER: " + filter);
   //        FeatureCollection filtered = features.subCollection( filter );
   //        log.info( "RESULT: "  + filtered.size() );
   contentProvider.filter(filter);
 }
  @Override
  public void postCreateTable(String schemaName, SimpleFeatureType featureType, Connection cx)
      throws SQLException {

    Statement st = cx.createStatement();
    String tableName = featureType.getTypeName();

    try {
      // post process the feature type and set up constraints based on geometry type
      for (PropertyDescriptor ad : featureType.getDescriptors()) {
        if (ad instanceof GeometryDescriptor) {
          GeometryDescriptor gd = (GeometryDescriptor) ad;
          Class binding = ad.getType().getBinding();
          String propertyName = ad.getName().getLocalPart();

          // create a spatial index
          int epsg = -1;
          try {
            CoordinateReferenceSystem crs = gd.getCoordinateReferenceSystem();
            if (crs == null) {
              continue;
            }

            epsg = CRS.lookupEpsgCode(crs, true);
          } catch (FactoryException e) {
            LOGGER.log(Level.FINER, "Unable to look epsg code", e);
          }

          StringBuffer sql = new StringBuffer();
          sql.append("CALL AddGeometryColumn(");
          if (schemaName != null) {
            sql.append("'").append(schemaName).append("'");
          } else {
            sql.append("NULL");
          }
          sql.append(", '").append(tableName).append("'");
          sql.append(", '").append(gd.getLocalName()).append("'");
          sql.append(", ").append(epsg);
          sql.append(", '").append(Geometries.getForBinding(binding).getName()).append("'");
          sql.append(", ").append(2); // TODO: dimension
          sql.append(")");

          LOGGER.fine(sql.toString());
          st.execute(sql.toString());

          if (epsg != -1) {
            sql = new StringBuffer();
            sql.append("CALL CreateSpatialIndex(");
            if (schemaName == null) {
              sql.append("NULL");
            } else {
              sql.append("'").append(schemaName).append("'");
            }

            sql.append(",'").append(tableName).append("'");
            sql.append(",'").append(propertyName).append("'");
            sql.append(",'").append(epsg).append("')");

            LOGGER.fine(sql.toString());
            st.execute(sql.toString());
          }
        }
      }
    } finally {
      dataStore.closeSafe(st);
    }
  }
Beispiel #11
0
  private void writeCSV(GeoGIT geogit, Writer out, Iterator<RevCommit> log) throws Exception {
    String response =
        "ChangeType,FeatureId,CommitId,Parent CommitIds,Author Name,Author Email,Author Commit Time,Committer Name,Committer Email,Committer Commit Time,Commit Message";
    out.write(response);
    response = "";
    String path = paths.get(0);
    // This is the feature type object
    Optional<NodeRef> ref =
        geogit
            .command(FindTreeChild.class)
            .setChildPath(path)
            .setParent(geogit.getRepository().workingTree().getTree())
            .call();
    Optional<RevObject> type = Optional.absent();
    if (ref.isPresent()) {
      type =
          geogit
              .command(RevObjectParse.class)
              .setRefSpec(ref.get().getMetadataId().toString())
              .call();
    } else {
      throw new CommandSpecException("Couldn't resolve the given path.");
    }
    if (type.isPresent() && type.get() instanceof RevFeatureType) {
      RevFeatureType featureType = (RevFeatureType) type.get();
      Collection<PropertyDescriptor> attribs = featureType.type().getDescriptors();
      int attributeLength = attribs.size();
      for (PropertyDescriptor attrib : attribs) {
        response += "," + escapeCsv(attrib.getName().toString());
      }
      response += '\n';
      out.write(response);
      response = "";
      RevCommit commit = null;

      while (log.hasNext()) {
        commit = log.next();
        String parentId =
            commit.getParentIds().size() >= 1
                ? commit.getParentIds().get(0).toString()
                : ObjectId.NULL.toString();
        Iterator<DiffEntry> diff =
            geogit
                .command(DiffOp.class)
                .setOldVersion(parentId)
                .setNewVersion(commit.getId().toString())
                .setFilter(path)
                .call();
        while (diff.hasNext()) {
          DiffEntry entry = diff.next();
          response += entry.changeType().toString() + ",";
          String fid = "";
          if (entry.newPath() != null) {
            if (entry.oldPath() != null) {
              fid = entry.oldPath() + " -> " + entry.newPath();
            } else {
              fid = entry.newPath();
            }
          } else if (entry.oldPath() != null) {
            fid = entry.oldPath();
          }
          response += fid + ",";
          response += commit.getId().toString() + ",";
          response += parentId;
          if (commit.getParentIds().size() > 1) {
            for (int index = 1; index < commit.getParentIds().size(); index++) {
              response += " " + commit.getParentIds().get(index).toString();
            }
          }
          response += ",";
          if (commit.getAuthor().getName().isPresent()) {
            response += escapeCsv(commit.getAuthor().getName().get());
          }
          response += ",";
          if (commit.getAuthor().getEmail().isPresent()) {
            response += escapeCsv(commit.getAuthor().getEmail().get());
          }
          response +=
              ","
                  + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss z")
                      .format(new Date(commit.getAuthor().getTimestamp()))
                  + ",";
          if (commit.getCommitter().getName().isPresent()) {
            response += escapeCsv(commit.getCommitter().getName().get());
          }
          response += ",";
          if (commit.getCommitter().getEmail().isPresent()) {
            response += escapeCsv(commit.getCommitter().getEmail().get());
          }
          response +=
              ","
                  + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss z")
                      .format(new Date(commit.getCommitter().getTimestamp()))
                  + ",";
          String message = escapeCsv(commit.getMessage());
          response += message;
          if (entry.newObjectId() == ObjectId.NULL) {
            // Feature was removed so we need to fill out blank attribute values
            for (int index = 0; index < attributeLength; index++) {
              response += ",";
            }
          } else {
            // Feature was added or modified so we need to write out the
            // attribute
            // values from the feature
            Optional<RevObject> feature =
                geogit.command(RevObjectParse.class).setObjectId(entry.newObjectId()).call();
            RevFeature revFeature = (RevFeature) feature.get();
            List<Optional<Object>> values = revFeature.getValues();
            for (int index = 0; index < values.size(); index++) {
              Optional<Object> value = values.get(index);
              PropertyDescriptor attrib = (PropertyDescriptor) attribs.toArray()[index];
              String stringValue = "";
              if (value.isPresent()) {
                FieldType attributeType = FieldType.forBinding(attrib.getType().getBinding());
                switch (attributeType) {
                  case DATE:
                    stringValue =
                        new SimpleDateFormat("MM/dd/yyyy z").format((java.sql.Date) value.get());
                    break;
                  case DATETIME:
                    stringValue =
                        new SimpleDateFormat("MM/dd/yyyy HH:mm:ss z").format((Date) value.get());
                    break;
                  case TIME:
                    stringValue = new SimpleDateFormat("HH:mm:ss z").format((Time) value.get());
                    break;
                  case TIMESTAMP:
                    stringValue =
                        new SimpleDateFormat("MM/dd/yyyy HH:mm:ss z")
                            .format((Timestamp) value.get());
                    break;
                  default:
                    stringValue = escapeCsv(value.get().toString());
                }
                response += "," + stringValue;
              } else {
                response += ",";
              }
            }
          }
          response += '\n';
          out.write(response);
          response = "";
        }
      }
    } else {
      // Couldn't resolve FeatureType
      throw new CommandSpecException("Couldn't resolve the given path to a feature type.");
    }
  }
  /**
   * Write SQL string to create tables in the test database based on the property files.
   *
   * @param propertyFiles Property files from app-schema-test suite.
   * @param parser The parser (WKT or an SC4O one for 3D tests)
   * @throws IllegalAttributeException
   * @throws NoSuchElementException
   * @throws IOException
   */
  private void createTables(Map<String, File> propertyFiles, String parser)
      throws IllegalAttributeException, NoSuchElementException, IOException {

    StringBuffer buf = new StringBuffer();
    StringBuffer spatialIndex = new StringBuffer();
    // drop table procedure I copied from Victor's Oracle_Data_ref_set.sql
    buf.append("CREATE OR REPLACE PROCEDURE DROP_TABLE_OR_VIEW(TabName in Varchar2) IS ")
        .append("temp number:=0;")
        .append(" tes VARCHAR2 (200) := TabName;")
        .append(" drp_stmt VARCHAR2 (200):=null;")
        .append("BEGIN select count(*) into temp from user_tables where TABLE_NAME = tes;")
        .append("if temp = 1 then drp_stmt := 'Drop Table '||tes;")
        .append("EXECUTE IMMEDIATE drp_stmt;")
        // drop views too
        .append("else select count(*) into temp from user_views where VIEW_NAME = tes;")
        .append("if temp = 1 then drp_stmt := 'Drop VIEW '||tes;")
        .append("EXECUTE IMMEDIATE drp_stmt;end if;end if;")
        .append("EXCEPTION WHEN OTHERS THEN ")
        .append(
            "raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);")
        .append("END DROP_TABLE_OR_VIEW;\n");

    for (String fileName : propertyFiles.keySet()) {
      File file = new File(propertyFiles.get(fileName), fileName);

      try (PropertyFeatureReader reader = new PropertyFeatureReader("test", file)) {
        SimpleFeatureType schema = reader.getFeatureType();
        String tableName = schema.getName().getLocalPart().toUpperCase();
        // drop table if exists
        buf.append("CALL DROP_TABLE_OR_VIEW('").append(tableName).append("')\n");
        // create the table
        buf.append("CREATE TABLE ").append(tableName).append("(");
        // + pkey
        int size = schema.getAttributeCount() + 1;
        String[] fieldNames = new String[size];
        List<String> createParams = new ArrayList<String>();
        int j = 0;
        String type;
        String field;
        int spatialIndexCounter = 0;
        for (PropertyDescriptor desc : schema.getDescriptors()) {
          field = desc.getName().toString().toUpperCase();
          fieldNames[j] = field;
          if (desc instanceof GeometryDescriptor) {
            type = "SDO_GEOMETRY";
            // Update spatial index
            int srid = getSrid(((GeometryType) desc.getType()));

            spatialIndex
                .append("DELETE FROM user_sdo_geom_metadata WHERE table_name = '")
                .append(tableName)
                .append("'\n");

            spatialIndex
                .append("Insert into user_sdo_geom_metadata ")
                .append("(TABLE_NAME,COLUMN_NAME,DIMINFO,SRID)")
                .append("values ('")
                .append(tableName)
                .append("','")
                .append(field)
                .append("',MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',140.962,144.909,0.00001),")
                .append("MDSYS.SDO_DIM_ELEMENT('Y',-38.858,-33.98,0.00001)")
                .append( // support 3d index
                    ((GeometryDescriptor) desc).getCoordinateReferenceSystem() != null
                            && ((GeometryDescriptor) desc)
                                    .getCoordinateReferenceSystem()
                                    .getCoordinateSystem()
                                    .getDimension()
                                == 3
                        ? ", MDSYS.SDO_DIM_ELEMENT('Z',-100000, 100000, 1) ),"
                        : "),")
                .append(srid)
                .append(")\n");

            // ensure it's <= 30 characters to avoid Oracle exception
            String indexName =
                (tableName.length() <= 26 ? tableName : tableName.substring(0, 26)) + "_IDX";
            if (spatialIndexCounter > 0) {
              // to avoid duplicate index name when there are > 1 geometry in the same table
              indexName += spatialIndexCounter;
            }

            spatialIndex
                .append("CREATE INDEX \"")
                .append(indexName)
                .append("\" ON \"")
                .append(tableName)
                .append("\"(\"")
                .append(field)
                .append("\") ")
                .append("INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\"\n");
            spatialIndexCounter++;
          } else {
            type = Classes.getShortName(desc.getType().getBinding());
            if (type.equalsIgnoreCase("String")) {
              type = "NVARCHAR2(250)";
            } else if (type.equalsIgnoreCase("Double")) {
              type = "NUMBER";
            }
            // etc. assign as required
          }
          createParams.add(field + " " + type);
          j++;
        }
        // Add numeric PK for sorting
        fieldNames[j] = "PKEY";
        createParams.add("PKEY VARCHAR2(30)");
        buf.append(StringUtils.join(createParams.iterator(), ", "));
        buf.append(")\n");
        buf.append(
            "ALTER TABLE " + tableName + " ADD CONSTRAINT " + tableName + " PRIMARY KEY (PKEY)\n");
        // then insert rows
        SimpleFeature feature;
        FeatureId id;
        while (reader.hasNext()) {
          buf.append("INSERT INTO ").append(tableName).append("(");
          feature = reader.next();
          buf.append(StringUtils.join(fieldNames, ", "));
          buf.append(") ");
          buf.append("VALUES (");
          Collection<Property> properties = feature.getProperties();
          String[] values = new String[size];
          int valueIndex = 0;
          for (Property prop : properties) {
            Object value = prop.getValue();
            if (value instanceof Geometry) {
              // use wkt writer to convert geometry to string, so third dimension can be supported
              // if present.
              Geometry geom = (Geometry) value;
              value = new WKTWriter(geom.getCoordinate().z == Double.NaN ? 2 : 3).write(geom);
            }
            if (value == null || value.toString().equalsIgnoreCase("null")) {
              values[valueIndex] = "null";
            } else if (prop.getType() instanceof GeometryType) {
              int srid = getSrid(((GeometryType) prop.getType()));
              StringBuffer geomValue = new StringBuffer(parser + "('");
              geomValue.append(value).append("'");
              if (srid > -1) {
                // attach srid
                geomValue.append(", ").append(srid);
              }
              geomValue.append(")");
              values[valueIndex] = geomValue.toString();
            } else if (prop.getType().getBinding().getSimpleName().equalsIgnoreCase("DATE")) {
              values[valueIndex] = "TO_DATE('" + value + "', 'yyyy-MM-dd')";
            } else {
              values[valueIndex] = "'" + value + "'";
            }
            valueIndex++;
          }
          id = feature.getIdentifier();
          // insert primary key
          values[valueIndex] = "'" + id.toString() + "'";
          buf.append(StringUtils.join(values, ","));
          buf.append(")\n");
        }
      }
      buf.append(spatialIndex.toString());
      spatialIndex.delete(0, spatialIndex.length());
      if (buf.length() > 0) {
        this.sql = buf.toString();
      }
    }
  }
  public void post(Representation entity) {
    InputStream input = null;

    try {
      input = getRequest().getEntity().getStream();
      final GeoGIG ggit = getGeogig(getRequest()).get();
      final Reader body = new InputStreamReader(input);
      final JsonParser parser = new JsonParser();
      final JsonElement conflictJson = parser.parse(body);

      if (conflictJson.isJsonObject()) {
        final JsonObject conflict = conflictJson.getAsJsonObject();
        String featureId = null;
        RevFeature ourFeature = null;
        RevFeatureType ourFeatureType = null;
        RevFeature theirFeature = null;
        RevFeatureType theirFeatureType = null;
        JsonObject merges = null;
        if (conflict.has("path") && conflict.get("path").isJsonPrimitive()) {
          featureId = conflict.get("path").getAsJsonPrimitive().getAsString();
        }
        Preconditions.checkState(featureId != null);

        if (conflict.has("ours") && conflict.get("ours").isJsonPrimitive()) {
          String ourCommit = conflict.get("ours").getAsJsonPrimitive().getAsString();
          Optional<NodeRef> ourNode = parseID(ObjectId.valueOf(ourCommit), featureId, ggit);
          if (ourNode.isPresent()) {
            Optional<RevObject> object =
                ggit.command(RevObjectParse.class).setObjectId(ourNode.get().objectId()).call();
            Preconditions.checkState(object.isPresent() && object.get() instanceof RevFeature);

            ourFeature = (RevFeature) object.get();

            object =
                ggit.command(RevObjectParse.class)
                    .setObjectId(ourNode.get().getMetadataId())
                    .call();
            Preconditions.checkState(object.isPresent() && object.get() instanceof RevFeatureType);

            ourFeatureType = (RevFeatureType) object.get();
          }
        }

        if (conflict.has("theirs") && conflict.get("theirs").isJsonPrimitive()) {
          String theirCommit = conflict.get("theirs").getAsJsonPrimitive().getAsString();
          Optional<NodeRef> theirNode = parseID(ObjectId.valueOf(theirCommit), featureId, ggit);
          if (theirNode.isPresent()) {
            Optional<RevObject> object =
                ggit.command(RevObjectParse.class).setObjectId(theirNode.get().objectId()).call();
            Preconditions.checkState(object.isPresent() && object.get() instanceof RevFeature);

            theirFeature = (RevFeature) object.get();

            object =
                ggit.command(RevObjectParse.class)
                    .setObjectId(theirNode.get().getMetadataId())
                    .call();
            Preconditions.checkState(object.isPresent() && object.get() instanceof RevFeatureType);

            theirFeatureType = (RevFeatureType) object.get();
          }
        }

        if (conflict.has("merges") && conflict.get("merges").isJsonObject()) {
          merges = conflict.get("merges").getAsJsonObject();
        }
        Preconditions.checkState(merges != null);

        Preconditions.checkState(ourFeatureType != null || theirFeatureType != null);

        SimpleFeatureBuilder featureBuilder =
            new SimpleFeatureBuilder(
                (SimpleFeatureType)
                    (ourFeatureType != null ? ourFeatureType.type() : theirFeatureType.type()));

        ImmutableList<PropertyDescriptor> descriptors =
            (ourFeatureType == null ? theirFeatureType : ourFeatureType).sortedDescriptors();

        for (Entry<String, JsonElement> entry : merges.entrySet()) {
          int descriptorIndex = getDescriptorIndex(entry.getKey(), descriptors);
          if (descriptorIndex != -1 && entry.getValue().isJsonObject()) {
            PropertyDescriptor descriptor = descriptors.get(descriptorIndex);
            JsonObject attributeObject = entry.getValue().getAsJsonObject();
            if (attributeObject.has("ours")
                && attributeObject.get("ours").isJsonPrimitive()
                && attributeObject.get("ours").getAsBoolean()) {
              featureBuilder.set(
                  descriptor.getName(),
                  ourFeature == null ? null : ourFeature.getValues().get(descriptorIndex).orNull());
            } else if (attributeObject.has("theirs")
                && attributeObject.get("theirs").isJsonPrimitive()
                && attributeObject.get("theirs").getAsBoolean()) {
              featureBuilder.set(
                  descriptor.getName(),
                  theirFeature == null
                      ? null
                      : theirFeature.getValues().get(descriptorIndex).orNull());
            } else if (attributeObject.has("value")
                && attributeObject.get("value").isJsonPrimitive()) {
              JsonPrimitive primitive = attributeObject.get("value").getAsJsonPrimitive();
              if (primitive.isString()) {
                try {
                  Object object =
                      valueFromString(
                          FieldType.forBinding(descriptor.getType().getBinding()),
                          primitive.getAsString());
                  featureBuilder.set(descriptor.getName(), object);
                } catch (Exception e) {
                  throw new Exception(
                      "Unable to convert attribute ("
                          + entry.getKey()
                          + ") to required type: "
                          + descriptor.getType().getBinding().toString());
                }
              } else if (primitive.isNumber()) {
                try {
                  Object value =
                      valueFromNumber(
                          FieldType.forBinding(descriptor.getType().getBinding()),
                          primitive.getAsNumber());
                  featureBuilder.set(descriptor.getName(), value);
                } catch (Exception e) {
                  throw new Exception(
                      "Unable to convert attribute ("
                          + entry.getKey()
                          + ") to required type: "
                          + descriptor.getType().getBinding().toString());
                }
              } else if (primitive.isBoolean()) {
                try {
                  Object value =
                      valueFromBoolean(
                          FieldType.forBinding(descriptor.getType().getBinding()),
                          primitive.getAsBoolean());
                  featureBuilder.set(descriptor.getName(), value);
                } catch (Exception e) {
                  throw new Exception(
                      "Unable to convert attribute ("
                          + entry.getKey()
                          + ") to required type: "
                          + descriptor.getType().getBinding().toString());
                }
              } else if (primitive.isJsonNull()) {
                featureBuilder.set(descriptor.getName(), null);
              } else {
                throw new Exception(
                    "Unsupported JSON type for attribute value (" + entry.getKey() + ")");
              }
            }
          }
        }
        SimpleFeature feature = featureBuilder.buildFeature(NodeRef.nodeFromPath(featureId));
        RevFeature revFeature = RevFeatureBuilder.build(feature);
        ggit.getRepository().stagingDatabase().put(revFeature);

        getResponse()
            .setEntity(
                new StringRepresentation(revFeature.getId().toString(), MediaType.TEXT_PLAIN));
      }

    } catch (Exception e) {
      throw new RestletException(e.getMessage(), Status.SERVER_ERROR_INTERNAL, e);
    } finally {
      if (input != null) Closeables.closeQuietly(input);
    }
  }