start work on the groovy plugin
This commit is contained in:
parent
913bc2f947
commit
cb7e92b0f8
|
@ -30,6 +30,7 @@
|
||||||
<w>jgroups</w>
|
<w>jgroups</w>
|
||||||
<w>joda</w>
|
<w>joda</w>
|
||||||
<w>jsonp</w>
|
<w>jsonp</w>
|
||||||
|
<w>kimchy</w>
|
||||||
<w>lifecycle</w>
|
<w>lifecycle</w>
|
||||||
<w>linefeeds</w>
|
<w>linefeeds</w>
|
||||||
<w>lucene</w>
|
<w>lucene</w>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/elasticsearch.iml" filepath="$PROJECT_DIR$/.idea/modules/elasticsearch.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/elasticsearch.iml" filepath="$PROJECT_DIR$/.idea/modules/elasticsearch.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/elasticsearch-root.iml" filepath="$PROJECT_DIR$/.idea/modules/elasticsearch-root.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/elasticsearch-root.iml" filepath="$PROJECT_DIR$/.idea/modules/elasticsearch-root.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules//plugin-attachments.iml" filepath="$PROJECT_DIR$/.idea/modules//plugin-attachments.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules//plugin-attachments.iml" filepath="$PROJECT_DIR$/.idea/modules//plugin-attachments.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules//plugin-groovy.iml" filepath="$PROJECT_DIR$/.idea/modules//plugin-groovy.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules//test-integration.iml" filepath="$PROJECT_DIR$/.idea/modules//test-integration.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules//test-integration.iml" filepath="$PROJECT_DIR$/.idea/modules//test-integration.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules//test-testng.iml" filepath="$PROJECT_DIR$/.idea/modules//test-testng.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules//test-testng.iml" filepath="$PROJECT_DIR$/.idea/modules//test-testng.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||||
|
<output url="file://$MODULE_DIR$/../../plugins/groovy/build/classes/main" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/../../plugins/groovy/build/classes/test" />
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$/../../plugins/groovy">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/../../plugins/groovy/src/main/groovy" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/../../plugins/groovy/src/test/groovy" isTestSource="true" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="groovy-1.7.2" level="application" />
|
||||||
|
<orderEntry type="module" module-name="elasticsearch" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="testng" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
|
||||||
|
<orderEntry type="module" module-name="test-testng" scope="TEST" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
|
|
|
@ -18,6 +18,12 @@ explodedDistLibDir = new File(explodedDistDir, 'lib')
|
||||||
explodedDistBinDir = new File(explodedDistDir, 'bin')
|
explodedDistBinDir = new File(explodedDistDir, 'bin')
|
||||||
explodedDistConfigDir = new File(explodedDistDir, 'config')
|
explodedDistConfigDir = new File(explodedDistDir, 'config')
|
||||||
|
|
||||||
|
//mavenRepoUrl = "file://localhost/" + projectDir.absolutePath + "/build/maven/repository"
|
||||||
|
//mavenSnapshotRepoUrl = "file://localhost/" + projectDir.absolutePath + "/build/maven/snapshotRepository"
|
||||||
|
mavenRepoUrl = "http://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||||
|
mavenSnapshotRepoUrl = "http://oss.sonatype.org/content/repositories/snapshots"
|
||||||
|
mavenRepoUser = "kimchy"
|
||||||
|
mavenRepoPass = System.getenv("REPO_PASS")
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = 'org.elasticsearch'
|
group = 'org.elasticsearch'
|
||||||
|
|
|
@ -97,15 +97,12 @@ artifacts {
|
||||||
|
|
||||||
uploadArchives {
|
uploadArchives {
|
||||||
repositories.mavenDeployer {
|
repositories.mavenDeployer {
|
||||||
// repository(url: "file://localhost/" + rootProject.projectDir.absolutePath + "/build/maven/repository")
|
|
||||||
// snapshotRepository(url: "file://localhost/" + rootProject.projectDir.absolutePath + "/build/maven/snapshotRepository")
|
|
||||||
|
|
||||||
configuration = configurations.deployerJars
|
configuration = configurations.deployerJars
|
||||||
repository(url: "http://oss.sonatype.org/service/local/staging/deploy/maven2/") {
|
repository(url: rootProject.mavenRepoUrl) {
|
||||||
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
|
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
|
||||||
}
|
}
|
||||||
snapshotRepository(url: "http://oss.sonatype.org/content/repositories/snapshots") {
|
snapshotRepository(url: rootProject.mavenSnapshotRepoUrl) {
|
||||||
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
|
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
pom.project {
|
pom.project {
|
||||||
|
|
|
@ -20,11 +20,19 @@
|
||||||
package org.elasticsearch.action;
|
package org.elasticsearch.action;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (Shay Banon)
|
* A listener for action responses or failures.
|
||||||
|
*
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public interface ActionListener<Response> {
|
public interface ActionListener<Response> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A response handler.
|
||||||
|
*/
|
||||||
void onResponse(Response response);
|
void onResponse(Response response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A failure handler.
|
||||||
|
*/
|
||||||
void onFailure(Throwable e);
|
void onFailure(Throwable e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.elasticsearch.action;
|
||||||
import org.elasticsearch.util.io.stream.Streamable;
|
import org.elasticsearch.util.io.stream.Streamable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (Shay Banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public interface ActionRequest extends Streamable {
|
public interface ActionRequest extends Streamable {
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ package org.elasticsearch.action;
|
||||||
import org.elasticsearch.util.io.stream.Streamable;
|
import org.elasticsearch.util.io.stream.Streamable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (Shay Banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public interface ActionResponse extends Streamable {
|
public interface ActionResponse extends Streamable {
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ActionFuture} that listeners can be added to.
|
||||||
|
*
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public interface ListenableActionFuture<T> extends ActionFuture<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an action listener to be invoked when a response has received.
|
||||||
|
*/
|
||||||
|
void addListener(final ActionListener<T> listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an action listener (runnable) to be invoked when a response has received.
|
||||||
|
*/
|
||||||
|
void addListener(final Runnable listener);
|
||||||
|
}
|
|
@ -58,6 +58,13 @@ public class DeleteResponse implements ActionResponse, Streamable {
|
||||||
return this.index;
|
return this.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index the document was deleted from.
|
||||||
|
*/
|
||||||
|
public String getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the document deleted.
|
* The type of the document deleted.
|
||||||
*/
|
*/
|
||||||
|
@ -65,6 +72,13 @@ public class DeleteResponse implements ActionResponse, Streamable {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the document deleted.
|
||||||
|
*/
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the document deleted.
|
* The id of the document deleted.
|
||||||
*/
|
*/
|
||||||
|
@ -72,6 +86,13 @@ public class DeleteResponse implements ActionResponse, Streamable {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the document deleted.
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void readFrom(StreamInput in) throws IOException {
|
@Override public void readFrom(StreamInput in) throws IOException {
|
||||||
index = in.readUTF();
|
index = in.readUTF();
|
||||||
id = in.readUTF();
|
id = in.readUTF();
|
||||||
|
|
|
@ -50,10 +50,18 @@ public class GetField implements Streamable, Iterable<Object> {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Object> values() {
|
public List<Object> values() {
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Object> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public Iterator<Object> iterator() {
|
@Override public Iterator<Object> iterator() {
|
||||||
return values.iterator();
|
return values.iterator();
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
|
||||||
|
|
||||||
private Map<String, GetField> fields;
|
private Map<String, GetField> fields;
|
||||||
|
|
||||||
|
private Map<String, Object> sourceAsMap;
|
||||||
|
|
||||||
private byte[] source;
|
private byte[] source;
|
||||||
|
|
||||||
GetResponse() {
|
GetResponse() {
|
||||||
|
@ -79,6 +81,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the document exists.
|
||||||
|
*/
|
||||||
|
public boolean isExists() {
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The index the document was fetched from.
|
* The index the document was fetched from.
|
||||||
*/
|
*/
|
||||||
|
@ -86,6 +95,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
|
||||||
return this.index;
|
return this.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index the document was fetched from.
|
||||||
|
*/
|
||||||
|
public String getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the document.
|
* The type of the document.
|
||||||
*/
|
*/
|
||||||
|
@ -93,6 +109,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the document.
|
||||||
|
*/
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the document.
|
* The id of the document.
|
||||||
*/
|
*/
|
||||||
|
@ -100,6 +123,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the document.
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The source of the document if exists.
|
* The source of the document if exists.
|
||||||
*/
|
*/
|
||||||
|
@ -125,17 +155,29 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (sourceAsMap != null) {
|
||||||
|
return sourceAsMap;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return defaultObjectMapper().readValue(source, 0, source.length, Map.class);
|
sourceAsMap = defaultObjectMapper().readValue(source, 0, source.length, Map.class);
|
||||||
|
return sourceAsMap;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ElasticSearchParseException("Failed to parse source to map", e);
|
throw new ElasticSearchParseException("Failed to parse source to map", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getSource() {
|
||||||
|
return sourceAsMap();
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, GetField> fields() {
|
public Map<String, GetField> fields() {
|
||||||
return this.fields;
|
return this.fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, GetField> getFields() {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
public GetField field(String name) {
|
public GetField field(String name) {
|
||||||
return fields.get(name);
|
return fields.get(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,9 @@ public class IndexRequest extends ShardReplicationOperationRequest {
|
||||||
private byte[] source;
|
private byte[] source;
|
||||||
private OpType opType = OpType.INDEX;
|
private OpType opType = OpType.INDEX;
|
||||||
|
|
||||||
|
public IndexRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new index request against the specific index. The {@link #type(String)},
|
* Constructs a new index request against the specific index. The {@link #type(String)},
|
||||||
* {@link #id(String)} and {@link #source(byte[])} must be set.
|
* {@link #id(String)} and {@link #source(byte[])} must be set.
|
||||||
|
@ -127,9 +130,6 @@ public class IndexRequest extends ShardReplicationOperationRequest {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexRequest() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public ActionRequestValidationException validate() {
|
@Override public ActionRequestValidationException validate() {
|
||||||
ActionRequestValidationException validationException = super.validate();
|
ActionRequestValidationException validationException = super.validate();
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
|
|
|
@ -58,6 +58,13 @@ public class IndexResponse implements ActionResponse, Streamable {
|
||||||
return this.index;
|
return this.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index the document was indexed into.
|
||||||
|
*/
|
||||||
|
public String getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the document indexed.
|
* The type of the document indexed.
|
||||||
*/
|
*/
|
||||||
|
@ -65,6 +72,13 @@ public class IndexResponse implements ActionResponse, Streamable {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the document indexed.
|
||||||
|
*/
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the document indexed.
|
* The id of the document indexed.
|
||||||
*/
|
*/
|
||||||
|
@ -72,6 +86,13 @@ public class IndexResponse implements ActionResponse, Streamable {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the document indexed.
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void readFrom(StreamInput in) throws IOException {
|
@Override public void readFrom(StreamInput in) throws IOException {
|
||||||
index = in.readUTF();
|
index = in.readUTF();
|
||||||
id = in.readUTF();
|
id = in.readUTF();
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.action.support;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchException;
|
||||||
|
import org.elasticsearch.action.ActionListener;
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Lists.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public abstract class AbstractListenableActionFuture<T, L> extends AdapterActionFuture<T, L> {
|
||||||
|
|
||||||
|
private final boolean listenerThreaded;
|
||||||
|
|
||||||
|
private final ThreadPool threadPool;
|
||||||
|
|
||||||
|
private volatile Object listeners;
|
||||||
|
|
||||||
|
private boolean executedListeners = false;
|
||||||
|
|
||||||
|
protected AbstractListenableActionFuture(boolean listenerThreaded, ThreadPool threadPool) {
|
||||||
|
this.listenerThreaded = listenerThreaded;
|
||||||
|
this.threadPool = threadPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(final ActionListener<T> listener) {
|
||||||
|
internalAddListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(final Runnable listener) {
|
||||||
|
internalAddListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void internalAddListener(Object listener) {
|
||||||
|
boolean executeImmediate = false;
|
||||||
|
synchronized (this) {
|
||||||
|
if (executedListeners) {
|
||||||
|
executeImmediate = true;
|
||||||
|
} else {
|
||||||
|
Object listeners = this.listeners;
|
||||||
|
if (listeners == null) {
|
||||||
|
listeners = listener;
|
||||||
|
} else if (listeners instanceof List) {
|
||||||
|
((List) this.listeners).add(listener);
|
||||||
|
} else {
|
||||||
|
Object orig = listeners;
|
||||||
|
listeners = newArrayListWithExpectedSize(2);
|
||||||
|
((List) listeners).add(orig);
|
||||||
|
((List) listeners).add(listener);
|
||||||
|
}
|
||||||
|
this.listeners = listeners;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (executeImmediate) {
|
||||||
|
executeListener(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void done() {
|
||||||
|
super.done();
|
||||||
|
synchronized (this) {
|
||||||
|
executedListeners = true;
|
||||||
|
}
|
||||||
|
Object listeners = this.listeners;
|
||||||
|
if (listeners != null) {
|
||||||
|
if (listeners instanceof List) {
|
||||||
|
List list = (List) listeners;
|
||||||
|
for (Object listener : list) {
|
||||||
|
executeListener(listener);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
executeListener(listeners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeListener(final Object listener) {
|
||||||
|
if (listenerThreaded) {
|
||||||
|
if (listener instanceof Runnable) {
|
||||||
|
threadPool.execute((Runnable) listener);
|
||||||
|
} else {
|
||||||
|
threadPool.execute(new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
ActionListener<T> lst = (ActionListener<T>) listener;
|
||||||
|
try {
|
||||||
|
lst.onResponse(actionGet());
|
||||||
|
} catch (ElasticSearchException e) {
|
||||||
|
lst.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (listener instanceof Runnable) {
|
||||||
|
((Runnable) listener).run();
|
||||||
|
} else {
|
||||||
|
ActionListener<T> lst = (ActionListener<T>) listener;
|
||||||
|
try {
|
||||||
|
lst.onResponse(actionGet());
|
||||||
|
} catch (ElasticSearchException e) {
|
||||||
|
lst.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.action.support;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchException;
|
||||||
|
import org.elasticsearch.ElasticSearchInterruptedException;
|
||||||
|
import org.elasticsearch.ElasticSearchTimeoutException;
|
||||||
|
import org.elasticsearch.action.ActionFuture;
|
||||||
|
import org.elasticsearch.action.ActionListener;
|
||||||
|
import org.elasticsearch.transport.TransportException;
|
||||||
|
import org.elasticsearch.util.TimeValue;
|
||||||
|
import org.elasticsearch.util.concurrent.AbstractFuture;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public abstract class AdapterActionFuture<T, L> extends AbstractFuture<T> implements ActionFuture<T>, ActionListener<L> {
|
||||||
|
|
||||||
|
@Override public T actionGet() throws ElasticSearchException {
|
||||||
|
try {
|
||||||
|
return get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new ElasticSearchInterruptedException(e.getMessage());
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
if (e.getCause() instanceof ElasticSearchException) {
|
||||||
|
throw (ElasticSearchException) e.getCause();
|
||||||
|
} else {
|
||||||
|
throw new TransportException("Failed execution", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public T actionGet(String timeout) throws ElasticSearchException {
|
||||||
|
return actionGet(TimeValue.parseTimeValue(timeout, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public T actionGet(long timeoutMillis) throws ElasticSearchException {
|
||||||
|
return actionGet(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public T actionGet(TimeValue timeout) throws ElasticSearchException {
|
||||||
|
return actionGet(timeout.millis(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public T actionGet(long timeout, TimeUnit unit) throws ElasticSearchException {
|
||||||
|
try {
|
||||||
|
return get(timeout, unit);
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
throw new ElasticSearchTimeoutException(e.getMessage());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new ElasticSearchInterruptedException(e.getMessage());
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
if (e.getCause() instanceof ElasticSearchException) {
|
||||||
|
throw (ElasticSearchException) e.getCause();
|
||||||
|
} else {
|
||||||
|
throw new ElasticSearchException("Failed execution", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onResponse(L result) {
|
||||||
|
set(convert(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFailure(Throwable e) {
|
||||||
|
setException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T convert(L listenerResponse);
|
||||||
|
}
|
|
@ -19,143 +19,16 @@
|
||||||
|
|
||||||
package org.elasticsearch.action.support;
|
package org.elasticsearch.action.support;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticSearchException;
|
|
||||||
import org.elasticsearch.ElasticSearchInterruptedException;
|
|
||||||
import org.elasticsearch.ElasticSearchTimeoutException;
|
|
||||||
import org.elasticsearch.action.ActionFuture;
|
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.transport.TransportException;
|
|
||||||
import org.elasticsearch.util.TimeValue;
|
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (shay.banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public class PlainActionFuture<T> implements ActionFuture<T>, ActionListener<T> {
|
public class PlainActionFuture<T> extends AdapterActionFuture<T, T> {
|
||||||
|
|
||||||
public static <T> PlainActionFuture<T> newFuture() {
|
public static <T> PlainActionFuture<T> newFuture() {
|
||||||
return new PlainActionFuture<T>();
|
return new PlainActionFuture<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final CountDownLatch latch;
|
@Override protected T convert(T listenerResponse) {
|
||||||
|
return listenerResponse;
|
||||||
private volatile boolean done;
|
|
||||||
private volatile boolean canceled;
|
|
||||||
private volatile T result;
|
|
||||||
private volatile Throwable exp;
|
|
||||||
|
|
||||||
public PlainActionFuture() {
|
|
||||||
latch = new CountDownLatch(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean cancel(boolean mayInterruptIfRunning) {
|
|
||||||
if (done)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
canceled = true;
|
|
||||||
latch.countDown();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isCancelled() {
|
|
||||||
return canceled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isDone() {
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T get() throws InterruptedException, ExecutionException {
|
|
||||||
latch.await();
|
|
||||||
|
|
||||||
if (!done || canceled) {
|
|
||||||
throw new InterruptedException("future was interrupted");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp != null) {
|
|
||||||
throw new ExecutionException(exp.getMessage(), exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
|
||||||
latch.await(timeout, unit);
|
|
||||||
|
|
||||||
if (!done || canceled) {
|
|
||||||
throw new TimeoutException("response did not arrive");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp != null) {
|
|
||||||
throw new ExecutionException(exp.getMessage(), exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T actionGet() throws ElasticSearchException {
|
|
||||||
try {
|
|
||||||
return get();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new ElasticSearchInterruptedException(e.getMessage());
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
if (e.getCause() instanceof ElasticSearchException) {
|
|
||||||
throw (ElasticSearchException) e.getCause();
|
|
||||||
} else {
|
|
||||||
throw new TransportException("Failed execution", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T actionGet(String timeout) throws ElasticSearchException {
|
|
||||||
return actionGet(TimeValue.parseTimeValue(timeout, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T actionGet(long timeoutMillis) throws ElasticSearchException {
|
|
||||||
return actionGet(timeoutMillis, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T actionGet(TimeValue timeout) throws ElasticSearchException {
|
|
||||||
return actionGet(timeout.millis(), TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T actionGet(long timeout, TimeUnit unit) throws ElasticSearchException {
|
|
||||||
try {
|
|
||||||
return get(timeout, unit);
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
throw new ElasticSearchTimeoutException(e.getMessage());
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new ElasticSearchInterruptedException(e.getMessage());
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
if (e.getCause() instanceof ElasticSearchException) {
|
|
||||||
throw (ElasticSearchException) e.getCause();
|
|
||||||
} else {
|
|
||||||
throw new ElasticSearchException("Failed execution", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void onResponse(T result) {
|
|
||||||
this.done = true;
|
|
||||||
this.result = result;
|
|
||||||
|
|
||||||
if (canceled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void onFailure(Throwable e) {
|
|
||||||
this.done = true;
|
|
||||||
this.exp = e;
|
|
||||||
|
|
||||||
if (canceled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
latch.countDown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.action.support;
|
||||||
|
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public class PlainListenableActionFuture<T> extends AbstractListenableActionFuture<T, T> {
|
||||||
|
|
||||||
|
public PlainListenableActionFuture(boolean listenerThreaded, ThreadPool threadPool) {
|
||||||
|
super(listenerThreaded, threadPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected T convert(T response) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
|
||||||
return totalShards;
|
return totalShards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total shards this request ran against.
|
||||||
|
*/
|
||||||
|
public int getTotalShards() {
|
||||||
|
return totalShards;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The successful shards this request was executed on.
|
* The successful shards this request was executed on.
|
||||||
*/
|
*/
|
||||||
|
@ -73,6 +80,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
|
||||||
return successfulShards;
|
return successfulShards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The successful shards this request was executed on.
|
||||||
|
*/
|
||||||
|
public int getSuccessfulShards() {
|
||||||
|
return successfulShards;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The failed shards this request was executed on.
|
* The failed shards this request was executed on.
|
||||||
*/
|
*/
|
||||||
|
@ -80,6 +94,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
|
||||||
return failedShards;
|
return failedShards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The failed shards this request was executed on.
|
||||||
|
*/
|
||||||
|
public int getFailedShards() {
|
||||||
|
return failedShards;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of shard failures exception.
|
* The list of shard failures exception.
|
||||||
*/
|
*/
|
||||||
|
@ -90,6 +111,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
|
||||||
return shardFailures;
|
return shardFailures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of shard failures exception.
|
||||||
|
*/
|
||||||
|
public List<ShardOperationFailedException> getShardFailures() {
|
||||||
|
return shardFailures;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void readFrom(StreamInput in) throws IOException {
|
@Override public void readFrom(StreamInput in) throws IOException {
|
||||||
totalShards = in.readVInt();
|
totalShards = in.readVInt();
|
||||||
successfulShards = in.readVInt();
|
successfulShards = in.readVInt();
|
||||||
|
|
|
@ -53,6 +53,10 @@ import org.elasticsearch.action.terms.TermsRequest;
|
||||||
*/
|
*/
|
||||||
public class Requests {
|
public class Requests {
|
||||||
|
|
||||||
|
public static IndexRequest indexRequest() {
|
||||||
|
return new IndexRequest();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an index request against a specific index. Note the {@link IndexRequest#type(String)} must be
|
* Create an index request against a specific index. Note the {@link IndexRequest#type(String)} must be
|
||||||
* set as well and optionally the {@link IndexRequest#id(String)}.
|
* set as well and optionally the {@link IndexRequest#id(String)}.
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.client.internal;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public interface InternalClient extends Client {
|
||||||
|
|
||||||
|
ThreadPool threadPool();
|
||||||
|
}
|
|
@ -44,14 +44,17 @@ import org.elasticsearch.action.terms.TermsRequest;
|
||||||
import org.elasticsearch.action.terms.TermsResponse;
|
import org.elasticsearch.action.terms.TermsResponse;
|
||||||
import org.elasticsearch.action.terms.TransportTermsAction;
|
import org.elasticsearch.action.terms.TransportTermsAction;
|
||||||
import org.elasticsearch.client.AdminClient;
|
import org.elasticsearch.client.AdminClient;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.internal.InternalClient;
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.util.component.AbstractComponent;
|
import org.elasticsearch.util.component.AbstractComponent;
|
||||||
import org.elasticsearch.util.settings.Settings;
|
import org.elasticsearch.util.settings.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (shay.banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public class NodeClient extends AbstractComponent implements Client {
|
public class NodeClient extends AbstractComponent implements InternalClient {
|
||||||
|
|
||||||
|
private final ThreadPool threadPool;
|
||||||
|
|
||||||
private final NodeAdminClient admin;
|
private final NodeAdminClient admin;
|
||||||
|
|
||||||
|
@ -73,12 +76,13 @@ public class NodeClient extends AbstractComponent implements Client {
|
||||||
|
|
||||||
private final TransportMoreLikeThisAction moreLikeThisAction;
|
private final TransportMoreLikeThisAction moreLikeThisAction;
|
||||||
|
|
||||||
@Inject public NodeClient(Settings settings, NodeAdminClient admin,
|
@Inject public NodeClient(Settings settings, ThreadPool threadPool, NodeAdminClient admin,
|
||||||
TransportIndexAction indexAction, TransportDeleteAction deleteAction,
|
TransportIndexAction indexAction, TransportDeleteAction deleteAction,
|
||||||
TransportDeleteByQueryAction deleteByQueryAction, TransportGetAction getAction, TransportCountAction countAction,
|
TransportDeleteByQueryAction deleteByQueryAction, TransportGetAction getAction, TransportCountAction countAction,
|
||||||
TransportSearchAction searchAction, TransportSearchScrollAction searchScrollAction,
|
TransportSearchAction searchAction, TransportSearchScrollAction searchScrollAction,
|
||||||
TransportTermsAction termsAction, TransportMoreLikeThisAction moreLikeThisAction) {
|
TransportTermsAction termsAction, TransportMoreLikeThisAction moreLikeThisAction) {
|
||||||
super(settings);
|
super(settings);
|
||||||
|
this.threadPool = threadPool;
|
||||||
this.admin = admin;
|
this.admin = admin;
|
||||||
this.indexAction = indexAction;
|
this.indexAction = indexAction;
|
||||||
this.deleteAction = deleteAction;
|
this.deleteAction = deleteAction;
|
||||||
|
@ -91,6 +95,10 @@ public class NodeClient extends AbstractComponent implements Client {
|
||||||
this.moreLikeThisAction = moreLikeThisAction;
|
this.moreLikeThisAction = moreLikeThisAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public ThreadPool threadPool() {
|
||||||
|
return this.threadPool;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void close() {
|
@Override public void close() {
|
||||||
// nothing really to do
|
// nothing really to do
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ import org.elasticsearch.action.search.SearchScrollRequest;
|
||||||
import org.elasticsearch.action.terms.TermsRequest;
|
import org.elasticsearch.action.terms.TermsRequest;
|
||||||
import org.elasticsearch.action.terms.TermsResponse;
|
import org.elasticsearch.action.terms.TermsResponse;
|
||||||
import org.elasticsearch.client.AdminClient;
|
import org.elasticsearch.client.AdminClient;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.internal.InternalClient;
|
||||||
import org.elasticsearch.client.transport.action.ClientTransportActionModule;
|
import org.elasticsearch.client.transport.action.ClientTransportActionModule;
|
||||||
import org.elasticsearch.client.transport.support.InternalTransportClient;
|
import org.elasticsearch.client.transport.support.InternalTransportClient;
|
||||||
import org.elasticsearch.cluster.ClusterNameModule;
|
import org.elasticsearch.cluster.ClusterNameModule;
|
||||||
|
@ -77,7 +77,7 @@ import static org.elasticsearch.util.settings.ImmutableSettings.*;
|
||||||
*
|
*
|
||||||
* @author kimchy (shay.banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public class TransportClient implements Client {
|
public class TransportClient implements InternalClient {
|
||||||
|
|
||||||
private final Injector injector;
|
private final Injector injector;
|
||||||
|
|
||||||
|
@ -209,6 +209,10 @@ public class TransportClient implements Client {
|
||||||
ThreadLocals.clearReferencesThreadLocals();
|
ThreadLocals.clearReferencesThreadLocals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public ThreadPool threadPool() {
|
||||||
|
return internalClient.threadPool();
|
||||||
|
}
|
||||||
|
|
||||||
@Override public AdminClient admin() {
|
@Override public AdminClient admin() {
|
||||||
return internalClient.admin();
|
return internalClient.admin();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import org.elasticsearch.action.search.SearchScrollRequest;
|
||||||
import org.elasticsearch.action.terms.TermsRequest;
|
import org.elasticsearch.action.terms.TermsRequest;
|
||||||
import org.elasticsearch.action.terms.TermsResponse;
|
import org.elasticsearch.action.terms.TermsResponse;
|
||||||
import org.elasticsearch.client.AdminClient;
|
import org.elasticsearch.client.AdminClient;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.internal.InternalClient;
|
||||||
import org.elasticsearch.client.transport.TransportClientNodesService;
|
import org.elasticsearch.client.transport.TransportClientNodesService;
|
||||||
import org.elasticsearch.client.transport.action.count.ClientTransportCountAction;
|
import org.elasticsearch.client.transport.action.count.ClientTransportCountAction;
|
||||||
import org.elasticsearch.client.transport.action.delete.ClientTransportDeleteAction;
|
import org.elasticsearch.client.transport.action.delete.ClientTransportDeleteAction;
|
||||||
|
@ -52,13 +52,16 @@ import org.elasticsearch.client.transport.action.search.ClientTransportSearchAct
|
||||||
import org.elasticsearch.client.transport.action.search.ClientTransportSearchScrollAction;
|
import org.elasticsearch.client.transport.action.search.ClientTransportSearchScrollAction;
|
||||||
import org.elasticsearch.client.transport.action.terms.ClientTransportTermsAction;
|
import org.elasticsearch.client.transport.action.terms.ClientTransportTermsAction;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.util.component.AbstractComponent;
|
import org.elasticsearch.util.component.AbstractComponent;
|
||||||
import org.elasticsearch.util.settings.Settings;
|
import org.elasticsearch.util.settings.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (Shay Banon)
|
* @author kimchy (Shay Banon)
|
||||||
*/
|
*/
|
||||||
public class InternalTransportClient extends AbstractComponent implements Client {
|
public class InternalTransportClient extends AbstractComponent implements InternalClient {
|
||||||
|
|
||||||
|
private final ThreadPool threadPool;
|
||||||
|
|
||||||
private final TransportClientNodesService nodesService;
|
private final TransportClientNodesService nodesService;
|
||||||
|
|
||||||
|
@ -82,12 +85,14 @@ public class InternalTransportClient extends AbstractComponent implements Client
|
||||||
|
|
||||||
private final ClientTransportMoreLikeThisAction moreLikeThisAction;
|
private final ClientTransportMoreLikeThisAction moreLikeThisAction;
|
||||||
|
|
||||||
@Inject public InternalTransportClient(Settings settings, TransportClientNodesService nodesService, InternalTransportAdminClient adminClient,
|
@Inject public InternalTransportClient(Settings settings, ThreadPool threadPool,
|
||||||
|
TransportClientNodesService nodesService, InternalTransportAdminClient adminClient,
|
||||||
ClientTransportIndexAction indexAction, ClientTransportDeleteAction deleteAction, ClientTransportGetAction getAction,
|
ClientTransportIndexAction indexAction, ClientTransportDeleteAction deleteAction, ClientTransportGetAction getAction,
|
||||||
ClientTransportDeleteByQueryAction deleteByQueryAction, ClientTransportCountAction countAction,
|
ClientTransportDeleteByQueryAction deleteByQueryAction, ClientTransportCountAction countAction,
|
||||||
ClientTransportSearchAction searchAction, ClientTransportSearchScrollAction searchScrollAction,
|
ClientTransportSearchAction searchAction, ClientTransportSearchScrollAction searchScrollAction,
|
||||||
ClientTransportTermsAction termsAction, ClientTransportMoreLikeThisAction moreLikeThisAction) {
|
ClientTransportTermsAction termsAction, ClientTransportMoreLikeThisAction moreLikeThisAction) {
|
||||||
super(settings);
|
super(settings);
|
||||||
|
this.threadPool = threadPool;
|
||||||
this.nodesService = nodesService;
|
this.nodesService = nodesService;
|
||||||
this.adminClient = adminClient;
|
this.adminClient = adminClient;
|
||||||
|
|
||||||
|
@ -106,6 +111,10 @@ public class InternalTransportClient extends AbstractComponent implements Client
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public ThreadPool threadPool() {
|
||||||
|
return this.threadPool;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public AdminClient admin() {
|
@Override public AdminClient admin() {
|
||||||
return adminClient;
|
return adminClient;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,73 +21,22 @@ package org.elasticsearch.transport;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticSearchException;
|
import org.elasticsearch.ElasticSearchException;
|
||||||
import org.elasticsearch.ElasticSearchInterruptedException;
|
import org.elasticsearch.ElasticSearchInterruptedException;
|
||||||
|
import org.elasticsearch.util.concurrent.AbstractFuture;
|
||||||
import org.elasticsearch.util.io.stream.Streamable;
|
import org.elasticsearch.util.io.stream.Streamable;
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kimchy (Shay Banon)
|
* @author kimchy (shay.banon)
|
||||||
*/
|
*/
|
||||||
public class PlainTransportFuture<V extends Streamable> implements TransportFuture<V>, TransportResponseHandler<V> {
|
public class PlainTransportFuture<V extends Streamable> extends AbstractFuture<V> implements TransportFuture<V>, TransportResponseHandler<V> {
|
||||||
|
|
||||||
private final CountDownLatch latch;
|
|
||||||
private final TransportResponseHandler<V> handler;
|
private final TransportResponseHandler<V> handler;
|
||||||
private volatile boolean done;
|
|
||||||
private volatile boolean canceled;
|
|
||||||
private volatile V result;
|
|
||||||
private volatile Exception exp;
|
|
||||||
|
|
||||||
public PlainTransportFuture(TransportResponseHandler<V> handler) {
|
public PlainTransportFuture(TransportResponseHandler<V> handler) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
latch = new CountDownLatch(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean cancel(boolean mayInterruptIfRunning) {
|
|
||||||
if (done)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
canceled = true;
|
|
||||||
latch.countDown();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isCancelled() {
|
|
||||||
return canceled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isDone() {
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V get() throws InterruptedException, ExecutionException {
|
|
||||||
latch.await();
|
|
||||||
|
|
||||||
if (!done || canceled) {
|
|
||||||
throw new InterruptedException("future was interrupted");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp != null) {
|
|
||||||
throw new ExecutionException(exp.getMessage(), exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
|
||||||
latch.await(timeout, unit);
|
|
||||||
|
|
||||||
if (!done || canceled) {
|
|
||||||
throw new TimeoutException("response did not arrive");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp != null) {
|
|
||||||
throw new ExecutionException(exp.getMessage(), exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public V txGet() throws ElasticSearchException {
|
@Override public V txGet() throws ElasticSearchException {
|
||||||
|
@ -123,25 +72,13 @@ public class PlainTransportFuture<V extends Streamable> implements TransportFutu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void handleResponse(V response) {
|
@Override public void handleResponse(V response) {
|
||||||
this.done = true;
|
|
||||||
this.result = response;
|
|
||||||
|
|
||||||
if (canceled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
handler.handleResponse(response);
|
handler.handleResponse(response);
|
||||||
latch.countDown();
|
set(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void handleException(RemoteTransportException exp) {
|
@Override public void handleException(RemoteTransportException exp) {
|
||||||
this.done = true;
|
|
||||||
this.exp = exp;
|
|
||||||
|
|
||||||
if (canceled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
handler.handleException(exp);
|
handler.handleException(exp);
|
||||||
latch.countDown();
|
setException(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean spawn() {
|
@Override public boolean spawn() {
|
||||||
|
|
|
@ -0,0 +1,328 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.util.concurrent;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>An abstract implementation of the {@link Future} interface. This class
|
||||||
|
* is an abstraction of {@link java.util.concurrent.FutureTask} to support use
|
||||||
|
* for tasks other than {@link Runnable}s. It uses an
|
||||||
|
* {@link AbstractQueuedSynchronizer} to deal with concurrency issues and
|
||||||
|
* guarantee thread safety. It could be used as a base class to
|
||||||
|
* {@code FutureTask}, or any other implementor of the {@code Future} interface.
|
||||||
|
*
|
||||||
|
* <p>This class implements all methods in {@code Future}. Subclasses should
|
||||||
|
* provide a way to set the result of the computation through the protected
|
||||||
|
* methods {@link #set(Object)}, {@link #setException(Throwable)}, or
|
||||||
|
* {@link #cancel()}. If subclasses want to implement cancellation they can
|
||||||
|
* override the {@link #cancel(boolean)} method with a real implementation, the
|
||||||
|
* default implementation doesn't support cancellation.
|
||||||
|
*
|
||||||
|
* <p>The state changing methods all return a boolean indicating success or
|
||||||
|
* failure in changing the future's state. Valid states are running,
|
||||||
|
* completed, failed, or cancelled. Because this class does not implement
|
||||||
|
* cancellation it is left to the subclass to distinguish between created
|
||||||
|
* and running tasks.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractFuture<V> implements Future<V> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronization control for AbstractFutures.
|
||||||
|
*/
|
||||||
|
private final Sync<V> sync = new Sync<V>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Blocks until either the task completes or the timeout expires. Uses the
|
||||||
|
* sync blocking-with-timeout support provided by AQS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public V get(long timeout, TimeUnit unit) throws InterruptedException,
|
||||||
|
TimeoutException, ExecutionException {
|
||||||
|
return sync.get(unit.toNanos(timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Blocks until the task completes or we get interrupted. Uses the
|
||||||
|
* interruptible blocking support provided by AQS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public V get() throws InterruptedException, ExecutionException {
|
||||||
|
return sync.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks if the sync is not in the running state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public boolean isDone() {
|
||||||
|
return sync.isDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks if the sync is in the cancelled state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return sync.isCancelled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default implementation of cancel that never cancels the future.
|
||||||
|
* Subclasses should override this to implement cancellation if desired.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should invoke this method to set the result of the computation
|
||||||
|
* to {@code value}. This will set the state of the future to
|
||||||
|
* {@link AbstractFuture.Sync#COMPLETED} and call {@link #done()} if the
|
||||||
|
* state was successfully changed.
|
||||||
|
*
|
||||||
|
* @param value the value that was the result of the task.
|
||||||
|
* @return true if the state was successfully changed.
|
||||||
|
*/
|
||||||
|
protected boolean set(V value) {
|
||||||
|
boolean result = sync.set(value);
|
||||||
|
if (result) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should invoke this method to set the result of the computation
|
||||||
|
* to an error, {@code throwable}. This will set the state of the future to
|
||||||
|
* {@link AbstractFuture.Sync#COMPLETED} and call {@link #done()} if the
|
||||||
|
* state was successfully changed.
|
||||||
|
*
|
||||||
|
* @param throwable the exception that the task failed with.
|
||||||
|
* @return true if the state was successfully changed.
|
||||||
|
* @throws Error if the throwable was an {@link Error}.
|
||||||
|
*/
|
||||||
|
protected boolean setException(Throwable throwable) {
|
||||||
|
boolean result = sync.setException(throwable);
|
||||||
|
if (result) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's an Error, we want to make sure it reaches the top of the
|
||||||
|
// call stack, so we rethrow it.
|
||||||
|
if (throwable instanceof Error) {
|
||||||
|
throw (Error) throwable;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should invoke this method to mark the future as cancelled.
|
||||||
|
* This will set the state of the future to {@link
|
||||||
|
* AbstractFuture.Sync#CANCELLED} and call {@link #done()} if the state was
|
||||||
|
* successfully changed.
|
||||||
|
*
|
||||||
|
* @return true if the state was successfully changed.
|
||||||
|
*/
|
||||||
|
protected final boolean cancel() {
|
||||||
|
boolean result = sync.cancel();
|
||||||
|
if (result) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by the success, failed, or cancelled methods to indicate that the
|
||||||
|
* value is now available and the latch can be released. Subclasses can
|
||||||
|
* use this method to deal with any actions that should be undertaken when
|
||||||
|
* the task has completed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected void done() {
|
||||||
|
// Default implementation does nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Following the contract of {@link AbstractQueuedSynchronizer} we create a
|
||||||
|
* private subclass to hold the synchronizer. This synchronizer is used to
|
||||||
|
* implement the blocking and waiting calls as well as to handle state changes
|
||||||
|
* in a thread-safe manner. The current state of the future is held in the
|
||||||
|
* Sync state, and the lock is released whenever the state changes to either
|
||||||
|
* {@link #COMPLETED} or {@link #CANCELLED}.
|
||||||
|
*
|
||||||
|
* <p>To avoid races between threads doing release and acquire, we transition
|
||||||
|
* to the final state in two steps. One thread will successfully CAS from
|
||||||
|
* RUNNING to COMPLETING, that thread will then set the result of the
|
||||||
|
* computation, and only then transition to COMPLETED or CANCELLED.
|
||||||
|
*
|
||||||
|
* <p>We don't use the integer argument passed between acquire methods so we
|
||||||
|
* pass around a -1 everywhere.
|
||||||
|
*/
|
||||||
|
static final class Sync<V> extends AbstractQueuedSynchronizer {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
|
/* Valid states. */
|
||||||
|
static final int RUNNING = 0;
|
||||||
|
static final int COMPLETING = 1;
|
||||||
|
static final int COMPLETED = 2;
|
||||||
|
static final int CANCELLED = 4;
|
||||||
|
|
||||||
|
private V value;
|
||||||
|
private ExecutionException exception;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acquisition succeeds if the future is done, otherwise it fails.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int tryAcquireShared(int ignored) {
|
||||||
|
if (isDone()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We always allow a release to go through, this means the state has been
|
||||||
|
* successfully changed and the result is available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean tryReleaseShared(int finalState) {
|
||||||
|
setState(finalState);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until the task is complete or the timeout expires. Throws a
|
||||||
|
* {@link TimeoutException} if the timer expires, otherwise behaves like
|
||||||
|
* {@link #get()}.
|
||||||
|
*/
|
||||||
|
V get(long nanos) throws TimeoutException, CancellationException,
|
||||||
|
ExecutionException, InterruptedException {
|
||||||
|
|
||||||
|
// Attempt to acquire the shared lock with a timeout.
|
||||||
|
if (!tryAcquireSharedNanos(-1, nanos)) {
|
||||||
|
throw new TimeoutException("Timeout waiting for task.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until {@link #complete(Object, Throwable, int)} has been
|
||||||
|
* successfully called. Throws a {@link CancellationException} if the task
|
||||||
|
* was cancelled, or a {@link ExecutionException} if the task completed with
|
||||||
|
* an error.
|
||||||
|
*/
|
||||||
|
V get() throws CancellationException, ExecutionException,
|
||||||
|
InterruptedException {
|
||||||
|
|
||||||
|
// Acquire the shared lock allowing interruption.
|
||||||
|
acquireSharedInterruptibly(-1);
|
||||||
|
return getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the actual value retrieval. Will return the value
|
||||||
|
* on success, an exception on failure, a cancellation on cancellation, or
|
||||||
|
* an illegal state if the synchronizer is in an invalid state.
|
||||||
|
*/
|
||||||
|
private V getValue() throws CancellationException, ExecutionException {
|
||||||
|
int state = getState();
|
||||||
|
switch (state) {
|
||||||
|
case COMPLETED:
|
||||||
|
if (exception != null) {
|
||||||
|
throw exception;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CANCELLED:
|
||||||
|
throw new CancellationException("Task was cancelled.");
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Error, synchronizer in invalid state: " + state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the state is {@link #COMPLETED} or {@link #CANCELLED}.
|
||||||
|
*/
|
||||||
|
boolean isDone() {
|
||||||
|
return (getState() & (COMPLETED | CANCELLED)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the state is {@link #CANCELLED}.
|
||||||
|
*/
|
||||||
|
boolean isCancelled() {
|
||||||
|
return getState() == CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transition to the COMPLETED state and set the value.
|
||||||
|
*/
|
||||||
|
boolean set(V v) {
|
||||||
|
return complete(v, null, COMPLETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transition to the COMPLETED state and set the exception.
|
||||||
|
*/
|
||||||
|
boolean setException(Throwable t) {
|
||||||
|
return complete(null, t, COMPLETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transition to the CANCELLED state.
|
||||||
|
*/
|
||||||
|
boolean cancel() {
|
||||||
|
return complete(null, null, CANCELLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of completing a task. Either {@code v} or {@code t} will
|
||||||
|
* be set but not both. The {@code finalState} is the state to change to
|
||||||
|
* from {@link #RUNNING}. If the state is not in the RUNNING state we
|
||||||
|
* return {@code false}.
|
||||||
|
*
|
||||||
|
* @param v the value to set as the result of the computation.
|
||||||
|
* @param t the exception to set as the result of the computation.
|
||||||
|
* @param finalState the state to transition to.
|
||||||
|
*/
|
||||||
|
private boolean complete(V v, Throwable t, int finalState) {
|
||||||
|
if (compareAndSetState(RUNNING, COMPLETING)) {
|
||||||
|
this.value = v;
|
||||||
|
this.exception = t == null ? null : new ExecutionException(t);
|
||||||
|
releaseShared(finalState);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The state was not RUNNING, so there are no valid transitions.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,8 +65,6 @@ public class BinaryJsonBuilder extends JsonBuilder<BinaryJsonBuilder> {
|
||||||
|
|
||||||
private final JsonFactory factory;
|
private final JsonFactory factory;
|
||||||
|
|
||||||
private StringBuilder cachedStringBuilder;
|
|
||||||
|
|
||||||
public BinaryJsonBuilder() throws IOException {
|
public BinaryJsonBuilder() throws IOException {
|
||||||
this(Jackson.defaultJsonFactory());
|
this(Jackson.defaultJsonFactory());
|
||||||
}
|
}
|
||||||
|
@ -85,10 +83,6 @@ public class BinaryJsonBuilder extends JsonBuilder<BinaryJsonBuilder> {
|
||||||
this.builder = this;
|
this.builder = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected StringBuilder cachedStringBuilder() {
|
|
||||||
return cachedStringBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public BinaryJsonBuilder raw(byte[] json) throws IOException {
|
@Override public BinaryJsonBuilder raw(byte[] json) throws IOException {
|
||||||
flush();
|
flush();
|
||||||
bos.write(json);
|
bos.write(json);
|
||||||
|
|
|
@ -69,6 +69,8 @@ public abstract class JsonBuilder<T extends JsonBuilder> {
|
||||||
|
|
||||||
protected FieldCaseConversion fieldCaseConversion = globalFieldCaseConversion;
|
protected FieldCaseConversion fieldCaseConversion = globalFieldCaseConversion;
|
||||||
|
|
||||||
|
protected StringBuilder cachedStringBuilder;
|
||||||
|
|
||||||
public static StringJsonBuilder stringJsonBuilder() throws IOException {
|
public static StringJsonBuilder stringJsonBuilder() throws IOException {
|
||||||
return StringJsonBuilder.Cached.cached();
|
return StringJsonBuilder.Cached.cached();
|
||||||
}
|
}
|
||||||
|
@ -143,9 +145,9 @@ public abstract class JsonBuilder<T extends JsonBuilder> {
|
||||||
|
|
||||||
public T field(String name) throws IOException {
|
public T field(String name) throws IOException {
|
||||||
if (fieldCaseConversion == FieldCaseConversion.UNDERSCORE) {
|
if (fieldCaseConversion == FieldCaseConversion.UNDERSCORE) {
|
||||||
name = Strings.toUnderscoreCase(name);
|
name = Strings.toUnderscoreCase(name, cachedStringBuilder);
|
||||||
} else if (fieldCaseConversion == FieldCaseConversion.CAMELCASE) {
|
} else if (fieldCaseConversion == FieldCaseConversion.CAMELCASE) {
|
||||||
name = Strings.toCamelCase(name);
|
name = Strings.toCamelCase(name, cachedStringBuilder);
|
||||||
}
|
}
|
||||||
generator.writeFieldName(name);
|
generator.writeFieldName(name);
|
||||||
return builder;
|
return builder;
|
||||||
|
@ -403,10 +405,6 @@ public abstract class JsonBuilder<T extends JsonBuilder> {
|
||||||
|
|
||||||
public abstract String string() throws IOException;
|
public abstract String string() throws IOException;
|
||||||
|
|
||||||
protected StringBuilder cachedStringBuilder() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
generator.close();
|
generator.close();
|
||||||
|
|
|
@ -69,8 +69,6 @@ public class StringJsonBuilder extends JsonBuilder<StringJsonBuilder> {
|
||||||
|
|
||||||
final UnicodeUtil.UTF8Result utf8Result = new UnicodeUtil.UTF8Result();
|
final UnicodeUtil.UTF8Result utf8Result = new UnicodeUtil.UTF8Result();
|
||||||
|
|
||||||
private StringBuilder cachedStringBuilder;
|
|
||||||
|
|
||||||
public StringJsonBuilder() throws IOException {
|
public StringJsonBuilder() throws IOException {
|
||||||
this(Jackson.defaultJsonFactory());
|
this(Jackson.defaultJsonFactory());
|
||||||
}
|
}
|
||||||
|
@ -89,10 +87,6 @@ public class StringJsonBuilder extends JsonBuilder<StringJsonBuilder> {
|
||||||
this.builder = this;
|
this.builder = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected StringBuilder cachedStringBuilder() {
|
|
||||||
return cachedStringBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public StringJsonBuilder raw(byte[] json) throws IOException {
|
@Override public StringJsonBuilder raw(byte[] json) throws IOException {
|
||||||
flush();
|
flush();
|
||||||
Unicode.UTF16Result result = Unicode.unsafeFromBytesAsUtf16(json);
|
Unicode.UTF16Result result = Unicode.unsafeFromBytesAsUtf16(json);
|
||||||
|
|
|
@ -107,15 +107,12 @@ artifacts {
|
||||||
|
|
||||||
uploadArchives {
|
uploadArchives {
|
||||||
repositories.mavenDeployer {
|
repositories.mavenDeployer {
|
||||||
// repository(url: "file://localhost/" + rootProject.projectDir.absolutePath + "/build/maven/repository")
|
|
||||||
// snapshotRepository(url: "file://localhost/" + rootProject.projectDir.absolutePath + "/build/maven/snapshotRepository")
|
|
||||||
|
|
||||||
configuration = configurations.deployerJars
|
configuration = configurations.deployerJars
|
||||||
repository(url: "http://oss.sonatype.org/service/local/staging/deploy/maven2/") {
|
repository(url: rootProject.mavenRepoUrl) {
|
||||||
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
|
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
|
||||||
}
|
}
|
||||||
snapshotRepository(url: "http://oss.sonatype.org/content/repositories/snapshots") {
|
snapshotRepository(url: rootProject.mavenSnapshotRepoUrl) {
|
||||||
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
|
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
pom.project {
|
pom.project {
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
dependsOn(':elasticsearch')
|
||||||
|
|
||||||
|
apply plugin: 'groovy'
|
||||||
|
apply plugin: 'maven'
|
||||||
|
|
||||||
|
archivesBaseName = "elasticsearch-groovy"
|
||||||
|
|
||||||
|
explodedDistDir = new File(distsDir, 'exploded')
|
||||||
|
|
||||||
|
manifest.mainAttributes("Implementation-Title": "ElasticSearch::Plugins::Groovy", "Implementation-Version": rootProject.version, "Implementation-Date": buildTimeStr)
|
||||||
|
|
||||||
|
configurations.compile.transitive = true
|
||||||
|
configurations.testCompile.transitive = true
|
||||||
|
|
||||||
|
// no need to use the resource dir
|
||||||
|
sourceSets.main.resources.srcDir 'src/main/groovy'
|
||||||
|
sourceSets.test.resources.srcDir 'src/test/groovy'
|
||||||
|
|
||||||
|
// add the source files to the dist jar
|
||||||
|
jar {
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
dists
|
||||||
|
distLib {
|
||||||
|
visible = false
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':elasticsearch')
|
||||||
|
|
||||||
|
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.2'
|
||||||
|
|
||||||
|
testCompile project(':test-testng')
|
||||||
|
testCompile('org.testng:testng:5.10:jdk15') { transitive = false }
|
||||||
|
testCompile 'org.hamcrest:hamcrest-all:1.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useTestNG()
|
||||||
|
jmvArgs = ["-ea", "-Xmx1024m"]
|
||||||
|
suiteName = project.name
|
||||||
|
listeners = ["org.elasticsearch.util.testng.Listeners"]
|
||||||
|
systemProperties["es.test.log.conf"] = System.getProperty("es.test.log.conf", "log4j-gradle.properties")
|
||||||
|
}
|
||||||
|
|
||||||
|
task explodedDist(dependsOn: [jar], description: 'Builds the plugin zip file') << {
|
||||||
|
[explodedDistDir]*.mkdirs()
|
||||||
|
|
||||||
|
copy {
|
||||||
|
from configurations.distLib
|
||||||
|
into explodedDistDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove elasticsearch files (compile above adds the elasticsearch one)
|
||||||
|
ant.delete { fileset(dir: explodedDistDir, includes: "elasticsearch-*.jar") }
|
||||||
|
|
||||||
|
copy {
|
||||||
|
from libsDir
|
||||||
|
into explodedDistDir
|
||||||
|
}
|
||||||
|
|
||||||
|
ant.delete { fileset(dir: explodedDistDir, includes: "elasticsearch-*-javadoc.jar") }
|
||||||
|
ant.delete { fileset(dir: explodedDistDir, includes: "elasticsearch-*-sources.jar") }
|
||||||
|
}
|
||||||
|
|
||||||
|
task zip(type: Zip, dependsOn: ['explodedDist']) {
|
||||||
|
from(explodedDistDir) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task release(dependsOn: [zip]) << {
|
||||||
|
ant.delete(dir: explodedDistDir)
|
||||||
|
copy {
|
||||||
|
from distsDir
|
||||||
|
into(new File(rootProject.distsDir, "plugins"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
deployerJars
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
deployerJars "org.apache.maven.wagon:wagon-http:1.0-beta-2"
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from javadoc.destinationDir
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives sourcesJar
|
||||||
|
archives javadocJar
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadArchives {
|
||||||
|
repositories.mavenDeployer {
|
||||||
|
configuration = configurations.deployerJars
|
||||||
|
repository(url: rootProject.mavenRepoUrl) {
|
||||||
|
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
|
||||||
|
}
|
||||||
|
snapshotRepository(url: rootProject.mavenSnapshotRepoUrl) {
|
||||||
|
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.project {
|
||||||
|
inceptionYear '2009'
|
||||||
|
name 'elasticsearch-plugins-groovy'
|
||||||
|
description 'Groovy Plugin for ElasticSearch'
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name 'The Apache Software License, Version 2.0'
|
||||||
|
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||||
|
distribution 'repo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
connection 'git://github.com/elasticsearch/elasticsearch.git'
|
||||||
|
developerConnection 'git@github.com:elasticsearch/elasticsearch.git'
|
||||||
|
url 'http://github.com/elasticsearch/elasticsearch'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.whenConfigured {pom ->
|
||||||
|
pom.dependencies = pom.dependencies.findAll {dep -> dep.scope != 'test' } // removes the test scoped ones
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.elasticsearch.groovy.client
|
||||||
|
|
||||||
|
import org.elasticsearch.client.internal.InternalClient
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class GAdminClient {
|
||||||
|
|
||||||
|
private final InternalClient internalClient;
|
||||||
|
|
||||||
|
final GIndicesAdminClient indices;
|
||||||
|
|
||||||
|
final GClusterAdminClient cluster;
|
||||||
|
|
||||||
|
def GAdminClient(internalClient) {
|
||||||
|
this.internalClient = internalClient;
|
||||||
|
|
||||||
|
this.indices = new GIndicesAdminClient(internalClient)
|
||||||
|
this.cluster = new GClusterAdminClient(internalClient)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.groovy.client
|
||||||
|
|
||||||
|
import org.elasticsearch.action.ActionListener
|
||||||
|
import org.elasticsearch.action.delete.DeleteRequest
|
||||||
|
import org.elasticsearch.action.delete.DeleteResponse
|
||||||
|
import org.elasticsearch.action.get.GetRequest
|
||||||
|
import org.elasticsearch.action.get.GetResponse
|
||||||
|
import org.elasticsearch.action.index.IndexRequest
|
||||||
|
import org.elasticsearch.action.index.IndexResponse
|
||||||
|
import org.elasticsearch.client.Client
|
||||||
|
import org.elasticsearch.client.internal.InternalClient
|
||||||
|
import org.elasticsearch.groovy.client.action.GActionFuture
|
||||||
|
import org.elasticsearch.groovy.util.json.JsonBuilder
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class GClient {
|
||||||
|
|
||||||
|
static {
|
||||||
|
IndexRequest.metaClass.setSource = {Closure c ->
|
||||||
|
delegate.source(new JsonBuilder().buildAsBytes(c))
|
||||||
|
}
|
||||||
|
IndexRequest.metaClass.source = {Closure c ->
|
||||||
|
delegate.source(new JsonBuilder().buildAsBytes(c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Client client;
|
||||||
|
|
||||||
|
private final InternalClient internalClient
|
||||||
|
|
||||||
|
final GAdminClient admin;
|
||||||
|
|
||||||
|
def GClient(client) {
|
||||||
|
this.client = client;
|
||||||
|
this.internalClient = client;
|
||||||
|
|
||||||
|
this.admin = new GAdminClient(internalClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<IndexResponse> index(Closure c) {
|
||||||
|
IndexRequest request = new IndexRequest()
|
||||||
|
c.setDelegate request
|
||||||
|
c.call()
|
||||||
|
index(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<IndexResponse> index(IndexRequest request) {
|
||||||
|
GActionFuture<IndexResponse> future = new GActionFuture<IndexResponse>(internalClient.threadPool(), request);
|
||||||
|
client.index(request, future)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
|
||||||
|
void index(IndexRequest request, ActionListener<IndexResponse> listener) {
|
||||||
|
client.index(request, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<GetResponse> get(Closure c) {
|
||||||
|
GetRequest request = new GetRequest()
|
||||||
|
c.setDelegate request
|
||||||
|
c.call()
|
||||||
|
get(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<GetResponse> get(GetRequest request) {
|
||||||
|
GActionFuture<GetResponse> future = new GActionFuture<GetResponse>(internalClient.threadPool(), request);
|
||||||
|
client.get(request, future)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
|
||||||
|
void get(GetRequest request, ActionListener<GetResponse> listener) {
|
||||||
|
client.get(request, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<DeleteResponse> delete(Closure c) {
|
||||||
|
DeleteRequest request = new DeleteRequest()
|
||||||
|
c.setDelegate request
|
||||||
|
c.call()
|
||||||
|
delete(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<DeleteResponse> delete(DeleteRequest request) {
|
||||||
|
GActionFuture<DeleteResponse> future = new GActionFuture<DeleteResponse>(internalClient.threadPool(), request);
|
||||||
|
client.delete(request, future)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete(DeleteRequest request, ActionListener<DeleteResponse> listener) {
|
||||||
|
client.delete(request, listener)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.elasticsearch.groovy.client
|
||||||
|
|
||||||
|
import org.elasticsearch.client.ClusterAdminClient
|
||||||
|
import org.elasticsearch.client.internal.InternalClient
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class GClusterAdminClient {
|
||||||
|
|
||||||
|
private final InternalClient internalClient;
|
||||||
|
|
||||||
|
private final ClusterAdminClient clusterAdminClient;
|
||||||
|
|
||||||
|
def GClusterAdminClient(internalClient) {
|
||||||
|
this.internalClient = internalClient;
|
||||||
|
this.clusterAdminClient = internalClient.admin().cluster();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package org.elasticsearch.groovy.client
|
||||||
|
|
||||||
|
import org.elasticsearch.action.ActionListener
|
||||||
|
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest
|
||||||
|
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse
|
||||||
|
import org.elasticsearch.client.IndicesAdminClient
|
||||||
|
import org.elasticsearch.client.internal.InternalClient
|
||||||
|
import org.elasticsearch.groovy.client.action.GActionFuture
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class GIndicesAdminClient {
|
||||||
|
|
||||||
|
private final InternalClient internalClient;
|
||||||
|
|
||||||
|
private final IndicesAdminClient indicesAdminClient;
|
||||||
|
|
||||||
|
def GIndicesAdminClient(internalClient) {
|
||||||
|
this.internalClient = internalClient;
|
||||||
|
this.indicesAdminClient = internalClient.admin().indices();
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<RefreshResponse> refresh(Closure c) {
|
||||||
|
RefreshRequest request = new RefreshRequest()
|
||||||
|
c.setDelegate request
|
||||||
|
c.call()
|
||||||
|
refresh(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
GActionFuture<RefreshResponse> refresh(RefreshRequest request) {
|
||||||
|
GActionFuture<RefreshResponse> future = new GActionFuture<RefreshResponse>(internalClient.threadPool(), request);
|
||||||
|
indicesAdminClient.refresh(request, future)
|
||||||
|
return future
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh(RefreshRequest request, ActionListener<RefreshResponse> listener) {
|
||||||
|
indicesAdminClient.refresh(request, listener)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elastic Search and Shay Banon under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. Elastic Search licenses this
|
||||||
|
* file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.groovy.client.action;
|
||||||
|
|
||||||
|
import groovy.lang.Closure;
|
||||||
|
import org.elasticsearch.ElasticSearchException;
|
||||||
|
import org.elasticsearch.action.ActionListener;
|
||||||
|
import org.elasticsearch.action.ActionRequest;
|
||||||
|
import org.elasticsearch.action.support.PlainListenableActionFuture;
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
import org.elasticsearch.util.TimeValue;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public class GActionFuture<T> extends PlainListenableActionFuture<T> {
|
||||||
|
|
||||||
|
protected GActionFuture(ThreadPool threadPool, ActionRequest request) {
|
||||||
|
super(request.listenerThreaded(), threadPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListener(final Closure listener) {
|
||||||
|
addListener(new ActionListener<T>() {
|
||||||
|
@Override public void onResponse(T t) {
|
||||||
|
listener.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFailure(Throwable e) {
|
||||||
|
listener.call(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccess(final Closure success) {
|
||||||
|
addListener(new ActionListener<T>() {
|
||||||
|
@Override public void onResponse(T t) {
|
||||||
|
success.call(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFailure(Throwable e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFailure(final Closure failure) {
|
||||||
|
addListener(new ActionListener<T>() {
|
||||||
|
@Override public void onResponse(T t) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFailure(Throwable e) {
|
||||||
|
failure.call(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getResponse() {
|
||||||
|
return actionGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T response(String timeout) throws ElasticSearchException {
|
||||||
|
return super.actionGet(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T response(long timeoutMillis) throws ElasticSearchException {
|
||||||
|
return super.actionGet(timeoutMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T response(TimeValue timeout) throws ElasticSearchException {
|
||||||
|
return super.actionGet(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T response(long timeout, TimeUnit unit) throws ElasticSearchException {
|
||||||
|
return super.actionGet(timeout, unit);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package org.elasticsearch.groovy.node
|
||||||
|
|
||||||
|
import org.elasticsearch.groovy.client.GClient
|
||||||
|
import org.elasticsearch.node.Node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class GNode {
|
||||||
|
|
||||||
|
final Node node;
|
||||||
|
|
||||||
|
final GClient client;
|
||||||
|
|
||||||
|
def GNode(Node node) {
|
||||||
|
this.node = node;
|
||||||
|
this.client = new GClient(node.client())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The settings that were used to create the node.
|
||||||
|
*/
|
||||||
|
def getSettings() {
|
||||||
|
node.settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the node. If the node is already started, this method is no-op.
|
||||||
|
*/
|
||||||
|
def getStart() {
|
||||||
|
node.start()
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the node. If the node is already started, this method is no-op.
|
||||||
|
*/
|
||||||
|
def getStop() {
|
||||||
|
node.stop()
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the node (and {@link #stop} s if its running).
|
||||||
|
*/
|
||||||
|
def getClose() {
|
||||||
|
node.close()
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.elasticsearch.groovy.node
|
||||||
|
|
||||||
|
import org.elasticsearch.groovy.util.json.JsonBuilder
|
||||||
|
import org.elasticsearch.node.Node
|
||||||
|
import org.elasticsearch.node.internal.InternalNode
|
||||||
|
import org.elasticsearch.util.settings.ImmutableSettings
|
||||||
|
import org.elasticsearch.util.settings.loader.JsonSettingsLoader
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public class GNodeBuilder {
|
||||||
|
|
||||||
|
private final ImmutableSettings.Builder settingsBuilder = ImmutableSettings.settingsBuilder();
|
||||||
|
|
||||||
|
private boolean loadConfigSettings = true;
|
||||||
|
|
||||||
|
public static GNodeBuilder nodeBuilder() {
|
||||||
|
new GNodeBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
def settings(Closure settings) {
|
||||||
|
byte[] settingsBytes = new JsonBuilder().buildAsBytes(settings);
|
||||||
|
settingsBuilder.put(new JsonSettingsLoader().load(settingsBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
def getBuild() {
|
||||||
|
Node node = new InternalNode(settingsBuilder.build(), loadConfigSettings)
|
||||||
|
new GNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
def getNode() {
|
||||||
|
build.start
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
package org.elasticsearch.groovy.util.json
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchGenerationException
|
||||||
|
import org.elasticsearch.util.io.FastByteArrayOutputStream
|
||||||
|
import org.elasticsearch.util.io.FastCharArrayWriter
|
||||||
|
import static org.elasticsearch.util.json.Jackson.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to build JSON data.
|
||||||
|
*
|
||||||
|
* @author Marc Palmer
|
||||||
|
* @author Graeme Rocher
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
class JsonBuilder {
|
||||||
|
|
||||||
|
static NODE_ELEMENT = "element"
|
||||||
|
|
||||||
|
def root
|
||||||
|
|
||||||
|
def current
|
||||||
|
|
||||||
|
def nestingStack = []
|
||||||
|
|
||||||
|
def build(Closure c) {
|
||||||
|
return buildRoot(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
String buildAsString(Closure c) {
|
||||||
|
FastCharArrayWriter writer = FastCharArrayWriter.Cached.cached();
|
||||||
|
try {
|
||||||
|
def json = build(c)
|
||||||
|
defaultObjectMapper().writeValue(writer, json);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticSearchGenerationException("Failed to generate [" + c + "]", e);
|
||||||
|
}
|
||||||
|
return writer.toStringTrim()
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buildAsBytes(Closure c) {
|
||||||
|
FastByteArrayOutputStream os = FastByteArrayOutputStream.Cached.cached();
|
||||||
|
try {
|
||||||
|
def json = build(c)
|
||||||
|
defaultObjectMapper().writeValue(os, json);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticSearchGenerationException("Failed to generate [" + c + "]", e);
|
||||||
|
}
|
||||||
|
return os.copiedByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildRoot(Closure c) {
|
||||||
|
c.delegate = this
|
||||||
|
//c.resolveStrategy = Closure.DELEGATE_FIRST
|
||||||
|
root = [:]
|
||||||
|
current = root
|
||||||
|
def returnValue = c.call()
|
||||||
|
if (!root) {
|
||||||
|
return returnValue
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
def invokeMethod(String methodName) {
|
||||||
|
current[methodName] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
List array(Closure c) {
|
||||||
|
def prev = current
|
||||||
|
def list = []
|
||||||
|
try {
|
||||||
|
|
||||||
|
current = list
|
||||||
|
c.call(list)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
current = prev
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
def invokeMethod(String methodName, Object args) {
|
||||||
|
if (args.size()) {
|
||||||
|
if (args[0] instanceof Map) {
|
||||||
|
// switch root to an array if elements used at top level
|
||||||
|
if ((current == root) && (methodName == NODE_ELEMENT) && !(root instanceof List)) {
|
||||||
|
if (root.size()) {
|
||||||
|
throw new IllegalArgumentException('Cannot have array elements in root node if properties of root have already been set')
|
||||||
|
} else {
|
||||||
|
root = []
|
||||||
|
current = root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def n = [:]
|
||||||
|
if (current instanceof List) {
|
||||||
|
current << n
|
||||||
|
} else {
|
||||||
|
current[methodName] = n
|
||||||
|
}
|
||||||
|
n.putAll(args[0])
|
||||||
|
} else if (args[-1] instanceof Closure) {
|
||||||
|
final Object callable = args[-1]
|
||||||
|
handleClosureNode(methodName, callable)
|
||||||
|
} else if (args.size() == 1) {
|
||||||
|
if (methodName != NODE_ELEMENT) {
|
||||||
|
throw new IllegalArgumentException('Array elements must be defined with the "element" method call eg: element(value)')
|
||||||
|
}
|
||||||
|
// switch root to an array if elements used at top level
|
||||||
|
if (current == root) {
|
||||||
|
if (root.size() && methodName != NODE_ELEMENT) {
|
||||||
|
throw new IllegalArgumentException('Cannot have array elements in root node if properties of root have already been set')
|
||||||
|
} else if (!(root instanceof List)) {
|
||||||
|
root = []
|
||||||
|
current = root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current instanceof List) {
|
||||||
|
current << args[0]
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException('Array elements can only be defined under "array" nodes')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("This builder does not support invocation of [$methodName] with arg list ${args.dump()}")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current[methodName] = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleClosureNode(String methodName, callable) {
|
||||||
|
def n = [:]
|
||||||
|
nestingStack << current
|
||||||
|
|
||||||
|
if (current instanceof List) {
|
||||||
|
current << n
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current[methodName] = n
|
||||||
|
}
|
||||||
|
current = n
|
||||||
|
callable.call()
|
||||||
|
current = nestingStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setProperty(String propName, Object value) {
|
||||||
|
if (value instanceof Closure) {
|
||||||
|
handleClosureNode(propName, value)
|
||||||
|
}
|
||||||
|
else if (value instanceof List) {
|
||||||
|
value = value.collect {
|
||||||
|
if (it instanceof Closure) {
|
||||||
|
def callable = it
|
||||||
|
final JsonBuilder localBuilder = new JsonBuilder()
|
||||||
|
callable.delegate = localBuilder
|
||||||
|
callable.resolveStrategy = Closure.DELEGATE_FIRST
|
||||||
|
final Map nestedObject = localBuilder.buildRoot(callable)
|
||||||
|
return nestedObject
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
current[propName] = value
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current[propName] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getProperty(String propName) {
|
||||||
|
current[propName]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
log4j.rootLogger=INFO, out
|
||||||
|
log4j.logger.jgroups=WARN
|
||||||
|
|
||||||
|
#log4j.logger.discovery=TRACE
|
||||||
|
#log4j.logger.cluster.service=TRACE
|
||||||
|
#log4j.logger.cluster.action.shard=DEBUG
|
||||||
|
#log4j.logger.indices.cluster=DEBUG
|
||||||
|
#log4j.logger.index=TRACE
|
||||||
|
#log4j.logger.index.engine=DEBUG
|
||||||
|
#log4j.logger.index.shard.service=DEBUG
|
||||||
|
#log4j.logger.index.shard.recovery=DEBUG
|
||||||
|
#log4j.logger.index.cache=DEBUG
|
||||||
|
#log4j.logger.http=TRACE
|
||||||
|
#log4j.logger.monitor.memory=TRACE
|
||||||
|
#log4j.logger.monitor.memory=TRACE
|
||||||
|
#log4j.logger.cluster.action.shard=TRACE
|
||||||
|
#log4j.logger.index.gateway=TRACE
|
||||||
|
|
||||||
|
log4j.appender.out=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.out.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.out.layout.ConversionPattern=[%d{ABSOLUTE}][%-5p][%-25c] %m%n
|
|
@ -0,0 +1,136 @@
|
||||||
|
package org.elasticsearch.groovy.test.client
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import org.elasticsearch.action.index.IndexRequest
|
||||||
|
import org.elasticsearch.action.index.IndexResponse
|
||||||
|
import org.elasticsearch.groovy.node.GNode
|
||||||
|
import org.elasticsearch.groovy.node.GNodeBuilder
|
||||||
|
import static org.elasticsearch.client.Requests.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class SimpleActionsTests extends GroovyTestCase {
|
||||||
|
|
||||||
|
void testSimpleOperations() {
|
||||||
|
GNodeBuilder nodeBuilder = new GNodeBuilder()
|
||||||
|
nodeBuilder.settings {
|
||||||
|
node {
|
||||||
|
local = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GNode node = nodeBuilder.node
|
||||||
|
|
||||||
|
def response = node.client.index(new IndexRequest(
|
||||||
|
index: "test",
|
||||||
|
type: "type1",
|
||||||
|
id: "1",
|
||||||
|
source: {
|
||||||
|
test = "value"
|
||||||
|
complex {
|
||||||
|
value1 = "value1"
|
||||||
|
value2 = "value2"
|
||||||
|
}
|
||||||
|
})).response
|
||||||
|
assertEquals "test", response.index
|
||||||
|
assertEquals "type1", response.type
|
||||||
|
assertEquals "1", response.id
|
||||||
|
|
||||||
|
def refresh = node.client.admin.indices.refresh {}
|
||||||
|
assertEquals 0, refresh.response.failedShards
|
||||||
|
|
||||||
|
def getR = node.client.get {
|
||||||
|
index "test"
|
||||||
|
type "type1"
|
||||||
|
id "1"
|
||||||
|
}
|
||||||
|
assertTrue getR.response.exists
|
||||||
|
assertEquals "test", getR.response.index
|
||||||
|
assertEquals "type1", getR.response.type
|
||||||
|
assertEquals "1", getR.response.id
|
||||||
|
assertEquals '{"test":"value","complex":{"value1":"value1","value2":"value2"}}', getR.response.sourceAsString()
|
||||||
|
assertEquals "value", getR.response.source.test
|
||||||
|
assertEquals "value1", getR.response.source.complex.value1
|
||||||
|
|
||||||
|
response = node.client.index({
|
||||||
|
index = "test"
|
||||||
|
type = "type1"
|
||||||
|
id = "1"
|
||||||
|
source = {
|
||||||
|
test = "value"
|
||||||
|
complex {
|
||||||
|
value1 = "value1"
|
||||||
|
value2 = "value2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).response
|
||||||
|
assertEquals "test", response.index
|
||||||
|
assertEquals "type1", response.type
|
||||||
|
assertEquals "1", response.id
|
||||||
|
|
||||||
|
def indexR = node.client.index(indexRequest().with {
|
||||||
|
index "test"
|
||||||
|
type "type1"
|
||||||
|
id "1"
|
||||||
|
source {
|
||||||
|
test = "value"
|
||||||
|
complex {
|
||||||
|
value1 = "value1"
|
||||||
|
value2 = "value2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
CountDownLatch latch = new CountDownLatch(1)
|
||||||
|
indexR.success = {IndexResponse responseX ->
|
||||||
|
assertEquals "test", responseX.index
|
||||||
|
assertEquals "test", indexR.response.index
|
||||||
|
assertEquals "type1", responseX.type
|
||||||
|
assertEquals "type1", indexR.response.type
|
||||||
|
assertEquals "1", responseX.id
|
||||||
|
assertEquals "1", indexR.response.id
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
latch.await()
|
||||||
|
|
||||||
|
indexR = node.client.index {
|
||||||
|
index "test"
|
||||||
|
type "type1"
|
||||||
|
id "1"
|
||||||
|
source {
|
||||||
|
test = "value"
|
||||||
|
complex {
|
||||||
|
value1 = "value1"
|
||||||
|
value2 = "value2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
latch = new CountDownLatch(1)
|
||||||
|
indexR.listener = {
|
||||||
|
assertEquals "test", indexR.response.index
|
||||||
|
assertEquals "type1", indexR.response.type
|
||||||
|
assertEquals "1", indexR.response.id
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
latch.await()
|
||||||
|
|
||||||
|
def delete = node.client.delete {
|
||||||
|
index "test"
|
||||||
|
type "type1"
|
||||||
|
id "1"
|
||||||
|
}
|
||||||
|
assertEquals "test", delete.response.index
|
||||||
|
assertEquals "type1", delete.response.type
|
||||||
|
assertEquals "1", delete.response.id
|
||||||
|
|
||||||
|
refresh = node.client.admin.indices.refresh {}
|
||||||
|
assertEquals 0, refresh.response.failedShards
|
||||||
|
|
||||||
|
getR = node.client.get {
|
||||||
|
index "test"
|
||||||
|
type "type1"
|
||||||
|
id "1"
|
||||||
|
}
|
||||||
|
assertFalse getR.response.exists
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package org.elasticsearch.groovy.test.node
|
||||||
|
|
||||||
|
import org.elasticsearch.groovy.node.GNode
|
||||||
|
import org.elasticsearch.groovy.node.GNodeBuilder
|
||||||
|
import static org.elasticsearch.groovy.node.GNodeBuilder.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class GNodeBuilderTests extends GroovyTestCase {
|
||||||
|
|
||||||
|
void testGNodeBuilder() {
|
||||||
|
GNodeBuilder nodeBuilder = nodeBuilder();
|
||||||
|
nodeBuilder.settings {
|
||||||
|
node {
|
||||||
|
local = true
|
||||||
|
}
|
||||||
|
cluster {
|
||||||
|
name = "test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GNode node = nodeBuilder.node
|
||||||
|
node.stop.close
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
package org.elasticsearch.groovy.util.json
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
class JsonBuilderTests extends GroovyTestCase {
|
||||||
|
|
||||||
|
void testSimple() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
rootprop = "something"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"rootprop":"something"}', result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
void testArrays() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
categories = ['a', 'b', 'c']
|
||||||
|
rootprop = "something"
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"categories":["a","b","c"],"rootprop":"something"}', result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSubObjects() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
categories = ['a', 'b', 'c']
|
||||||
|
rootprop = "something"
|
||||||
|
test {
|
||||||
|
subprop = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"categories":["a","b","c"],"rootprop":"something","test":{"subprop":10}}', result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAssignedObjects() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
categories = ['a', 'b', 'c']
|
||||||
|
rootprop = "something"
|
||||||
|
test = {
|
||||||
|
subprop = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"categories":["a","b","c"],"rootprop":"something","test":{"subprop":10}}', result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNamedArgumentHandling() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
categories = ['a', 'b', 'c']
|
||||||
|
rootprop = "something"
|
||||||
|
test subprop: 10, three: [1, 2, 3]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"categories":["a","b","c"],"rootprop":"something","test":{"subprop":10,"three":[1,2,3]}}', result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void testArrayOfClosures() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
foo = [{ bar = "hello" }]
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"foo":[{"bar":"hello"}]}', result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRootElementList() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
|
||||||
|
def results = ['one', 'two', 'three']
|
||||||
|
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
for (b in results) {
|
||||||
|
element b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '["one","two","three"]', result.toString()
|
||||||
|
|
||||||
|
result = builder.buildAsString {
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '["one","two","three"]', result.toString()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void testExampleFromReferenceGuide() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
|
||||||
|
def results = ['one', 'two', 'three']
|
||||||
|
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
for (b in results) {
|
||||||
|
element title: b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '[{"title":"one"},{"title":"two"},{"title":"three"}]', result.toString()
|
||||||
|
|
||||||
|
|
||||||
|
result = builder.buildAsString {
|
||||||
|
books = results.collect {
|
||||||
|
[title: it]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"books":[{"title":"one"},{"title":"two"},{"title":"three"}]}', result.toString()
|
||||||
|
|
||||||
|
result = builder.buildAsString {
|
||||||
|
books = array {
|
||||||
|
for (b in results) {
|
||||||
|
book title: b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"books":[{"title":"one"},{"title":"two"},{"title":"three"}]}', result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAppendToArray() {
|
||||||
|
def builder = new JsonBuilder()
|
||||||
|
|
||||||
|
def results = ['one', 'two', 'three']
|
||||||
|
|
||||||
|
def result = builder.buildAsString {
|
||||||
|
books = array {list ->
|
||||||
|
for (b in results) {
|
||||||
|
list << [title: b]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals '{"books":[{"title":"one"},{"title":"two"},{"title":"three"}]}', result.toString()
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ include 'test-integration'
|
||||||
include 'benchmark-micro'
|
include 'benchmark-micro'
|
||||||
|
|
||||||
include 'plugins-attachments'
|
include 'plugins-attachments'
|
||||||
|
include 'plugins-groovy'
|
||||||
|
|
||||||
rootProject.name = 'elasticsearch-root'
|
rootProject.name = 'elasticsearch-root'
|
||||||
rootProject.children.each {project ->
|
rootProject.children.each {project ->
|
||||||
|
|
Loading…
Reference in New Issue