start work on the groovy plugin

This commit is contained in:
kimchy 2010-04-14 08:34:47 +03:00
parent 913bc2f947
commit cb7e92b0f8
44 changed files with 1886 additions and 245 deletions

View File

@ -30,6 +30,7 @@
<w>jgroups</w>
<w>joda</w>
<w>jsonp</w>
<w>kimchy</w>
<w>lifecycle</w>
<w>linefeeds</w>
<w>lucene</w>

View File

@ -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-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-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-testng.iml" filepath="$PROJECT_DIR$/.idea/modules//test-testng.iml" />
</modules>

View File

@ -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>

View File

@ -18,6 +18,12 @@ explodedDistLibDir = new File(explodedDistDir, 'lib')
explodedDistBinDir = new File(explodedDistDir, 'bin')
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 {
group = 'org.elasticsearch'

View File

@ -97,15 +97,12 @@ artifacts {
uploadArchives {
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
repository(url: "http://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
repository(url: rootProject.mavenRepoUrl) {
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
}
snapshotRepository(url: "http://oss.sonatype.org/content/repositories/snapshots") {
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
snapshotRepository(url: rootProject.mavenSnapshotRepoUrl) {
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
}
pom.project {

View File

@ -20,11 +20,19 @@
package org.elasticsearch.action;
/**
* @author kimchy (Shay Banon)
* A listener for action responses or failures.
*
* @author kimchy (shay.banon)
*/
public interface ActionListener<Response> {
/**
* A response handler.
*/
void onResponse(Response response);
/**
* A failure handler.
*/
void onFailure(Throwable e);
}

View File

@ -22,7 +22,7 @@ package org.elasticsearch.action;
import org.elasticsearch.util.io.stream.Streamable;
/**
* @author kimchy (Shay Banon)
* @author kimchy (shay.banon)
*/
public interface ActionRequest extends Streamable {

View File

@ -22,7 +22,7 @@ package org.elasticsearch.action;
import org.elasticsearch.util.io.stream.Streamable;
/**
* @author kimchy (Shay Banon)
* @author kimchy (shay.banon)
*/
public interface ActionResponse extends Streamable {
}

View File

@ -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);
}

View File

@ -58,6 +58,13 @@ public class DeleteResponse implements ActionResponse, Streamable {
return this.index;
}
/**
* The index the document was deleted from.
*/
public String getIndex() {
return index;
}
/**
* The type of the document deleted.
*/
@ -65,6 +72,13 @@ public class DeleteResponse implements ActionResponse, Streamable {
return this.type;
}
/**
* The type of the document deleted.
*/
public String getType() {
return type;
}
/**
* The id of the document deleted.
*/
@ -72,6 +86,13 @@ public class DeleteResponse implements ActionResponse, Streamable {
return this.id;
}
/**
* The id of the document deleted.
*/
public String getId() {
return id;
}
@Override public void readFrom(StreamInput in) throws IOException {
index = in.readUTF();
id = in.readUTF();

View File

@ -50,10 +50,18 @@ public class GetField implements Streamable, Iterable<Object> {
return name;
}
public String getName() {
return name;
}
public List<Object> values() {
return values;
}
public List<Object> getValues() {
return values;
}
@Override public Iterator<Object> iterator() {
return values.iterator();
}

View File

@ -55,6 +55,8 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
private Map<String, GetField> fields;
private Map<String, Object> sourceAsMap;
private byte[] source;
GetResponse() {
@ -79,6 +81,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
return exists;
}
/**
* Does the document exists.
*/
public boolean isExists() {
return exists;
}
/**
* The index the document was fetched from.
*/
@ -86,6 +95,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
return this.index;
}
/**
* The index the document was fetched from.
*/
public String getIndex() {
return index;
}
/**
* The type of the document.
*/
@ -93,6 +109,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
return type;
}
/**
* The type of the document.
*/
public String getType() {
return type;
}
/**
* The id of the document.
*/
@ -100,6 +123,13 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
return id;
}
/**
* The id of the document.
*/
public String getId() {
return id;
}
/**
* The source of the document if exists.
*/
@ -125,17 +155,29 @@ public class GetResponse implements ActionResponse, Streamable, Iterable<GetFiel
if (source == null) {
return null;
}
if (sourceAsMap != null) {
return sourceAsMap;
}
try {
return defaultObjectMapper().readValue(source, 0, source.length, Map.class);
sourceAsMap = defaultObjectMapper().readValue(source, 0, source.length, Map.class);
return sourceAsMap;
} catch (Exception e) {
throw new ElasticSearchParseException("Failed to parse source to map", e);
}
}
public Map<String, Object> getSource() {
return sourceAsMap();
}
public Map<String, GetField> fields() {
return this.fields;
}
public Map<String, GetField> getFields() {
return fields;
}
public GetField field(String name) {
return fields.get(name);
}

View File

@ -104,6 +104,9 @@ public class IndexRequest extends ShardReplicationOperationRequest {
private byte[] source;
private OpType opType = OpType.INDEX;
public IndexRequest() {
}
/**
* Constructs a new index request against the specific index. The {@link #type(String)},
* {@link #id(String)} and {@link #source(byte[])} must be set.
@ -127,9 +130,6 @@ public class IndexRequest extends ShardReplicationOperationRequest {
this.source = source;
}
IndexRequest() {
}
@Override public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = super.validate();
if (type == null) {

View File

@ -58,6 +58,13 @@ public class IndexResponse implements ActionResponse, Streamable {
return this.index;
}
/**
* The index the document was indexed into.
*/
public String getIndex() {
return index;
}
/**
* The type of the document indexed.
*/
@ -65,6 +72,13 @@ public class IndexResponse implements ActionResponse, Streamable {
return this.type;
}
/**
* The type of the document indexed.
*/
public String getType() {
return type;
}
/**
* The id of the document indexed.
*/
@ -72,6 +86,13 @@ public class IndexResponse implements ActionResponse, Streamable {
return this.id;
}
/**
* The id of the document indexed.
*/
public String getId() {
return id;
}
@Override public void readFrom(StreamInput in) throws IOException {
index = in.readUTF();
id = in.readUTF();

View File

@ -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);
}
}
}
}
}

View File

@ -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);
}

View File

@ -19,143 +19,16 @@
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)
*/
public class PlainActionFuture<T> implements ActionFuture<T>, ActionListener<T> {
public class PlainActionFuture<T> extends AdapterActionFuture<T, T> {
public static <T> PlainActionFuture<T> newFuture() {
return new PlainActionFuture<T>();
}
private final CountDownLatch latch;
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();
@Override protected T convert(T listenerResponse) {
return listenerResponse;
}
}

View File

@ -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;
}
}

View File

@ -66,6 +66,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
return totalShards;
}
/**
* The total shards this request ran against.
*/
public int getTotalShards() {
return totalShards;
}
/**
* The successful shards this request was executed on.
*/
@ -73,6 +80,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
return successfulShards;
}
/**
* The successful shards this request was executed on.
*/
public int getSuccessfulShards() {
return successfulShards;
}
/**
* The failed shards this request was executed on.
*/
@ -80,6 +94,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
return failedShards;
}
/**
* The failed shards this request was executed on.
*/
public int getFailedShards() {
return failedShards;
}
/**
* The list of shard failures exception.
*/
@ -90,6 +111,13 @@ public abstract class BroadcastOperationResponse implements ActionResponse {
return shardFailures;
}
/**
* The list of shard failures exception.
*/
public List<ShardOperationFailedException> getShardFailures() {
return shardFailures;
}
@Override public void readFrom(StreamInput in) throws IOException {
totalShards = in.readVInt();
successfulShards = in.readVInt();

View File

@ -53,6 +53,10 @@ import org.elasticsearch.action.terms.TermsRequest;
*/
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
* set as well and optionally the {@link IndexRequest#id(String)}.

View File

@ -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();
}

View File

@ -44,14 +44,17 @@ import org.elasticsearch.action.terms.TermsRequest;
import org.elasticsearch.action.terms.TermsResponse;
import org.elasticsearch.action.terms.TransportTermsAction;
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.settings.Settings;
/**
* @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;
@ -73,12 +76,13 @@ public class NodeClient extends AbstractComponent implements Client {
private final TransportMoreLikeThisAction moreLikeThisAction;
@Inject public NodeClient(Settings settings, NodeAdminClient admin,
@Inject public NodeClient(Settings settings, ThreadPool threadPool, NodeAdminClient admin,
TransportIndexAction indexAction, TransportDeleteAction deleteAction,
TransportDeleteByQueryAction deleteByQueryAction, TransportGetAction getAction, TransportCountAction countAction,
TransportSearchAction searchAction, TransportSearchScrollAction searchScrollAction,
TransportTermsAction termsAction, TransportMoreLikeThisAction moreLikeThisAction) {
super(settings);
this.threadPool = threadPool;
this.admin = admin;
this.indexAction = indexAction;
this.deleteAction = deleteAction;
@ -91,6 +95,10 @@ public class NodeClient extends AbstractComponent implements Client {
this.moreLikeThisAction = moreLikeThisAction;
}
@Override public ThreadPool threadPool() {
return this.threadPool;
}
@Override public void close() {
// nothing really to do
}

View File

@ -43,7 +43,7 @@ import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.terms.TermsRequest;
import org.elasticsearch.action.terms.TermsResponse;
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.support.InternalTransportClient;
import org.elasticsearch.cluster.ClusterNameModule;
@ -77,7 +77,7 @@ import static org.elasticsearch.util.settings.ImmutableSettings.*;
*
* @author kimchy (shay.banon)
*/
public class TransportClient implements Client {
public class TransportClient implements InternalClient {
private final Injector injector;
@ -209,6 +209,10 @@ public class TransportClient implements Client {
ThreadLocals.clearReferencesThreadLocals();
}
@Override public ThreadPool threadPool() {
return internalClient.threadPool();
}
@Override public AdminClient admin() {
return internalClient.admin();
}

View File

@ -40,7 +40,7 @@ import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.terms.TermsRequest;
import org.elasticsearch.action.terms.TermsResponse;
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.action.count.ClientTransportCountAction;
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.terms.ClientTransportTermsAction;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.util.component.AbstractComponent;
import org.elasticsearch.util.settings.Settings;
/**
* @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;
@ -82,12 +85,14 @@ public class InternalTransportClient extends AbstractComponent implements Client
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,
ClientTransportDeleteByQueryAction deleteByQueryAction, ClientTransportCountAction countAction,
ClientTransportSearchAction searchAction, ClientTransportSearchScrollAction searchScrollAction,
ClientTransportTermsAction termsAction, ClientTransportMoreLikeThisAction moreLikeThisAction) {
super(settings);
this.threadPool = threadPool;
this.nodesService = nodesService;
this.adminClient = adminClient;
@ -106,6 +111,10 @@ public class InternalTransportClient extends AbstractComponent implements Client
// nothing to do here
}
@Override public ThreadPool threadPool() {
return this.threadPool;
}
@Override public AdminClient admin() {
return adminClient;
}

View File

@ -21,73 +21,22 @@ package org.elasticsearch.transport;
import org.elasticsearch.ElasticSearchException;
import org.elasticsearch.ElasticSearchInterruptedException;
import org.elasticsearch.util.concurrent.AbstractFuture;
import org.elasticsearch.util.io.stream.Streamable;
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 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 volatile boolean done;
private volatile boolean canceled;
private volatile V result;
private volatile Exception exp;
public PlainTransportFuture(TransportResponseHandler<V> 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 {
@ -123,25 +72,13 @@ public class PlainTransportFuture<V extends Streamable> implements TransportFutu
}
@Override public void handleResponse(V response) {
this.done = true;
this.result = response;
if (canceled)
return;
handler.handleResponse(response);
latch.countDown();
set(response);
}
@Override public void handleException(RemoteTransportException exp) {
this.done = true;
this.exp = exp;
if (canceled)
return;
handler.handleException(exp);
latch.countDown();
setException(exp);
}
@Override public boolean spawn() {

View File

@ -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;
}
}
}

View File

@ -65,8 +65,6 @@ public class BinaryJsonBuilder extends JsonBuilder<BinaryJsonBuilder> {
private final JsonFactory factory;
private StringBuilder cachedStringBuilder;
public BinaryJsonBuilder() throws IOException {
this(Jackson.defaultJsonFactory());
}
@ -85,10 +83,6 @@ public class BinaryJsonBuilder extends JsonBuilder<BinaryJsonBuilder> {
this.builder = this;
}
@Override protected StringBuilder cachedStringBuilder() {
return cachedStringBuilder;
}
@Override public BinaryJsonBuilder raw(byte[] json) throws IOException {
flush();
bos.write(json);

View File

@ -69,6 +69,8 @@ public abstract class JsonBuilder<T extends JsonBuilder> {
protected FieldCaseConversion fieldCaseConversion = globalFieldCaseConversion;
protected StringBuilder cachedStringBuilder;
public static StringJsonBuilder stringJsonBuilder() throws IOException {
return StringJsonBuilder.Cached.cached();
}
@ -143,9 +145,9 @@ public abstract class JsonBuilder<T extends JsonBuilder> {
public T field(String name) throws IOException {
if (fieldCaseConversion == FieldCaseConversion.UNDERSCORE) {
name = Strings.toUnderscoreCase(name);
name = Strings.toUnderscoreCase(name, cachedStringBuilder);
} else if (fieldCaseConversion == FieldCaseConversion.CAMELCASE) {
name = Strings.toCamelCase(name);
name = Strings.toCamelCase(name, cachedStringBuilder);
}
generator.writeFieldName(name);
return builder;
@ -403,10 +405,6 @@ public abstract class JsonBuilder<T extends JsonBuilder> {
public abstract String string() throws IOException;
protected StringBuilder cachedStringBuilder() {
return null;
}
public void close() {
try {
generator.close();

View File

@ -69,8 +69,6 @@ public class StringJsonBuilder extends JsonBuilder<StringJsonBuilder> {
final UnicodeUtil.UTF8Result utf8Result = new UnicodeUtil.UTF8Result();
private StringBuilder cachedStringBuilder;
public StringJsonBuilder() throws IOException {
this(Jackson.defaultJsonFactory());
}
@ -89,10 +87,6 @@ public class StringJsonBuilder extends JsonBuilder<StringJsonBuilder> {
this.builder = this;
}
@Override protected StringBuilder cachedStringBuilder() {
return cachedStringBuilder;
}
@Override public StringJsonBuilder raw(byte[] json) throws IOException {
flush();
Unicode.UTF16Result result = Unicode.unsafeFromBytesAsUtf16(json);

View File

@ -107,15 +107,12 @@ artifacts {
uploadArchives {
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
repository(url: "http://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
repository(url: rootProject.mavenRepoUrl) {
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
}
snapshotRepository(url: "http://oss.sonatype.org/content/repositories/snapshots") {
authentication(userName: "kimchy", password: System.getenv("REPO_PASS"))
snapshotRepository(url: rootProject.mavenSnapshotRepoUrl) {
authentication(userName: rootProject.mavenRepoUser, password: rootProject.mavenRepoPass)
}
pom.project {

138
plugins/groovy/build.gradle Normal file
View File

@ -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
}
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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();
}
}

View File

@ -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)
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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]
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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()
}
}

View File

@ -7,6 +7,7 @@ include 'test-integration'
include 'benchmark-micro'
include 'plugins-attachments'
include 'plugins-groovy'
rootProject.name = 'elasticsearch-root'
rootProject.children.each {project ->