diff --git a/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java b/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java index bfb707a12be..e4ab12b3941 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java @@ -468,15 +468,13 @@ public class IndexMetaData { } builder.settings(settingsBuilder.build()); } else if ("mappings".equals(currentFieldName)) { - while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - if (token == XContentParser.Token.VALUE_EMBEDDED_OBJECT) { - builder.putMapping(new MappingMetaData(new CompressedString(parser.binaryValue()))); - } else { - Map mapping = parser.mapOrdered(); - if (mapping.size() == 1) { - String mappingType = mapping.keySet().iterator().next(); - builder.putMapping(new MappingMetaData(mappingType, mapping)); - } + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + currentFieldName = parser.currentName(); + } else if (token == XContentParser.Token.START_OBJECT) { + String mappingType = currentFieldName; + Map mappingSource = MapBuilder.newMapBuilder().put(mappingType, parser.mapOrdered()).map(); + builder.putMapping(new MappingMetaData(mappingType, mappingSource)); } } } else if ("aliases".equals(currentFieldName)) { diff --git a/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java b/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java index 3026d4e753b..6e583c1df4e 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java @@ -47,6 +47,7 @@ public class IndexTemplateMetaData { private final Settings settings; + // the mapping source should always include the type as top level private final ImmutableMap mappings; public IndexTemplateMetaData(String name, int order, String template, Settings settings, ImmutableMap mappings) { @@ -210,8 +211,7 @@ public class IndexTemplateMetaData { for (Map.Entry entry : indexTemplateMetaData.mappings().entrySet()) { byte[] data = entry.getValue().uncompressed(); XContentParser parser = XContentFactory.xContent(data).createParser(data); - Map mapping = parser.map(); - parser.close(); + Map mapping = parser.mapOrderedAndClose(); builder.map(mapping); } builder.endArray(); @@ -219,6 +219,21 @@ public class IndexTemplateMetaData { builder.endObject(); } + public static IndexTemplateMetaData fromXContentStandalone(XContentParser parser) throws IOException { + XContentParser.Token token = parser.nextToken(); + if (token == null) { + throw new IOException("no data"); + } + if (token != XContentParser.Token.START_OBJECT) { + throw new IOException("should start object"); + } + token = parser.nextToken(); + if (token != XContentParser.Token.FIELD_NAME) { + throw new IOException("the first field should be the template name"); + } + return fromXContent(parser); + } + public static IndexTemplateMetaData fromXContent(XContentParser parser) throws IOException { Builder builder = new Builder(parser.currentName()); @@ -238,8 +253,20 @@ public class IndexTemplateMetaData { } builder.settings(settingsBuilder.build()); } else if ("mappings".equals(currentFieldName)) { + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + currentFieldName = parser.currentName(); + } else if (token == XContentParser.Token.START_OBJECT) { + String mappingType = currentFieldName; + Map mappingSource = MapBuilder.newMapBuilder().put(mappingType, parser.mapOrdered()).map(); + builder.putMapping(mappingType, XContentFactory.jsonBuilder().map(mappingSource).string()); + } + } + } + } else if (token == XContentParser.Token.START_ARRAY) { + if ("mappings".equals(currentFieldName)) { while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - Map mapping = parser.map(); + Map mapping = parser.mapOrdered(); if (mapping.size() == 1) { String mappingType = mapping.keySet().iterator().next(); String mappingSource = XContentFactory.jsonBuilder().map(mapping).string(); diff --git a/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java b/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java index 2c36ae60ae0..d6ddd274c90 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java @@ -19,10 +19,10 @@ package org.elasticsearch.cluster.metadata; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.common.io.Closeables; import org.elasticsearch.ElasticSearchException; import org.elasticsearch.Version; import org.elasticsearch.cluster.ClusterService; @@ -46,6 +46,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.env.Environment; import org.elasticsearch.index.Index; import org.elasticsearch.index.mapper.DocumentMapper; @@ -141,10 +142,9 @@ public class MetaDataCreateIndexService extends AbstractComponent { return currentState; } - List templates = ImmutableList.of(); // we only find a template when its an API call (a new index) // find templates, highest order are better matching - templates = findTemplates(request, currentState); + List templates = findTemplates(request, currentState); // add the request mapping Map> mappings = Maps.newHashMap(); @@ -398,6 +398,30 @@ public class MetaDataCreateIndexService extends AbstractComponent { templates.add(template); } } + + // see if we have templates defined under config + File templatesDir = new File(environment.configFile(), "templates"); + if (templatesDir.exists() && templatesDir.isDirectory()) { + File[] templatesFiles = templatesDir.listFiles(); + if (templatesFiles != null) { + for (File templatesFile : templatesFiles) { + XContentParser parser = null; + try { + byte[] templatesData = Streams.copyToByteArray(templatesFile); + parser = XContentHelper.createParser(templatesData, 0, templatesData.length); + IndexTemplateMetaData template = IndexTemplateMetaData.Builder.fromXContentStandalone(parser); + if (Regex.simpleMatch(template.template(), request.index)) { + templates.add(template); + } + } catch (Exception e) { + logger.warn("[{}] failed to read template [{}] from config", request.index, templatesFile.getAbsolutePath()); + } finally { + Closeables.closeQuietly(parser); + } + } + } + } + Collections.sort(templates, new Comparator() { @Override public int compare(IndexTemplateMetaData o1, IndexTemplateMetaData o2) { diff --git a/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java b/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java index 95e326abf89..939a19dd268 100644 --- a/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java +++ b/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java @@ -19,13 +19,14 @@ package org.elasticsearch.common.xcontent; +import java.io.Closeable; import java.io.IOException; import java.util.Map; /** * */ -public interface XContentParser { +public interface XContentParser extends Closeable { enum Token { START_OBJECT { diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/template/put/RestPutIndexTemplateAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/template/put/RestPutIndexTemplateAction.java index ecc95753559..b7964050ee2 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/indices/template/put/RestPutIndexTemplateAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/template/put/RestPutIndexTemplateAction.java @@ -71,7 +71,7 @@ public class RestPutIndexTemplateAction extends BaseRestHandler { // parse the parameters Map source = XContentFactory.xContent(request.contentByteArray(), request.contentByteArrayOffset(), request.contentLength()) - .createParser(request.contentByteArray(), request.contentByteArrayOffset(), request.contentLength()).mapAndClose(); + .createParser(request.contentByteArray(), request.contentByteArrayOffset(), request.contentLength()).mapOrderedAndClose(); if (source.containsKey("template")) { putRequest.template(source.get("template").toString());