public SmartNameFieldMappers smartName(String smartName, @Nullable String[] types) {
   if (types == null || types.length == 0) {
     return smartName(smartName);
   }
   if (types.length == 1 && types[0].equals("_all")) {
     return smartName(smartName);
   }
   for (String type : types) {
     DocumentMapper documentMapper = mappers.get(type);
     // we found a mapper
     if (documentMapper != null) {
       // see if we find a field for it
       FieldMappers mappers = documentMapper.mappers().smartName(smartName);
       if (mappers != null) {
         return new SmartNameFieldMappers(this, mappers, documentMapper, false);
       }
     }
   }
   // did not find explicit field in the type provided, see if its prefixed with type
   int dotIndex = smartName.indexOf('.');
   if (dotIndex != -1) {
     String possibleType = smartName.substring(0, dotIndex);
     DocumentMapper possibleDocMapper = mappers.get(possibleType);
     if (possibleDocMapper != null) {
       String possibleName = smartName.substring(dotIndex + 1);
       FieldMappers mappers = possibleDocMapper.mappers().smartName(possibleName);
       if (mappers != null) {
         return new SmartNameFieldMappers(this, mappers, possibleDocMapper, true);
       }
     }
   }
   // we did not find the field mapping in any of the types, so don't go and try to find
   // it in other types...
   return null;
 }
 /**
  * Returns smart field mappers based on a smart name. A smart name is one that can optioannly be
  * prefixed with a type (and then a '.'). If it is, then the {@link
  * MapperService.SmartNameFieldMappers} will have the doc mapper set.
  *
  * <p>
  *
  * <p>It also (without the optional type prefix) try and find the {@link FieldMappers} for the
  * specific name. It will first try to find it based on the full name (with the dots if its a
  * compound name). If it is not found, will try and find it based on the indexName (which can be
  * controlled in the mapping), and last, will try it based no the name itself.
  *
  * <p>
  *
  * <p>If nothing is found, returns null.
  */
 public SmartNameFieldMappers smartName(String smartName) {
   int dotIndex = smartName.indexOf('.');
   if (dotIndex != -1) {
     String possibleType = smartName.substring(0, dotIndex);
     DocumentMapper possibleDocMapper = mappers.get(possibleType);
     if (possibleDocMapper != null) {
       String possibleName = smartName.substring(dotIndex + 1);
       FieldMappers mappers = possibleDocMapper.mappers().smartName(possibleName);
       if (mappers != null) {
         return new SmartNameFieldMappers(this, mappers, possibleDocMapper, true);
       }
     }
   }
   FieldMappers fieldMappers = fullName(smartName);
   if (fieldMappers != null) {
     return new SmartNameFieldMappers(this, fieldMappers, null, false);
   }
   fieldMappers = indexName(smartName);
   if (fieldMappers != null) {
     return new SmartNameFieldMappers(this, fieldMappers, null, false);
   }
   fieldMappers = name(smartName);
   if (fieldMappers != null) {
     return new SmartNameFieldMappers(this, fieldMappers, null, false);
   }
   return null;
 }
    @Override
    protected Analyzer getWrappedAnalyzer(String fieldName) {
      int dotIndex = fieldName.indexOf('.');
      if (dotIndex != -1) {
        String possibleType = fieldName.substring(0, dotIndex);
        DocumentMapper possibleDocMapper = mappers.get(possibleType);
        if (possibleDocMapper != null) {
          return possibleDocMapper.mappers().searchQuoteAnalyzer();
        }
      }
      FieldMappers mappers = fieldMappers.fullName(fieldName);
      if (mappers != null
          && mappers.mapper() != null
          && mappers.mapper().searchQuoteAnalyzer() != null) {
        return mappers.mapper().searchQuoteAnalyzer();
      }

      mappers = fieldMappers.indexName(fieldName);
      if (mappers != null
          && mappers.mapper() != null
          && mappers.mapper().searchQuoteAnalyzer() != null) {
        return mappers.mapper().searchQuoteAnalyzer();
      }
      return defaultAnalyzer;
    }
 public SmartNameObjectMapper smartNameObjectMapper(String smartName, @Nullable String[] types) {
   if (types == null || types.length == 0) {
     return smartNameObjectMapper(smartName);
   }
   if (types.length == 1 && types[0].equals("_all")) {
     return smartNameObjectMapper(smartName);
   }
   for (String type : types) {
     DocumentMapper possibleDocMapper = mappers.get(type);
     if (possibleDocMapper != null) {
       ObjectMapper mapper = possibleDocMapper.objectMappers().get(smartName);
       if (mapper != null) {
         return new SmartNameObjectMapper(mapper, possibleDocMapper);
       }
     }
   }
   // did not find one, see if its prefixed by type
   int dotIndex = smartName.indexOf('.');
   if (dotIndex != -1) {
     String possibleType = smartName.substring(0, dotIndex);
     DocumentMapper possibleDocMapper = mappers.get(possibleType);
     if (possibleDocMapper != null) {
       String possiblePath = smartName.substring(dotIndex + 1);
       ObjectMapper mapper = possibleDocMapper.objectMappers().get(possiblePath);
       if (mapper != null) {
         return new SmartNameObjectMapper(mapper, possibleDocMapper);
       }
     }
   }
   // did not explicitly find one under the types provided, or prefixed by type...
   return null;
 }
 public Analyzer searchQuoteAnalyzer() {
   if (hasMapper()) {
     Analyzer analyzer = mapper().searchQuoteAnalyzer();
     if (analyzer != null) {
       return analyzer;
     }
   }
   if (docMapper != null && docMapper.searchQuotedAnalyzer() != null) {
     return docMapper.searchQuotedAnalyzer();
   }
   return mapperService.searchQuoteAnalyzer();
 }
 public void remove(String type) {
   synchronized (typeMutex) {
     DocumentMapper docMapper = mappers.get(type);
     if (docMapper == null) {
       return;
     }
     docMapper.close();
     mappers = newMapBuilder(mappers).remove(type).map();
     removeObjectAndFieldMappers(docMapper);
     for (DocumentTypeListener typeListener : typeListeners) {
       typeListener.removed(type);
     }
   }
 }
  public synchronized MergeResult merge(DocumentMapper mergeWith, MergeFlags mergeFlags) {
    MergeContext mergeContext = new MergeContext(this, mergeFlags);
    rootObjectMapper.merge(mergeWith.rootObjectMapper, mergeContext);

    for (Map.Entry<Class<? extends RootMapper>, RootMapper> entry : rootMappers.entrySet()) {
      // root mappers included in root object will get merge in the rootObjectMapper
      if (entry.getValue().includeInObject()) {
        continue;
      }
      RootMapper mergeWithRootMapper = mergeWith.rootMappers.get(entry.getKey());
      if (mergeWithRootMapper != null) {
        entry.getValue().merge(mergeWithRootMapper, mergeContext);
      }
    }

    if (!mergeFlags.simulate()) {
      if (!mergeContext.newFieldMappers().mappers.isEmpty()) {
        addFieldMappers(mergeContext.newFieldMappers().mappers);
      }
      if (!mergeContext.newObjectMappers().mappers.isEmpty()) {
        addObjectMappers(mergeContext.newObjectMappers().mappers);
      }
      // let the merge with attributes to override the attributes
      meta = mergeWith.meta();
      // update the source of the merged one
      refreshSource();
    }
    return new MergeResult(mergeContext.buildConflicts());
  }
 /**
  * Returns all the fields that match the given pattern. If the pattern is prefixed with a type
  * then the fields will be returned with a type prefix.
  */
 public Set<String> simpleMatchToIndexNames(String pattern) {
   if (!Regex.isSimpleMatchPattern(pattern)) {
     return ImmutableSet.of(pattern);
   }
   int dotIndex = pattern.indexOf('.');
   if (dotIndex != -1) {
     String possibleType = pattern.substring(0, dotIndex);
     DocumentMapper possibleDocMapper = mappers.get(possibleType);
     if (possibleDocMapper != null) {
       Set<String> typedFields = Sets.newHashSet();
       for (String indexName : possibleDocMapper.mappers().simpleMatchToIndexNames(pattern)) {
         typedFields.add(possibleType + "." + indexName);
       }
       return typedFields;
     }
   }
   return fieldMappers.simpleMatchToIndexNames(pattern);
 }
 public SmartNameObjectMapper smartNameObjectMapper(String smartName) {
   int dotIndex = smartName.indexOf('.');
   if (dotIndex != -1) {
     String possibleType = smartName.substring(0, dotIndex);
     DocumentMapper possibleDocMapper = mappers.get(possibleType);
     if (possibleDocMapper != null) {
       String possiblePath = smartName.substring(dotIndex + 1);
       ObjectMapper mapper = possibleDocMapper.objectMappers().get(possiblePath);
       if (mapper != null) {
         return new SmartNameObjectMapper(mapper, possibleDocMapper);
       }
     }
   }
   ObjectMappers mappers = objectMapper(smartName);
   if (mappers != null) {
     return new SmartNameObjectMapper(mappers.mapper(), null);
   }
   return null;
 }
 /**
  * Returns all the fields that match the given pattern, with an optional narrowing based on a list
  * of types.
  */
 public Set<String> simpleMatchToIndexNames(String pattern, @Nullable String[] types) {
   if (types == null || types.length == 0) {
     return simpleMatchToIndexNames(pattern);
   }
   if (types.length == 1 && types[0].equals("_all")) {
     return simpleMatchToIndexNames(pattern);
   }
   if (!Regex.isSimpleMatchPattern(pattern)) {
     return ImmutableSet.of(pattern);
   }
   Set<String> fields = Sets.newHashSet();
   for (String type : types) {
     DocumentMapper possibleDocMapper = mappers.get(type);
     if (possibleDocMapper != null) {
       for (String indexName : possibleDocMapper.mappers().simpleMatchToIndexNames(pattern)) {
         fields.add(indexName);
       }
     }
   }
   return fields;
 }
  private void removeObjectAndFieldMappers(DocumentMapper docMapper) {
    synchronized (mappersMutex) {
      fieldMappers.removeMappers(docMapper.mappers());

      ImmutableOpenMap.Builder<String, ObjectMappers> fullPathObjectMappers =
          ImmutableOpenMap.builder(this.fullPathObjectMappers);
      for (ObjectMapper mapper : docMapper.objectMappers().values()) {
        ObjectMappers mappers = fullPathObjectMappers.get(mapper.fullPath());
        if (mappers != null) {
          mappers = mappers.remove(mapper);
          if (mappers.isEmpty()) {
            fullPathObjectMappers.remove(mapper.fullPath());
          } else {
            fullPathObjectMappers.put(mapper.fullPath(), mappers);
          }
        }
      }

      this.fullPathObjectMappers = fullPathObjectMappers.build();
    }
  }
 /** Same as {@link #smartName(String)}, except it returns just the field mappers. */
 public FieldMappers smartNameFieldMappers(String smartName) {
   int dotIndex = smartName.indexOf('.');
   if (dotIndex != -1) {
     String possibleType = smartName.substring(0, dotIndex);
     DocumentMapper possibleDocMapper = mappers.get(possibleType);
     if (possibleDocMapper != null) {
       String possibleName = smartName.substring(dotIndex + 1);
       FieldMappers mappers = possibleDocMapper.mappers().smartName(possibleName);
       if (mappers != null) {
         return mappers;
       }
     }
   }
   FieldMappers mappers = fullName(smartName);
   if (mappers != null) {
     return mappers;
   }
   mappers = indexName(smartName);
   if (mappers != null) {
     return mappers;
   }
   return name(smartName);
 }
  /**
   * A filter for search. If a filter is required, will return it, otherwise, will return
   * <tt>null</tt>.
   */
  @Nullable
  public Filter searchFilter(String... types) {
    boolean filterPercolateType = hasMapping(PercolatorService.TYPE_NAME);
    if (types != null && filterPercolateType) {
      for (String type : types) {
        if (PercolatorService.TYPE_NAME.equals(type)) {
          filterPercolateType = false;
          break;
        }
      }
    }
    Filter excludePercolatorType = null;
    if (filterPercolateType) {
      excludePercolatorType =
          new NotFilter(documentMapper(PercolatorService.TYPE_NAME).typeFilter());
    }

    if (types == null || types.length == 0) {
      if (hasNested && filterPercolateType) {
        return new AndFilter(ImmutableList.of(excludePercolatorType, NonNestedDocsFilter.INSTANCE));
      } else if (hasNested) {
        return NonNestedDocsFilter.INSTANCE;
      } else if (filterPercolateType) {
        return excludePercolatorType;
      } else {
        return null;
      }
    }
    // if we filter by types, we don't need to filter by non nested docs
    // since they have different types (starting with __)
    if (types.length == 1) {
      DocumentMapper docMapper = documentMapper(types[0]);
      if (docMapper == null) {
        return new TermFilter(new Term(types[0]));
      }
      return docMapper.typeFilter();
    }
    // see if we can use terms filter
    boolean useTermsFilter = true;
    for (String type : types) {
      DocumentMapper docMapper = documentMapper(type);
      if (docMapper == null) {
        useTermsFilter = false;
        break;
      }
      if (!docMapper.typeMapper().fieldType().indexed()) {
        useTermsFilter = false;
        break;
      }
    }

    if (useTermsFilter) {
      BytesRef[] typesBytes = new BytesRef[types.length];
      for (int i = 0; i < typesBytes.length; i++) {
        typesBytes[i] = new BytesRef(types[i]);
      }
      TermsFilter termsFilter = new TermsFilter(TypeFieldMapper.NAME, typesBytes);
      if (filterPercolateType) {
        return new AndFilter(ImmutableList.of(excludePercolatorType, termsFilter));
      } else {
        return termsFilter;
      }
    } else {
      // Current bool filter requires that at least one should clause matches, even with a must
      // clause.
      XBooleanFilter bool = new XBooleanFilter();
      for (String type : types) {
        DocumentMapper docMapper = documentMapper(type);
        if (docMapper == null) {
          bool.add(
              new FilterClause(
                  new TermFilter(new Term(TypeFieldMapper.NAME, type)),
                  BooleanClause.Occur.SHOULD));
        } else {
          bool.add(new FilterClause(docMapper.typeFilter(), BooleanClause.Occur.SHOULD));
        }
      }
      if (filterPercolateType) {
        bool.add(excludePercolatorType, BooleanClause.Occur.MUST);
      }

      return bool;
    }
  }
  // never expose this to the outside world, we need to reparse the doc mapper so we get fresh
  // instances of field mappers to properly remove existing doc mapper
  private DocumentMapper merge(DocumentMapper mapper) {
    synchronized (typeMutex) {
      if (mapper.type().length() == 0) {
        throw new InvalidTypeNameException("mapping type name is empty");
      }
      if (mapper.type().charAt(0) == '_' && !PercolatorService.TYPE_NAME.equals(mapper.type())) {
        throw new InvalidTypeNameException(
            "mapping type name [" + mapper.type() + "] can't start with '_'");
      }
      if (mapper.type().contains("#")) {
        throw new InvalidTypeNameException(
            "mapping type name [" + mapper.type() + "] should not include '#' in it");
      }
      if (mapper.type().contains(",")) {
        throw new InvalidTypeNameException(
            "mapping type name [" + mapper.type() + "] should not include ',' in it");
      }
      if (mapper.type().contains(".")) {
        logger.warn(
            "Type [{}] contains a '.', it is recommended not to include it within a type name",
            mapper.type());
      }
      // we can add new field/object mappers while the old ones are there
      // since we get new instances of those, and when we remove, we remove
      // by instance equality
      DocumentMapper oldMapper = mappers.get(mapper.type());

      if (oldMapper != null) {
        DocumentMapper.MergeResult result = oldMapper.merge(mapper, mergeFlags().simulate(false));
        if (result.hasConflicts()) {
          // TODO: What should we do???
          if (logger.isDebugEnabled()) {
            logger.debug(
                "merging mapping for type [{}] resulted in conflicts: [{}]",
                mapper.type(),
                Arrays.toString(result.conflicts()));
          }
        }
        return oldMapper;
      } else {
        FieldMapperListener.Aggregator fieldMappersAgg = new FieldMapperListener.Aggregator();
        mapper.traverse(fieldMappersAgg);
        addFieldMappers(
            fieldMappersAgg.mappers.toArray(new FieldMapper[fieldMappersAgg.mappers.size()]));
        mapper.addFieldMapperListener(fieldMapperListener, false);

        ObjectMapperListener.Aggregator objectMappersAgg = new ObjectMapperListener.Aggregator();
        mapper.traverse(objectMappersAgg);
        addObjectMappers(
            objectMappersAgg.mappers.toArray(new ObjectMapper[objectMappersAgg.mappers.size()]));
        mapper.addObjectMapperListener(objectMapperListener, false);

        mappers = newMapBuilder(mappers).put(mapper.type(), mapper).map();
        for (DocumentTypeListener typeListener : typeListeners) {
          typeListener.created(mapper.type());
        }
        return mapper;
      }
    }
  }
 public void close() {
   for (DocumentMapper documentMapper : mappers.values()) {
     documentMapper.close();
   }
 }