private void serializeNullValue(ParseContext context, String lastFieldName) throws IOException {
   // we can only handle null values if we have mappings for them
   Mapper mapper = mappers.get(lastFieldName);
   if (mapper != null) {
     mapper.parse(context);
   }
 }
 @Override
 public void traverse(ObjectMapperListener objectMapperListener) {
   objectMapperListener.objectMapper(this);
   for (Mapper mapper : mappers.values()) {
     mapper.traverse(objectMapperListener);
   }
 }
    @Override
    public Y build(BuilderContext context) {
      ContentPath.Type origPathType = context.path().pathType();
      context.path().pathType(pathType);
      context.path().add(name);

      Map<String, Mapper> mappers = new HashMap<>();
      for (Mapper.Builder builder : mappersBuilders) {
        Mapper mapper = builder.build(context);
        mappers.put(mapper.simpleName(), mapper);
      }
      context.path().pathType(origPathType);
      context.path().remove();

      ObjectMapper objectMapper =
          createMapper(
              name,
              context.path().fullPathAsText(name),
              enabled,
              nested,
              dynamic,
              pathType,
              mappers,
              context.indexSettings());
      objectMapper.includeInAllIfNotSet(includeInAll);

      return (Y) objectMapper;
    }
 private void serializeArray(ParseContext context, String lastFieldName) throws IOException {
   String arrayFieldName = lastFieldName;
   Mapper mapper = mappers.get(lastFieldName);
   if (mapper != null && mapper instanceof ArrayValueMapperParser) {
     mapper.parse(context);
   } else {
     XContentParser parser = context.parser();
     XContentParser.Token token;
     while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
       if (token == XContentParser.Token.START_OBJECT) {
         serializeObject(context, lastFieldName);
       } else if (token == XContentParser.Token.START_ARRAY) {
         serializeArray(context, lastFieldName);
       } else if (token == XContentParser.Token.FIELD_NAME) {
         lastFieldName = parser.currentName();
       } else if (token == XContentParser.Token.VALUE_NULL) {
         serializeNullValue(context, lastFieldName);
       } else if (token == null) {
         throw new MapperParsingException(
             "object mapping for ["
                 + name
                 + "] with array for ["
                 + arrayFieldName
                 + "] tried to parse as array, but got EOF, is there a mismatch in types for the same field?");
       } else {
         serializeValue(context, lastFieldName, token);
       }
     }
   }
 }
Beispiel #5
0
  @Override
  public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
    builder.startObject(name());
    builder.field("type", RegisterOntologyType.ONTOLOGY_TYPE);

    builder.startObject(OntologySettings.ONTOLOGY_SETTINGS_KEY);
    if (StringUtils.isNotBlank(ontologySettings.getOntologyUri())) {
      builder.field(OntologySettings.ONTOLOGY_URI_PARAM, ontologySettings.getOntologyUri());
      builder.field(OntologySettings.LABEL_URI_PARAM, ontologySettings.getLabelPropertyUris());
      builder.field(
          OntologySettings.DEFINITION_URI_PARAM, ontologySettings.getDefinitionPropertyUris());
      builder.field(OntologySettings.SYNONYM_URI_PARAM, ontologySettings.getSynonymPropertyUris());
    }
    if (StringUtils.isNotBlank(ontologySettings.getOlsBaseUrl())) {
      builder.field(OntologySettings.OLS_BASE_URL_PARAM, ontologySettings.getOlsBaseUrl());
      builder.field(OntologySettings.OLS_ONTOLOGY_PARAM, ontologySettings.getOlsOntology());
    }
    builder.field(OntologySettings.INCLUDE_INDIRECT_PARAM, ontologySettings.isIncludeIndirect());
    builder.field(OntologySettings.INCLUDE_RELATIONS_PARAM, ontologySettings.isIncludeRelations());
    builder.endObject();

    builder.startObject(ONTOLOGY_PROPERTIES);
    for (Mapper mapper : sortMappers()) {
      mapper.toXContent(builder, params);
    }
    builder.endObject(); // ontology_properties

    builder.endObject(); // name

    return builder;
  }
  private void serializeObject(final ParseContext context, String currentFieldName)
      throws IOException {
    if (currentFieldName == null) {
      throw new MapperParsingException(
          "object mapping ["
              + name
              + "] trying to serialize an object with no field associated with it, current value ["
              + context.parser().textOrNull()
              + "]");
    }
    context.path().add(currentFieldName);

    Mapper objectMapper = mappers.get(currentFieldName);
    if (objectMapper != null) {
      objectMapper.parse(context);
    } else {
      Dynamic dynamic = this.dynamic;
      if (dynamic == null) {
        dynamic = context.root().dynamic();
      }
      if (dynamic == Dynamic.STRICT) {
        throw new StrictDynamicMappingException(fullPath, currentFieldName);
      } else if (dynamic == Dynamic.TRUE) {
        // we sync here just so we won't add it twice. Its not the end of the world
        // to sync here since next operations will get it before
        synchronized (mutex) {
          objectMapper = mappers.get(currentFieldName);
          if (objectMapper == null) {
            // remove the current field name from path, since template search and the object builder
            // add it as well...
            context.path().remove();
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "object");
            if (builder == null) {
              builder = MapperBuilders.object(currentFieldName).enabled(true).pathType(pathType);
              // if this is a non root object, then explicitly set the dynamic behavior if set
              if (!(this instanceof RootObjectMapper) && this.dynamic != Defaults.DYNAMIC) {
                ((Builder) builder).dynamic(this.dynamic);
              }
            }
            BuilderContext builderContext =
                new BuilderContext(context.indexSettings(), context.path());
            objectMapper = builder.build(builderContext);
            putDynamicMapper(context, currentFieldName, objectMapper);
          } else {
            objectMapper.parse(context);
          }
        }
      } else {
        // not dynamic, read everything up to end object
        context.parser().skipChildren();
      }
    }

    context.path().remove();
  }
 private void serializeNullValue(ParseContext context, String lastFieldName) throws IOException {
   // we can only handle null values if we have mappings for them
   Mapper mapper = mappers.get(lastFieldName);
   if (mapper != null) {
     if (mapper instanceof FieldMapper) {
       if (!((FieldMapper) mapper).supportsNullValue()) {
         throw new MapperParsingException(
             "no object mapping found for null value in [" + lastFieldName + "]");
       }
     }
     mapper.parse(context);
   }
 }
  private void serializeArray(ParseContext context, String lastFieldName) throws IOException {
    String arrayFieldName = lastFieldName;
    Mapper mapper = mappers.get(lastFieldName);
    if (mapper != null) {
      // There is a concrete mapper for this field already. Need to check if the mapper
      // expects an array, if so we pass the context straight to the mapper and if not
      // we serialize the array components
      if (mapper instanceof ArrayValueMapperParser) {
        mapper.parse(context);
      } else {
        serializeNonDynamicArray(context, lastFieldName, arrayFieldName);
      }
    } else {

      Dynamic dynamic = this.dynamic;
      if (dynamic == null) {
        dynamic = context.root().dynamic();
      }
      if (dynamic == Dynamic.STRICT) {
        throw new StrictDynamicMappingException(fullPath, arrayFieldName);
      } else if (dynamic == Dynamic.TRUE) {
        // we sync here just so we won't add it twice. Its not the end of the world
        // to sync here since next operations will get it before
        synchronized (mutex) {
          mapper = mappers.get(arrayFieldName);
          if (mapper == null) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, arrayFieldName, "object");
            if (builder == null) {
              serializeNonDynamicArray(context, lastFieldName, arrayFieldName);
              return;
            }
            BuilderContext builderContext =
                new BuilderContext(context.indexSettings(), context.path());
            mapper = builder.build(builderContext);
            if (mapper != null && mapper instanceof ArrayValueMapperParser) {
              putDynamicMapper(context, arrayFieldName, mapper);
            } else {
              serializeNonDynamicArray(context, lastFieldName, arrayFieldName);
            }
          } else {

            serializeNonDynamicArray(context, lastFieldName, arrayFieldName);
          }
        }
      } else {

        serializeNonDynamicArray(context, lastFieldName, arrayFieldName);
      }
    }
  }
 public ObjectMapper putMapper(Mapper mapper) {
   if (mapper instanceof AllFieldMapper.IncludeInAll) {
     ((AllFieldMapper.IncludeInAll) mapper).includeInAllIfNotSet(includeInAll);
   }
   synchronized (mutex) {
     mappers = mappers.copyAndPut(mapper.name(), mapper);
   }
   return this;
 }
 private void serializeValue(
     final ParseContext context, String currentFieldName, XContentParser.Token token)
     throws IOException {
   if (currentFieldName == null) {
     throw new MapperParsingException(
         "object mapping ["
             + name
             + "] trying to serialize a value with no field associated with it, current value ["
             + context.parser().textOrNull()
             + "]");
   }
   Mapper mapper = mappers.get(currentFieldName);
   if (mapper != null) {
     mapper.parse(context);
   } else {
     parseDynamicValue(context, currentFieldName, token);
   }
 }
 public ObjectMapper putMapper(Mapper mapper) {
   if (mapper instanceof AllFieldMapper.IncludeInAll) {
     ((AllFieldMapper.IncludeInAll) mapper).includeInAllIfNotSet(includeInAll);
   }
   synchronized (mutex) {
     mappers = newMapBuilder(mappers).put(mapper.name(), mapper).immutableMap();
   }
   return this;
 }
 @Override
 public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException {
   super.merge(mergeWith, mergeContext);
   if (!this.getClass().equals(mergeWith.getClass())) {
     return;
   }
   if (!mergeContext.mergeFlags().simulate()) {
     this.nullValue = ((IpFieldMapper) mergeWith).nullValue;
   }
 }
Beispiel #13
0
 public ObjectMapper putMapper(Mapper mapper) {
   if (mapper instanceof AllFieldMapper.IncludeInAll) {
     ((AllFieldMapper.IncludeInAll) mapper).includeInAllIfNotSet(includeInAll);
   }
   synchronized (mutex) {
     UpdateInPlaceMap<String, Mapper>.Mutator mappingMutator = this.mappers.mutator();
     mappingMutator.put(mapper.name(), mapper);
     mappingMutator.close();
   }
   return this;
 }
 @Override
 public void merge(Mapper mergeWith, MergeResult mergeResult) throws MergeMappingException {
   super.merge(mergeWith, mergeResult);
   if (!this.getClass().equals(mergeWith.getClass())) {
     return;
   }
   if (!mergeResult.simulate()) {
     this.fieldType = this.fieldType.clone();
     this.fieldType.setNullValue(((ShortFieldMapper) mergeWith).fieldType().nullValue());
     this.fieldType.freeze();
   }
 }
 private void serializeArray(ParseContext context, String lastFieldName) throws IOException {
   Mapper mapper = mappers.get(lastFieldName);
   if (mapper != null && mapper instanceof ArrayValueMapperParser) {
     mapper.parse(context);
   } else {
     XContentParser parser = context.parser();
     XContentParser.Token token;
     while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
       if (token == XContentParser.Token.START_OBJECT) {
         serializeObject(context, lastFieldName);
       } else if (token == XContentParser.Token.START_ARRAY) {
         serializeArray(context, lastFieldName);
       } else if (token == XContentParser.Token.FIELD_NAME) {
         lastFieldName = parser.currentName();
       } else if (token == XContentParser.Token.VALUE_NULL) {
         serializeNullValue(context, lastFieldName);
       } else {
         serializeValue(context, lastFieldName, token);
       }
     }
   }
 }
 @Override
 public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException {
   super.merge(mergeWith, mergeContext);
   if (!this.getClass().equals(mergeWith.getClass())) {
     return;
   }
   if (!mergeContext.mergeFlags().simulate()) {
     this.precisionStep = ((NumberFieldMapper) mergeWith).precisionStep;
     this.includeInAll = ((NumberFieldMapper) mergeWith).includeInAll;
     this.fuzzyFactor = ((NumberFieldMapper) mergeWith).fuzzyFactor;
     this.dFuzzyFactor = parseFuzzyFactor(this.fuzzyFactor);
   }
 }
  @Override
  public void merge(Mapper mergeWith, MergeResult mergeResult) throws MergeMappingException {
    super.merge(mergeWith, mergeResult);
    if (!this.getClass().equals(mergeWith.getClass())) {
      return;
    }

    GeoShapeFieldMapper gsfm = (GeoShapeFieldMapper) mergeWith;
    if (mergeResult.simulate() == false && mergeResult.hasConflicts() == false) {
      if (gsfm.coerce.explicit()) {
        this.coerce = gsfm.coerce;
      }
    }
  }
  private void putDynamicMapper(ParseContext context, String arrayFieldName, Mapper mapper)
      throws IOException {
    // ...now re add it
    context.path().add(arrayFieldName);
    context.setMappingsModified();

    if (context.isWithinNewMapper()) {
      // within a new mapper, no need to traverse,
      // just parse
      mapper.parse(context);
    } else {
      // create a context of new mapper, so we batch
      // aggregate all the changes within
      // this object mapper once, and traverse all of
      // them to add them in a single go
      context.setWithinNewMapper();
      try {
        mapper.parse(context);
        FieldMapperListener.Aggregator newFields = new FieldMapperListener.Aggregator();
        ObjectMapperListener.Aggregator newObjects = new ObjectMapperListener.Aggregator();
        mapper.traverse(newFields);
        mapper.traverse(newObjects);
        // callback on adding those fields!
        context.docMapper().addFieldMappers(newFields.mappers);
        context.docMapper().addObjectMappers(newObjects.mappers);
      } finally {
        context.clearWithinNewMapper();
      }
    }

    // only put after we traversed and did the
    // callbacks, so other parsing won't see it only
    // after we
    // properly traversed it and adding the mappers
    putMapper(mapper);
  }
Beispiel #19
0
 @Override
 public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException {
   super.merge(mergeWith, mergeContext);
   if (!this.getClass().equals(mergeWith.getClass())) {
     return;
   }
   OntologySettings mergeSettings = ((OntologyMapper) mergeWith).ontologySettings;
   if (mergeSettings.getOntologyUri() != null
       && !mergeSettings.getOntologyUri().equals(ontologySettings.getOntologyUri())) {
     mergeContext.addConflict("mapper [" + names.fullName() + "] has different ontology URI");
   } else if (mergeSettings.getOlsBaseUrl() != null
       && !mergeSettings.getOlsBaseUrl().equals(ontologySettings.getOlsBaseUrl())) {
     mergeContext.addConflict("mapper [" + names.fullName() + "] has different OLS base URL");
   }
 }
  @Override
  public void merge(final Mapper mergeWith, final MergeContext mergeContext)
      throws MergeMappingException {
    if (!(mergeWith instanceof ObjectMapper)) {
      mergeContext.addConflict(
          "Can't merge a non object mapping ["
              + mergeWith.name()
              + "] with an object mapping ["
              + name()
              + "]");
      return;
    }
    ObjectMapper mergeWithObject = (ObjectMapper) mergeWith;

    if (nested().isNested()) {
      if (!mergeWithObject.nested().isNested()) {
        mergeContext.addConflict(
            "object mapping [" + name() + "] can't be changed from nested to non-nested");
        return;
      }
    } else {
      if (mergeWithObject.nested().isNested()) {
        mergeContext.addConflict(
            "object mapping [" + name() + "] can't be changed from non-nested to nested");
        return;
      }
    }

    doMerge(mergeWithObject, mergeContext);

    List<Mapper> mappersToTraverse = new ArrayList<Mapper>();
    synchronized (mutex) {
      for (Mapper mergeWithMapper : mergeWithObject.mappers.values()) {
        Mapper mergeIntoMapper = mappers.get(mergeWithMapper.name());
        if (mergeIntoMapper == null) {
          // no mapping, simply add it if not simulating
          if (!mergeContext.mergeFlags().simulate()) {
            putMapper(mergeWithMapper);
            mappersToTraverse.add(mergeWithMapper);
          }
        } else {
          if ((mergeWithMapper instanceof MultiFieldMapper)
              && !(mergeIntoMapper instanceof MultiFieldMapper)) {
            MultiFieldMapper mergeWithMultiField = (MultiFieldMapper) mergeWithMapper;
            mergeWithMultiField.merge(mergeIntoMapper, mergeContext);
            if (!mergeContext.mergeFlags().simulate()) {
              putMapper(mergeWithMultiField);
              // now, record mappers to traverse events for all mappers
              for (Mapper mapper : mergeWithMultiField.mappers().values()) {
                mappersToTraverse.add(mapper);
              }
            }
          } else {
            mergeIntoMapper.merge(mergeWithMapper, mergeContext);
          }
        }
      }
    }
    // call this outside of the mutex
    for (Mapper mapper : mappersToTraverse) {
      mapper.traverse(mergeContext.newFieldMappers());
      mapper.traverse(mergeContext.newObjectMappers());
    }
  }
  public void toXContent(XContentBuilder builder, Params params, ToXContent custom)
      throws IOException {
    builder.startObject(simpleName());
    if (nested.isNested()) {
      builder.field("type", NESTED_CONTENT_TYPE);
      if (nested.isIncludeInParent()) {
        builder.field("include_in_parent", true);
      }
      if (nested.isIncludeInRoot()) {
        builder.field("include_in_root", true);
      }
    } else if (mappers.isEmpty()
        && custom
            == null) { // only write the object content type if there are no properties, otherwise,
                       // it is automatically detected
      builder.field("type", CONTENT_TYPE);
    }
    if (dynamic != null) {
      builder.field("dynamic", dynamic.name().toLowerCase(Locale.ROOT));
    }
    if (enabled != Defaults.ENABLED) {
      builder.field("enabled", enabled);
    }
    if (pathType != Defaults.PATH_TYPE) {
      builder.field("path", pathType.name().toLowerCase(Locale.ROOT));
    }
    if (includeInAll != null) {
      builder.field("include_in_all", includeInAll);
    }

    if (custom != null) {
      custom.toXContent(builder, params);
    }

    doXContent(builder, params);

    // sort the mappers so we get consistent serialization format
    Mapper[] sortedMappers = Iterables.toArray(mappers.values(), Mapper.class);
    Arrays.sort(
        sortedMappers,
        new Comparator<Mapper>() {
          @Override
          public int compare(Mapper o1, Mapper o2) {
            return o1.name().compareTo(o2.name());
          }
        });

    int count = 0;
    for (Mapper mapper : sortedMappers) {
      if (!(mapper instanceof MetadataFieldMapper)) {
        if (count++ == 0) {
          builder.startObject("properties");
        }
        mapper.toXContent(builder, params);
      }
    }
    if (count > 0) {
      builder.endObject();
    }
    builder.endObject();
  }
  @Override
  public void merge(final Mapper mergeWith, final MergeResult mergeResult)
      throws MergeMappingException {
    if (!(mergeWith instanceof ObjectMapper)) {
      mergeResult.addConflict(
          "Can't merge a non object mapping ["
              + mergeWith.name()
              + "] with an object mapping ["
              + name()
              + "]");
      return;
    }
    ObjectMapper mergeWithObject = (ObjectMapper) mergeWith;

    if (nested().isNested()) {
      if (!mergeWithObject.nested().isNested()) {
        mergeResult.addConflict(
            "object mapping [" + name() + "] can't be changed from nested to non-nested");
        return;
      }
    } else {
      if (mergeWithObject.nested().isNested()) {
        mergeResult.addConflict(
            "object mapping [" + name() + "] can't be changed from non-nested to nested");
        return;
      }
    }

    if (!mergeResult.simulate()) {
      if (mergeWithObject.dynamic != null) {
        this.dynamic = mergeWithObject.dynamic;
      }
    }

    doMerge(mergeWithObject, mergeResult);

    List<Mapper> mappersToPut = new ArrayList<>();
    List<ObjectMapper> newObjectMappers = new ArrayList<>();
    List<FieldMapper> newFieldMappers = new ArrayList<>();
    for (Mapper mapper : mergeWithObject) {
      Mapper mergeWithMapper = mapper;
      Mapper mergeIntoMapper = mappers.get(mergeWithMapper.simpleName());
      if (mergeIntoMapper == null) {
        // no mapping, simply add it if not simulating
        if (!mergeResult.simulate()) {
          mappersToPut.add(mergeWithMapper);
          MapperUtils.collect(mergeWithMapper, newObjectMappers, newFieldMappers);
        }
      } else if (mergeIntoMapper instanceof MetadataFieldMapper == false) {
        // root mappers can only exist here for backcompat, and are merged in Mapping
        mergeIntoMapper.merge(mergeWithMapper, mergeResult);
      }
    }
    if (!newFieldMappers.isEmpty()) {
      mergeResult.addFieldMappers(newFieldMappers);
    }
    if (!newObjectMappers.isEmpty()) {
      mergeResult.addObjectMappers(newObjectMappers);
    }
    // add the mappers only after the administration have been done, so it will not be visible to
    // parser (which first try to read with no lock)
    for (Mapper mapper : mappersToPut) {
      putMapper(mapper);
    }
  }
 /**
  * Put a new mapper. NOTE: this method must be called under the current {@link DocumentMapper}
  * lock if concurrent updates are expected.
  */
 public void putMapper(Mapper mapper) {
   if (mapper instanceof AllFieldMapper.IncludeInAll) {
     ((AllFieldMapper.IncludeInAll) mapper).includeInAllIfNotSet(includeInAll);
   }
   mappers = mappers.copyAndPut(mapper.simpleName(), mapper);
 }
  public void parseDynamicValue(
      final ParseContext context, String currentFieldName, XContentParser.Token token)
      throws IOException {
    Dynamic dynamic = this.dynamic;
    if (dynamic == null) {
      dynamic = context.root().dynamic();
    }
    if (dynamic == Dynamic.STRICT) {
      throw new StrictDynamicMappingException(fullPath, currentFieldName);
    }
    if (dynamic == Dynamic.FALSE) {
      return;
    }
    // we sync here since we don't want to add this field twice to the document mapper
    // its not the end of the world, since we add it to the mappers once we create it
    // so next time we won't even get here for this field
    synchronized (mutex) {
      Mapper mapper = mappers.get(currentFieldName);
      if (mapper == null) {
        BuilderContext builderContext = new BuilderContext(context.indexSettings(), context.path());
        if (token == XContentParser.Token.VALUE_STRING) {
          boolean resolved = false;

          // do a quick test to see if its fits a dynamic template, if so, use it.
          // we need to do it here so we can handle things like attachment templates, where calling
          // text (to see if its a date) causes the binary value to be cleared
          if (!resolved) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "string", null);
            if (builder != null) {
              mapper = builder.build(builderContext);
              resolved = true;
            }
          }

          if (!resolved && context.parser().textLength() == 0) {
            // empty string with no mapping, treat it like null value
            return;
          }

          if (!resolved && context.root().dateDetection()) {
            String text = context.parser().text();
            // a safe check since "1" gets parsed as well
            if (Strings.countOccurrencesOf(text, ":") > 1
                || Strings.countOccurrencesOf(text, "-") > 1
                || Strings.countOccurrencesOf(text, "/") > 1) {
              for (FormatDateTimeFormatter dateTimeFormatter :
                  context.root().dynamicDateTimeFormatters()) {
                try {
                  dateTimeFormatter.parser().parseMillis(text);
                  Mapper.Builder builder =
                      context.root().findTemplateBuilder(context, currentFieldName, "date");
                  if (builder == null) {
                    builder = dateField(currentFieldName).dateTimeFormatter(dateTimeFormatter);
                  }
                  mapper = builder.build(builderContext);
                  resolved = true;
                  break;
                } catch (Exception e) {
                  // failure to parse this, continue
                }
              }
            }
          }
          if (!resolved && context.root().numericDetection()) {
            String text = context.parser().text();
            try {
              Long.parseLong(text);
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "long");
              if (builder == null) {
                builder = longField(currentFieldName);
              }
              mapper = builder.build(builderContext);
              resolved = true;
            } catch (Exception e) {
              // not a long number
            }
            if (!resolved) {
              try {
                Double.parseDouble(text);
                Mapper.Builder builder =
                    context.root().findTemplateBuilder(context, currentFieldName, "double");
                if (builder == null) {
                  builder = doubleField(currentFieldName);
                }
                mapper = builder.build(builderContext);
                resolved = true;
              } catch (Exception e) {
                // not a long number
              }
            }
          }
          if (!resolved) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "string");
            if (builder == null) {
              builder = stringField(currentFieldName);
            }
            mapper = builder.build(builderContext);
          }
        } else if (token == XContentParser.Token.VALUE_NUMBER) {
          XContentParser.NumberType numberType = context.parser().numberType();
          if (numberType == XContentParser.NumberType.INT) {
            if (context.parser().estimatedNumberType()) {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "long");
              if (builder == null) {
                builder = longField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            } else {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "integer");
              if (builder == null) {
                builder = integerField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            }
          } else if (numberType == XContentParser.NumberType.LONG) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "long");
            if (builder == null) {
              builder = longField(currentFieldName);
            }
            mapper = builder.build(builderContext);
          } else if (numberType == XContentParser.NumberType.FLOAT) {
            if (context.parser().estimatedNumberType()) {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "double");
              if (builder == null) {
                builder = doubleField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            } else {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "float");
              if (builder == null) {
                builder = floatField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            }
          } else if (numberType == XContentParser.NumberType.DOUBLE) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "double");
            if (builder == null) {
              builder = doubleField(currentFieldName);
            }
            mapper = builder.build(builderContext);
          }
        } else if (token == XContentParser.Token.VALUE_BOOLEAN) {
          Mapper.Builder builder =
              context.root().findTemplateBuilder(context, currentFieldName, "boolean");
          if (builder == null) {
            builder = booleanField(currentFieldName);
          }
          mapper = builder.build(builderContext);
        } else if (token == XContentParser.Token.VALUE_EMBEDDED_OBJECT) {
          Mapper.Builder builder =
              context.root().findTemplateBuilder(context, currentFieldName, "binary");
          if (builder == null) {
            builder = binaryField(currentFieldName);
          }
          mapper = builder.build(builderContext);
        } else {
          Mapper.Builder builder =
              context.root().findTemplateBuilder(context, currentFieldName, null);
          if (builder != null) {
            mapper = builder.build(builderContext);
          } else {
            // TODO how do we identify dynamically that its a binary value?
            throw new ElasticsearchIllegalStateException(
                "Can't handle serializing a dynamic type with content token ["
                    + token
                    + "] and field name ["
                    + currentFieldName
                    + "]");
          }
        }

        if (context.isWithinNewMapper()) {
          mapper.parse(context);
        } else {
          context.setWithinNewMapper();
          try {
            mapper.parse(context);
            FieldMapperListener.Aggregator newFields = new FieldMapperListener.Aggregator();
            mapper.traverse(newFields);
            context.docMapper().addFieldMappers(newFields.mappers);
          } finally {
            context.clearWithinNewMapper();
          }
        }

        // only put after we traversed and did the callbacks, so other parsing won't see it only
        // after we
        // properly traversed it and adding the mappers
        putMapper(mapper);
        context.setMappingsModified();
      } else {
        mapper.parse(context);
      }
    }
  }
  public void toXContent(
      XContentBuilder builder, Params params, ToXContent custom, Mapper... additionalMappers)
      throws IOException {
    builder.startObject(name);
    if (nested.isNested()) {
      builder.field("type", NESTED_CONTENT_TYPE);
      if (nested.isIncludeInParent()) {
        builder.field("include_in_parent", true);
      }
      if (nested.isIncludeInRoot()) {
        builder.field("include_in_root", true);
      }
    } else if (mappers
        .isEmpty()) { // only write the object content type if there are no properties, otherwise,
                      // it is automatically detected
      builder.field("type", CONTENT_TYPE);
    }
    // grr, ugly! on root, dynamic defaults to TRUE, on children, it defaults to null to
    // inherit the root behavior
    if (this instanceof RootObjectMapper) {
      if (dynamic != Dynamic.TRUE) {
        builder.field("dynamic", dynamic.name().toLowerCase());
      }
    } else {
      if (dynamic != Defaults.DYNAMIC) {
        builder.field("dynamic", dynamic.name().toLowerCase());
      }
    }
    if (enabled != Defaults.ENABLED) {
      builder.field("enabled", enabled);
    }
    if (pathType != Defaults.PATH_TYPE) {
      builder.field("path", pathType.name().toLowerCase());
    }
    if (includeInAll != null) {
      builder.field("include_in_all", includeInAll);
    }

    if (custom != null) {
      custom.toXContent(builder, params);
    }

    doXContent(builder, params);

    // sort the mappers so we get consistent serialization format
    TreeMap<String, Mapper> sortedMappers = new TreeMap<String, Mapper>(mappers);

    // check internal mappers first (this is only relevant for root object)
    for (Mapper mapper : sortedMappers.values()) {
      if (mapper instanceof InternalMapper) {
        mapper.toXContent(builder, params);
      }
    }
    if (additionalMappers != null && additionalMappers.length > 0) {
      TreeMap<String, Mapper> additionalSortedMappers = new TreeMap<String, Mapper>();
      for (Mapper mapper : additionalMappers) {
        additionalSortedMappers.put(mapper.name(), mapper);
      }

      for (Mapper mapper : additionalSortedMappers.values()) {
        mapper.toXContent(builder, params);
      }
    }

    if (!mappers.isEmpty()) {
      builder.startObject("properties");
      for (Mapper mapper : sortedMappers.values()) {
        if (!(mapper instanceof InternalMapper)) {
          mapper.toXContent(builder, params);
        }
      }
      builder.endObject();
    }
    builder.endObject();
  }
 @Override
 public void close() {
   for (Mapper mapper : mappers.values()) {
     mapper.close();
   }
 }
  private void serializeValue(
      final ParseContext context, String currentFieldName, XContentParser.Token token)
      throws IOException {
    if (currentFieldName == null) {
      throw new MapperParsingException(
          "object mapping ["
              + name
              + "] trying to serialize a value with no field associated with it, current value ["
              + context.parser().textOrNull()
              + "]");
    }
    Mapper mapper = mappers.get(currentFieldName);
    if (mapper != null) {
      mapper.parse(context);
      return;
    }
    Dynamic dynamic = this.dynamic;
    if (dynamic == null) {
      dynamic = context.root().dynamic();
    }
    if (dynamic == Dynamic.STRICT) {
      throw new StrictDynamicMappingException(fullPath, currentFieldName);
    }
    if (dynamic == Dynamic.FALSE) {
      return;
    }
    // we sync here since we don't want to add this field twice to the document mapper
    // its not the end of the world, since we add it to the mappers once we create it
    // so next time we won't even get here for this field
    boolean newMapper = false;
    synchronized (mutex) {
      mapper = mappers.get(currentFieldName);
      if (mapper == null) {
        newMapper = true;
        BuilderContext builderContext = new BuilderContext(context.indexSettings(), context.path());
        if (token == XContentParser.Token.VALUE_STRING) {
          boolean resolved = false;

          // do a quick test to see if its fits a dynamic template, if so, use it.
          // we need to do it here so we can handle things like attachment templates, where calling
          // text (to see if its a date) causes the binary value to be cleared
          if (!resolved) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "string", null);
            if (builder != null) {
              mapper = builder.build(builderContext);
              resolved = true;
            }
          }

          if (!resolved && context.parser().textLength() == 0) {
            // empty string with no mapping, treat it like null value
            return;
          }

          if (!resolved && context.root().dateDetection()) {
            String text = context.parser().text();
            // a safe check since "1" gets parsed as well
            if (Strings.countOccurrencesOf(text, ":") > 1
                || Strings.countOccurrencesOf(text, "-") > 1
                || Strings.countOccurrencesOf(text, "/") > 1) {
              for (FormatDateTimeFormatter dateTimeFormatter :
                  context.root().dynamicDateTimeFormatters()) {
                try {
                  dateTimeFormatter.parser().parseMillis(text);
                  Mapper.Builder builder =
                      context.root().findTemplateBuilder(context, currentFieldName, "date");
                  if (builder == null) {
                    builder = dateField(currentFieldName).dateTimeFormatter(dateTimeFormatter);
                  }
                  mapper = builder.build(builderContext);
                  resolved = true;
                  break;
                } catch (Exception e) {
                  // failure to parse this, continue
                }
              }
            }
          }
          if (!resolved && context.root().numericDetection()) {
            String text = context.parser().text();
            try {
              Long.parseLong(text);
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "long");
              if (builder == null) {
                builder = longField(currentFieldName);
              }
              mapper = builder.build(builderContext);
              resolved = true;
            } catch (Exception e) {
              // not a long number
            }
            if (!resolved) {
              try {
                Double.parseDouble(text);
                Mapper.Builder builder =
                    context.root().findTemplateBuilder(context, currentFieldName, "double");
                if (builder == null) {
                  builder = doubleField(currentFieldName);
                }
                mapper = builder.build(builderContext);
                resolved = true;
              } catch (Exception e) {
                // not a long number
              }
            }
          }
          // DON'T do automatic ip detection logic, since it messes up with docs that have hosts and
          // ips
          // check if its an ip
          //                if (!resolved && text.indexOf('.') != -1) {
          //                    try {
          //                        IpFieldMapper.ipToLong(text);
          //                        XContentMapper.Builder builder =
          // context.root().findTemplateBuilder(context, currentFieldName, "ip");
          //                        if (builder == null) {
          //                            builder = ipField(currentFieldName);
          //                        }
          //                        mapper = builder.build(builderContext);
          //                        resolved = true;
          //                    } catch (Exception e) {
          //                        // failure to parse, not ip...
          //                    }
          //                }
          if (!resolved) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "string");
            if (builder == null) {
              builder = stringField(currentFieldName);
            }
            mapper = builder.build(builderContext);
          }
        } else if (token == XContentParser.Token.VALUE_NUMBER) {
          XContentParser.NumberType numberType = context.parser().numberType();
          if (numberType == XContentParser.NumberType.INT) {
            if (context.parser().estimatedNumberType()) {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "long");
              if (builder == null) {
                builder = longField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            } else {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "integer");
              if (builder == null) {
                builder = integerField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            }
          } else if (numberType == XContentParser.NumberType.LONG) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "long");
            if (builder == null) {
              builder = longField(currentFieldName);
            }
            mapper = builder.build(builderContext);
          } else if (numberType == XContentParser.NumberType.FLOAT) {
            if (context.parser().estimatedNumberType()) {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "double");
              if (builder == null) {
                builder = doubleField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            } else {
              Mapper.Builder builder =
                  context.root().findTemplateBuilder(context, currentFieldName, "float");
              if (builder == null) {
                builder = floatField(currentFieldName);
              }
              mapper = builder.build(builderContext);
            }
          } else if (numberType == XContentParser.NumberType.DOUBLE) {
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "double");
            if (builder == null) {
              builder = doubleField(currentFieldName);
            }
            mapper = builder.build(builderContext);
          }
        } else if (token == XContentParser.Token.VALUE_BOOLEAN) {
          Mapper.Builder builder =
              context.root().findTemplateBuilder(context, currentFieldName, "boolean");
          if (builder == null) {
            builder = booleanField(currentFieldName);
          }
          mapper = builder.build(builderContext);
        } else if (token == XContentParser.Token.VALUE_EMBEDDED_OBJECT) {
          Mapper.Builder builder =
              context.root().findTemplateBuilder(context, currentFieldName, "binary");
          if (builder == null) {
            builder = binaryField(currentFieldName);
          }
          mapper = builder.build(builderContext);
        } else {
          Mapper.Builder builder =
              context.root().findTemplateBuilder(context, currentFieldName, null);
          if (builder != null) {
            mapper = builder.build(builderContext);
          } else {
            // TODO how do we identify dynamically that its a binary value?
            throw new ElasticSearchIllegalStateException(
                "Can't handle serializing a dynamic type with content token ["
                    + token
                    + "] and field name ["
                    + currentFieldName
                    + "]");
          }
        }
        putMapper(mapper);
        context.setMappingsModified();
      }
    }
    if (newMapper) {
      mapper.traverse(context.newFieldMappers());
    }
    mapper.parse(context);
  }
  public void testReuseExistingMappings() throws IOException, Exception {
    IndexService indexService =
        createIndex(
            "test",
            Settings.EMPTY,
            "type",
            "my_field1",
            "type=text,store=true",
            "my_field2",
            "type=integer,store=false",
            "my_field3",
            "type=long,doc_values=false",
            "my_field4",
            "type=float,index=false",
            "my_field5",
            "type=double,store=true",
            "my_field6",
            "type=date,doc_values=false",
            "my_field7",
            "type=boolean,doc_values=false");

    // Even if the dynamic type of our new field is long, we already have a mapping for the same
    // field
    // of type string so it should be mapped as a string
    DocumentMapper newMapper =
        indexService.mapperService().documentMapperWithAutoCreate("type2").getDocumentMapper();
    Mapper update =
        parse(
            newMapper,
            indexService.mapperService().documentMapperParser(),
            XContentFactory.jsonBuilder()
                .startObject()
                .field("my_field1", 42)
                .field("my_field2", 43)
                .field("my_field3", 44)
                .field("my_field4", 45)
                .field("my_field5", 46)
                .field("my_field6", 47)
                .field("my_field7", true)
                .endObject());
    Mapper myField1Mapper = null;
    Mapper myField2Mapper = null;
    Mapper myField3Mapper = null;
    Mapper myField4Mapper = null;
    Mapper myField5Mapper = null;
    Mapper myField6Mapper = null;
    Mapper myField7Mapper = null;
    for (Mapper m : update) {
      switch (m.name()) {
        case "my_field1":
          myField1Mapper = m;
          break;
        case "my_field2":
          myField2Mapper = m;
          break;
        case "my_field3":
          myField3Mapper = m;
          break;
        case "my_field4":
          myField4Mapper = m;
          break;
        case "my_field5":
          myField5Mapper = m;
          break;
        case "my_field6":
          myField6Mapper = m;
          break;
        case "my_field7":
          myField7Mapper = m;
          break;
      }
    }
    assertNotNull(myField1Mapper);
    // same type
    assertTrue(myField1Mapper instanceof TextFieldMapper);
    // and same option
    assertTrue(((TextFieldMapper) myField1Mapper).fieldType().stored());

    // Even if dynamic mappings would map a numeric field as a long, here it should map it as a
    // integer
    // since we already have a mapping of type integer
    assertNotNull(myField2Mapper);
    // same type
    assertEquals("integer", ((FieldMapper) myField2Mapper).fieldType().typeName());
    // and same option
    assertFalse(((FieldMapper) myField2Mapper).fieldType().stored());

    assertNotNull(myField3Mapper);
    assertTrue(myField3Mapper instanceof NumberFieldMapper);
    assertFalse(
        ((NumberFieldType) ((NumberFieldMapper) myField3Mapper).fieldType()).hasDocValues());

    assertNotNull(myField4Mapper);
    assertTrue(myField4Mapper instanceof NumberFieldMapper);
    assertEquals(IndexOptions.NONE, ((FieldMapper) myField4Mapper).fieldType().indexOptions());

    assertNotNull(myField5Mapper);

    assertTrue(myField5Mapper instanceof NumberFieldMapper);
    assertTrue(((NumberFieldMapper) myField5Mapper).fieldType().stored());

    assertNotNull(myField6Mapper);
    assertTrue(myField6Mapper instanceof DateFieldMapper);
    assertFalse(((DateFieldType) ((DateFieldMapper) myField6Mapper).fieldType()).hasDocValues());

    assertNotNull(myField7Mapper);
    assertTrue(myField7Mapper instanceof BooleanFieldMapper);
    assertFalse(
        ((BooleanFieldType) ((BooleanFieldMapper) myField7Mapper).fieldType()).hasDocValues());

    // This can't work
    try {
      parse(
          newMapper,
          indexService.mapperService().documentMapperParser(),
          XContentFactory.jsonBuilder().startObject().field("my_field2", "foobar").endObject());
      fail("Cannot succeed, incompatible types");
    } catch (MapperParsingException e) {
      // expected
    }
  }
  private void serializeObject(final ParseContext context, String currentFieldName)
      throws IOException {
    if (currentFieldName == null) {
      throw new MapperParsingException(
          "object mapping ["
              + name
              + "] trying to serialize an object with no field associated with it, current value ["
              + context.parser().textOrNull()
              + "]");
    }
    context.path().add(currentFieldName);

    Mapper objectMapper = mappers.get(currentFieldName);
    if (objectMapper != null) {
      objectMapper.parse(context);
    } else {
      Dynamic dynamic = this.dynamic;
      if (dynamic == null) {
        dynamic = context.root().dynamic();
      }
      if (dynamic == Dynamic.STRICT) {
        throw new StrictDynamicMappingException(currentFieldName);
      } else if (dynamic == Dynamic.TRUE) {
        // we sync here just so we won't add it twice. Its not the end of the world
        // to sync here since next operations will get it before
        boolean newMapper = false;
        synchronized (mutex) {
          objectMapper = mappers.get(currentFieldName);
          if (objectMapper == null) {
            newMapper = true;
            Mapper.Builder builder =
                context.root().findTemplateBuilder(context, currentFieldName, "object");
            if (builder == null) {
              builder =
                  MapperBuilders.object(currentFieldName)
                      .enabled(true)
                      .dynamic(dynamic)
                      .pathType(pathType);
            }
            // remove the current field name from path, since the object builder adds it as well...
            context.path().remove();
            BuilderContext builderContext =
                new BuilderContext(context.indexSettings(), context.path());
            objectMapper = builder.build(builderContext);
            putMapper(objectMapper);
            // now re add it
            context.path().add(currentFieldName);
            context.addedMapper();
          }
        }
        // traverse and parse outside of the mutex
        if (newMapper) {
          // we need to traverse in case we have a dynamic template and need to add field mappers
          // introduced by it
          objectMapper.traverse(
              new FieldMapperListener() {
                @Override
                public void fieldMapper(FieldMapper fieldMapper) {
                  context.docMapper().addFieldMapper(fieldMapper);
                }
              });
          objectMapper.traverse(
              new ObjectMapperListener() {
                @Override
                public void objectMapper(ObjectMapper objectMapper) {
                  context.docMapper().addObjectMapper(objectMapper);
                }
              });
        }
        // now, parse it
        objectMapper.parse(context);
      } else {
        // not dynamic, read everything up to end object
        context.parser().skipChildren();
      }
    }

    context.path().remove();
  }
 @Override
 public void traverse(FieldMapperListener fieldMapperListener) {
   for (Mapper mapper : mappers.values()) {
     mapper.traverse(fieldMapperListener);
   }
 }