浏览代码

remove lang url parameter from stored script requests (#25779)

Also has updates to ScriptMetaData for allowing the old namespace format to be loaded all the way back through 5.0; however, it will throw an exception if two scripts share the same id but different languages.
Jack Conradson 8 年之前
父节点
当前提交
9f7463e796
共有 33 个文件被更改,包括 283 次插入591 次删除
  1. 9 23
      core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/DeleteStoredScriptRequest.java
  2. 0 6
      core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/DeleteStoredScriptRequestBuilder.java
  3. 9 25
      core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/GetStoredScriptRequest.java
  4. 0 6
      core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/GetStoredScriptRequestBuilder.java
  5. 21 25
      core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java
  6. 0 5
      core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestBuilder.java
  7. 3 3
      core/src/main/java/org/elasticsearch/client/ClusterAdminClient.java
  8. 4 4
      core/src/main/java/org/elasticsearch/client/support/AbstractClient.java
  9. 2 20
      core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestDeleteStoredScriptAction.java
  10. 11 41
      core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetStoredScriptAction.java
  11. 8 22
      core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestPutStoredScriptAction.java
  12. 44 94
      core/src/main/java/org/elasticsearch/script/ScriptMetaData.java
  13. 6 10
      core/src/main/java/org/elasticsearch/script/ScriptService.java
  14. 10 29
      core/src/main/java/org/elasticsearch/script/StoredScriptSource.java
  15. 1 3
      core/src/test/java/org/elasticsearch/action/admin/cluster/storedscripts/GetStoredScriptRequestTests.java
  16. 4 4
      core/src/test/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestTests.java
  17. 1 1
      core/src/test/java/org/elasticsearch/client/AbstractClientHeadersTestCase.java
  18. 57 34
      core/src/test/java/org/elasticsearch/script/ScriptMetaDataTests.java
  19. 20 20
      core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java
  20. 1 1
      core/src/test/java/org/elasticsearch/script/StoredScriptSourceTests.java
  21. 25 160
      core/src/test/java/org/elasticsearch/script/StoredScriptTests.java
  22. 7 11
      core/src/test/java/org/elasticsearch/script/StoredScriptsIT.java
  23. 9 8
      core/src/test/java/org/elasticsearch/search/aggregations/metrics/ScriptedMetricIT.java
  24. 2 2
      core/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptIT.java
  25. 2 2
      core/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketSelectorIT.java
  26. 6 6
      core/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java
  27. 7 0
      docs/reference/migration/migrate_6_0/scripting.asciidoc
  28. 1 2
      modules/lang-expression/src/test/java/org/elasticsearch/script/expression/StoredExpressionTests.java
  29. 4 15
      modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateIT.java
  30. 4 4
      modules/lang-painless/src/test/resources/rest-api-spec/test/painless/16_update2.yml
  31. 2 2
      rest-api-spec/src/main/resources/rest-api-spec/api/delete_script.json
  32. 2 2
      rest-api-spec/src/main/resources/rest-api-spec/api/get_script.json
  33. 1 1
      rest-api-spec/src/main/resources/rest-api-spec/api/put_script.json

+ 9 - 23
core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/DeleteStoredScriptRequest.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.action.admin.cluster.storedscripts;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionRequestValidationException;
 import org.elasticsearch.action.support.master.AcknowledgedRequest;
 import org.elasticsearch.common.io.stream.StreamInput;
@@ -31,17 +32,15 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
 public class DeleteStoredScriptRequest extends AcknowledgedRequest<DeleteStoredScriptRequest> {
 
     private String id;
-    private String lang;
 
     DeleteStoredScriptRequest() {
         super();
     }
 
-    public DeleteStoredScriptRequest(String id, String lang) {
+    public DeleteStoredScriptRequest(String id) {
         super();
 
         this.id = id;
-        this.lang = lang;
     }
 
     @Override
@@ -54,10 +53,6 @@ public class DeleteStoredScriptRequest extends AcknowledgedRequest<DeleteStoredS
             validationException = addValidationError("id cannot contain '#' for stored script", validationException);
         }
 
-        if (lang != null && lang.contains("#")) {
-            validationException = addValidationError("lang cannot contain '#' for stored script", validationException);
-        }
-
         return validationException;
     }
 
@@ -71,24 +66,12 @@ public class DeleteStoredScriptRequest extends AcknowledgedRequest<DeleteStoredS
         return this;
     }
 
-    public String lang() {
-        return lang;
-    }
-
-    public DeleteStoredScriptRequest lang(String lang) {
-        this.lang = lang;
-
-        return this;
-    }
-
     @Override
     public void readFrom(StreamInput in) throws IOException {
         super.readFrom(in);
 
-        lang = in.readString();
-
-        if (lang.isEmpty()) {
-            lang = null;
+        if (in.getVersion().before(Version.V_6_0_0_alpha2)) {
+            in.readString(); // read lang from previous versions
         }
 
         id = in.readString();
@@ -98,12 +81,15 @@ public class DeleteStoredScriptRequest extends AcknowledgedRequest<DeleteStoredS
     public void writeTo(StreamOutput out) throws IOException {
         super.writeTo(out);
 
-        out.writeString(lang == null ? "" : lang);
+        if (out.getVersion().before(Version.V_6_0_0_alpha2)) {
+            out.writeString(""); // write an empty lang to previous versions
+        }
+
         out.writeString(id);
     }
 
     @Override
     public String toString() {
-        return "delete stored script {id [" + id + "]" + (lang != null ? ", lang [" + lang + "]" : "") + "}";
+        return "delete stored script {id [" + id + "]}";
     }
 }

+ 0 - 6
core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/DeleteStoredScriptRequestBuilder.java

@@ -29,12 +29,6 @@ public class DeleteStoredScriptRequestBuilder extends AcknowledgedRequestBuilder
         super(client, action, new DeleteStoredScriptRequest());
     }
 
-    public DeleteStoredScriptRequestBuilder setLang(String lang) {
-        request.lang(lang);
-
-        return this;
-    }
-
     public DeleteStoredScriptRequestBuilder setId(String id) {
         request.id(id);
 

+ 9 - 25
core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/GetStoredScriptRequest.java

@@ -19,10 +19,9 @@
 
 package org.elasticsearch.action.admin.cluster.storedscripts;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionRequestValidationException;
-import org.elasticsearch.action.ValidateActions;
 import org.elasticsearch.action.support.master.MasterNodeReadRequest;
-import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 
@@ -33,17 +32,15 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
 public class GetStoredScriptRequest extends MasterNodeReadRequest<GetStoredScriptRequest> {
 
     protected String id;
-    protected String lang;
 
     GetStoredScriptRequest() {
         super();
     }
 
-    public GetStoredScriptRequest(String id, String lang) {
+    public GetStoredScriptRequest(String id) {
         super();
 
         this.id = id;
-        this.lang = lang;
     }
 
     @Override
@@ -56,10 +53,6 @@ public class GetStoredScriptRequest extends MasterNodeReadRequest<GetStoredScrip
             validationException = addValidationError("id cannot contain '#' for stored script", validationException);
         }
 
-        if (lang != null && lang.contains("#")) {
-            validationException = addValidationError("lang cannot contain '#' for stored script", validationException);
-        }
-
         return validationException;
     }
 
@@ -73,24 +66,12 @@ public class GetStoredScriptRequest extends MasterNodeReadRequest<GetStoredScrip
         return this;
     }
 
-    public String lang() {
-        return lang;
-    }
-
-    public GetStoredScriptRequest lang(String lang) {
-        this.lang = lang;
-
-        return this;
-    }
-
     @Override
     public void readFrom(StreamInput in) throws IOException {
         super.readFrom(in);
 
-        lang = in.readString();
-
-        if (lang.isEmpty()) {
-            lang = null;
+        if (in.getVersion().before(Version.V_6_0_0_alpha2)) {
+            in.readString(); // read lang from previous versions
         }
 
         id = in.readString();
@@ -100,12 +81,15 @@ public class GetStoredScriptRequest extends MasterNodeReadRequest<GetStoredScrip
     public void writeTo(StreamOutput out) throws IOException {
         super.writeTo(out);
 
-        out.writeString(lang == null ? "" : lang);
+        if (out.getVersion().before(Version.V_6_0_0_alpha2)) {
+            out.writeString(""); // write an empty lang to previous versions
+        }
+
         out.writeString(id);
     }
 
     @Override
     public String toString() {
-        return "get script [" + lang + "][" + id + "]";
+        return "get script [" + id + "]";
     }
 }

+ 0 - 6
core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/GetStoredScriptRequestBuilder.java

@@ -21,7 +21,6 @@ package org.elasticsearch.action.admin.cluster.storedscripts;
 
 import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
 import org.elasticsearch.client.ElasticsearchClient;
-import org.elasticsearch.common.Nullable;
 
 public class GetStoredScriptRequestBuilder extends MasterNodeReadOperationRequestBuilder<GetStoredScriptRequest,
         GetStoredScriptResponse, GetStoredScriptRequestBuilder> {
@@ -31,11 +30,6 @@ public class GetStoredScriptRequestBuilder extends MasterNodeReadOperationReques
         super(client, action, new GetStoredScriptRequest());
     }
 
-    public GetStoredScriptRequestBuilder setLang(@Nullable String lang) {
-        request.lang(lang);
-        return this;
-    }
-
     public GetStoredScriptRequestBuilder setId(String id) {
         request.id(id);
         return this;

+ 21 - 25
core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java

@@ -28,6 +28,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.script.StoredScriptSource;
 
 import java.io.IOException;
 import java.util.Objects;
@@ -37,22 +38,22 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
 public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptRequest> {
 
     private String id;
-    private String lang;
     private String context;
     private BytesReference content;
     private XContentType xContentType;
+    private StoredScriptSource source;
 
     public PutStoredScriptRequest() {
         super();
     }
 
-    public PutStoredScriptRequest(String id, String lang, String context, BytesReference content, XContentType xContentType) {
+    public PutStoredScriptRequest(String id, String context, BytesReference content, XContentType xContentType, StoredScriptSource source) {
         super();
         this.id = id;
-        this.lang = lang;
         this.context = context;
         this.content = content;
         this.xContentType = Objects.requireNonNull(xContentType);
+        this.source = source;
     }
 
     @Override
@@ -65,10 +66,6 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
             validationException = addValidationError("id cannot contain '#' for stored script", validationException);
         }
 
-        if (lang != null && lang.contains("#")) {
-            validationException = addValidationError("lang cannot contain '#' for stored script", validationException);
-        }
-
         if (content == null) {
             validationException = addValidationError("must specify code for stored script", validationException);
         }
@@ -82,17 +79,6 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
 
     public PutStoredScriptRequest id(String id) {
         this.id = id;
-
-        return this;
-    }
-
-    public String lang() {
-        return lang;
-    }
-
-    public PutStoredScriptRequest lang(String lang) {
-        this.lang = lang;
-
         return this;
     }
 
@@ -113,12 +99,17 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
         return xContentType;
     }
 
+    public StoredScriptSource source() {
+        return source;
+    }
+
     /**
      * Set the script source and the content type of the bytes.
      */
     public PutStoredScriptRequest content(BytesReference content, XContentType xContentType) {
         this.content = content;
         this.xContentType = Objects.requireNonNull(xContentType);
+        this.source = StoredScriptSource.parse(content, xContentType);
         return this;
     }
 
@@ -126,12 +117,9 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
     public void readFrom(StreamInput in) throws IOException {
         super.readFrom(in);
 
-        lang = in.readString();
-
-        if (lang.isEmpty()) {
-            lang = null;
+        if (in.getVersion().before(Version.V_6_0_0_alpha2)) {
+            in.readString(); // read lang from previous versions
         }
-
         id = in.readOptionalString();
         content = in.readBytesReference();
         if (in.getVersion().onOrAfter(Version.V_5_3_0)) {
@@ -141,6 +129,9 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
         }
         if (in.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) {
             context = in.readOptionalString();
+            source = new StoredScriptSource(in);
+        } else {
+            source = StoredScriptSource.parse(content, xContentType == null ? XContentType.JSON : xContentType);
         }
     }
 
@@ -148,7 +139,9 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
     public void writeTo(StreamOutput out) throws IOException {
         super.writeTo(out);
 
-        out.writeString(lang == null ? "" : lang);
+        if (out.getVersion().before(Version.V_6_0_0_alpha2)) {
+            out.writeString(source == null ? "" : source.getLang());
+        }
         out.writeOptionalString(id);
         out.writeBytesReference(content);
         if (out.getVersion().onOrAfter(Version.V_5_3_0)) {
@@ -156,6 +149,7 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
         }
         if (out.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) {
             out.writeOptionalString(context);
+            source.writeTo(out);
         }
     }
 
@@ -169,6 +163,8 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
             // ignore
         }
 
-        return "put stored script {id [" + id + "]" + (lang != null ? ", lang [" + lang + "]" : "") + ", content [" + source + "]}";
+        return "put stored script {id [" + id + "]" +
+            (context != null ? ", context [" + context + "]" : "") +
+            ", content [" + source + "]}";
     }
 }

+ 0 - 5
core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestBuilder.java

@@ -43,9 +43,4 @@ public class PutStoredScriptRequestBuilder extends AcknowledgedRequestBuilder<Pu
         request.content(source, xContentType);
         return this;
     }
-
-    public PutStoredScriptRequestBuilder setLang(String lang) {
-        request.lang(lang);
-        return this;
-    }
 }

+ 3 - 3
core/src/main/java/org/elasticsearch/client/ClusterAdminClient.java

@@ -298,7 +298,7 @@ public interface ClusterAdminClient extends ElasticsearchClient {
     /**
      * Returns top N hot-threads samples per node. The hot-threads are only
      * sampled for the node ids specified in the request.
-     * 
+     *
      */
     ActionFuture<NodesHotThreadsResponse> nodesHotThreads(NodesHotThreadsRequest request);
 
@@ -682,7 +682,7 @@ public interface ClusterAdminClient extends ElasticsearchClient {
     /**
      * Delete a script from the cluster state
      */
-    DeleteStoredScriptRequestBuilder prepareDeleteStoredScript(String scriptLang, String id);
+    DeleteStoredScriptRequestBuilder prepareDeleteStoredScript(String id);
 
     /**
      * Store a script in the cluster state
@@ -702,7 +702,7 @@ public interface ClusterAdminClient extends ElasticsearchClient {
     /**
      * Get a script from the cluster state
      */
-    GetStoredScriptRequestBuilder prepareGetStoredScript(@Nullable String scriptLang, String id);
+    GetStoredScriptRequestBuilder prepareGetStoredScript(String id);
 
     /**
      * Get a script from the cluster state

+ 4 - 4
core/src/main/java/org/elasticsearch/client/support/AbstractClient.java

@@ -1192,8 +1192,8 @@ public abstract class AbstractClient extends AbstractComponent implements Client
         }
 
         @Override
-        public GetStoredScriptRequestBuilder prepareGetStoredScript(String scriptLang, String id) {
-            return prepareGetStoredScript().setLang(scriptLang).setId(id);
+        public GetStoredScriptRequestBuilder prepareGetStoredScript(String id) {
+            return prepareGetStoredScript().setId(id);
         }
 
         @Override
@@ -1228,8 +1228,8 @@ public abstract class AbstractClient extends AbstractComponent implements Client
         }
 
         @Override
-        public DeleteStoredScriptRequestBuilder prepareDeleteStoredScript(@Nullable String scriptLang, String id){
-            return prepareDeleteStoredScript().setLang(scriptLang).setId(id);
+        public DeleteStoredScriptRequestBuilder prepareDeleteStoredScript(String id){
+            return prepareDeleteStoredScript().setId(id);
         }
     }
 

+ 2 - 20
core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestDeleteStoredScriptAction.java

@@ -35,11 +35,7 @@ public class RestDeleteStoredScriptAction extends BaseRestHandler {
     public RestDeleteStoredScriptAction(Settings settings, RestController controller) {
         super(settings);
 
-        // Note {lang} is actually {id} in the first handler.  It appears
-        // parameters as part of the path must be of the same ordering relative
-        // to name or they will not work as expected.
-        controller.registerHandler(DELETE, "/_scripts/{lang}", this);
-        controller.registerHandler(DELETE, "/_scripts/{lang}/{id}", this);
+        controller.registerHandler(DELETE, "/_scripts/{id}", this);
     }
 
     @Override
@@ -50,21 +46,7 @@ public class RestDeleteStoredScriptAction extends BaseRestHandler {
     @Override
     public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
         String id = request.param("id");
-        String lang = request.param("lang");
-
-        // In the case where only {lang} is not null, we make it {id} because of
-        // name ordering issues in the handlers' paths.
-        if (id == null) {
-            id = lang;
-            lang = null;
-        }
-
-        if (lang != null) {
-            deprecationLogger.deprecated(
-                "specifying lang [" + lang + "] as part of the url path is deprecated");
-        }
-
-        DeleteStoredScriptRequest deleteStoredScriptRequest = new DeleteStoredScriptRequest(id, lang);
+        DeleteStoredScriptRequest deleteStoredScriptRequest = new DeleteStoredScriptRequest(id);
         return channel -> client.admin().cluster().deleteStoredScript(deleteStoredScriptRequest, new AcknowledgedRestListener<>(channel));
     }
 }

+ 11 - 41
core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetStoredScriptAction.java

@@ -40,17 +40,12 @@ import static org.elasticsearch.rest.RestRequest.Method.GET;
 public class RestGetStoredScriptAction extends BaseRestHandler {
 
     public static final ParseField _ID_PARSE_FIELD = new ParseField("_id");
-
     public static final ParseField FOUND_PARSE_FIELD = new ParseField("found");
 
     public RestGetStoredScriptAction(Settings settings, RestController controller) {
         super(settings);
 
-        // Note {lang} is actually {id} in the first handler.  It appears
-        // parameters as part of the path must be of the same ordering relative
-        // to name or they will not work as expected.
-        controller.registerHandler(GET, "/_scripts/{lang}", this);
-        controller.registerHandler(GET, "/_scripts/{lang}/{id}", this);
+        controller.registerHandler(GET, "/_scripts/{id}", this);
     }
 
     @Override
@@ -60,25 +55,8 @@ public class RestGetStoredScriptAction extends BaseRestHandler {
 
     @Override
     public RestChannelConsumer prepareRequest(final RestRequest request, NodeClient client) throws IOException {
-        String id;
-        String lang;
-
-        // In the case where only {lang} is not null, we make it {id} because of
-        // name ordering issues in the handlers' paths.
-        if (request.param("id") == null) {
-            id = request.param("lang");;
-            lang = null;
-        } else {
-            id = request.param("id");
-            lang = request.param("lang");
-        }
-
-        if (lang != null) {
-            deprecationLogger.deprecated(
-                "specifying lang [" + lang + "] as part of the url path is deprecated");
-        }
-
-        GetStoredScriptRequest getRequest = new GetStoredScriptRequest(id, lang);
+        String id = request.param("id");
+        GetStoredScriptRequest getRequest = new GetStoredScriptRequest(id);
 
         return channel -> client.admin().cluster().getStoredScript(getRequest, new RestBuilderListener<GetStoredScriptResponse>(channel) {
             @Override
@@ -86,28 +64,20 @@ public class RestGetStoredScriptAction extends BaseRestHandler {
                 builder.startObject();
                 builder.field(_ID_PARSE_FIELD.getPreferredName(), id);
 
-                if (lang != null) {
-                    builder.field(StoredScriptSource.LANG_PARSE_FIELD.getPreferredName(), lang);
-                }
-
                 StoredScriptSource source = response.getSource();
                 boolean found = source != null;
                 builder.field(FOUND_PARSE_FIELD.getPreferredName(), found);
 
                 if (found) {
-                    if (lang == null) {
-                        builder.startObject(StoredScriptSource.SCRIPT_PARSE_FIELD.getPreferredName());
-                        builder.field(StoredScriptSource.LANG_PARSE_FIELD.getPreferredName(), source.getLang());
-                        builder.field(StoredScriptSource.SOURCE_PARSE_FIELD.getPreferredName(), source.getSource());
-
-                        if (source.getOptions().isEmpty() == false) {
-                            builder.field(StoredScriptSource.OPTIONS_PARSE_FIELD.getPreferredName(), source.getOptions());
-                        }
-
-                        builder.endObject();
-                    } else {
-                        builder.field(StoredScriptSource.SCRIPT_PARSE_FIELD.getPreferredName(), source.getSource());
+                    builder.startObject(StoredScriptSource.SCRIPT_PARSE_FIELD.getPreferredName());
+                    builder.field(StoredScriptSource.LANG_PARSE_FIELD.getPreferredName(), source.getLang());
+                    builder.field(StoredScriptSource.SOURCE_PARSE_FIELD.getPreferredName(), source.getSource());
+
+                    if (source.getOptions().isEmpty() == false) {
+                        builder.field(StoredScriptSource.OPTIONS_PARSE_FIELD.getPreferredName(), source.getOptions());
                     }
+
+                    builder.endObject();
                 }
 
                 builder.endObject();

+ 8 - 22
core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestPutStoredScriptAction.java

@@ -22,10 +22,12 @@ import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptReque
 import org.elasticsearch.client.node.NodeClient;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentType;
 import org.elasticsearch.rest.BaseRestHandler;
 import org.elasticsearch.rest.RestController;
 import org.elasticsearch.rest.RestRequest;
 import org.elasticsearch.rest.action.AcknowledgedRestListener;
+import org.elasticsearch.script.StoredScriptSource;
 
 import java.io.IOException;
 
@@ -37,13 +39,9 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
     public RestPutStoredScriptAction(Settings settings, RestController controller) {
         super(settings);
 
-        // Note {lang} is actually {id} in the first two handlers.  It appears
-        // parameters as part of the path must be of the same ordering relative
-        // to name or they will not work as expected.
-        controller.registerHandler(POST, "/_scripts/{lang}", this);
-        controller.registerHandler(PUT, "/_scripts/{lang}", this);
-        controller.registerHandler(POST, "/_scripts/{lang}/{id}", this);
-        controller.registerHandler(PUT, "/_scripts/{lang}/{id}", this);
+        controller.registerHandler(POST, "/_scripts/{id}", this);
+        controller.registerHandler(PUT, "/_scripts/{id}", this);
+        controller.registerHandler(PUT, "/_scripts/{id}/{context}", this);
     }
 
     @Override
@@ -54,24 +52,12 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
     @Override
     public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
         String id = request.param("id");
-        String lang = request.param("lang");
         String context = request.param("context");
-
-        // In the case where only {lang} is not null, we make it {id} because of
-        // name ordering issues in the handlers' paths.
-        if (id == null) {
-            id = lang;
-            lang = null;
-        }
-
         BytesReference content = request.requiredContent();
+        XContentType xContentType = request.getXContentType();
+        StoredScriptSource source = StoredScriptSource.parse(content, xContentType);
 
-        if (lang != null) {
-            deprecationLogger.deprecated(
-                "specifying lang [" + lang + "] as part of the url path is deprecated, use request content instead");
-        }
-
-        PutStoredScriptRequest putRequest = new PutStoredScriptRequest(id, lang, context, content, request.getXContentType());
+        PutStoredScriptRequest putRequest = new PutStoredScriptRequest(id, context, content, request.getXContentType(), source);
         return channel -> client.admin().cluster().putStoredScript(putRequest, new AcknowledgedRestListener<>(channel));
     }
 }

+ 44 - 94
core/src/main/java/org/elasticsearch/script/ScriptMetaData.java

@@ -45,10 +45,7 @@ import java.util.Map;
 
 /**
  * {@link ScriptMetaData} is used to store user-defined scripts
- * as part of the {@link ClusterState}.  Currently scripts can
- * be stored as part of the new namespace for a stored script where
- * only an id is used or as part of the deprecated namespace where
- * both a language and an id are used.
+ * as part of the {@link ClusterState} using only an id as the key.
  */
 public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXContent {
 
@@ -71,73 +68,28 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
         }
 
         /**
-         * Add a new script to the existing stored scripts.  The script will be added under
-         * both the new namespace and the deprecated namespace, so that look ups under
-         * the deprecated namespace will continue to work.  Should a script already exist under
-         * the new namespace using a different language, it will be replaced and a deprecation
-         * warning will be issued.  The replaced script will still exist under the deprecated
-         * namespace and can continue to be looked up this way until it is deleted.
-         * <p>
-         * Take for example script 'A' with lang 'L0' and data 'D0'.  If we add script 'A' to the
-         * empty set, the scripts {@link Map} will be ["A" -- D0, "A#L0" -- D0].  If a script
-         * 'A' with lang 'L1' and data 'D1' is then added, the scripts {@link Map} will be
-         * ["A" -- D1, "A#L1" -- D1, "A#L0" -- D0].
+         * Add a new script to the existing stored scripts based on a user-specified id.  If
+         * a script with the same id already exists it will be overwritten.
          * @param id The user-specified id to use for the look up.
          * @param source The user-specified stored script data held in {@link StoredScriptSource}.
          */
         public Builder storeScript(String id, StoredScriptSource source) {
-            StoredScriptSource previous = scripts.put(id, source);
-            scripts.put(source.getLang() + "#" + id, source);
-
-            if (previous != null && previous.getLang().equals(source.getLang()) == false) {
-                DEPRECATION_LOGGER.deprecated("stored script [" + id + "] already exists using a different lang " +
-                    "[" + previous.getLang() + "], the new namespace for stored scripts will only use (id) instead of (lang, id)");
-            }
+            scripts.put(id, source);
 
             return this;
         }
 
         /**
-         * Delete a script from the existing stored scripts.  The script will be removed from the
-         * new namespace if the script language matches the current script under the same id or
-         * if the script language is {@code null}.  The script will be removed from the deprecated
-         * namespace on any delete either using using the specified lang parameter or the language
-         * found from looking up the script in the new namespace.
-         * <p>
-         * Take for example a scripts {@link Map} with {"A" -- D1, "A#L1" -- D1, "A#L0" -- D0}.
-         * If a script is removed specified by an id 'A' and lang {@code null} then the scripts
-         * {@link Map} will be {"A#L0" -- D0}.  To remove the final script, the deprecated
-         * namespace must be used, so an id 'A' and lang 'L0' would need to be specified.
+         * Delete a script from the existing stored scripts based on a user-specified id.
          * @param id The user-specified id to use for the look up.
-         * @param lang The user-specified language to use for the look up if using the deprecated
-         *             namespace, otherwise {@code null}.
          */
-        public Builder deleteScript(String id, String lang) {
-            StoredScriptSource source = scripts.get(id);
-
-            if (lang == null) {
-                if (source == null) {
-                    throw new ResourceNotFoundException("stored script [" + id + "] does not exist and cannot be deleted");
-                }
+        public Builder deleteScript(String id) {
+            StoredScriptSource deleted = scripts.remove(id);
 
-                lang = source.getLang();
+            if (deleted == null) {
+                throw new ResourceNotFoundException("stored script [" + id + "] does not exist and cannot be deleted");
             }
 
-            if (source != null) {
-                if (lang.equals(source.getLang())) {
-                    scripts.remove(id);
-                }
-            }
-
-            source = scripts.get(lang + "#" + id);
-
-            if (source == null) {
-                throw new ResourceNotFoundException(
-                    "stored script [" + id + "] using lang [" + lang + "] does not exist and cannot be deleted");
-            }
-
-            scripts.remove(lang + "#" + id);
-
             return this;
         }
 
@@ -193,23 +145,13 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
      * Convenience method to build and return a new
      * {@link ScriptMetaData} deleting the specified stored script.
      */
-    static ScriptMetaData deleteStoredScript(ScriptMetaData previous, String id, String lang) {
+    static ScriptMetaData deleteStoredScript(ScriptMetaData previous, String id) {
         Builder builder = new ScriptMetaData.Builder(previous);
-        builder.deleteScript(id, lang);
+        builder.deleteScript(id);
 
         return builder.build();
     }
 
-    /**
-     * Standard logger necessary for allocation of the deprecation logger.
-     */
-    private static final Logger LOGGER = ESLoggerFactory.getLogger(ScriptMetaData.class);
-
-    /**
-     * Deprecation logger necessary for namespace changes related to stored scripts.
-     */
-    private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(LOGGER);
-
     /**
      * The type of {@link ClusterState} data.
      */
@@ -218,7 +160,7 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
     /**
      * This will parse XContent into {@link ScriptMetaData}.
      *
-     * The following format will be parsed for the new namespace:
+     * The following format will be parsed:
      *
      * {@code
      * {
@@ -228,23 +170,15 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
      * }
      * }
      *
-     * The following format will be parsed for the deprecated namespace:
-     *
-     * {@code
-     * {
-     *     "<id>" : "<code>",
-     *     "<id>" : "<code>",
-     *     ...
-     * }
-     * }
-     *
-     * Note when using the deprecated namespace, the language will be pulled from
-     * the id and options will be set to an empty {@link Map}.
+     * When loading from a source prior to 6.0, if multiple scripts
+     * using the old namespace id format of [lang#id] are found to have the
+     * same id but different languages an error will occur.
      */
     public static ScriptMetaData fromXContent(XContentParser parser) throws IOException {
         Map<String, StoredScriptSource> scripts = new HashMap<>();
         String id = null;
         StoredScriptSource source;
+        StoredScriptSource exists;
 
         Token token = parser.currentToken();
 
@@ -270,13 +204,25 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
                     }
 
                     int split = id.indexOf('#');
+                    String lang;
 
                     if (split == -1) {
                         throw new IllegalArgumentException("illegal stored script id [" + id + "], does not contain lang");
                     } else {
-                        source = new StoredScriptSource(id.substring(0, split), parser.text(), Collections.emptyMap());
+                        lang = id.substring(0, split);
+                        id = id.substring(split + 1);
+                        source = new StoredScriptSource(lang, parser.text(), Collections.emptyMap());
+                    }
+
+                    exists = scripts.get(id);
+
+                    if (exists == null) {
+                        scripts.put(id, source);
+                    } else if (exists.getLang().equals(lang) == false) {
+                        throw new IllegalArgumentException("illegal stored script, id [" + id + "] used for multiple scripts with " +
+                            "different languages [" + exists.getLang() + "] and [" + lang + "]; scripts using the old namespace " +
+                            "of [lang#id] as a stored script id will have to be updated to use only the new namespace of [id]");
                     }
-                    scripts.put(id, source);
 
                     id = null;
 
@@ -287,8 +233,18 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
                             "unexpected token [" + token + "], expected [<id>, <code>, {]");
                     }
 
+                    exists = scripts.get(id);
                     source = StoredScriptSource.fromXContent(parser);
-                    scripts.put(id, source);
+
+                    if (exists == null) {
+                        scripts.put(id, source);
+                    } else if (exists.getLang().equals(source.getLang()) == false) {
+                        throw new IllegalArgumentException("illegal stored script, id [" + id + "] used for multiple scripts with " +
+                            "different languages [" + exists.getLang() + "] and [" + source.getLang() + "]; scripts using the old " +
+                            "namespace of [lang#id] as a stored script id will have to be updated to use only the new namespace of [id]");
+                    }
+
+                    id = null;
 
                     break;
                 default:
@@ -421,16 +377,10 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
     }
 
     /**
-     * Retrieves a stored script from the new namespace if lang is {@code null}.
-     * Otherwise, returns a stored script from the deprecated namespace.  Either
-     * way an id is required.
+     * Retrieves a stored script based on a user-specified id.
      */
-    StoredScriptSource getStoredScript(String id, String lang) {
-        if (lang == null) {
-            return scripts.get(id);
-        } else {
-            return scripts.get(lang + "#" + id);
-        }
+    StoredScriptSource getStoredScript(String id) {
+        return scripts.get(id);
     }
 
     @Override

+ 6 - 10
core/src/main/java/org/elasticsearch/script/ScriptService.java

@@ -237,7 +237,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
             // context is supported
             // * a stored script must be pulled from the cluster state every time in case
             // the script has been updated since the last compilation
-            StoredScriptSource source = getScriptFromClusterState(id, lang);
+            StoredScriptSource source = getScriptFromClusterState(id);
             lang = source.getLang();
             idOrCode = source.getSource();
             options = source.getOptions();
@@ -360,14 +360,14 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
         return contextsAllowed == null || contextsAllowed.isEmpty() == false;
     }
 
-    StoredScriptSource getScriptFromClusterState(String id, String lang) {
+    StoredScriptSource getScriptFromClusterState(String id) {
         ScriptMetaData scriptMetadata = clusterState.metaData().custom(ScriptMetaData.TYPE);
 
         if (scriptMetadata == null) {
             throw new ResourceNotFoundException("unable to find script [" + id + "] in cluster state");
         }
 
-        StoredScriptSource source = scriptMetadata.getStoredScript(id, lang);
+        StoredScriptSource source = scriptMetadata.getStoredScript(id);
 
         if (source == null) {
             throw new ResourceNotFoundException("unable to find script [" + id + "] in cluster state");
@@ -385,7 +385,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
                 request.content().length() + "] for script [" + request.id() + "]");
         }
 
-        StoredScriptSource source = StoredScriptSource.parse(request.lang(), request.content(), request.xContentType());
+        StoredScriptSource source = request.source();
 
         if (isLangSupported(source.getLang()) == false) {
             throw new IllegalArgumentException("unable to put stored script with unsupported lang [" + source.getLang() + "]");
@@ -434,10 +434,6 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
 
     public void deleteStoredScript(ClusterService clusterService, DeleteStoredScriptRequest request,
                                    ActionListener<DeleteStoredScriptResponse> listener) {
-        if (request.lang() != null && isLangSupported(request.lang()) == false) {
-            throw new IllegalArgumentException("unable to delete stored script with unsupported lang [" + request.lang() +"]");
-        }
-
         clusterService.submitStateUpdateTask("delete-script-" + request.id(),
             new AckedClusterStateUpdateTask<DeleteStoredScriptResponse>(request, listener) {
 
@@ -449,7 +445,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
             @Override
             public ClusterState execute(ClusterState currentState) throws Exception {
                 ScriptMetaData smd = currentState.metaData().custom(ScriptMetaData.TYPE);
-                smd = ScriptMetaData.deleteStoredScript(smd, request.id(), request.lang());
+                smd = ScriptMetaData.deleteStoredScript(smd, request.id());
                 MetaData.Builder mdb = MetaData.builder(currentState.getMetaData()).putCustom(ScriptMetaData.TYPE, smd);
 
                 return ClusterState.builder(currentState).metaData(mdb).build();
@@ -461,7 +457,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
         ScriptMetaData scriptMetadata = state.metaData().custom(ScriptMetaData.TYPE);
 
         if (scriptMetadata != null) {
-            return scriptMetadata.getStoredScript(request.id(), request.lang());
+            return scriptMetadata.getStoredScript(request.id());
         } else {
             return null;
         }

+ 10 - 29
core/src/main/java/org/elasticsearch/script/StoredScriptSource.java

@@ -238,13 +238,10 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
      * Also templates may be part of the 'source' parameter in a script.  The Parser
      * can handle this case as well.
      *
-     * @param lang    An optional parameter to allow for use of the deprecated stored
-     *                script namespace.  This will be used to specify the language
-     *                coming in as a url parameter from a request or for stored templates.
      * @param content The content from the request to be parsed as described above.
      * @return        The parsed {@link StoredScriptSource}.
      */
-    public static StoredScriptSource parse(String lang, BytesReference content, XContentType xContentType) {
+    public static StoredScriptSource parse(BytesReference content, XContentType xContentType) {
         try (XContentParser parser = xContentType.xContent().createParser(NamedXContentRegistry.EMPTY, content)) {
             Token token = parser.nextToken();
 
@@ -254,6 +251,10 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
 
             token = parser.nextToken();
 
+            if (token == Token.END_OBJECT) {
+                return new StoredScriptSource(Script.DEFAULT_TEMPLATE_LANG, "", Collections.emptyMap());
+            }
+
             if (token != Token.FIELD_NAME) {
                 throw new ParsingException(parser.getTokenLocation(), "unexpected token [" + token + ", expected [" +
                     SCRIPT_PARSE_FIELD.getPreferredName() + ", " + TEMPLATE_PARSE_FIELD.getPreferredName());
@@ -264,37 +265,17 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
             if (SCRIPT_PARSE_FIELD.getPreferredName().equals(name)) {
                 token = parser.nextToken();
 
-                if (token == Token.VALUE_STRING) {
-                    if (lang == null) {
-                        throw new IllegalArgumentException(
-                            "must specify lang as a url parameter when using the deprecated stored script namespace");
-                    }
-
-                    return new StoredScriptSource(lang, parser.text(), Collections.emptyMap());
-                } else if (token == Token.START_OBJECT) {
-                    if (lang == null) {
-                        return PARSER.apply(parser, null).build();
-                    } else {
-                        //this is really for search templates, that need to be converted to json format
-                        try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
-                            builder.copyCurrentStructure(parser);
-                            return new StoredScriptSource(lang, builder.string(), Collections.emptyMap());
-                        }
-                    }
-
+                if (token == Token.START_OBJECT) {
+                    return PARSER.apply(parser, null).build();
                 } else {
                     throw new ParsingException(parser.getTokenLocation(), "unexpected token [" + token + "], expected [{, <source>]");
                 }
             } else {
-                if (lang == null) {
-                    throw new IllegalArgumentException("unexpected stored script format");
-                }
-
                 if (TEMPLATE_PARSE_FIELD.getPreferredName().equals(name)) {
                     token = parser.nextToken();
 
                     if (token == Token.VALUE_STRING) {
-                        return new StoredScriptSource(lang, parser.text(), Collections.emptyMap());
+                        return new StoredScriptSource(Script.DEFAULT_TEMPLATE_LANG, parser.text(), Collections.emptyMap());
                     }
                 }
 
@@ -307,7 +288,7 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
                         builder.copyCurrentStructure(parser);
                     }
 
-                    return new StoredScriptSource(lang, builder.string(), Collections.emptyMap());
+                    return new StoredScriptSource(Script.DEFAULT_TEMPLATE_LANG, builder.string(), Collections.emptyMap());
                 }
             }
         } catch (IOException ioe) {
@@ -365,7 +346,7 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
     /**
      * Standard StoredScriptSource constructor.
      * @param lang    The language to compile the script with.  Must not be {@code null}.
-     * @param source    The source source to compile with.  Must not be {@code null}.
+     * @param source  The source source to compile with.  Must not be {@code null}.
      * @param options Compiler options to be compiled with.  Must not be {@code null},
      *                use an empty {@link Map} to represent no options.
      */

+ 1 - 3
core/src/test/java/org/elasticsearch/action/admin/cluster/storedscripts/GetStoredScriptRequestTests.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.action.admin.cluster.storedscripts;
 
-import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
 import org.elasticsearch.common.io.stream.BytesStreamOutput;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.test.ESTestCase;
@@ -31,7 +30,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
 
 public class GetStoredScriptRequestTests extends ESTestCase {
     public void testGetIndexedScriptRequestSerialization() throws IOException {
-        GetStoredScriptRequest request = new GetStoredScriptRequest("lang", "id");
+        GetStoredScriptRequest request = new GetStoredScriptRequest("id");
 
         BytesStreamOutput out = new BytesStreamOutput();
         out.setVersion(randomVersion(random()));
@@ -43,6 +42,5 @@ public class GetStoredScriptRequestTests extends ESTestCase {
         request2.readFrom(in);
 
         assertThat(request2.id(), equalTo(request.id()));
-        assertThat(request2.lang(), equalTo(request.lang()));
     }
 }

+ 4 - 4
core/src/test/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestTests.java

@@ -24,16 +24,18 @@ import org.elasticsearch.common.bytes.BytesArray;
 import org.elasticsearch.common.io.stream.BytesStreamOutput;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.script.StoredScriptSource;
 import org.elasticsearch.test.ESTestCase;
 
 import java.io.IOException;
 import java.util.Base64;
+import java.util.Collections;
 
 public class PutStoredScriptRequestTests extends ESTestCase {
 
     public void testSerialization() throws IOException {
-        PutStoredScriptRequest storedScriptRequest =
-            new PutStoredScriptRequest("foo", "bar", "context", new BytesArray("{}"), XContentType.JSON);
+        PutStoredScriptRequest storedScriptRequest = new PutStoredScriptRequest("bar", "context", new BytesArray("{}"), XContentType.JSON,
+                new StoredScriptSource("foo", "bar", Collections.emptyMap()));
 
         assertEquals(XContentType.JSON, storedScriptRequest.xContentType());
         try (BytesStreamOutput output = new BytesStreamOutput()) {
@@ -43,7 +45,6 @@ public class PutStoredScriptRequestTests extends ESTestCase {
                 PutStoredScriptRequest serialized = new PutStoredScriptRequest();
                 serialized.readFrom(in);
                 assertEquals(XContentType.JSON, serialized.xContentType());
-                assertEquals(storedScriptRequest.lang(), serialized.lang());
                 assertEquals(storedScriptRequest.id(), serialized.id());
                 assertEquals(storedScriptRequest.context(), serialized.context());
             }
@@ -59,7 +60,6 @@ public class PutStoredScriptRequestTests extends ESTestCase {
             PutStoredScriptRequest serialized = new PutStoredScriptRequest();
             serialized.readFrom(in);
             assertEquals(XContentType.JSON, serialized.xContentType());
-            assertEquals("mustache", serialized.lang());
             assertEquals("script", serialized.id());
             assertEquals(new BytesArray("{}"), serialized.content());
 

+ 1 - 1
core/src/test/java/org/elasticsearch/client/AbstractClientHeadersTestCase.java

@@ -104,7 +104,7 @@ public abstract class AbstractClientHeadersTestCase extends ESTestCase {
         client.prepareGet("idx", "type", "id").execute(new AssertingActionListener<>(GetAction.NAME, client.threadPool()));
         client.prepareSearch().execute(new AssertingActionListener<>(SearchAction.NAME, client.threadPool()));
         client.prepareDelete("idx", "type", "id").execute(new AssertingActionListener<>(DeleteAction.NAME, client.threadPool()));
-        client.admin().cluster().prepareDeleteStoredScript("lang", "id").execute(new AssertingActionListener<>(DeleteStoredScriptAction.NAME, client.threadPool()));
+        client.admin().cluster().prepareDeleteStoredScript("id").execute(new AssertingActionListener<>(DeleteStoredScriptAction.NAME, client.threadPool()));
         client.prepareIndex("idx", "type", "id").setSource("source", XContentType.JSON).execute(new AssertingActionListener<>(IndexAction.NAME, client.threadPool()));
 
         // choosing arbitrary cluster admin actions to test

+ 57 - 34
core/src/test/java/org/elasticsearch/script/ScriptMetaDataTests.java

@@ -21,6 +21,7 @@ package org.elasticsearch.script;
 import org.elasticsearch.cluster.DiffableUtils;
 import org.elasticsearch.common.bytes.BytesArray;
 import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentParser;
@@ -32,81 +33,103 @@ import java.io.UncheckedIOException;
 
 public class ScriptMetaDataTests extends AbstractSerializingTestCase<ScriptMetaData> {
 
+    public void testFromXContentLoading() throws Exception {
+        // failure to load to old namespace scripts with the same id but different langs
+        XContentBuilder builder = XContentFactory.jsonBuilder();
+        builder.startObject().field("lang0#id0", "script0").field("lang1#id0", "script1").endObject();
+        XContentParser parser0 = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, builder.bytes());
+        expectThrows(IllegalArgumentException.class, () -> ScriptMetaData.fromXContent(parser0));
+
+        // failure to load a new namespace script and old namespace script with the same id but different langs
+        builder = XContentFactory.jsonBuilder();
+        builder.startObject().field("lang0#id0", "script0")
+            .startObject("id0").field("lang", "lang1").field("source", "script1").endObject().endObject();
+        XContentParser parser1 = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, builder.bytes());
+        expectThrows(IllegalArgumentException.class, () -> ScriptMetaData.fromXContent(parser1));
+
+        // failure to load a new namespace script and old namespace script with the same id but different langs with additional scripts
+        builder = XContentFactory.jsonBuilder();
+        builder.startObject().field("lang0#id0", "script0").field("lang0#id1", "script1")
+            .startObject("id1").field("lang", "lang0").field("source", "script0").endObject()
+            .startObject("id0").field("lang", "lang1").field("source", "script1").endObject().endObject();
+        XContentParser parser2 = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, builder.bytes());
+        expectThrows(IllegalArgumentException.class, () -> ScriptMetaData.fromXContent(parser2));
+
+        // okay to load the same script from the new and old namespace if the lang is the same
+        builder = XContentFactory.jsonBuilder();
+        builder.startObject().field("lang0#id0", "script0")
+            .startObject("id0").field("lang", "lang0").field("source", "script1").endObject().endObject();
+        XContentParser parser3 = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY, builder.bytes());
+        ScriptMetaData.fromXContent(parser3);
+    }
+
     public void testGetScript() throws Exception {
         ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
 
         XContentBuilder sourceBuilder = XContentFactory.jsonBuilder();
         sourceBuilder.startObject().startObject("template").field("field", "value").endObject().endObject();
-        builder.storeScript("template", StoredScriptSource.parse("lang", sourceBuilder.bytes(), sourceBuilder.contentType()));
+        builder.storeScript("template", StoredScriptSource.parse(sourceBuilder.bytes(), sourceBuilder.contentType()));
 
         sourceBuilder = XContentFactory.jsonBuilder();
         sourceBuilder.startObject().field("template", "value").endObject();
-        builder.storeScript("template_field", StoredScriptSource.parse("lang", sourceBuilder.bytes(), sourceBuilder.contentType()));
-
-        sourceBuilder = XContentFactory.jsonBuilder();
-        sourceBuilder.startObject().startObject("script").field("field", "value").endObject().endObject();
-        builder.storeScript("script", StoredScriptSource.parse("lang", sourceBuilder.bytes(), sourceBuilder.contentType()));
-
-        sourceBuilder = XContentFactory.jsonBuilder();
-        sourceBuilder.startObject().field("script", "value").endObject();
-        builder.storeScript("script_field", StoredScriptSource.parse("lang", sourceBuilder.bytes(), sourceBuilder.contentType()));
+        builder.storeScript("template_field", StoredScriptSource.parse(sourceBuilder.bytes(), sourceBuilder.contentType()));
 
         sourceBuilder = XContentFactory.jsonBuilder();
-        sourceBuilder.startObject().field("field", "value").endObject();
-        builder.storeScript("any", StoredScriptSource.parse("lang", sourceBuilder.bytes(), sourceBuilder.contentType()));
+        sourceBuilder.startObject().startObject("script").field("lang", "_lang").field("source", "_source").endObject().endObject();
+        builder.storeScript("script", StoredScriptSource.parse(sourceBuilder.bytes(), sourceBuilder.contentType()));
 
         ScriptMetaData scriptMetaData = builder.build();
-        assertEquals("{\"field\":\"value\"}", scriptMetaData.getStoredScript("template", "lang").getSource());
-        assertEquals("value", scriptMetaData.getStoredScript("template_field", "lang").getSource());
-        assertEquals("{\"field\":\"value\"}", scriptMetaData.getStoredScript("script", "lang").getSource());
-        assertEquals("value", scriptMetaData.getStoredScript("script_field", "lang").getSource());
-        assertEquals("{\"field\":\"value\"}", scriptMetaData.getStoredScript("any", "lang").getSource());
+        assertEquals("_source", scriptMetaData.getStoredScript("script").getSource());
+        assertEquals("{\"field\":\"value\"}", scriptMetaData.getStoredScript("template").getSource());
+        assertEquals("value", scriptMetaData.getStoredScript("template_field").getSource());
     }
 
     public void testDiff() throws Exception {
         ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
-        builder.storeScript("1", StoredScriptSource.parse("lang", new BytesArray("{\"foo\":\"abc\"}"), XContentType.JSON));
-        builder.storeScript("2", StoredScriptSource.parse("lang", new BytesArray("{\"foo\":\"def\"}"), XContentType.JSON));
-        builder.storeScript("3", StoredScriptSource.parse("lang", new BytesArray("{\"foo\":\"ghi\"}"), XContentType.JSON));
+        builder.storeScript("1", StoredScriptSource.parse(new BytesArray("{\"foo\":\"abc\"}"), XContentType.JSON));
+        builder.storeScript("2", StoredScriptSource.parse(new BytesArray("{\"foo\":\"def\"}"), XContentType.JSON));
+        builder.storeScript("3", StoredScriptSource.parse(new BytesArray("{\"foo\":\"ghi\"}"), XContentType.JSON));
         ScriptMetaData scriptMetaData1 = builder.build();
 
         builder = new ScriptMetaData.Builder(scriptMetaData1);
-        builder.storeScript("2", StoredScriptSource.parse("lang", new BytesArray("{\"foo\":\"changed\"}"), XContentType.JSON));
-        builder.deleteScript("3", "lang");
-        builder.storeScript("4", StoredScriptSource.parse("lang", new BytesArray("{\"foo\":\"jkl\"}"), XContentType.JSON));
+        builder.storeScript("2", StoredScriptSource.parse(new BytesArray("{\"foo\":\"changed\"}"), XContentType.JSON));
+        builder.deleteScript("3");
+        builder.storeScript("4", StoredScriptSource.parse(new BytesArray("{\"foo\":\"jkl\"}"), XContentType.JSON));
         ScriptMetaData scriptMetaData2 = builder.build();
 
         ScriptMetaData.ScriptMetadataDiff diff = (ScriptMetaData.ScriptMetadataDiff) scriptMetaData2.diff(scriptMetaData1);
-        assertEquals(2, ((DiffableUtils.MapDiff) diff.pipelines).getDeletes().size());
+        assertEquals(1, ((DiffableUtils.MapDiff) diff.pipelines).getDeletes().size());
         assertEquals("3", ((DiffableUtils.MapDiff) diff.pipelines).getDeletes().get(0));
-        assertEquals(2, ((DiffableUtils.MapDiff) diff.pipelines).getDiffs().size());
+        assertEquals(1, ((DiffableUtils.MapDiff) diff.pipelines).getDiffs().size());
         assertNotNull(((DiffableUtils.MapDiff) diff.pipelines).getDiffs().get("2"));
-        assertEquals(2, ((DiffableUtils.MapDiff) diff.pipelines).getUpserts().size());
+        assertEquals(1, ((DiffableUtils.MapDiff) diff.pipelines).getUpserts().size());
         assertNotNull(((DiffableUtils.MapDiff) diff.pipelines).getUpserts().get("4"));
 
         ScriptMetaData result = (ScriptMetaData) diff.apply(scriptMetaData1);
-        assertEquals("{\"foo\":\"abc\"}", result.getStoredScript("1", "lang").getSource());
-        assertEquals("{\"foo\":\"changed\"}", result.getStoredScript("2", "lang").getSource());
-        assertEquals("{\"foo\":\"jkl\"}", result.getStoredScript("4", "lang").getSource());
+        assertEquals("{\"foo\":\"abc\"}", result.getStoredScript("1").getSource());
+        assertEquals("{\"foo\":\"changed\"}", result.getStoredScript("2").getSource());
+        assertEquals("{\"foo\":\"jkl\"}", result.getStoredScript("4").getSource());
     }
 
     public void testBuilder() {
         ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
-        builder.storeScript("_id", StoredScriptSource.parse("_lang", new BytesArray("{\"script\":\"1 + 1\"}"), XContentType.JSON));
+        builder.storeScript("_id", StoredScriptSource.parse(
+            new BytesArray("{\"script\": {\"lang\": \"painless\", \"source\": \"1 + 1\"} }"), XContentType.JSON));
 
         ScriptMetaData result = builder.build();
-        assertEquals("1 + 1", result.getStoredScript("_id", "_lang").getSource());
+        assertEquals("1 + 1", result.getStoredScript("_id").getSource());
     }
 
     private ScriptMetaData randomScriptMetaData(XContentType sourceContentType) throws IOException {
         ScriptMetaData.Builder builder = new ScriptMetaData.Builder(null);
         int numScripts = scaledRandomIntBetween(0, 32);
         for (int i = 0; i < numScripts; i++) {
-            String lang = randomAlphaOfLength(4);
             XContentBuilder sourceBuilder = XContentBuilder.builder(sourceContentType.xContent());
-            sourceBuilder.startObject().field("script", randomAlphaOfLength(4)).endObject();
+            sourceBuilder.startObject().field("script").startObject()
+                .field("lang", randomAlphaOfLength(4)).field("source", randomAlphaOfLength(10))
+                .endObject().endObject();
             builder.storeScript(randomAlphaOfLength(i + 1),
-                StoredScriptSource.parse(lang, sourceBuilder.bytes(), sourceBuilder.contentType()));
+                StoredScriptSource.parse(sourceBuilder.bytes(), sourceBuilder.contentType()));
         }
         return builder.build();
     }

+ 20 - 20
core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java

@@ -75,10 +75,7 @@ public class ScriptServiceTests extends ESTestCase {
         Settings finalSettings = Settings.builder().put(baseSettings).put(additionalSettings).build();
         scriptService = new ScriptService(finalSettings, engines, contexts) {
             @Override
-            StoredScriptSource getScriptFromClusterState(String id, String lang) {
-                if (lang != null) {
-                    throw new IllegalArgumentException("expected null lang in test");
-                }
+            StoredScriptSource getScriptFromClusterState(String id) {
                 //mock the script that gets retrieved from an index
                 return new StoredScriptSource("test", "1+1", Collections.emptyMap());
             }
@@ -233,28 +230,31 @@ public class ScriptServiceTests extends ESTestCase {
     }
 
     public void testStoreScript() throws Exception {
-        BytesReference script = XContentFactory.jsonBuilder().startObject()
-                    .field("script", "abc")
-                .endObject().bytes();
-
-        ScriptMetaData scriptMetaData = ScriptMetaData.putStoredScript(null, "_id",
-            StoredScriptSource.parse("_lang", script, XContentType.JSON));
+        BytesReference script = XContentFactory.jsonBuilder()
+            .startObject()
+            .field("script")
+            .startObject()
+            .field("lang", "_lang")
+            .field("source", "abc")
+            .endObject()
+            .endObject().bytes();
+        ScriptMetaData scriptMetaData = ScriptMetaData.putStoredScript(null, "_id", StoredScriptSource.parse(script, XContentType.JSON));
         assertNotNull(scriptMetaData);
-        assertEquals("abc", scriptMetaData.getStoredScript("_id", "_lang").getSource());
+        assertEquals("abc", scriptMetaData.getStoredScript("_id").getSource());
     }
 
     public void testDeleteScript() throws Exception {
         ScriptMetaData scriptMetaData = ScriptMetaData.putStoredScript(null, "_id",
-            StoredScriptSource.parse("_lang", new BytesArray("{\"script\":\"abc\"}"), XContentType.JSON));
-        scriptMetaData = ScriptMetaData.deleteStoredScript(scriptMetaData, "_id", "_lang");
+            StoredScriptSource.parse(new BytesArray("{\"script\": {\"lang\": \"_lang\", \"source\": \"abc\"} }"), XContentType.JSON));
+        scriptMetaData = ScriptMetaData.deleteStoredScript(scriptMetaData, "_id");
         assertNotNull(scriptMetaData);
-        assertNull(scriptMetaData.getStoredScript("_id", "_lang"));
+        assertNull(scriptMetaData.getStoredScript("_id"));
 
         ScriptMetaData errorMetaData = scriptMetaData;
         ResourceNotFoundException e = expectThrows(ResourceNotFoundException.class, () -> {
-            ScriptMetaData.deleteStoredScript(errorMetaData, "_id", "_lang");
+            ScriptMetaData.deleteStoredScript(errorMetaData, "_id");
         });
-        assertEquals("stored script [_id] using lang [_lang] does not exist and cannot be deleted", e.getMessage());
+        assertEquals("stored script [_id] does not exist and cannot be deleted", e.getMessage());
     }
 
     public void testGetStoredScript() throws Exception {
@@ -263,14 +263,14 @@ public class ScriptServiceTests extends ESTestCase {
             .metaData(MetaData.builder()
                 .putCustom(ScriptMetaData.TYPE,
                     new ScriptMetaData.Builder(null).storeScript("_id",
-                        StoredScriptSource.parse("_lang", new BytesArray("{\"script\":\"abc\"}"), XContentType.JSON)).build()))
+                        StoredScriptSource.parse(new BytesArray("{\"script\": {\"lang\": \"_lang\", \"source\": \"abc\"} }"),
+                            XContentType.JSON)).build()))
             .build();
 
-        assertEquals("abc", scriptService.getStoredScript(cs, new GetStoredScriptRequest("_id", "_lang")).getSource());
-        assertNull(scriptService.getStoredScript(cs, new GetStoredScriptRequest("_id2", "_lang")));
+        assertEquals("abc", scriptService.getStoredScript(cs, new GetStoredScriptRequest("_id")).getSource());
 
         cs = ClusterState.builder(new ClusterName("_name")).build();
-        assertNull(scriptService.getStoredScript(cs, new GetStoredScriptRequest("_id", "_lang")));
+        assertNull(scriptService.getStoredScript(cs, new GetStoredScriptRequest("_id")));
     }
 
     private void assertCompileRejected(String lang, String script, ScriptType scriptType, ScriptContext scriptContext) {

+ 1 - 1
core/src/test/java/org/elasticsearch/script/StoredScriptSourceTests.java

@@ -48,7 +48,7 @@ public class StoredScriptSourceTests extends AbstractSerializingTestCase<StoredS
             if (randomBoolean()) {
                 options.put(Script.CONTENT_TYPE_OPTION, xContentType.mediaType());
             }
-            return StoredScriptSource.parse(lang, template.bytes(), xContentType);
+            return StoredScriptSource.parse(template.bytes(), xContentType);
         } catch (IOException e) {
             throw new AssertionError("Failed to create test instance", e);
         }

+ 25 - 160
core/src/test/java/org/elasticsearch/script/StoredScriptTests.java

@@ -32,7 +32,6 @@ import java.io.UncheckedIOException;
 import java.util.Collections;
 
 import static java.util.Collections.emptyMap;
-import static java.util.Collections.singletonMap;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.nullValue;
 
@@ -41,152 +40,24 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
     public void testBasicAddDelete() {
         StoredScriptSource source = new StoredScriptSource("lang", "code", emptyMap());
         ScriptMetaData smd = ScriptMetaData.putStoredScript(null, "test", source);
+        assertThat(smd.getStoredScript("test"), equalTo(source));
 
-        assertThat(smd.getStoredScript("test", null), equalTo(source));
-        assertThat(smd.getStoredScript("test", "lang"), equalTo(source));
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test", null);
-
-        assertThat(smd.getStoredScript("test", null), nullValue());
-        assertThat(smd.getStoredScript("test", "lang"), nullValue());
-    }
-
-    public void testDifferentMultiAddDelete() {
-        StoredScriptSource source0 = new StoredScriptSource("lang0", "code0", emptyMap());
-        StoredScriptSource source1 = new StoredScriptSource("lang0", "code1", emptyMap());
-        StoredScriptSource source2 = new StoredScriptSource("lang1", "code2",
-            singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()));
-
-        ScriptMetaData smd = ScriptMetaData.putStoredScript(null, "test0", source0);
-        smd = ScriptMetaData.putStoredScript(smd, "test1", source1);
-        smd = ScriptMetaData.putStoredScript(smd, "test2", source2);
-
-        assertThat(smd.getStoredScript("test0", null), equalTo(source0));
-        assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0));
-        assertThat(smd.getStoredScript("test1", null), equalTo(source1));
-        assertThat(smd.getStoredScript("test1", "lang0"), equalTo(source1));
-        assertThat(smd.getStoredScript("test2", null), equalTo(source2));
-        assertThat(smd.getStoredScript("test2", "lang1"), equalTo(source2));
-
-        assertThat(smd.getStoredScript("test3", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test2", "lang0"), nullValue());
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test0", null);
-
-        assertThat(smd.getStoredScript("test0", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang0"), nullValue());
-        assertThat(smd.getStoredScript("test1", null), equalTo(source1));
-        assertThat(smd.getStoredScript("test1", "lang0"), equalTo(source1));
-        assertThat(smd.getStoredScript("test2", null), equalTo(source2));
-        assertThat(smd.getStoredScript("test2", "lang1"), equalTo(source2));
-
-        assertThat(smd.getStoredScript("test3", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test2", "lang0"), nullValue());
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test2", "lang1");
-
-        assertThat(smd.getStoredScript("test0", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang0"), nullValue());
-        assertThat(smd.getStoredScript("test1", null), equalTo(source1));
-        assertThat(smd.getStoredScript("test1", "lang0"), equalTo(source1));
-        assertThat(smd.getStoredScript("test2", null), nullValue());
-        assertThat(smd.getStoredScript("test2", "lang1"), nullValue());
-
-        assertThat(smd.getStoredScript("test3", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test2", "lang0"), nullValue());
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test1", "lang0");
-
-        assertThat(smd.getStoredScript("test0", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang0"), nullValue());
-        assertThat(smd.getStoredScript("test1", null), nullValue());
-        assertThat(smd.getStoredScript("test1", "lang0"), nullValue());
-        assertThat(smd.getStoredScript("test2", null), nullValue());
-        assertThat(smd.getStoredScript("test2", "lang1"), nullValue());
-
-        assertThat(smd.getStoredScript("test3", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test2", "lang0"), nullValue());
-    }
-
-    public void testSameMultiAddDelete() {
-        StoredScriptSource source0 = new StoredScriptSource("lang0", "code0", emptyMap());
-        StoredScriptSource source1 = new StoredScriptSource("lang1", "code1", emptyMap());
-        StoredScriptSource source2 = new StoredScriptSource("lang2", "code1", emptyMap());
-        StoredScriptSource source3 = new StoredScriptSource("lang1", "code2",
-            singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()));
-
-        ScriptMetaData smd = ScriptMetaData.putStoredScript(null, "test0", source0);
-        smd = ScriptMetaData.putStoredScript(smd, "test0", source1);
-        assertWarnings("stored script [test0] already exists using a different lang [lang0]," +
-            " the new namespace for stored scripts will only use (id) instead of (lang, id)");
-        smd = ScriptMetaData.putStoredScript(smd, "test3", source3);
-        smd = ScriptMetaData.putStoredScript(smd, "test0", source2);
-        assertWarnings("stored script [test0] already exists using a different lang [lang1]," +
-            " the new namespace for stored scripts will only use (id) instead of (lang, id)");
-
-        assertThat(smd.getStoredScript("test0", null), equalTo(source2));
-        assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0));
-        assertThat(smd.getStoredScript("test0", "lang1"), equalTo(source1));
-        assertThat(smd.getStoredScript("test0", "lang2"), equalTo(source2));
-        assertThat(smd.getStoredScript("test3", null), equalTo(source3));
-        assertThat(smd.getStoredScript("test3", "lang1"), equalTo(source3));
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test0", "lang1");
-
-        assertThat(smd.getStoredScript("test0", null), equalTo(source2));
-        assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0));
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang2"), equalTo(source2));
-        assertThat(smd.getStoredScript("test3", null), equalTo(source3));
-        assertThat(smd.getStoredScript("test3", "lang1"), equalTo(source3));
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test0", null);
-
-        assertThat(smd.getStoredScript("test0", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0));
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang2"), nullValue());
-        assertThat(smd.getStoredScript("test3", null), equalTo(source3));
-        assertThat(smd.getStoredScript("test3", "lang1"), equalTo(source3));
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test3", "lang1");
-
-        assertThat(smd.getStoredScript("test0", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang0"), equalTo(source0));
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang2"), nullValue());
-        assertThat(smd.getStoredScript("test3", null), nullValue());
-        assertThat(smd.getStoredScript("test3", "lang1"), nullValue());
-
-        smd = ScriptMetaData.deleteStoredScript(smd, "test0", "lang0");
-
-        assertThat(smd.getStoredScript("test0", null), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang0"), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang1"), nullValue());
-        assertThat(smd.getStoredScript("test0", "lang2"), nullValue());
-        assertThat(smd.getStoredScript("test3", null), nullValue());
-        assertThat(smd.getStoredScript("test3", "lang1"), nullValue());
+        smd = ScriptMetaData.deleteStoredScript(smd, "test");
+        assertThat(smd.getStoredScript("test"), nullValue());
     }
 
     public void testInvalidDelete() {
         ResourceNotFoundException rnfe =
-            expectThrows(ResourceNotFoundException.class, () -> ScriptMetaData.deleteStoredScript(null, "test", "lang"));
-        assertThat(rnfe.getMessage(), equalTo("stored script [test] using lang [lang] does not exist and cannot be deleted"));
-
-        rnfe = expectThrows(ResourceNotFoundException.class, () -> ScriptMetaData.deleteStoredScript(null, "test", null));
+            expectThrows(ResourceNotFoundException.class, () -> ScriptMetaData.deleteStoredScript(null, "test"));
         assertThat(rnfe.getMessage(), equalTo("stored script [test] does not exist and cannot be deleted"));
     }
 
     public void testSourceParsing() throws Exception {
         // simple script value string
         try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
-            builder.startObject().field("script", "code").endObject();
+            builder.startObject().startObject("script").field("lang", "lang").field("source", "code").endObject().endObject();
 
-            StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON);
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
             StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap());
 
             assertThat(parsed, equalTo(source));
@@ -196,8 +67,8 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
         try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
             builder.startObject().field("template", "code").endObject();
 
-            StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON);
-            StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap());
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
+            StoredScriptSource source = new StoredScriptSource("mustache", "code", Collections.emptyMap());
 
             assertThat(parsed, equalTo(source));
         }
@@ -211,8 +82,8 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
                 code = cb.startObject().field("query", "code").endObject().string();
             }
 
-            StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON);
-            StoredScriptSource source = new StoredScriptSource("lang", code, Collections.emptyMap());
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
+            StoredScriptSource source = new StoredScriptSource("mustache", code, Collections.emptyMap());
 
             assertThat(parsed, equalTo(source));
         }
@@ -226,23 +97,26 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
                 code = cb.startObject().field("query", "code").endObject().string();
             }
 
-            StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON);
-            StoredScriptSource source = new StoredScriptSource("lang", code, Collections.emptyMap());
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
+            StoredScriptSource source = new StoredScriptSource("mustache", code, Collections.emptyMap());
 
             assertThat(parsed, equalTo(source));
         }
 
         // complex template using script as the field name
         try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
-            builder.startObject().field("script").startObject().field("query", "code").endObject().endObject();
+            builder.startObject().startObject("script").field("lang", "mustache")
+                .startObject("source").field("query", "code").endObject()
+                .endObject().endObject();
             String code;
 
             try (XContentBuilder cb = XContentFactory.contentBuilder(builder.contentType())) {
                 code = cb.startObject().field("query", "code").endObject().string();
             }
 
-            StoredScriptSource parsed = StoredScriptSource.parse("lang", builder.bytes(), XContentType.JSON);
-            StoredScriptSource source = new StoredScriptSource("lang", code, Collections.emptyMap());
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
+            StoredScriptSource source = new StoredScriptSource("mustache", code,
+                Collections.singletonMap("content_type", "application/json; charset=UTF-8"));
 
             assertThat(parsed, equalTo(source));
         }
@@ -251,7 +125,7 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
         try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
             builder.startObject().field("script").startObject().field("lang", "lang").field("source", "code").endObject().endObject();
 
-            StoredScriptSource parsed = StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON);
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
             StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap());
 
             assertThat(parsed, equalTo(source));
@@ -261,7 +135,7 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
         try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
             builder.startObject().field("script").startObject().field("lang", "lang").field("code", "code").endObject().endObject();
 
-            StoredScriptSource parsed = StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON);
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
             StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap());
 
             assertThat(parsed, equalTo(source));
@@ -273,7 +147,7 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
             builder.startObject().field("script").startObject().field("lang", "lang").field("source", "code")
                 .field("options").startObject().endObject().endObject().endObject();
 
-            StoredScriptSource parsed = StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON);
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
             StoredScriptSource source = new StoredScriptSource("lang", "code", Collections.emptyMap());
 
             assertThat(parsed, equalTo(source));
@@ -289,7 +163,7 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
                 code = cb.startObject().field("query", "code").endObject().string();
             }
 
-            StoredScriptSource parsed = StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON);
+            StoredScriptSource parsed = StoredScriptSource.parse(builder.bytes(), XContentType.JSON);
             StoredScriptSource source = new StoredScriptSource("lang", code,
                 Collections.singletonMap(Script.CONTENT_TYPE_OPTION, builder.contentType().mediaType()));
 
@@ -298,21 +172,12 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
     }
 
     public void testSourceParsingErrors() throws Exception {
-        // check for missing lang parameter when parsing a template
-        try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
-            builder.startObject().field("template", "code").endObject();
-
-            IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
-                StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON));
-            assertThat(iae.getMessage(), equalTo("unexpected stored script format"));
-        }
-
         // check for missing lang parameter when parsing a script
         try (XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON)) {
             builder.startObject().field("script").startObject().field("source", "code").endObject().endObject();
 
             IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
-                StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON));
+                StoredScriptSource.parse(builder.bytes(), XContentType.JSON));
             assertThat(iae.getMessage(), equalTo("must specify lang for stored script"));
         }
 
@@ -321,7 +186,7 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
             builder.startObject().field("script").startObject().field("lang", "lang").endObject().endObject();
 
             IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
-                StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON));
+                StoredScriptSource.parse(builder.bytes(), XContentType.JSON));
             assertThat(iae.getMessage(), equalTo("must specify source for stored script"));
         }
 
@@ -331,7 +196,7 @@ public class StoredScriptTests extends AbstractSerializingTestCase<StoredScriptS
                 .startObject("options").field("option", "option").endObject().endObject().endObject();
 
             IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
-                StoredScriptSource.parse(null, builder.bytes(), XContentType.JSON));
+                StoredScriptSource.parse(builder.bytes(), XContentType.JSON));
             assertThat(iae.getMessage(), equalTo("illegal compiler options [{option=option}] specified"));
         }
     }

+ 7 - 11
core/src/test/java/org/elasticsearch/script/StoredScriptsIT.java

@@ -51,35 +51,31 @@ public class StoredScriptsIT extends ESIntegTestCase {
 
     public void testBasics() {
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(LANG)
                 .setId("foobar")
-                .setContent(new BytesArray("{\"script\":\"1\"}"), XContentType.JSON));
-        String script = client().admin().cluster().prepareGetStoredScript(LANG, "foobar")
+                .setContent(new BytesArray("{\"script\": {\"lang\": \"" + LANG + "\", \"source\": \"1\"} }"), XContentType.JSON));
+        String script = client().admin().cluster().prepareGetStoredScript("foobar")
                 .get().getSource().getSource();
         assertNotNull(script);
         assertEquals("1", script);
 
         assertAcked(client().admin().cluster().prepareDeleteStoredScript()
-                .setId("foobar")
-                .setLang(LANG));
-        StoredScriptSource source = client().admin().cluster().prepareGetStoredScript(LANG, "foobar")
+                .setId("foobar"));
+        StoredScriptSource source = client().admin().cluster().prepareGetStoredScript("foobar")
                 .get().getSource();
         assertNull(source);
 
         IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> client().admin().cluster().preparePutStoredScript()
-                .setLang("lang#")
                 .setId("id#")
                 .setContent(new BytesArray("{}"), XContentType.JSON)
                 .get());
-        assertEquals("Validation Failed: 1: id cannot contain '#' for stored script;" +
-            "2: lang cannot contain '#' for stored script;", e.getMessage());
+        assertEquals("Validation Failed: 1: id cannot contain '#' for stored script;", e.getMessage());
     }
 
     public void testMaxScriptSize() {
         IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> client().admin().cluster().preparePutStoredScript()
-                .setLang(LANG)
                 .setId("foobar")
-                .setContent(new BytesArray(randomAlphaOfLength(SCRIPT_MAX_SIZE_IN_BYTES + 1)), XContentType.JSON)
+                .setContent(new BytesArray("{\"script\": { \"lang\": \"" + LANG + "\"," +
+                        " \"source\":\"0123456789abcdef\"} }"), XContentType.JSON)
                 .get()
         );
         assertEquals("exceeded max allowed stored script size in bytes [64] with size [65] for script [foobar]", e.getMessage());

+ 9 - 8
core/src/test/java/org/elasticsearch/search/aggregations/metrics/ScriptedMetricIT.java

@@ -26,6 +26,7 @@ import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.xcontent.XContentType;
 import org.elasticsearch.common.xcontent.support.XContentMapValues;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.script.MockScriptEngine;
 import org.elasticsearch.script.MockScriptPlugin;
 import org.elasticsearch.script.Script;
 import org.elasticsearch.script.ScriptType;
@@ -230,24 +231,24 @@ public class ScriptedMetricIT extends ESIntegTestCase {
         // the id of the stored script is used in test method while the source of the stored script
         // must match a predefined script from CustomScriptPlugin.pluginScripts() method
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(CustomScriptPlugin.NAME)
                 .setId("initScript_stored")
-                .setContent(new BytesArray("{\"script\":\"vars.multiplier = 3\"}"), XContentType.JSON));
+                .setContent(new BytesArray("{\"script\": {\"lang\": \"" + MockScriptPlugin.NAME + "\"," +
+                    " \"source\": \"vars.multiplier = 3\"} }"), XContentType.JSON));
 
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(CustomScriptPlugin.NAME)
                 .setId("mapScript_stored")
-                .setContent(new BytesArray("{\"script\":\"_agg.add(vars.multiplier)\"}"), XContentType.JSON));
+                .setContent(new BytesArray("{\"script\": {\"lang\": \"" + MockScriptPlugin.NAME + "\"," +
+                    " \"source\": \"_agg.add(vars.multiplier)\"} }"), XContentType.JSON));
 
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(CustomScriptPlugin.NAME)
                 .setId("combineScript_stored")
-                .setContent(new BytesArray("{\"script\":\"sum agg values as a new aggregation\"}"), XContentType.JSON));
+                .setContent(new BytesArray("{\"script\": {\"lang\": \"" + MockScriptPlugin.NAME + "\"," +
+                    " \"source\": \"sum agg values as a new aggregation\"} }"), XContentType.JSON));
 
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(CustomScriptPlugin.NAME)
                 .setId("reduceScript_stored")
-                .setContent(new BytesArray("{\"script\":\"sum aggs of agg values as a new aggregation\"}"), XContentType.JSON));
+                .setContent(new BytesArray("{\"script\": {\"lang\": \"" + MockScriptPlugin.NAME + "\"," +
+                    " \"source\": \"sum aggs of agg values as a new aggregation\"} }"), XContentType.JSON));
 
         indexRandom(true, builders);
         ensureSearchable();

+ 2 - 2
core/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptIT.java

@@ -481,9 +481,9 @@ public class BucketScriptIT extends ESIntegTestCase {
     public void testStoredScript() {
         assertAcked(client().admin().cluster().preparePutStoredScript()
                 .setId("my_script")
-                .setLang(CustomScriptPlugin.NAME)
                 // Script source is not interpreted but it references a pre-defined script from CustomScriptPlugin
-                .setContent(new BytesArray("{ \"script\": \"my_script\" }"), XContentType.JSON));
+                .setContent(new BytesArray("{ \"script\": {\"lang\": \"" + CustomScriptPlugin.NAME + "\"," +
+                    " \"source\": \"my_script\" } }"), XContentType.JSON));
 
         SearchResponse response = client()
                 .prepareSearch("idx")

+ 2 - 2
core/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketSelectorIT.java

@@ -433,9 +433,9 @@ public class BucketSelectorIT extends ESIntegTestCase {
     public void testStoredScript() {
         assertAcked(client().admin().cluster().preparePutStoredScript()
                 .setId("my_script")
-                .setLang(CustomScriptPlugin.NAME)
                 // Source is not interpreted but my_script is defined in CustomScriptPlugin
-                .setContent(new BytesArray("{ \"script\": \"Double.isNaN(_value0) ? false : (_value0 + _value1 > 100)\" }"),
+                .setContent(new BytesArray("{ \"script\": { \"lang\": \"" + CustomScriptPlugin.NAME + "\", " +
+                        "\"source\": \"Double.isNaN(_value0) ? false : (_value0 + _value1 > 100)\" } }"),
                     XContentType.JSON));
 
         Script script = new Script(ScriptType.STORED, null, "my_script", Collections.emptyMap());

+ 6 - 6
core/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java

@@ -541,9 +541,9 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         if(testScript) {
             logger.info("-->  creating test script");
             assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(MockScriptEngine.NAME)
                 .setId("foobar")
-                .setContent(new BytesArray("{\"script\":\"1\"}"), XContentType.JSON));
+                .setContent(new BytesArray(
+                    "{\"script\": { \"lang\": \"" + MockScriptEngine.NAME + "\", \"source\": \"1\"} }"), XContentType.JSON));
         }
 
         logger.info("--> snapshot without global state");
@@ -572,7 +572,7 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
 
         if (testScript) {
             logger.info("-->  delete test script");
-            assertAcked(client().admin().cluster().prepareDeleteStoredScript(MockScriptEngine.NAME, "foobar").get());
+            assertAcked(client().admin().cluster().prepareDeleteStoredScript("foobar").get());
         }
 
         logger.info("--> try restoring cluster state from snapshot without global state");
@@ -601,7 +601,7 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
 
         if (testScript) {
             logger.info("--> check that script is restored");
-            GetStoredScriptResponse getStoredScriptResponse = client().admin().cluster().prepareGetStoredScript(MockScriptEngine.NAME, "foobar").get();
+            GetStoredScriptResponse getStoredScriptResponse = client().admin().cluster().prepareGetStoredScript("foobar").get();
             assertNotNull(getStoredScriptResponse.getSource());
         }
 
@@ -631,7 +631,7 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         }
 
         if (testScript) {
-            assertAcked(client().admin().cluster().prepareDeleteStoredScript(MockScriptEngine.NAME, "foobar").get());
+            assertAcked(client().admin().cluster().prepareDeleteStoredScript("foobar").get());
         }
 
         getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
@@ -646,7 +646,7 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
         assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
         assertFalse(client().admin().cluster().prepareGetPipeline("barbaz").get().isFound());
-        assertNull(client().admin().cluster().prepareGetStoredScript(MockScriptEngine.NAME, "foobar").get().getSource());
+        assertNull(client().admin().cluster().prepareGetStoredScript("foobar").get().getSource());
         assertThat(client.prepareSearch("test-idx").setSize(0).get().getHits().getTotalHits(), equalTo(100L));
 
     }

+ 7 - 0
docs/reference/migration/migrate_6_0/scripting.asciidoc

@@ -35,6 +35,13 @@ different from a request that puts a stored script.  The language of the script
 already been stored as part of the cluster state and an `id` is sufficient to access
 all of the information necessary to execute a stored script.
 
+==== 'lang` can no longer be used when putting, getting, or deleting a stored script
+
+Stored scripts can no longer have the `lang` parameter specified as part of the url
+when performing PUT, GET, and DELETE actions on the `_scripts/` path.  All stored
+scripts must have a unique `id` as the namespace is only `id` now and no longer `lang`
+and `id`.
+
 ==== Stored search template apis removed
 
 The PUT, GET and DELETE `_search/template` apis have been removed. Store search templates with the stored scripts apis instead.

+ 1 - 2
modules/lang-expression/src/test/java/org/elasticsearch/script/expression/StoredExpressionTests.java

@@ -51,9 +51,8 @@ public class StoredExpressionTests extends ESIntegTestCase {
 
     public void testAllOpsDisabledIndexedScripts() throws IOException {
         client().admin().cluster().preparePutStoredScript()
-                .setLang(ExpressionScriptEngine.NAME)
                 .setId("script1")
-                .setContent(new BytesArray("{\"script\":\"2\"}"), XContentType.JSON)
+                .setContent(new BytesArray("{\"script\": {\"lang\": \"expression\", \"source\": \"2\"} }"), XContentType.JSON)
                 .get();
         client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}", XContentType.JSON).get();
         try {

+ 4 - 15
modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateIT.java

@@ -151,7 +151,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
 
     public void testIndexedTemplateClient() throws Exception {
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(MustacheScriptEngine.NAME)
                 .setId("testTemplate")
                 .setContent(new BytesArray("{" +
                         "\"template\":{" +
@@ -164,7 +163,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
 
 
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(MustacheScriptEngine.NAME)
                 .setId("testTemplate").setContent(new BytesArray("{" +
                         "\"template\":{" +
                         "                \"query\":{" +
@@ -175,7 +173,7 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
                         "}"), XContentType.JSON));
 
         GetStoredScriptResponse getResponse = client().admin().cluster()
-                .prepareGetStoredScript(MustacheScriptEngine.NAME, "testTemplate").get();
+                .prepareGetStoredScript("testTemplate").get();
         assertNotNull(getResponse.getSource());
 
         BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
@@ -196,17 +194,14 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
                 .get();
         assertHitCount(searchResponse.getResponse(), 4);
 
-        assertAcked(client().admin().cluster()
-                .prepareDeleteStoredScript(MustacheScriptEngine.NAME, "testTemplate"));
+        assertAcked(client().admin().cluster().prepareDeleteStoredScript("testTemplate"));
 
-        getResponse = client().admin().cluster()
-                .prepareGetStoredScript(MustacheScriptEngine.NAME, "testTemplate").get();
+        getResponse = client().admin().cluster().prepareGetStoredScript("testTemplate").get();
         assertNull(getResponse.getSource());
     }
 
     public void testIndexedTemplate() throws Exception {
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(MustacheScriptEngine.NAME)
                 .setId("1a")
                 .setContent(new BytesArray("{" +
                         "\"template\":{" +
@@ -219,7 +214,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
                 ), XContentType.JSON)
         );
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(MustacheScriptEngine.NAME)
                 .setId("2")
                 .setContent(new BytesArray("{" +
                         "\"template\":{" +
@@ -231,7 +225,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
                         "}"), XContentType.JSON)
         );
         assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setLang(MustacheScriptEngine.NAME)
                 .setId("3")
                 .setContent(new BytesArray("{" +
                         "\"template\":{" +
@@ -289,13 +282,11 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
         int iterations = randomIntBetween(2, 11);
         for (int i = 1; i < iterations; i++) {
             assertAcked(client().admin().cluster().preparePutStoredScript()
-                    .setLang(MustacheScriptEngine.NAME)
                     .setId("git01")
                     .setContent(new BytesArray("{\"template\":{\"query\": {\"match\": {\"searchtext\": {\"query\": \"{{P_Keyword1}}\"," +
                             "\"type\": \"ooophrase_prefix\"}}}}}"), XContentType.JSON));
 
-            GetStoredScriptResponse getResponse = client().admin().cluster()
-                    .prepareGetStoredScript(MustacheScriptEngine.NAME, "git01").get();
+            GetStoredScriptResponse getResponse = client().admin().cluster().prepareGetStoredScript("git01").get();
             assertNotNull(getResponse.getSource());
 
             Map<String, Object> templateParams = new HashMap<>();
@@ -309,7 +300,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
             assertWarnings("Deprecated field [type] used, replaced by [match_phrase and match_phrase_prefix query]");
 
             assertAcked(client().admin().cluster().preparePutStoredScript()
-                    .setLang(MustacheScriptEngine.NAME)
                     .setId("git01")
                     .setContent(new BytesArray("{\"query\": {\"match\": {\"searchtext\": {\"query\": \"{{P_Keyword1}}\"," +
                             "\"type\": \"phrase_prefix\"}}}}"), XContentType.JSON));
@@ -327,7 +317,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
         String multiQuery = "{\"query\":{\"terms\":{\"theField\":[\"{{#fieldParam}}\",\"{{.}}\",\"{{/fieldParam}}\"]}}}";
         assertAcked(
                 client().admin().cluster().preparePutStoredScript()
-                        .setLang(MustacheScriptEngine.NAME)
                         .setId("4")
                         .setContent(jsonBuilder().startObject().field("template", multiQuery).endObject().bytes(), XContentType.JSON)
         );

+ 4 - 4
modules/lang-painless/src/test/resources/rest-api-spec/test/painless/16_update2.yml

@@ -11,7 +11,7 @@
 
   - do:
      get_script:
-       lang: "1"
+       id: "1"
   - match: { found: true }
   - match: { _id: "1" }
   - match: { "script": {"lang": "painless", "source": "_score * doc['myParent.weight'].value"} }
@@ -19,20 +19,20 @@
   - do:
      catch: missing
      get_script:
-       lang: "2"
+       id: "2"
   - match: { found: false }
   - match: { _id: "2" }
   - is_false: script
 
   - do:
      delete_script:
-       lang: "1"
+       id: "1"
   - match: { acknowledged: true }
 
   - do:
      catch: missing
      delete_script:
-       lang: "non_existing"
+       id: "non_existing"
 
   - do:
       catch: request

+ 2 - 2
rest-api-spec/src/main/resources/rest-api-spec/api/delete_script.json

@@ -3,8 +3,8 @@
     "documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html",
     "methods": ["DELETE"],
     "url": {
-      "path": "/_scripts/{lang}",
-      "paths": [ "/_scripts/{lang}", "/_scripts/{lang}/{id}" ],
+      "path": "/_scripts/{id}",
+      "paths": [ "/_scripts/{id}" ],
       "parts": {
         "id": {
           "type" : "string",

+ 2 - 2
rest-api-spec/src/main/resources/rest-api-spec/api/get_script.json

@@ -3,8 +3,8 @@
     "documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting.html",
     "methods": ["GET"],
     "url": {
-      "path": "/_scripts/{lang}",
-      "paths": [ "/_scripts/{lang}", "/_scripts/{lang}/{id}" ],
+      "path": "/_scripts/{id}",
+      "paths": [ "/_scripts/{id}" ],
       "parts": {
         "id": {
           "type" : "string",

+ 1 - 1
rest-api-spec/src/main/resources/rest-api-spec/api/put_script.json

@@ -4,7 +4,7 @@
     "methods": ["PUT", "POST"],
     "url": {
       "path": "/_scripts/{id}",
-      "paths": [ "/_scripts/{id}", "/_scripts/{lang}/{id}" ],
+      "paths": [ "/_scripts/{id}", "/_scripts/{id}/{context}" ],
       "parts": {
         "id": {
           "type" : "string",