elasticsearch 的 jvm插件要实现Plugin接口,或者继承子AbstractPlugin抽象类。可以实现 Module 和 Services 两种组件,它们分别有 3个 生命周期 global , index ,shard 。
整体的项目结构是这样的。
我们这里继承子AbstractPlugin ,来增加我们的 TranslogRestModule 模块
package org.elasticsearch.plugin.translog;
import java.util.Collection;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.plugins.AbstractPlugin;
public class TranslogRestPlugin extends AbstractPlugin{
public String name() {
return "translog-rest";
}
@Override
public String description() {
return "view translog";
}
@Override
public Collection<Class<? extends Module>> modules() {
Collection<Class<? extends Module>> modules = Lists.newArrayList();
modules.add(TranslogRestModule.class);
return modules;
}
}
TranslogRestModule类 ,实例化我们的 TranslogRestHandler
package org.elasticsearch.plugin.translog;
import org.elasticsearch.common.inject.AbstractModule;
public class TranslogRestModule extends AbstractModule {
@Override
protected void configure() {
bind(TranslogRestHandler.class).asEagerSingleton();
}
}
TranslogRestHandler是我们最主要的一个类 , 他负责处理 /_translog 这个REST请求,通过 TranslogStreams.readTranslogOperation 方法读取 Translog 然后用 XContentBuilder 构造 JSON格式 ,返回给客户端。
package org.elasticsearch.plugin.translog;
import java.io.FileInputStream;
import java.io.IOException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.InputStreamStreamInput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.translog.Translog;
import org.elasticsearch.index.translog.TranslogStreams;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestXContentBuilder;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.OK;
public class TranslogRestHandler implements RestHandler{
private XContentBuilder builder;
@Inject
public TranslogRestHandler(RestController restController) {
restController.registerHandler(GET, "/_translog", this);
}
public void buildSave(Translog.Index op){
try {
builder.startObject()
.field("opType").value("save")
.field("id").value(op.id())
.field("type").value(op.type())
.field("version").value(op.version())
.field("routing").value(op.routing())
.field("parent").value(op.parent())
.field("timestamp").value(op.timestamp())
.field("ttl").value(op.ttl())
.field("version").value(op.version())
.field("source").value(op.source().toUtf8())
.endObject();
} catch (IOException e) {
e.printStackTrace();
}
}
public void buildCreate(Translog.Create op){
try {
builder.startObject()
.field("opType").value("create")
.field("id").value(op.id())
.field("type").value(op.type())
.field("version").value(op.version())
.field("routing").value(op.routing())
.field("parent").value(op.parent())
.field("timestamp").value(op.timestamp())
.field("ttl").value(op.ttl())
.field("version").value(op.version())
.field("source").value(op.source().toUtf8())
.endObject();
} catch (IOException e) {
e.printStackTrace();
}
}
public void buildDelete(Translog.Delete op){
try {
builder.startObject()
.field("opType").value("delete")
.field("id").value(op.uid().text())
.field("version").value(op.version())
.endObject();
} catch (IOException e) {
e.printStackTrace();
}
}
public void buildDeleteByQuery(Translog.DeleteByQuery op){
try {
builder.startObject()
.field("opType").value("deleteByQuery")
.field("source").value(op.source().toUtf8())
.endObject();
} catch (IOException e) {
e.printStackTrace();
}
}
public XContentBuilder buildTranslog(String filePath,int size){
FileInputStream fs = null;
int count = 0;
try {
fs = new FileInputStream(filePath);
InputStreamStreamInput si = new InputStreamStreamInput(fs);
while (true) {
if(count>=size){
break;
}
Translog.Operation operation;
try {
int opSize = si.readInt();
// System.out.println("opSize = "+opSize);
operation = TranslogStreams.readTranslogOperation(si);
switch (operation.opType()) {
case CREATE:
Translog.Create create = (Translog.Create) operation;
buildCreate(create);
break;
case SAVE:
Translog.Index index = (Translog.Index) operation;
buildSave(index);
break;
case DELETE:
Translog.Delete delete = (Translog.Delete) operation;
buildDelete(delete);
break;
case DELETE_BY_QUERY:
Translog.DeleteByQuery dbq = (Translog.DeleteByQuery) operation;
buildDeleteByQuery(dbq);
break;
default:
System.out.println("Invaid Operation Type");
break;
}
count++;
}catch(Exception e){
break;
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=fs){
try {
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return builder;
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel) {
String file = request.param("file");
String sizeStr = request.param("size");
int size = 10;
if(null!=sizeStr){
size = Integer.parseInt(sizeStr);
}
try {
builder = RestXContentBuilder.restContentBuilder(request);
if(null!=file){
builder.startArray();
buildTranslog(file,size);
builder.endArray();
}else{
builder.startObject()
.field("success").value(false)
.field("error").value("缺少参数:file")
.endObject();
}
channel.sendResponse(new XContentRestResponse(request,OK,builder));
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后 es-plugin.properties 这个配置文件,是我们必须的一个类,它主要告诉ES, 哪个类是我们插件的实现类 ,对于site插件,提供插件的名称和描述信息,细节可以参考 PluginsService类 和 loadPluginsFromClasspath 方法
plugin=org.elasticsearch.plugin.translog.TranslogRestPlugin
好了,现在可以去安装我们的插件了。有2个办法。
手动安装,导出Jar包,复制到 /plugins/translogRest/TranslogRest.jar 下面。
命令安装,plugin --install translogRest --url file:/d:/TranslogRest.jar
浏览器里或者curl
http://localhost:9200/_translog?pretty=true
返回
{
success: false,
error: "缺少参数:file"
}
表示我们的插件,已经安装成功。