diff --git a/build.xml b/build.xml index 6affa3a..cffea64 100644 --- a/build.xml +++ b/build.xml @@ -5,7 +5,7 @@ - + @@ -84,8 +84,8 @@ - - + + diff --git a/lib/HdrHistogram-2.1.9.jar b/lib/HdrHistogram-2.1.9.jar new file mode 100644 index 0000000..efa2637 Binary files /dev/null and b/lib/HdrHistogram-2.1.9.jar differ diff --git a/lib/accessors-smart-1.2.jar b/lib/accessors-smart-1.2.jar new file mode 100644 index 0000000..f4505e9 Binary files /dev/null and b/lib/accessors-smart-1.2.jar differ diff --git a/lib/aggs-matrix-stats-client-7.5.1.jar b/lib/aggs-matrix-stats-client-7.5.1.jar new file mode 100644 index 0000000..d469f2e Binary files /dev/null and b/lib/aggs-matrix-stats-client-7.5.1.jar differ diff --git a/lib/asm-5.0.4.jar b/lib/asm-5.0.4.jar new file mode 100644 index 0000000..cdb283d Binary files /dev/null and b/lib/asm-5.0.4.jar differ diff --git a/lib/commons-codec-1.11.jar b/lib/commons-codec-1.11.jar new file mode 100644 index 0000000..2245120 Binary files /dev/null and b/lib/commons-codec-1.11.jar differ diff --git a/lib/commons-logging-1.1.3.jar b/lib/commons-logging-1.1.3.jar new file mode 100644 index 0000000..ab51254 Binary files /dev/null and b/lib/commons-logging-1.1.3.jar differ diff --git a/lib/compiler-0.9.6.jar b/lib/compiler-0.9.6.jar new file mode 100644 index 0000000..96578e3 Binary files /dev/null and b/lib/compiler-0.9.6.jar differ diff --git a/lib/elasticsearch-7.5.1.jar b/lib/elasticsearch-7.5.1.jar new file mode 100644 index 0000000..46df036 Binary files /dev/null and b/lib/elasticsearch-7.5.1.jar differ diff --git a/lib/elasticsearch-cli-7.5.1.jar b/lib/elasticsearch-cli-7.5.1.jar new file mode 100644 index 0000000..d65e2c5 Binary files /dev/null and b/lib/elasticsearch-cli-7.5.1.jar differ diff --git a/lib/elasticsearch-core-7.5.1.jar b/lib/elasticsearch-core-7.5.1.jar new file mode 100644 index 0000000..c33a7e6 Binary files /dev/null and b/lib/elasticsearch-core-7.5.1.jar differ diff --git a/lib/elasticsearch-geo-7.5.1.jar b/lib/elasticsearch-geo-7.5.1.jar new file mode 100644 index 0000000..5a2d130 Binary files /dev/null and b/lib/elasticsearch-geo-7.5.1.jar differ diff --git a/lib/elasticsearch-rest-client-7.5.1.jar b/lib/elasticsearch-rest-client-7.5.1.jar new file mode 100644 index 0000000..eeea30b Binary files /dev/null and b/lib/elasticsearch-rest-client-7.5.1.jar differ diff --git a/lib/elasticsearch-rest-high-level-client-7.5.1.jar b/lib/elasticsearch-rest-high-level-client-7.5.1.jar new file mode 100644 index 0000000..68efe0c Binary files /dev/null and b/lib/elasticsearch-rest-high-level-client-7.5.1.jar differ diff --git a/lib/elasticsearch-secure-sm-7.5.1.jar b/lib/elasticsearch-secure-sm-7.5.1.jar new file mode 100644 index 0000000..e2a113e Binary files /dev/null and b/lib/elasticsearch-secure-sm-7.5.1.jar differ diff --git a/lib/elasticsearch-ssl-config-7.5.1.jar b/lib/elasticsearch-ssl-config-7.5.1.jar new file mode 100644 index 0000000..0c44a95 Binary files /dev/null and b/lib/elasticsearch-ssl-config-7.5.1.jar differ diff --git a/lib/elasticsearch-x-content-7.5.1.jar b/lib/elasticsearch-x-content-7.5.1.jar new file mode 100644 index 0000000..b1b6234 Binary files /dev/null and b/lib/elasticsearch-x-content-7.5.1.jar differ diff --git a/lib/hppc-0.8.1.jar b/lib/hppc-0.8.1.jar new file mode 100644 index 0000000..39a7c24 Binary files /dev/null and b/lib/hppc-0.8.1.jar differ diff --git a/lib/httpasyncclient-4.1.4.jar b/lib/httpasyncclient-4.1.4.jar new file mode 100644 index 0000000..e6b3b29 Binary files /dev/null and b/lib/httpasyncclient-4.1.4.jar differ diff --git a/lib/httpclient-4.5.10.jar b/lib/httpclient-4.5.10.jar new file mode 100644 index 0000000..d0c7821 Binary files /dev/null and b/lib/httpclient-4.5.10.jar differ diff --git a/lib/httpcore-4.4.12.jar b/lib/httpcore-4.4.12.jar new file mode 100644 index 0000000..1838672 Binary files /dev/null and b/lib/httpcore-4.4.12.jar differ diff --git a/lib/httpcore-nio-4.4.12.jar b/lib/httpcore-nio-4.4.12.jar new file mode 100644 index 0000000..b6183e6 Binary files /dev/null and b/lib/httpcore-nio-4.4.12.jar differ diff --git a/lib/jackson-core-2.8.11.jar b/lib/jackson-core-2.8.11.jar new file mode 100644 index 0000000..27caa12 Binary files /dev/null and b/lib/jackson-core-2.8.11.jar differ diff --git a/lib/jackson-dataformat-cbor-2.8.11.jar b/lib/jackson-dataformat-cbor-2.8.11.jar new file mode 100644 index 0000000..8330550 Binary files /dev/null and b/lib/jackson-dataformat-cbor-2.8.11.jar differ diff --git a/lib/jackson-dataformat-smile-2.8.11.jar b/lib/jackson-dataformat-smile-2.8.11.jar new file mode 100644 index 0000000..142c798 Binary files /dev/null and b/lib/jackson-dataformat-smile-2.8.11.jar differ diff --git a/lib/jackson-dataformat-yaml-2.8.11.jar b/lib/jackson-dataformat-yaml-2.8.11.jar new file mode 100644 index 0000000..9054d1e Binary files /dev/null and b/lib/jackson-dataformat-yaml-2.8.11.jar differ diff --git a/lib/jna-4.5.1.jar b/lib/jna-4.5.1.jar new file mode 100644 index 0000000..e220187 Binary files /dev/null and b/lib/jna-4.5.1.jar differ diff --git a/lib/joda-time-2.10.3.jar b/lib/joda-time-2.10.3.jar new file mode 100644 index 0000000..0de2c0b Binary files /dev/null and b/lib/joda-time-2.10.3.jar differ diff --git a/lib/jopt-simple-5.0.2.jar b/lib/jopt-simple-5.0.2.jar new file mode 100644 index 0000000..2c7a087 Binary files /dev/null and b/lib/jopt-simple-5.0.2.jar differ diff --git a/lib/json-path-2.4.0.jar b/lib/json-path-2.4.0.jar new file mode 100644 index 0000000..6229306 Binary files /dev/null and b/lib/json-path-2.4.0.jar differ diff --git a/lib/json-smart-2.3.jar b/lib/json-smart-2.3.jar new file mode 100644 index 0000000..0cd52ea Binary files /dev/null and b/lib/json-smart-2.3.jar differ diff --git a/lib/lang-mustache-client-7.5.1.jar b/lib/lang-mustache-client-7.5.1.jar new file mode 100644 index 0000000..76db6dc Binary files /dev/null and b/lib/lang-mustache-client-7.5.1.jar differ diff --git a/lib/log4j-api-2.11.1.jar b/lib/log4j-api-2.11.1.jar new file mode 100644 index 0000000..96362a6 Binary files /dev/null and b/lib/log4j-api-2.11.1.jar differ diff --git a/lib/lucene-analyzers-common-8.3.0.jar b/lib/lucene-analyzers-common-8.3.0.jar new file mode 100644 index 0000000..c1eca15 Binary files /dev/null and b/lib/lucene-analyzers-common-8.3.0.jar differ diff --git a/lib/lucene-backward-codecs-8.3.0.jar b/lib/lucene-backward-codecs-8.3.0.jar new file mode 100644 index 0000000..54972f5 Binary files /dev/null and b/lib/lucene-backward-codecs-8.3.0.jar differ diff --git a/lib/lucene-core-8.3.0.jar b/lib/lucene-core-8.3.0.jar new file mode 100644 index 0000000..b647ec0 Binary files /dev/null and b/lib/lucene-core-8.3.0.jar differ diff --git a/lib/lucene-grouping-8.3.0.jar b/lib/lucene-grouping-8.3.0.jar new file mode 100644 index 0000000..47fc8fc Binary files /dev/null and b/lib/lucene-grouping-8.3.0.jar differ diff --git a/lib/lucene-highlighter-8.3.0.jar b/lib/lucene-highlighter-8.3.0.jar new file mode 100644 index 0000000..ae7f425 Binary files /dev/null and b/lib/lucene-highlighter-8.3.0.jar differ diff --git a/lib/lucene-join-8.3.0.jar b/lib/lucene-join-8.3.0.jar new file mode 100644 index 0000000..834bb8a Binary files /dev/null and b/lib/lucene-join-8.3.0.jar differ diff --git a/lib/lucene-memory-8.3.0.jar b/lib/lucene-memory-8.3.0.jar new file mode 100644 index 0000000..46c9d1d Binary files /dev/null and b/lib/lucene-memory-8.3.0.jar differ diff --git a/lib/lucene-misc-8.3.0.jar b/lib/lucene-misc-8.3.0.jar new file mode 100644 index 0000000..5f932fa Binary files /dev/null and b/lib/lucene-misc-8.3.0.jar differ diff --git a/lib/lucene-queries-8.3.0.jar b/lib/lucene-queries-8.3.0.jar new file mode 100644 index 0000000..7723369 Binary files /dev/null and b/lib/lucene-queries-8.3.0.jar differ diff --git a/lib/lucene-queryparser-8.3.0.jar b/lib/lucene-queryparser-8.3.0.jar new file mode 100644 index 0000000..f606b55 Binary files /dev/null and b/lib/lucene-queryparser-8.3.0.jar differ diff --git a/lib/lucene-sandbox-8.3.0.jar b/lib/lucene-sandbox-8.3.0.jar new file mode 100644 index 0000000..a17813d Binary files /dev/null and b/lib/lucene-sandbox-8.3.0.jar differ diff --git a/lib/lucene-spatial-8.3.0.jar b/lib/lucene-spatial-8.3.0.jar new file mode 100644 index 0000000..523f480 Binary files /dev/null and b/lib/lucene-spatial-8.3.0.jar differ diff --git a/lib/lucene-spatial-extras-8.3.0.jar b/lib/lucene-spatial-extras-8.3.0.jar new file mode 100644 index 0000000..90d4c52 Binary files /dev/null and b/lib/lucene-spatial-extras-8.3.0.jar differ diff --git a/lib/lucene-spatial3d-8.3.0.jar b/lib/lucene-spatial3d-8.3.0.jar new file mode 100644 index 0000000..a0b8b84 Binary files /dev/null and b/lib/lucene-spatial3d-8.3.0.jar differ diff --git a/lib/lucene-suggest-8.3.0.jar b/lib/lucene-suggest-8.3.0.jar new file mode 100644 index 0000000..dd97cf9 Binary files /dev/null and b/lib/lucene-suggest-8.3.0.jar differ diff --git a/lib/mapper-extras-client-7.5.1.jar b/lib/mapper-extras-client-7.5.1.jar new file mode 100644 index 0000000..50db20e Binary files /dev/null and b/lib/mapper-extras-client-7.5.1.jar differ diff --git a/lib/netty-buffer-4.1.43.Final.jar b/lib/netty-buffer-4.1.43.Final.jar new file mode 100644 index 0000000..bf9a298 Binary files /dev/null and b/lib/netty-buffer-4.1.43.Final.jar differ diff --git a/lib/netty-codec-4.1.43.Final.jar b/lib/netty-codec-4.1.43.Final.jar new file mode 100644 index 0000000..bafba25 Binary files /dev/null and b/lib/netty-codec-4.1.43.Final.jar differ diff --git a/lib/netty-codec-http-4.1.43.Final.jar b/lib/netty-codec-http-4.1.43.Final.jar new file mode 100644 index 0000000..fbb830a Binary files /dev/null and b/lib/netty-codec-http-4.1.43.Final.jar differ diff --git a/lib/netty-common-4.1.43.Final.jar b/lib/netty-common-4.1.43.Final.jar new file mode 100644 index 0000000..3bad97e Binary files /dev/null and b/lib/netty-common-4.1.43.Final.jar differ diff --git a/lib/netty-handler-4.1.43.Final.jar b/lib/netty-handler-4.1.43.Final.jar new file mode 100644 index 0000000..7a2cac1 Binary files /dev/null and b/lib/netty-handler-4.1.43.Final.jar differ diff --git a/lib/netty-resolver-4.1.43.Final.jar b/lib/netty-resolver-4.1.43.Final.jar new file mode 100644 index 0000000..3a8ad38 Binary files /dev/null and b/lib/netty-resolver-4.1.43.Final.jar differ diff --git a/lib/netty-transport-4.1.43.Final.jar b/lib/netty-transport-4.1.43.Final.jar new file mode 100644 index 0000000..870e7c3 Binary files /dev/null and b/lib/netty-transport-4.1.43.Final.jar differ diff --git a/lib/parent-join-client-7.5.1.jar b/lib/parent-join-client-7.5.1.jar new file mode 100644 index 0000000..1f6f582 Binary files /dev/null and b/lib/parent-join-client-7.5.1.jar differ diff --git a/lib/percolator-client-7.5.1.jar b/lib/percolator-client-7.5.1.jar new file mode 100644 index 0000000..9144c02 Binary files /dev/null and b/lib/percolator-client-7.5.1.jar differ diff --git a/lib/rank-eval-client-7.5.1.jar b/lib/rank-eval-client-7.5.1.jar new file mode 100644 index 0000000..10cb622 Binary files /dev/null and b/lib/rank-eval-client-7.5.1.jar differ diff --git a/lib/reindex-client-7.5.1.jar b/lib/reindex-client-7.5.1.jar new file mode 100644 index 0000000..fad3b00 Binary files /dev/null and b/lib/reindex-client-7.5.1.jar differ diff --git a/lib/slf4j-api-1.7.25.jar b/lib/slf4j-api-1.7.25.jar new file mode 100644 index 0000000..0143c09 Binary files /dev/null and b/lib/slf4j-api-1.7.25.jar differ diff --git a/lib/snakeyaml-1.17.jar b/lib/snakeyaml-1.17.jar new file mode 100644 index 0000000..b0372a3 Binary files /dev/null and b/lib/snakeyaml-1.17.jar differ diff --git a/lib/t-digest-3.2.jar b/lib/t-digest-3.2.jar new file mode 100644 index 0000000..2f14401 Binary files /dev/null and b/lib/t-digest-3.2.jar differ diff --git a/lib/transport-7.5.1.jar b/lib/transport-7.5.1.jar new file mode 100644 index 0000000..cd0eb3f Binary files /dev/null and b/lib/transport-7.5.1.jar differ diff --git a/lib/transport-netty4-client-7.5.1.jar b/lib/transport-netty4-client-7.5.1.jar new file mode 100644 index 0000000..eebe310 Binary files /dev/null and b/lib/transport-netty4-client-7.5.1.jar differ diff --git a/plugin.xml b/plugin.xml index c18d224..b230c14 100644 --- a/plugin.xml +++ b/plugin.xml @@ -3,14 +3,18 @@ com.fr.plugin.db.es.v10 yes - 1.0 + 1.1 10.0 2019-10-25 fanruan.richie [2019-12-31]初始化插件。
]]>
+ + net.minidev.json + diff --git a/pom.xml b/pom.xml index fcc20c9..c59d855 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,6 @@ starter 10.0 - jar com.fr.plugin.db.es.v10 @@ -19,6 +18,11 @@ system ${project.basedir}/lib/finekit-10.0.jar + + com.jayway.jsonpath + json-path + 2.4.0 + org.elasticsearch.client transport @@ -45,10 +49,28 @@ org.apache.maven.plugins maven-compiler-plugin - 6 - 6 + 8 + 8 + + org.apache.maven.plugins + maven-dependency-plugin + + + copy + package + + copy-dependencies + + + + ${project.basedir}/lib + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md index f424a57..ac487ad 100644 --- a/readme.md +++ b/readme.md @@ -1 +1,19 @@ -# elasticsearch数据集插件 \ No newline at end of file +# Elasticsearch数据集插件 + +## 新建Elasticsearch数据连接 + +![connection](screenshots/connection.png) + +支持连接集群,以逗号分隔多个主机地址和端口即可,确保主机地址和端口数量一致。 + +## 新建Elasticsearch数据集 + +![tabledata](screenshots/tabledata.png) + +左侧区域是用于测试的,输入Elasticsearch命令后,点击执行按钮,可以在左下角输出区看到输出结果; + +右侧区域是用于实际查询的,每一个输入框区域都可以使用${p}的格式带入参数。 + +## 预览Elasticsearch数据集 + +![preview](screenshots/preview.png) \ No newline at end of file diff --git a/screenshots/connection.png b/screenshots/connection.png new file mode 100644 index 0000000..ff88fff Binary files /dev/null and b/screenshots/connection.png differ diff --git a/screenshots/preview.png b/screenshots/preview.png new file mode 100644 index 0000000..8f318fa Binary files /dev/null and b/screenshots/preview.png differ diff --git a/screenshots/tabledata.png b/screenshots/tabledata.png new file mode 100644 index 0000000..1997cee Binary files /dev/null and b/screenshots/tabledata.png differ diff --git a/src/main/java/com/fr/plugin/db/es/fun/ConfigAttribute.java b/src/main/java/com/fr/plugin/db/es/fun/ConfigAttribute.java new file mode 100644 index 0000000..a4d2c83 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/ConfigAttribute.java @@ -0,0 +1,85 @@ +package com.fr.plugin.db.es.fun; + +import com.fanruan.api.conf.BaseUniqueKey; +import com.fanruan.api.conf.HolderKit; +import com.fanruan.api.util.AssistKit; +import com.fr.config.holder.Conf; +import com.fr.stable.xml.XMLPrintWriter; +import com.fr.stable.xml.XMLable; +import com.fr.stable.xml.XMLableReader; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class ConfigAttribute extends BaseUniqueKey implements XMLable { + + public static final String XML_TAG = "ConfigAttribute"; + private static final long serialVersionUID = -2125057720890342129L; + + private Conf sorted = HolderKit.simple(false); + private Conf prepare = HolderKit.simple(false); + + + public ConfigAttribute() { + + } + + public boolean isSorted() { + return sorted.get(); + } + + public void setSorted(boolean sorted) { + this.sorted.set(sorted); + } + + public boolean isPrepare() { + return prepare.get(); + } + + public void setPrepare(boolean prepare) { + this.prepare.set(prepare); + } + + + @Override + public void readXML(XMLableReader reader) { + if (reader.isChildNode()) { + String tagName = reader.getTagName(); + if ("Attr".equals(tagName)) { + sorted.set(reader.getAttrAsBoolean("sorted", false)); + prepare.set(reader.getAttrAsBoolean("prepare", false)); + } + } + } + + @Override + public void writeXML(XMLPrintWriter writer) { + writer.startTAG("Attr"); + writer.attr("sorted", sorted.get()); + writer.attr("prepare", prepare.get()); + writer.end(); + } + + @Override + @SuppressWarnings("unchecked") + public Object clone() throws CloneNotSupportedException { + ConfigAttribute cloned = (ConfigAttribute) super.clone(); + cloned.sorted = (Conf) sorted.clone(); + cloned.prepare = (Conf) prepare.clone(); + return cloned; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof ConfigAttribute + && AssistKit.equals(this.sorted, ((ConfigAttribute) obj).sorted) + && AssistKit.equals(this.prepare, ((ConfigAttribute) obj).prepare); + } + + @Override + public int hashCode() { + return AssistKit.hashCode(sorted.get(), prepare.get()); + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java index c23a556..b504fb0 100644 --- a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java +++ b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java @@ -1,6 +1,26 @@ package com.fr.plugin.db.es.fun; +import com.fanruan.api.conf.HolderKit; import com.fanruan.api.data.open.BaseConnection; +import com.fanruan.api.i18n.I18nKit; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.ArrayKit; +import com.fanruan.api.util.StringKit; +import com.fanruan.api.util.TypeKit; +import com.fr.config.Identifier; +import com.fr.config.holder.Conf; +import com.fr.data.impl.Connection; +import com.fr.plugin.db.es.fun.help.ElasticsearchClientFactory; +import com.fr.stable.collections.combination.Pair; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; + +import java.io.IOException; +import java.util.List; /** * @author richie @@ -9,16 +29,130 @@ import com.fanruan.api.data.open.BaseConnection; */ public class ElasticsearchConnection extends BaseConnection { + public static final int DEFAULT_ES_PORT = 9200; + + @Identifier("host") + private Conf host = HolderKit.simple(StringKit.EMPTY); + @Identifier("port") + private Conf port = HolderKit.simple(String.valueOf(DEFAULT_ES_PORT)); + @Identifier("username") + private Conf username = HolderKit.simple(StringKit.EMPTY); + @Identifier("password") + private Conf password = HolderKit.simple(StringKit.EMPTY); + + public String getHost() { + return host.get(); + } + + public void setHost(String host) { + this.host.set(host); + } + + public String getPort() { + return port.get(); + } + + public void setPort(String port) { + this.port.set(port); + } + + public String getUsername() { + return username.get(); + } + + public void setUsername(String username) { + this.username.set(username); + } + + public String getPassword() { + return password.get(); + } + + public void setPassword(String password) { + this.password.set(password); + } + @Override public void testConnection() throws Exception { + RestHighLevelClient client = createRestHighLevelClient(); + boolean r; + try { + r = client.ping(RequestOptions.DEFAULT); + if (!r) { + throw new Exception("Failed"); + } + } catch (Exception e) { + throw new Exception(e); + } finally { + client.close(); + } + } + + public RestHighLevelClient createRestHighLevelClient() { + Pair setting = setting(); + return ElasticsearchClientFactory.buildHighLevelClient(setting.getFirst(), setting.getSecond(), getUsername(), getPassword()); + } + + public RestClient createClient() { + Pair setting = setting(); + return ElasticsearchClientFactory.buildClient(setting.getFirst(), setting.getSecond(), getUsername(), getPassword()); + } + private Pair setting() { + String host = getHost(); + String port = getPort(); + String[] hosts = host.split(","); + String[] portArr = port.split(","); + Integer[] ports = new Integer[portArr.length]; + for (int i = 0; i < portArr.length; i ++) { + ports[i] = Integer.parseInt(portArr[i]); + } + return new Pair(hosts, ports); } @Override - public String connectMessage(boolean b) { + public void addConnection(List list, String connectionName, Class[] acceptTypes) { + for (Class accept : acceptTypes) { + if (TypeKit.classInstanceOf(getClass(), accept)) { + list.add(connectionName); + break; + } + } + } + + @Override + public String[] summary(String... args) { + if (ArrayKit.getLength(args) < 3) { + return ArrayKit.EMPTY_STRING_ARRAY; + } + RestClient client = createClient(); + Request request = new Request(args[0], args[1]); + request.setJsonEntity(args[2]); + try { + Response response = client.performRequest(request); + return new String[]{EntityUtils.toString(response.getEntity())}; + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } finally { + try { + client.close(); + } catch (IOException e) { + LogKit.error(e.getMessage(), e); + } + } return null; } + @Override + public String connectMessage(boolean status) { + if (status) { + return I18nKit.getLocText("Plugin-Elasticsearch_Connection_Successfully") + "!"; + } else { + return I18nKit.getLocText("Plugin-Elasticsearch_Connection_Failed") + "!"; + } + + } + @Override public String getDriver() { return null; diff --git a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchDataModel.java b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchDataModel.java index de4e824..b1654fa 100644 --- a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchDataModel.java +++ b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchDataModel.java @@ -2,6 +2,18 @@ package com.fr.plugin.db.es.fun; import com.fanruan.api.data.open.BaseDataModel; import com.fanruan.api.err.TableDataException; +import com.fanruan.api.util.StringKit; +import com.fr.plugin.db.es.fun.assist.SimpleDataModel; +import com.fr.plugin.db.es.fun.category.ResultStandardizeSelector; +import com.fr.plugin.db.es.fun.type.ConverterType; +import com.fr.script.Calculator; +import org.apache.http.util.EntityUtils; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.RestClient; + +import java.nio.charset.StandardCharsets; +import java.util.List; /** * @author richie @@ -10,36 +22,112 @@ import com.fanruan.api.err.TableDataException; */ public class ElasticsearchDataModel extends BaseDataModel { - public ElasticsearchDataModel() { + private transient Calculator calculator; + private transient ElasticsearchConnection connection; + private transient String endPoint; + private transient String query; + private transient String script; + private transient ConverterType converterType; + private transient RestClient client; + private transient ConfigAttribute configAttribute; + private transient int rowCount; + private String[] columnNames; + private List> data; + public ElasticsearchDataModel( + Calculator calculator, + ElasticsearchConnection connection, + String endPoint, + String query, + String script, + ConverterType converterType, + ConfigAttribute configAttribute, + int rowCount) { + this.calculator = calculator; + this.connection = connection; + this.endPoint = endPoint; + this.query = query; + this.script = script; + this.converterType = converterType; + this.configAttribute = configAttribute; + this.rowCount = rowCount; } - private void initData() throws Exception { + private void fetchData() throws TableDataException { + if (data == null) { + synchronized (ElasticsearchDataModel.class) { + if (data == null) { + try { + initData(); + } catch (Exception e) { + throw new TableDataException(e.getMessage(), e); + } + } + } + } + } + private void initData() throws Exception { + if (client == null) { + client = connection.createClient(); + String text; + if (StringKit.isNotBlank(endPoint)) { + Request request = new Request("GET", endPoint); + request.setJsonEntity(query); + Response response = client.performRequest(request); + text = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + } else { + text = StringKit.EMPTY; + } + SimpleDataModel simple = ResultStandardizeSelector.select(converterType).result(text, script, configAttribute, rowCount); + if (simple != null) { + this.columnNames = simple.getColumnNames(); + this.data = simple.getData(); + } + } } @Override public int getColumnCount() throws TableDataException { - return 0; + fetchData(); + return columnNames == null ? 0 : columnNames.length; } @Override - public String getColumnName(int i) throws TableDataException { - return null; + public String getColumnName(int columnIndex) throws TableDataException { + fetchData(); + return columnNames == null ? null : columnNames[columnIndex]; + } + + @Override + public boolean hasRow(int rowIndex) throws com.fr.general.data.TableDataException { + fetchData(); + return data != null && data.size() > rowIndex; } @Override public int getRowCount() throws TableDataException { - return 0; + fetchData(); + return data == null ? 0 : data.size(); } @Override - public Object getValueAt(int i, int i1) throws TableDataException { + public Object getValueAt(int rowIndex, int columnIndex) throws TableDataException { + fetchData(); + if (data != null && data.size() > rowIndex) { + List rowData = data.get(rowIndex); + if (rowData != null && rowData.size() > columnIndex) { + return rowData.get(columnIndex); + } + } return null; } @Override public void release() throws Exception { - + if (client != null) { + client.close(); + client = null; + } } } diff --git a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchTableData.java b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchTableData.java index 924b578..5a2863f 100644 --- a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchTableData.java +++ b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchTableData.java @@ -4,18 +4,25 @@ import com.fanruan.api.conf.HolderKit; import com.fanruan.api.data.ConnectionKit; import com.fanruan.api.data.open.BaseTableData; import com.fanruan.api.util.AssistKit; +import com.fanruan.api.util.StringKit; import com.fanruan.api.xml.XmlKit; import com.fr.base.TableData; +import com.fr.config.Identifier; import com.fr.config.holder.Conf; import com.fr.data.impl.Connection; import com.fr.general.data.DataModel; import com.fr.intelli.record.Focus; +import com.fr.plugin.db.es.fun.help.RenderUtils; +import com.fr.plugin.db.es.fun.type.ConverterType; import com.fr.record.analyzer.EnableMetrics; import com.fr.script.Calculator; -import com.fr.stable.Nameable; +import com.fr.stable.NameReference; +import com.fr.stable.ParameterProvider; import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLableReader; +import java.util.Collection; + /** * @author richie * @version 10.0 @@ -24,7 +31,18 @@ import com.fr.stable.xml.XMLableReader; @EnableMetrics public class ElasticsearchTableData extends BaseTableData { + @Identifier("database") private Conf database = HolderKit.obj(null, Connection.class); + @Identifier("endPoint") + private Conf endPoint = HolderKit.simple(StringKit.EMPTY); + @Identifier("query") + private Conf query = HolderKit.simple(StringKit.EMPTY); + @Identifier("script") + private Conf script = HolderKit.simple(StringKit.EMPTY); + @Identifier("converterType") + private Conf converterType = HolderKit.simple(ConverterType.JSON.toInt()); + @Identifier("configAttribute") + private Conf configAttribute = HolderKit.obj(new ConfigAttribute(), ConfigAttribute.class); public ElasticsearchTableData() { @@ -38,6 +56,46 @@ public class ElasticsearchTableData extends BaseTableData { this.database.set(database); } + public String getEndPoint() { + return endPoint.get(); + } + + public void setEndPoint(String endPoint) { + this.endPoint.set(endPoint); + } + + public String getQuery() { + return query.get(); + } + + public void setQuery(String query) { + this.query.set(query); + } + + public String getScript() { + return script.get(); + } + + public void setScript(String script) { + this.script.set(script); + } + + public ConverterType getConverterType() { + return ConverterType.parse(converterType.get()); + } + + public void setConverterType(ConverterType converterType) { + this.converterType.set(converterType.toInt()); + } + + public ConfigAttribute getConfigAttribute() { + return configAttribute.get(); + } + + public void setConfigAttribute(ConfigAttribute configAttribute) { + this.configAttribute.set(configAttribute); + } + @Override public DataModel createDataModel(Calculator calculator) { return createDataModel(calculator, TableData.RESULT_ALL); @@ -47,15 +105,27 @@ public class ElasticsearchTableData extends BaseTableData { @Focus(id = "com.fr.plugin.db.es.v10", text = "Plugin_Elasticsearch_Table_Data") public DataModel createDataModel(Calculator calculator, int rowCount) { ElasticsearchConnection connection = getConnection(); + Collection parameterCollection = this.parameters.get(); + ParameterProvider[] parameterProviders = (ParameterProvider[]) parameterCollection.toArray(new ParameterProvider[0]); + ParameterProvider[] ps = Calculator.processParameters(calculator, parameterProviders); if (connection != null) { - return new ElasticsearchDataModel(); + return new ElasticsearchDataModel( + calculator, + connection, + RenderUtils.calculateQuery(endPoint.get(), ps), + RenderUtils.calculateQuery(query.get(), ps), + RenderUtils.calculateQuery(script.get(), ps), + getConverterType(), + getConfigAttribute(), + rowCount + ); } return null; } private ElasticsearchConnection getConnection() { - if (database.get() instanceof Nameable) { - String name = ((Nameable) database.get()).getName(); + if (database.get() instanceof NameReference) { + String name = ((NameReference) database.get()).getName(); return ConnectionKit.getConnection(name, ElasticsearchConnection.class); } return null; @@ -72,6 +142,19 @@ public class ElasticsearchTableData extends BaseTableData { Connection con = XmlKit.readXMLConnection(reader); this.setDatabase(con); } + } else if ("Query".equals(tmpName)) { + if ((tmpVal = reader.getElementValue()) != null) { + this.setQuery(tmpVal); + } + } if ("Script".equals(tmpName)) { + if ((tmpVal = reader.getElementValue()) != null) { + this.setQuery(tmpVal); + } + } else if (ConfigAttribute.XML_TAG.equals(tmpName)) { + configAttribute.set((ConfigAttribute) XmlKit.readXMLable(reader)); + } else if ("Attr".equals(tmpName)) { + setEndPoint(reader.getAttrAsString("endPoint", StringKit.EMPTY)); + setConverterType(ConverterType.parse(reader.getAttrAsInt("converterType", ConverterType.JSON.toInt()))); } } } @@ -82,23 +165,40 @@ public class ElasticsearchTableData extends BaseTableData { if (this.database.get() != null) { XmlKit.writeXMLConnection(writer, this.database.get()); } + if (configAttribute.get() != null) { + XmlKit.writeXMLable(writer, configAttribute.get(), ConfigAttribute.XML_TAG); + } + writer.startTAG("Query").textNode(getQuery()).end(); + writer.startTAG("Script").textNode(getQuery()).end(); + writer.startTAG("Attr"); + writer.attr("endPoint", getEndPoint()); + writer.attr("converterType", getConverterType().toInt()); + writer.end(); } @Override public Object clone() throws CloneNotSupportedException { ElasticsearchTableData cloned = (ElasticsearchTableData) super.clone(); cloned.database = (Conf) database.clone(); + cloned.endPoint = (Conf) endPoint.clone(); + cloned.converterType = (Conf) converterType.clone(); + cloned.query = (Conf) query.clone(); + cloned.script = (Conf) script.clone(); return cloned; } @Override public boolean equals(Object obj) { return obj instanceof ElasticsearchTableData - && AssistKit.equals(database, ((ElasticsearchTableData) obj).database); + && AssistKit.equals(database, ((ElasticsearchTableData) obj).database) + && AssistKit.equals(endPoint, ((ElasticsearchTableData) obj).endPoint) + && AssistKit.equals(converterType, ((ElasticsearchTableData) obj).converterType) + && AssistKit.equals(query, ((ElasticsearchTableData) obj).query) + && AssistKit.equals(script, ((ElasticsearchTableData) obj).script); } @Override public int hashCode() { - return AssistKit.hashCode(database.get()); + return AssistKit.hashCode(database.get(), endPoint.get(), converterType.get(), query.get(), script.get()); } } diff --git a/src/main/java/com/fr/plugin/db/es/fun/assist/SimpleDataModel.java b/src/main/java/com/fr/plugin/db/es/fun/assist/SimpleDataModel.java new file mode 100644 index 0000000..f9df9c0 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/assist/SimpleDataModel.java @@ -0,0 +1,51 @@ +package com.fr.plugin.db.es.fun.assist; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class SimpleDataModel { + + private List> data = new ArrayList>(); + private String[] columnNames = null; + private int rowCount; + + public SimpleDataModel(String[] columnNames, List> data){ + this.columnNames = columnNames; + this.data = data; + } + + public SimpleDataModel(String[] columnNames, List> data, int rowCount){ + this.columnNames = columnNames; + this.data = data; + this.rowCount = rowCount; + } + + public List> getData() { + return data; + } + + public void setData(List> data) { + this.data = data; + } + + public String[] getColumnNames() { + return columnNames; + } + + public void setColumnNames(String[] columnNames) { + this.columnNames = columnNames; + } + + public int getRowCount() { + return rowCount; + } + + public void setRowCount(int rowCount) { + this.rowCount = rowCount; + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/ResultStandardize.java b/src/main/java/com/fr/plugin/db/es/fun/category/ResultStandardize.java new file mode 100644 index 0000000..3e46d21 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/ResultStandardize.java @@ -0,0 +1,14 @@ +package com.fr.plugin.db.es.fun.category; + +import com.fr.plugin.db.es.fun.ConfigAttribute; +import com.fr.plugin.db.es.fun.assist.SimpleDataModel; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public interface ResultStandardize { + + SimpleDataModel result(String text, String script, ConfigAttribute configAttribute, int rowCount); +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/ResultStandardizeSelector.java b/src/main/java/com/fr/plugin/db/es/fun/category/ResultStandardizeSelector.java new file mode 100644 index 0000000..0c095e1 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/ResultStandardizeSelector.java @@ -0,0 +1,21 @@ +package com.fr.plugin.db.es.fun.category; + +import com.fr.plugin.db.es.fun.category.impl.JSONResultStandardize; +import com.fr.plugin.db.es.fun.category.impl.JSResultStandardize; +import com.fr.plugin.db.es.fun.type.ConverterType; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class ResultStandardizeSelector { + + public static ResultStandardize select(ConverterType converterType) { + if (converterType == ConverterType.JSON) { + return new JSONResultStandardize(); + } else { + return new JSResultStandardize(); + } + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/impl/JSONResultStandardize.java b/src/main/java/com/fr/plugin/db/es/fun/category/impl/JSONResultStandardize.java new file mode 100644 index 0000000..cf6a0b7 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/impl/JSONResultStandardize.java @@ -0,0 +1,166 @@ +package com.fr.plugin.db.es.fun.category.impl; + +import com.fr.plugin.db.es.fun.ConfigAttribute; +import com.fr.plugin.db.es.fun.assist.SimpleDataModel; +import com.fr.plugin.db.es.fun.category.ResultStandardize; +import com.jayway.jsonpath.JsonPath; +import net.minidev.json.JSONArray; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class JSONResultStandardize implements ResultStandardize { + + private List columnNames = new ArrayList<>(); + private List> data = new ArrayList>(); + + @Override + public SimpleDataModel result(String text, String script, ConfigAttribute configAttribute, int rowCount) { + Object object = JsonPath.read(text, script); + if (object instanceof LinkedHashMap) { + initJSONObject(new TreeMap<>((LinkedHashMap) object)); + } else if (object instanceof JSONArray) { + initJSONArray((JSONArray) object, configAttribute); + } else { + initSingleData(object); + } + return new SimpleDataModel(columnNames.toArray(new String[0]), data); + } + + private Map transferMap(Map data, ConfigAttribute attr) { + if (attr.isSorted()) { + return new TreeMap<>(data); + } + return data; + } + + private void initJSONObject(Map map) { + List row = new ArrayList(); + for (Map.Entry entry : map.entrySet()) { + columnNames.add(entry.getKey()); + row.add(entry.getValue()); + } + data.add(row); + } + + private void initJSONArray(JSONArray jsonArray, ConfigAttribute attr) { + if (attr.isPrepare()) { + iterateAllColumn(jsonArray, attr); + } else { + quickAttach(jsonArray, attr); + } + } + + private int findColumnIndexByName(String columnName) { + for (int i = 0, len = columnNames.size(); i < len; i++) { + if (columnName.equals(columnNames.get(i))) { + return i; + } + } + return -1; + } + + private void quickAttach(JSONArray jsonArray, ConfigAttribute attr) { + boolean findMap = false; + boolean colGet = false; + Set extraColumns = new LinkedHashSet(); + for (Object obj : jsonArray) { + List row = new ArrayList(); + if (obj instanceof LinkedHashMap) { + findMap = true; + Map map = transferMap((LinkedHashMap) obj, attr); + + Map lazy = new LinkedHashMap(); + + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + if (!colGet) { + columnNames.add(key); + } + if (findColumnIndexByName(key) != -1) { + row.add(entry.getValue()); + } else { + lazy.put(key, entry.getValue()); + } + } + for (Map.Entry entry : lazy.entrySet()) { + row.add(entry.getValue()); + extraColumns.add(entry.getKey()); + } + colGet = true; + data.add(row); + } else if (obj instanceof JSONArray) { + findMap = true; + JSONArray array = (JSONArray) obj; + for (int i = 0, len = array.size(); i < len; i++) { + if (!colGet) { + columnNames.add("value" + (i + 1)); + } + row.add(array.get(i)); + } + colGet = true; + data.add(row); + + } + } + columnNames.addAll(extraColumns); + if (!findMap) { + columnNames.add("value"); + for (Object obj : jsonArray) { + List row = new ArrayList(); + row.add(obj); + data.add(row); + } + } + } + + private void iterateAllColumn(JSONArray jsonArray, ConfigAttribute attr) { + Set columnString = transferColumnSet(attr); + for (Object obj : jsonArray) { + if (obj instanceof LinkedHashMap) { + Map map = transferMap((LinkedHashMap) obj, attr); + columnString.addAll(map.keySet()); + } else { + throw new RuntimeException("Illegal format, data must be JSONObject!"); + } + } + columnNames = new ArrayList<>(columnString); + for (Object obj : jsonArray) { + List row = new ArrayList(); + if (obj instanceof LinkedHashMap) { + Map map = (LinkedHashMap) obj; + for (String key : columnNames) { + row.add(map.get(key)); + } + } + data.add(row); + } + } + + private Set transferColumnSet(ConfigAttribute attr) { + if (attr.isSorted()) { + return new TreeSet<>(); + } + return new HashSet<>(); + } + + private void initSingleData(Object obj) { + columnNames.add("value"); + List row = new ArrayList<>(); + row.add(obj); + data.add(row); + } + +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/impl/JSResultStandardize.java b/src/main/java/com/fr/plugin/db/es/fun/category/impl/JSResultStandardize.java new file mode 100644 index 0000000..4b79bb0 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/impl/JSResultStandardize.java @@ -0,0 +1,18 @@ +package com.fr.plugin.db.es.fun.category.impl; + +import com.fr.plugin.db.es.fun.ConfigAttribute; +import com.fr.plugin.db.es.fun.assist.SimpleDataModel; +import com.fr.plugin.db.es.fun.category.ResultStandardize; +import com.fr.plugin.db.es.fun.category.script.ScriptClientSelector; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class JSResultStandardize implements ResultStandardize { + @Override + public SimpleDataModel result(String text, String script, ConfigAttribute configAttribute, int rowCount) { + return ScriptClientSelector.auto().build(text, script, rowCount); + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/EngineType.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/EngineType.java new file mode 100644 index 0000000..ff0f40e --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/EngineType.java @@ -0,0 +1,30 @@ +package com.fr.plugin.db.es.fun.category.script; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + */ +public enum EngineType { + + V8(0), JAVA(1); + + private int index; + + EngineType(int index) { + this.index = index; + } + + public int getType() { + return index; + } + + public static EngineType parse(int type) { + for (EngineType engineType : values()) { + if (engineType.index == type) { + return engineType; + } + } + return V8; + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/ScriptBridge.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/ScriptBridge.java new file mode 100644 index 0000000..f8cf10b --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/ScriptBridge.java @@ -0,0 +1,18 @@ +package com.fr.plugin.db.es.fun.category.script; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ScriptBridge { +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/ScriptClientSelector.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/ScriptClientSelector.java new file mode 100644 index 0000000..3f713fe --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/ScriptClientSelector.java @@ -0,0 +1,36 @@ +package com.fr.plugin.db.es.fun.category.script; + +import com.eclipsesource.v8.V8; +import com.fr.plugin.db.es.fun.category.script.client.ScriptClient; +import com.fr.plugin.db.es.fun.category.script.client.impl.NashornClient; +import com.fr.plugin.db.es.fun.category.script.client.impl.V8Client; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + * JS客户端选择器 + */ +public class ScriptClientSelector { + + private final static boolean SUPPORT_J2V8 = isSupportJ2v8(); + + public static boolean isSupportJ2v8() { + V8 v8; + try { + v8 = V8.createV8Runtime(); + } catch (IllegalStateException ex) { + return false; + } + v8.release(); + return true; + } + + public static ScriptClient auto() { + if (SUPPORT_J2V8) { + return new V8Client(); + } else { + return new NashornClient(); + } + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/client/NashornFiles.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/NashornFiles.java new file mode 100644 index 0000000..e9dce41 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/NashornFiles.java @@ -0,0 +1,37 @@ +package com.fr.plugin.db.es.fun.category.script.client; + + +import com.fanruan.api.log.LogKit; +import com.fanruan.api.macro.EncodeConstants; +import com.fanruan.api.util.IOKit; +import com.fr.plugin.db.es.fun.category.script.ScriptBridge; + +import javax.script.ScriptEngine; +import java.io.InputStream; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + */ +public class NashornFiles { + + private ScriptEngine scriptEngine; + + public NashornFiles(ScriptEngine scriptEngine) { + this.scriptEngine = scriptEngine; + } + + @ScriptBridge + public void require(String filePath) { + InputStream in = IOKit.readResource(filePath); + if (in != null) { + try { + String text = IOKit.inputStream2String(in, EncodeConstants.ENCODING_UTF_8); + scriptEngine.eval(text); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/client/ScriptClient.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/ScriptClient.java new file mode 100644 index 0000000..3e10a49 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/ScriptClient.java @@ -0,0 +1,14 @@ +package com.fr.plugin.db.es.fun.category.script.client; + + +import com.fr.plugin.db.es.fun.assist.SimpleDataModel; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + */ +public interface ScriptClient { + + SimpleDataModel build(String text, String query, int limit); +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/client/V8Files.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/V8Files.java new file mode 100644 index 0000000..0964f82 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/V8Files.java @@ -0,0 +1,36 @@ +package com.fr.plugin.db.es.fun.category.script.client; + + +import com.eclipsesource.v8.V8; +import com.fanruan.api.macro.EncodeConstants; +import com.fanruan.api.util.IOKit; +import com.fr.plugin.db.es.fun.category.script.ScriptBridge; + +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + */ +public class V8Files { + + private V8 v8; + + public V8Files(V8 v8) { + this.v8 = v8; + } + + @ScriptBridge + public void require(String filePath) { + InputStream in = IOKit.readResource(filePath); + if (in != null) { + try { + v8.executeVoidScript(IOKit.inputStream2String(in, EncodeConstants.ENCODING_UTF_8)); + } catch (UnsupportedEncodingException ignore) { + + } + } + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/client/impl/NashornClient.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/impl/NashornClient.java new file mode 100644 index 0000000..2f6a8b1 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/impl/NashornClient.java @@ -0,0 +1,101 @@ +package com.fr.plugin.db.es.fun.category.script.client.impl; + +import com.fr.base.TableData; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.db.es.fun.assist.SimpleDataModel; +import com.fr.plugin.db.es.fun.category.script.client.NashornFiles; +import com.fr.plugin.db.es.fun.category.script.client.ScriptClient; +import com.fr.plugin.db.es.fun.help.Console; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + */ +public class NashornClient implements ScriptClient { + + private static final String PREPARE_SCRIPT = + "function unique(array) {var res = [];for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {for (var j = 0, resLen = res.length; j < resLen; j++ ) {if (array[i] === res[j]) {break;}} if (j === resLen) {res.push(array[i])}} return res;}\n" + + "function merge(table, column) {return {content:table, column:column}};"; + + private ScriptEngine scriptEngine; + + public NashornClient() { + this.scriptEngine = findScriptEngine(); + } + + @Override + public SimpleDataModel build(String text, String query, int limit) { + scriptEngine.put("console", new Console()); + scriptEngine.put("Files", new NashornFiles(scriptEngine)); + try { + scriptEngine.eval(PREPARE_SCRIPT); + Map> r = (Map>) scriptEngine.eval(String.format( + "(function($){var $data = $; %s})(%s);", query, text)); + + Map columns = r.get("column"); + int columnCount = columns.size(); + String[] columnNames = new String[columnCount]; + int k = 0; + for (Map.Entry entry : columns.entrySet()) { + columnNames[k] = String.valueOf(entry.getValue()); + k++; + } + + Map content = r.get("content"); + int returnRowCount = content.size(); + int realCount = limit == TableData.RESULT_ALL ? returnRowCount : Math.min(returnRowCount, limit); + + List> data = new ArrayList>(); + int i = 0; + for (Map.Entry entry : content.entrySet()) { + if (i >= realCount) { + break; + } + List row = new ArrayList(); + + Object el = entry.getValue(); + if (el instanceof Map) { + Map rowCollection = (Map) entry.getValue(); + for (Map.Entry rowEntry : rowCollection.entrySet()) { + row.add(rowEntry.getValue()); + } + } else if (el instanceof Object[]) { + Object[] array = (Object[]) el; + row.addAll(Arrays.asList(array)); + } + + data.add(row); + i++; + } + return new SimpleDataModel(columnNames, data, realCount); + } catch (ScriptException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return null; + } + + private static ScriptEngine findScriptEngine() { + ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); + ScriptEngine engine = scriptEngineManager.getEngineByName("nashorn"); + if (engine == null) { + List factories = scriptEngineManager.getEngineFactories(); + for (ScriptEngineFactory factory : factories) { + ScriptEngine current = factory.getScriptEngine(); + if (current != null) { + engine = current; + } + } + } + return engine; + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/category/script/client/impl/V8Client.java b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/impl/V8Client.java new file mode 100644 index 0000000..aeb6c95 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/category/script/client/impl/V8Client.java @@ -0,0 +1,82 @@ +package com.fr.plugin.db.es.fun.category.script.client.impl; + +import com.eclipsesource.v8.V8; +import com.eclipsesource.v8.V8Array; +import com.eclipsesource.v8.V8Object; +import com.fr.base.TableData; +import com.fr.plugin.db.es.fun.assist.SimpleDataModel; +import com.fr.plugin.db.es.fun.category.script.client.ScriptClient; +import com.fr.plugin.db.es.fun.category.script.client.V8Files; +import com.fr.plugin.db.es.fun.help.Console; +import com.fr.plugin.db.es.fun.help.RegisterUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/30 + */ +public class V8Client implements ScriptClient { + + private V8 v8; + + public V8Client() { + this.v8 = V8.createV8Runtime(); + } + + @Override + public SimpleDataModel build(String text, String query, int limit) { + V8Object v8Console = initConsole(v8); + V8Object v8Require = initRequire(v8); + v8.executeVoidScript( + "function unique(array) {return Array.from(new Set(array));};" + + "function merge(table, column) {return {content:table, column:column}};"); + V8Object returnObj = v8.executeObjectScript(String.format( + "(function($){var $data = $; %s})(%s);", query, text)); + + V8Array v8Column = returnObj.getArray("column"); + V8Array v8Table = returnObj.getArray("content"); + int columnCount = v8Column.length(); + String[] columnNames = new String[columnCount]; + for (int i = 0; i < columnCount; i++) { + columnNames[i] = String.valueOf(v8Column.get(i)); + } + int returnRowCount = v8Table.length(); + int realCount = limit == TableData.RESULT_ALL ? returnRowCount : Math.min(returnRowCount, limit); + List> data = new ArrayList>(); + for (int i = 0; i < realCount; i++) { + V8Array v8Row = v8Table.getArray(i); + List row = new ArrayList(); + for (int j = 0, col = v8Row.length(); j < col; j++) { + row.add(v8Row.get(j)); + } + v8Row.release(); + data.add(row); + } + v8Require.release(); + v8Console.release(); + v8Table.release(); + v8Column.release(); + returnObj.release(); + v8.release(true); + return new SimpleDataModel(columnNames, data, realCount); + } + + private V8Object initConsole(V8 v8) { + V8Object v8Console = new V8Object(v8); + v8.add("console", v8Console); + Console console = new Console(); + RegisterUtils.registerJavaMethods(v8Console, console); + return v8Console; + } + + private V8Object initRequire(V8 v8) { + V8Object v8Files = new V8Object(v8); + v8.add("Files", v8Files); + V8Files files = new V8Files(v8); + RegisterUtils.registerJavaMethods(v8Files, files); + return v8Files; + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/help/Console.java b/src/main/java/com/fr/plugin/db/es/fun/help/Console.java new file mode 100644 index 0000000..d8b1a58 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/help/Console.java @@ -0,0 +1,28 @@ +package com.fr.plugin.db.es.fun.help; + +import com.fanruan.api.log.LogKit; +import com.fr.plugin.db.es.fun.category.script.ScriptBridge; +import com.fr.plugin.db.es.fun.category.script.ScriptClientSelector; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class Console { + + @ScriptBridge + public void log(Object message) { + LogKit.info(message == null ? null : message.toString()); + } + + @ScriptBridge + public void error(Object message) { + LogKit.error(message == null ? null : message.toString()); + } + + @ScriptBridge + public String engine() { + return ScriptClientSelector.isSupportJ2v8() ? "V8" : "Nashorn"; + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/help/ElasticsearchClientFactory.java b/src/main/java/com/fr/plugin/db/es/fun/help/ElasticsearchClientFactory.java new file mode 100644 index 0000000..ff2f42c --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/help/ElasticsearchClientFactory.java @@ -0,0 +1,53 @@ +package com.fr.plugin.db.es.fun.help; + +import com.fanruan.api.util.ArrayKit; +import com.fanruan.api.util.StringKit; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/31 + */ +public class ElasticsearchClientFactory { + + public static RestHighLevelClient buildHighLevelClient(String[] hosts, Integer[] ports, String username, String password) { + return new RestHighLevelClient(build(hosts, ports, username, password)); + } + + public static RestClient buildClient(String[] hosts, Integer[] ports, String username, String password) { + return build(hosts, ports, username, password).build(); + } + + private static RestClientBuilder build(String[] hosts, Integer[] ports, String username, String password) { + int hostCount = ArrayKit.getLength(hosts); + int portCount = ArrayKit.getLength(ports); + if (portCount != hostCount) { + throw new IllegalArgumentException("Hosts and ports must be matched!"); + } + HttpHost[] httpHosts = new HttpHost[hostCount]; + for (int i = 0; i < hostCount; i++) { + httpHosts[i] = new HttpHost(hosts[i], ports[i], "http"); + } + RestClientBuilder builder = RestClient.builder(httpHosts); + if (StringKit.isNotEmpty(username)) { + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); + builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { + @Override + public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) { + return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + } + }); + } + return builder; + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/help/RegisterUtils.java b/src/main/java/com/fr/plugin/db/es/fun/help/RegisterUtils.java new file mode 100644 index 0000000..cbbd4e9 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/help/RegisterUtils.java @@ -0,0 +1,24 @@ +package com.fr.plugin.db.es.fun.help; + +import com.eclipsesource.v8.V8Object; +import com.fr.plugin.db.es.fun.category.script.ScriptBridge; + +import java.lang.reflect.Method; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class RegisterUtils { + + public static void registerJavaMethods(V8Object v8Object, Object target) { + Method[] methods = target.getClass().getMethods(); + for (Method m : methods) { + if (m.getAnnotation(ScriptBridge.class) != null) { + v8Object.registerJavaMethod(target, m.getName(), m.getName(), m.getParameterTypes()); + } + } + } +} + diff --git a/src/main/java/com/fr/plugin/db/es/fun/help/RenderUtils.java b/src/main/java/com/fr/plugin/db/es/fun/help/RenderUtils.java new file mode 100644 index 0000000..dd9856b --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/help/RenderUtils.java @@ -0,0 +1,33 @@ +package com.fr.plugin.db.es.fun.help; + +import com.fanruan.api.util.RenderKit; +import com.fr.base.Parameter; +import com.fr.base.TemplateUtils; +import com.fr.stable.ArrayUtils; +import com.fr.stable.ParameterProvider; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/31 + */ +public class RenderUtils { + + public static String calculateQuery(String query, ParameterProvider[] ps) { + if (ArrayUtils.isEmpty(ps)) { + return query; + } + Map map = new HashMap<>(); + for (ParameterProvider p : ps) { + map.put(p.getName(), p.getValue()); + } + try { + return RenderKit.renderParameter4Tpl(query, map); + } catch (Exception e) { + return query; + } + } +} diff --git a/src/main/java/com/fr/plugin/db/es/fun/type/ConverterType.java b/src/main/java/com/fr/plugin/db/es/fun/type/ConverterType.java new file mode 100644 index 0000000..77e97a1 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/fun/type/ConverterType.java @@ -0,0 +1,29 @@ +package com.fr.plugin.db.es.fun.type; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019/12/31 + */ +public enum ConverterType { + JSON(0), JS(1); + + private int i; + + ConverterType(int i) { + this.i = i; + } + + public int toInt() { + return i; + } + + public static ConverterType parse(int i) { + for (ConverterType type : values()) { + if (i == type.i) { + return type; + } + } + return JSON; + } +} diff --git a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionChosePane.java b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionChosePane.java new file mode 100644 index 0000000..648eff8 --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionChosePane.java @@ -0,0 +1,141 @@ +package com.fr.plugin.db.es.ui; + +import com.fanruan.api.data.ConnectionKit; +import com.fanruan.api.design.macro.UIConstants; +import com.fanruan.api.design.ui.component.UIButton; +import com.fanruan.api.design.ui.component.UIDictionaryComboBox; +import com.fanruan.api.design.ui.component.UIPlaceholderTextField; +import com.fanruan.api.design.ui.component.UIRoundedBorder; +import com.fanruan.api.design.ui.component.code.SyntaxConstants; +import com.fanruan.api.design.ui.component.code.UISyntaxTextArea; +import com.fanruan.api.design.ui.component.code.UISyntaxTextScrollPane; +import com.fanruan.api.design.util.GUICoreKit; +import com.fanruan.api.design.work.ConnectionComboBoxPanel; +import com.fanruan.api.log.LogKit; +import com.fanruan.api.util.ArrayKit; +import com.fanruan.api.util.IOKit; +import com.fr.data.impl.Connection; +import com.fr.design.dialog.BasicPane; +import com.fr.plugin.db.es.fun.ElasticsearchConnection; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class ElasticsearchConnectionChosePane extends BasicPane { + + private ConnectionComboBoxPanel connectionComboBoxPanel; + private UIDictionaryComboBox typeComboBox; + private UIPlaceholderTextField queryAllTextField; + private UISyntaxTextArea consoleTextPane; + private UISyntaxTextArea outputTextPane; + + public ElasticsearchConnectionChosePane() { + setLayout(new BorderLayout(4, 4)); + connectionComboBoxPanel = new ConnectionComboBoxPanel(Connection.class) { + + protected void filterConnection(Connection connection, String conName, List nameList) { + connection.addConnection(nameList, conName, new Class[]{ElasticsearchConnection.class}); + } + }; + + add(connectionComboBoxPanel, BorderLayout.NORTH); + connectionComboBoxPanel.addComboBoxActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + + } + }); + JPanel centerPane = new JPanel(new BorderLayout()); + add(centerPane, BorderLayout.CENTER); + + typeComboBox = new UIDictionaryComboBox<>(new String[]{ + "GET", "POST", "PUT" + }, new String[]{ + "GET", "POST", "PUT" + }); + typeComboBox.setSelectedItem("GET"); + queryAllTextField = new UIPlaceholderTextField(); + queryAllTextField.setText("/_search?pretty=true"); + UIButton execButton = new UIButton(IOKit.readIcon("/com/fr/plugin/db/es/images/run.png")); + execButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + run(); + } + }); + centerPane.add(GUICoreKit.createBorderLayoutPane( + typeComboBox, BorderLayout.WEST, + queryAllTextField, BorderLayout.CENTER, + execButton, BorderLayout.EAST + ), BorderLayout.NORTH); + GridLayout gridLayout = new GridLayout(2, 1); + JPanel interactivePane = new JPanel(gridLayout); + centerPane.add(interactivePane, BorderLayout.CENTER); + + consoleTextPane = new UISyntaxTextArea(); + consoleTextPane.setEditable(false); + consoleTextPane.setText("{\n" + + " \"query\": {\n" + + " \"match_all\": {}\n" + + " }\n" + + "}"); + interactivePane.add(createShowTextPane(consoleTextPane)); + outputTextPane = new UISyntaxTextArea(); + interactivePane.add(createShowTextPane(outputTextPane)); + } + + private void run() { + String connectionName = getSelectConnectionName(); + final ElasticsearchConnection connection = ConnectionKit.getConnection(connectionName, ElasticsearchConnection.class); + if (connection != null) { + new SwingWorker() { + @Override + protected String doInBackground() { + String[] array = connection.summary(typeComboBox.getSelectedItem(), queryAllTextField.getText(), consoleTextPane.getText()); + return ArrayKit.isEmpty(array) ? null : array[0]; + } + + @Override + protected void done() { + try { + String text = get(); + outputTextPane.setText(text); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + }.execute(); + } + } + + private UISyntaxTextScrollPane createShowTextPane(UISyntaxTextArea consoleTextPane) { + consoleTextPane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); + UISyntaxTextScrollPane sqlTextScrollPane = new UISyntaxTextScrollPane(consoleTextPane); + sqlTextScrollPane.setLineNumbersEnabled(false); + sqlTextScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + sqlTextScrollPane.setPreferredSize(new Dimension(300, 120)); + return sqlTextScrollPane; + } + + + public String getSelectConnectionName() { + return connectionComboBoxPanel.getSelectedItem(); + } + + public void populateConnection(Connection connection) { + connectionComboBoxPanel.populate(connection); + } + + @Override + protected String title4PopupWindow() { + return "Choose"; + } +} \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java index d40df38..7c0a69c 100644 --- a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java +++ b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java @@ -1,9 +1,21 @@ package com.fr.plugin.db.es.ui; +import com.fanruan.api.design.DesignKit; +import com.fanruan.api.design.ui.component.UIButton; +import com.fanruan.api.design.ui.component.UILabel; +import com.fanruan.api.design.ui.component.UIPasswordField; +import com.fanruan.api.design.ui.component.UITextField; +import com.fanruan.api.design.ui.component.UITitledBorder; +import com.fanruan.api.design.ui.layout.TableLayoutKit; +import com.fanruan.api.design.util.GUICoreKit; import com.fanruan.api.design.work.DatabaseConnectionPane; +import com.fanruan.api.util.IOKit; import com.fr.plugin.db.es.fun.ElasticsearchConnection; import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; /** * @author richie @@ -12,23 +24,84 @@ import javax.swing.*; */ public class ElasticsearchConnectionPane extends DatabaseConnectionPane { + private UITextField hostTextField; + private UITextField portTextField; + private UITextField usernameTextField; + private UIPasswordField passwordTextField; + @Override protected JPanel mainPanel() { - return null; + JPanel pane = new JPanel(); + pane.setLayout(new BorderLayout()); + hostTextField = new UITextField(); + portTextField = new UITextField(); + usernameTextField = new UITextField(); + passwordTextField = new UIPasswordField(); + + JPanel globalConfigPane = new JPanel(); + GridLayout gridLayout = new GridLayout(1, 2); + globalConfigPane.setLayout(gridLayout); + + UIButton helpButton = new UIButton(); + helpButton.setIcon(IOKit.readIcon("/com/fr/plugin/db/es/images/help.png")); + helpButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JOptionPane.showMessageDialog( + SwingUtilities.getWindowAncestor(ElasticsearchConnectionPane.this), + DesignKit.i18nText("Plugin-Elasticsearch_Host_Cluster_Description"), + DesignKit.i18nText("Plugin-Elasticsearch_Host_Cluster"), + JOptionPane.INFORMATION_MESSAGE + ); + } + }); + + Component[][] components = new Component[][]{ + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Host") + ":"), + GUICoreKit.createBorderLayoutPane(hostTextField, BorderLayout.CENTER, helpButton, BorderLayout.EAST)}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Port") + ":"), portTextField}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Username") + ":"), usernameTextField}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Password") + ":"), passwordTextField}, + }; + + + double p = TableLayoutKit.PREFERRED; + + double[] rowSize = new double[]{p, p, p, p, p}; + double[] columnSize = new double[]{p, 400}; + + JPanel settingsUI = TableLayoutKit.createTableLayoutPane(components, rowSize, columnSize); + settingsUI.setBorder(UITitledBorder.createBorderWithTitle("Elasticsearch")); + + JPanel centerPane = GUICoreKit.createNormalFlowInnerContainerPane(); + + centerPane.add(settingsUI); + + pane.add(centerPane, BorderLayout.CENTER); + return pane; + } @Override - protected void populateSubDatabaseConnectionBean(ElasticsearchConnection elasticsearchConnection) { - + protected void populateSubDatabaseConnectionBean(ElasticsearchConnection connection) { + hostTextField.setText(connection.getHost()); + portTextField.setText(connection.getPort()); + usernameTextField.setText(connection.getUsername()); + passwordTextField.setText(connection.getPassword()); } @Override protected ElasticsearchConnection updateSubDatabaseConnectionBean() { - return null; + ElasticsearchConnection connection = new ElasticsearchConnection(); + connection.setHost(hostTextField.getText()); + connection.setPort(portTextField.getText()); + connection.setUsername(usernameTextField.getText()); + connection.setPassword(passwordTextField.getText()); + return connection; } @Override protected String title4PopupWindow() { - return null; + return "Elasticsearch"; } } diff --git a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchQueryPane.java b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchQueryPane.java new file mode 100644 index 0000000..939f58b --- /dev/null +++ b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchQueryPane.java @@ -0,0 +1,149 @@ +package com.fr.plugin.db.es.ui; + +import com.fanruan.api.design.DesignKit; +import com.fanruan.api.design.macro.UIConstants; +import com.fanruan.api.design.ui.component.UIDictionaryComboBox; +import com.fanruan.api.design.ui.component.UILabel; +import com.fanruan.api.design.ui.component.UIRoundedBorder; +import com.fanruan.api.design.ui.component.UITextField; +import com.fanruan.api.design.ui.component.code.SyntaxConstants; +import com.fanruan.api.design.ui.component.code.UISyntaxTextArea; +import com.fanruan.api.design.ui.component.code.UISyntaxTextScrollPane; +import com.fanruan.api.design.ui.layout.TableLayoutKit; +import com.fr.design.dialog.BasicPane; +import com.fr.plugin.db.es.fun.ConfigAttribute; +import com.fr.plugin.db.es.fun.type.ConverterType; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2020/1/2 + */ +public class ElasticsearchQueryPane extends BasicPane { + + private UITextField endPointTextField; + private UIDictionaryComboBox converterTypeComboBox; + private UISyntaxTextArea queryTextPane; + private UISyntaxTextArea scriptTextPane; + private UIDictionaryComboBox sortedComboBox; + private UIDictionaryComboBox prepareComboBox; + + @Override + protected String title4PopupWindow() { + return "JSON Query"; + } + + public ElasticsearchQueryPane() { + setLayout(new BorderLayout()); + + double p = TableLayoutKit.PREFERRED; + double f = TableLayoutKit.FILL; + + double[] rowSize = {p, p, p, p, p, p}; + double[] columnSize = {p, f}; + + endPointTextField = new UITextField(); + + queryTextPane = new UISyntaxTextArea(); + + converterTypeComboBox = new UIDictionaryComboBox<>(new ConverterType[]{ + ConverterType.JSON, + ConverterType.JS + }, new String[]{ + DesignKit.i18nText("Plugin-Elasticsearch_Auto"), + DesignKit.i18nText("Plugin-Elasticsearch_Program") + }); + converterTypeComboBox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + checkEnabled(); + } + }); + + scriptTextPane = new UISyntaxTextArea(); + + sortedComboBox = new UIDictionaryComboBox<>( + new Boolean[]{false, true}, + new String[]{DesignKit.i18nText("Plugin-Elasticsearch_Sort_Default"), com.fr.design.i18n.Toolkit.i18nText("Plugin-JSON_Sort_Open")}); + prepareComboBox = new UIDictionaryComboBox<>( + new Boolean[]{false, true}, + new String[]{DesignKit.i18nText("Plugin-Elasticsearch_Prepare_Keys_Default"), com.fr.design.i18n.Toolkit.i18nText("Plugin-JSON_Prepare_Keys_Open")} + ); + Component[][] coms = new Component[][]{ + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Endpoint") + ":"), endPointTextField}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Query") + ":"), createConditionTextPane(queryTextPane)}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Result_Type")+ ":"), converterTypeComboBox}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Result_Script")+ ":"), createConditionTextPane(scriptTextPane)}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Sort_Key") + ":"), sortedComboBox}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Key_Prepare") + ":"), prepareComboBox} + }; + JPanel panel = TableLayoutKit.createTableLayoutPane(coms, rowSize, columnSize); + add(panel, BorderLayout.CENTER); + } + + private UISyntaxTextScrollPane createConditionTextPane(UISyntaxTextArea sqlTextPane) { + sqlTextPane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); + UISyntaxTextScrollPane sqlTextScrollPane = new UISyntaxTextScrollPane(sqlTextPane); + sqlTextScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + sqlTextScrollPane.setPreferredSize(new Dimension(680, 120)); + return sqlTextScrollPane; + } + + private void checkEnabled() { + ConverterType converterType = getConverterType(); + sortedComboBox.setEnabled(converterType == ConverterType.JSON); + prepareComboBox.setEnabled(converterType == ConverterType.JSON); + } + + public String getEndPoint() { + return endPointTextField.getText(); + } + + public void setEndPoint(String endPoint) { + endPointTextField.setText(endPoint); + } + + public ConverterType getConverterType() { + return converterTypeComboBox.getSelectedItem(); + } + + public void setConverterTypeComboBox(ConverterType converterType) { + converterTypeComboBox.setSelectedItem(converterType); + } + + public String getQuery() { + return queryTextPane.getText(); + } + + public void setQuery(String query) { + queryTextPane.setText(query); + } + + public String getScript() { + return scriptTextPane.getText(); + } + + public void setScript(String script) { + scriptTextPane.setText(script); + } + + public ConfigAttribute getConfigAttr() { + ConfigAttribute attr = new ConfigAttribute(); + attr.setSorted(sortedComboBox.getSelectedItem()); + attr.setPrepare(prepareComboBox.getSelectedItem()); + return attr; + } + + public void setConfigAttr(ConfigAttribute attr) { + if (attr == null) { + return; + } + sortedComboBox.setSelectedItem(attr.isSorted()); + prepareComboBox.setSelectedItem(attr.isPrepare()); + } +} diff --git a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchTableDataPane.java b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchTableDataPane.java index df47efd..1e44c73 100644 --- a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchTableDataPane.java +++ b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchTableDataPane.java @@ -1,7 +1,26 @@ package com.fr.plugin.db.es.ui; +import com.fanruan.api.cal.ParameterKit; +import com.fanruan.api.data.ConnectionKit; +import com.fanruan.api.design.DesignKit; +import com.fanruan.api.design.ui.action.UpdateAction; +import com.fanruan.api.design.ui.component.UIToolbar; +import com.fanruan.api.design.ui.component.table.UITableEditorPane; +import com.fanruan.api.design.ui.component.table.action.UITableEditAction; +import com.fanruan.api.design.ui.component.table.model.ParameterTableModel; +import com.fanruan.api.design.ui.toolbar.ToolBarDef; import com.fanruan.api.design.work.BaseTableDataPane; +import com.fanruan.api.util.ArrayKit; +import com.fanruan.api.util.IOKit; +import com.fanruan.api.util.StringKit; import com.fr.plugin.db.es.fun.ElasticsearchTableData; +import com.fr.script.Calculator; +import com.fr.stable.ParameterProvider; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.ArrayList; /** * @author richie @@ -10,18 +29,164 @@ import com.fr.plugin.db.es.fun.ElasticsearchTableData; */ public class ElasticsearchTableDataPane extends BaseTableDataPane { - @Override - public void populateBean(ElasticsearchTableData elasticsearchTableData) { + private static final String PREVIEW_BUTTON = DesignKit.i18nText("Plugin-Elasticsearch_Preview"); + private static final String REFRESH_BUTTON = DesignKit.i18nText("Plugin-Elasticsearch_Refresh"); + + private ElasticsearchConnectionChosePane chosePane; + + private UITableEditorPane editorPane; + + private ElasticsearchQueryPane queryPane; + + public ElasticsearchTableDataPane() { + this.setLayout(new BorderLayout(4, 4)); + Box box = new Box(BoxLayout.Y_AXIS); + JPanel northPane = new JPanel(new BorderLayout(4, 4)); + JToolBar editToolBar = createToolBar(); + northPane.add(editToolBar, BorderLayout.CENTER); + northPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 6, 0)); + ParameterTableModel model = new ParameterTableModel() { + @Override + public UITableEditAction[] createAction() { + return ArrayKit.add( + super.createAction(), + new RefreshAction()); + } + }; + editorPane = new UITableEditorPane<>(model); + + box.add(northPane); + + addQueryPane(box); + + box.add(editorPane); + + JPanel sqlSplitPane = new JPanel(new BorderLayout(4, 4)); + sqlSplitPane.add(box, BorderLayout.CENTER); + + chosePane = new ElasticsearchConnectionChosePane(); + chosePane.setPreferredSize(new Dimension(300, 200)); + sqlSplitPane.add(chosePane, BorderLayout.WEST); + + this.add(sqlSplitPane, BorderLayout.CENTER); + } + + private void addQueryPane(Box box) { + queryPane = new ElasticsearchQueryPane(); + box.add(queryPane); + } + + private JToolBar createToolBar() { + ToolBarDef toolBarDef = new ToolBarDef(); + toolBarDef.addShortCut(new PreviewAction()); + UIToolbar editToolBar = ToolBarDef.createJToolBar(); + toolBarDef.updateToolBar(editToolBar); + return editToolBar; + } + + private class PreviewAction extends UpdateAction { + public PreviewAction() { + this.setName(PREVIEW_BUTTON); + this.setMnemonic('P'); + this.setSmallIcon(IOKit.readIcon("/com/fr/plugin/db/es/images/preview.png")); + } + public void actionPerformed(ActionEvent evt) { + checkParameter(); + DesignKit.previewTableData(ElasticsearchTableDataPane.this.updateBean()); + } + } + + + protected class RefreshAction extends UITableEditAction { + public RefreshAction() { + this.setName(REFRESH_BUTTON); + this.setSmallIcon(IOKit.readIcon("/com/fr/plugin/db/es/images/refresh.png")); + } + + public void actionPerformed(ActionEvent e) { + refresh(); + } + + @Override + public void checkEnabled() { + } + } + + private String[] parameterTextSource() { + return new String[]{ + queryPane.getQuery(), queryPane.getEndPoint(), queryPane.getScript() + }; + } + + private void refresh() { + String[] paramTexts = parameterTextSource(); + + java.util.List existParameterList = editorPane.update(); + ParameterProvider[] ps = existParameterList == null ? new ParameterProvider[0] : existParameterList.toArray(new ParameterProvider[0]); + editorPane.populate(ParameterKit.analyzeAndUnionSameParameters(paramTexts, ps)); + } + + + private void checkParameter() { + String[] paramTexts = parameterTextSource(); + + ParameterProvider[] parameters = ParameterKit.analyze4Parameters(paramTexts, false); + + if (parameters.length < 1 && editorPane.update().size() < 1) { + return; + } + boolean isIn = true; + java.util.List list = editorPane.update(); + java.util.List name = new ArrayList(); + for (int i = 0; i < list.size(); i++) { + name.add(list.get(i).getName()); + } + for (int i = 0; i < parameters.length; i++) { + if (!name.contains(parameters[i].getName())) { + isIn = false; + break; + } + } + if (list.size() == parameters.length && isIn) { + return; + } + refresh(); + } + + @Override + public void populateBean(ElasticsearchTableData tableData) { + if (tableData == null) { + return; + } + chosePane.populateConnection(tableData.getDatabase()); + editorPane.populate(tableData.getParameters(Calculator.createCalculator())); + queryPane.setEndPoint(tableData.getEndPoint()); + queryPane.setConfigAttr(tableData.getConfigAttribute()); + queryPane.setQuery(tableData.getQuery()); + queryPane.setConverterTypeComboBox(tableData.getConverterType()); + queryPane.setScript(tableData.getScript()); } @Override public ElasticsearchTableData updateBean() { - return null; + ElasticsearchTableData tableData = new ElasticsearchTableData(); + String name = chosePane.getSelectConnectionName(); + if (StringKit.isNotEmpty(name)) { + tableData.setDatabase(ConnectionKit.createNameConnection(name)); + } + java.util.List providerList = editorPane.update(); + tableData.setParameters(providerList.toArray(new ParameterProvider[0])); + tableData.setEndPoint(queryPane.getEndPoint()); + tableData.setQuery(queryPane.getQuery()); + tableData.setConverterType(queryPane.getConverterType()); + tableData.setConfigAttribute(queryPane.getConfigAttr()); + tableData.setScript(queryPane.getScript()); + return tableData; } @Override protected String title4PopupWindow() { - return null; + return DesignKit.i18nText("Plugin_Elasticsearch_Table_Data"); } } diff --git a/src/main/resources/com/fr/plugin/db/es/images/help.png b/src/main/resources/com/fr/plugin/db/es/images/help.png new file mode 100644 index 0000000..0bd60db Binary files /dev/null and b/src/main/resources/com/fr/plugin/db/es/images/help.png differ diff --git a/src/main/resources/com/fr/plugin/db/es/images/preview.png b/src/main/resources/com/fr/plugin/db/es/images/preview.png new file mode 100644 index 0000000..3e488f1 Binary files /dev/null and b/src/main/resources/com/fr/plugin/db/es/images/preview.png differ diff --git a/src/main/resources/com/fr/plugin/db/es/images/refresh.png b/src/main/resources/com/fr/plugin/db/es/images/refresh.png new file mode 100644 index 0000000..ee8f765 Binary files /dev/null and b/src/main/resources/com/fr/plugin/db/es/images/refresh.png differ diff --git a/src/main/resources/com/fr/plugin/db/es/images/run.png b/src/main/resources/com/fr/plugin/db/es/images/run.png new file mode 100644 index 0000000..96a86a0 Binary files /dev/null and b/src/main/resources/com/fr/plugin/db/es/images/run.png differ diff --git a/src/main/resources/com/fr/plugin/db/es/locale/es.properties b/src/main/resources/com/fr/plugin/db/es/locale/es.properties index 3223e88..7663a6e 100644 --- a/src/main/resources/com/fr/plugin/db/es/locale/es.properties +++ b/src/main/resources/com/fr/plugin/db/es/locale/es.properties @@ -1 +1,21 @@ -Plugin_Elasticsearch_Table_Data=Elasticsearch \ No newline at end of file +Plugin_Elasticsearch_Table_Data=Elasticsearch +Plugin-Elasticsearch_Host=Host +Plugin-Elasticsearch_Port=Port +Plugin-Elasticsearch_Username=Username +Plugin-Elasticsearch_Password=Password +Plugin-Elasticsearch_Connection_Successfully=Connect successfully +Plugin-Elasticsearch_Connection_Failed=Connect failed +Plugin-Elasticsearch_Preview=Preview +Plugin-Elasticsearch_Refresh=Refresh +Plugin-Elasticsearch_Auto=Auto +Plugin-Elasticsearch_Program=Program +Plugin-Elasticsearch_Sort_Default=Default +Plugin-Elasticsearch_Prepare_Keys_Default=Default +Plugin-Elasticsearch_Endpoint=Endpoint +Plugin-Elasticsearch_Query=Query +Plugin-Elasticsearch_Sort_Key=Sort key +Plugin-Elasticsearch_Key_Prepare=Key Prepare +Plugin-Elasticsearch_Result_Type=Processor Type +Plugin-Elasticsearch_Result_Script=Processor Script +Plugin-Elasticsearch_Host_Cluster=Cluster +Plugin-Elasticsearch_Host_Cluster_Description=Hosts and Ports must be the same count. \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/db/es/locale/es_en_US.properties b/src/main/resources/com/fr/plugin/db/es/locale/es_en_US.properties index 3223e88..7663a6e 100644 --- a/src/main/resources/com/fr/plugin/db/es/locale/es_en_US.properties +++ b/src/main/resources/com/fr/plugin/db/es/locale/es_en_US.properties @@ -1 +1,21 @@ -Plugin_Elasticsearch_Table_Data=Elasticsearch \ No newline at end of file +Plugin_Elasticsearch_Table_Data=Elasticsearch +Plugin-Elasticsearch_Host=Host +Plugin-Elasticsearch_Port=Port +Plugin-Elasticsearch_Username=Username +Plugin-Elasticsearch_Password=Password +Plugin-Elasticsearch_Connection_Successfully=Connect successfully +Plugin-Elasticsearch_Connection_Failed=Connect failed +Plugin-Elasticsearch_Preview=Preview +Plugin-Elasticsearch_Refresh=Refresh +Plugin-Elasticsearch_Auto=Auto +Plugin-Elasticsearch_Program=Program +Plugin-Elasticsearch_Sort_Default=Default +Plugin-Elasticsearch_Prepare_Keys_Default=Default +Plugin-Elasticsearch_Endpoint=Endpoint +Plugin-Elasticsearch_Query=Query +Plugin-Elasticsearch_Sort_Key=Sort key +Plugin-Elasticsearch_Key_Prepare=Key Prepare +Plugin-Elasticsearch_Result_Type=Processor Type +Plugin-Elasticsearch_Result_Script=Processor Script +Plugin-Elasticsearch_Host_Cluster=Cluster +Plugin-Elasticsearch_Host_Cluster_Description=Hosts and Ports must be the same count. \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/db/es/locale/es_zh_CN.properties b/src/main/resources/com/fr/plugin/db/es/locale/es_zh_CN.properties index 0ad3b6e..ff94079 100644 --- a/src/main/resources/com/fr/plugin/db/es/locale/es_zh_CN.properties +++ b/src/main/resources/com/fr/plugin/db/es/locale/es_zh_CN.properties @@ -1 +1,21 @@ -Plugin_Elasticsearch_Table_Data=Elasticsearch\u6570\u636E\u96C6 \ No newline at end of file +Plugin_Elasticsearch_Table_Data=Elasticsearch\u6570\u636E\u96C6 +Plugin-Elasticsearch_Host=\u5730\u5740 +Plugin-Elasticsearch_Port=\u7AEF\u53E3 +Plugin-Elasticsearch_Username=\u7528\u6237\u540D +Plugin-Elasticsearch_Password=\u5BC6\u7801 +Plugin-Elasticsearch_Connection_Successfully=\u8FDE\u63A5\u6210\u529F +Plugin-Elasticsearch_Connection_Failed=\u8FDE\u63A5\u5931\u8D25 +Plugin-Elasticsearch_Preview=\u9884\u89C8 +Plugin-Elasticsearch_Refresh=\u5237\u65B0 +Plugin-Elasticsearch_Auto=\u81EA\u52A8 +Plugin-Elasticsearch_Program=\u81EA\u5B9A\u4E49 +Plugin-Elasticsearch_Sort_Default=\u9ED8\u8BA4 +Plugin-Elasticsearch_Prepare_Keys_Default=\u9ED8\u8BA4 +Plugin-Elasticsearch_Endpoint=\u7AEF\u70B9 +Plugin-Elasticsearch_Query=\u67E5\u8BE2\u8BED\u53E5 +Plugin-Elasticsearch_Sort_Key=\u952E\u6392\u5E8F +Plugin-Elasticsearch_Key_Prepare=\u9884\u8BFB\u5217\u540D +Plugin-Elasticsearch_Result_Type=\u89C4\u6574\u7C7B\u578B +Plugin-Elasticsearch_Result_Script=\u89C4\u6574\u811A\u672C +Plugin-Elasticsearch_Host_Cluster=\u96C6\u7FA4\u914D\u7F6E\u8BF4\u660E +Plugin-Elasticsearch_Host_Cluster_Description=1\u3001\u4F7F\u7528\u9017\u53F7\u5206\u5272\u96C6\u7FA4\u4E2D\u7684\u591A\u4E2A\u6570\u636E\u5E93\u5730\u5740\u548C\u7AEF\u53E3\uFF0C\u5FC5\u987B\u8981\u6C42\u5730\u5740\u548C\u7AEF\u53E3\u6570\u91CF\u4E00\u81F4\uFF1B\n2\u3001\u6240\u6709elasticsearch\u8282\u70B9\u7684\u7528\u6237\u540D\u548C\u5BC6\u7801\u5FC5\u987B\u76F8\u540C\u3002