├── CHANGELOG ├── .travis.yml ├── docs ├── img │ └── quick-search.png └── userguide.md ├── elasticsearch-cockpit-plugin ├── src │ ├── main │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ └── services │ │ │ │ │ └── org.camunda.bpm.cockpit.plugin.spi.CockpitPlugin │ │ │ └── plugin-webapp │ │ │ │ └── dashboards │ │ │ │ └── app │ │ │ │ ├── pages │ │ │ │ ├── activity-monitor.html │ │ │ │ ├── main.js │ │ │ │ ├── process-definition.html │ │ │ │ ├── search.js │ │ │ │ ├── processDefinition.js │ │ │ │ ├── search.html │ │ │ │ └── activityMonitor.js │ │ │ │ ├── plugin.js │ │ │ │ └── lib │ │ │ │ └── nv.d3.min.css │ │ └── java │ │ │ └── org │ │ │ └── camunda │ │ │ └── bpm │ │ │ └── cockpit │ │ │ └── plugin │ │ │ ├── dashboards │ │ │ ├── resources │ │ │ │ ├── DateHistogramBucketPair.java │ │ │ │ ├── AggregationsResult.java │ │ │ │ ├── SearchResult.java │ │ │ │ ├── DashboardsRootResource.java │ │ │ │ ├── SearchResource.java │ │ │ │ └── ProcessInstanceHistogramResource.java │ │ │ └── DashboardsPlugin.java │ │ │ └── ElasticSearchClientProvider.java │ ├── test │ │ └── resources │ │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── org.camunda.bpm.engine.rest.spi.ProcessEngineProvider │ │ │ └── camunda.cfg.xml │ └── develop │ │ ├── resources │ │ └── WEB-INF │ │ │ └── applicationContext.xml │ │ └── java │ │ └── org │ │ └── camunda │ │ └── bpm │ │ └── extension │ │ └── elasticsearch │ │ └── cockpit │ │ └── demodata │ │ └── DemoDataGenerator.java └── pom.xml ├── start-es.sh ├── elasticsearch-engine-integration ├── src │ ├── test │ │ ├── resources │ │ │ ├── query │ │ │ │ ├── match_variable_value.json │ │ │ │ ├── bool_all.json │ │ │ │ └── querystring_all.json │ │ │ ├── config │ │ │ │ ├── elasticsearch-test.yml │ │ │ │ └── elasticsearch-test-remote.yml │ │ │ ├── camunda-bpm-elasticsearch-remote.json │ │ │ ├── camunda-bpm-elasticsearch.json │ │ │ ├── logging.properties │ │ │ ├── camunda.cfg.remote.xml │ │ │ ├── camunda.cfg.xml │ │ │ └── applicationContext.xml │ │ └── java │ │ │ └── org │ │ │ └── camunda │ │ │ └── bpm │ │ │ ├── elasticsearch │ │ │ ├── jackson │ │ │ │ └── JacksonMixInFilterTest.java │ │ │ ├── ProcessDataContainer.java │ │ │ ├── query │ │ │ │ └── HistoryEventsQueryTest.java │ │ │ ├── AbstractElasticSearchActiveMQTest.java │ │ │ ├── entity │ │ │ │ └── EntityFilterTest.java │ │ │ ├── cfg │ │ │ │ └── ElasticSearchHistoryPluginConfigurationTest.java │ │ │ ├── index │ │ │ │ ├── HistoryEventsIndexingTest.java │ │ │ │ └── HistoryEventsMappingTest.java │ │ │ ├── TestDataGenerator.java │ │ │ └── AbstractElasticSearchTest.java │ │ │ └── example │ │ │ └── invoice │ │ │ └── service │ │ │ └── ArchiveInvoiceService.java │ └── main │ │ ├── resources │ │ ├── camunda-bpm-elasticsearch.json │ │ └── mapping │ │ │ └── processinstance.json │ │ └── java │ │ └── org │ │ └── camunda │ │ └── bpm │ │ └── elasticsearch │ │ ├── jackson │ │ ├── HistoricDetailEventMixIn.java │ │ ├── HistoricTaskInstanceEventMixIn.java │ │ ├── HistoricProcessInstanceEventMixIn.java │ │ ├── HistoricScopeInstanceEventMixIn.java │ │ ├── HistoricActivityInstanceEventMixIn.java │ │ ├── HistoricFormPropertyEventMixIn.java │ │ ├── HistoricVariableUpdateEventMixIn.java │ │ ├── HistoryEventMixIn.java │ │ ├── JsonTransformer.java │ │ └── JacksonMixInFilterModule.java │ │ ├── handler │ │ ├── ElasticSearchHistoryEventHandler.java │ │ ├── ElasticSearchTransactionAwareCompositeEventHandler.java │ │ └── ElasticSearchTransactionAwareHistoryEventHandler.java │ │ ├── session │ │ ├── ElasticSearchSessionFactory.java │ │ └── ElasticSearchSession.java │ │ ├── index │ │ ├── ElasticSearchIndexStrategy.java │ │ ├── ElasticSearchBulkIndexStrategy.java │ │ └── ElasticSearchDefaultIndexStrategy.java │ │ ├── ElasticSearchHistoryEventDispatcher.java │ │ ├── util │ │ ├── ClassUtil.java │ │ └── ElasticSearchHelper.java │ │ └── entity │ │ └── ElasticSearchProcessInstanceHistoryEntity.java └── pom.xml ├── .gitignore ├── README.md ├── elasticsearch-commons ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── camunda │ └── bpm │ └── elasticsearch │ ├── util │ ├── JsonHelper.java │ └── IoUtil.java │ ├── ElasticSearchClient.java │ └── ElasticSearchHistoryPluginConfiguration.java ├── elasticsearch-jboss-module ├── src │ └── main │ │ └── modules │ │ └── org │ │ └── camunda │ │ └── bpm │ │ ├── jboss │ │ └── camunda-jboss-subsystem │ │ │ └── main │ │ │ └── module.xml │ │ └── elasticsearch │ │ └── main │ │ └── module.xml └── pom.xml ├── elasticsearch-lib-module └── pom.xml └── pom.xml /CHANGELOG: -------------------------------------------------------------------------------- 1 | # 1.0.0 2 | 3 | - initial release -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | - oraclejdk7 5 | services: 6 | - elasticsearch -------------------------------------------------------------------------------- /docs/img/quick-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camunda-community-hub/camunda-bpm-elasticsearch/HEAD/docs/img/quick-search.png -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/META-INF/services/org.camunda.bpm.cockpit.plugin.spi.CockpitPlugin: -------------------------------------------------------------------------------- 1 | org.camunda.bpm.cockpit.plugin.dashboards.DashboardsPlugin -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/test/resources/META-INF/services/org.camunda.bpm.engine.rest.spi.ProcessEngineProvider: -------------------------------------------------------------------------------- 1 | org.camunda.bpm.cockpit.engine.TestProcessEngineProvider -------------------------------------------------------------------------------- /start-es.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | distro/elasticsearch-1.4.4/bin/elasticsearch --node.name=camunda_bpm_remote_es --cluster.name=camunda_bpm_es_cluster -Des.script.disable_dynamic=false 3 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/pages/activity-monitor.html: -------------------------------------------------------------------------------- 1 |

Activity Monitor

2 |
3 | 4 |
5 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/plugin.js: -------------------------------------------------------------------------------- 1 | ngDefine('cockpit.plugin.dashboards', [ 2 | 'module:dashboards.pages:./pages/main', 3 | ], function(module) { 4 | 5 | }); 6 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/query/match_variable_value.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "nested": { 4 | "path": "variables", 5 | "query": { 6 | "match": { 7 | "variables.textValue": "somebody" 8 | } 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/config/elasticsearch-test.yml: -------------------------------------------------------------------------------- 1 | node.local : true 2 | node.client : false 3 | node.data : true 4 | node.http.enabled : true 5 | discovery.zen.ping.multicast.enabled : false 6 | network.host : _local_ 7 | script.disable_dynamic : false 8 | cluster.name : camunda_bpm_es_cluster -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/pages/main.js: -------------------------------------------------------------------------------- 1 | ngDefine('dashboards.pages', [ 2 | 'module:dashboards.pages.search:./search', 3 | 'module:dashboards.pages.activityMonitor:./activityMonitor', 4 | 'module:dashboards.pages.processDefinition:./processDefinition' 5 | ], function(module) { 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/config/elasticsearch-test-remote.yml: -------------------------------------------------------------------------------- 1 | node.local : false 2 | node.client : true 3 | node.data : false 4 | node.http.enabled : true 5 | discovery.zen.ping.multicast.enabled : true 6 | #discovery.zen.ping.unicast.hosts: 127.0.0.1:9300 7 | script.disable_dynamic: false 8 | cluster.name : camunda_bpm_es_cluster -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/jackson/JacksonMixInFilterTest.java: -------------------------------------------------------------------------------- 1 | package org.camunda.bpm.elasticsearch.jackson; 2 | 3 | /** 4 | * Tests the JacksonMixInFilter extension 5 | */ 6 | public class JacksonMixInFilterTest { 7 | 8 | // ObjectMapper 9 | // add Module 10 | // add FilterProvider 11 | 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .DS_Store 3 | 4 | # Package Files # 5 | *.jar 6 | *.war 7 | *.ear 8 | 9 | # IntelliJ files # 10 | .idea 11 | *.iml 12 | 13 | # eclipse files # 14 | .classpath 15 | .project 16 | .settings 17 | 18 | # vim # 19 | .swp 20 | 21 | # Generated folders # 22 | distro 23 | target 24 | 25 | # Generated files 26 | test*.json 27 | 28 | #elastic search data # 29 | **/data/elasticsearch 30 | *Test.json 31 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/resources/camunda-bpm-elasticsearch.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": "camundabpm", 3 | "type": "processinstance", 4 | "indexingStrategy": "org.camunda.bpm.elasticsearch.index.ElasticSearchDefaultIndexStrategy", 5 | "esHost": "localhost", 6 | "esPort": "9300", 7 | "esClusterName": "camunda_bpm_es_cluster", 8 | "transportClient": false, 9 | "properties": { 10 | "es.script.disable_dynamic": false 11 | } 12 | } -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/pages/process-definition.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

5 | 6 | {{ processDefinition.name || processDefinition.key }} 7 |

8 | 9 |
10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 | 18 |
19 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/camunda-bpm-elasticsearch-remote.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": "camundabpm", 3 | "type": "processinstance", 4 | "indexingStrategy": "org.camunda.bpm.elasticsearch.index.ElasticSearchDefaultIndexStrategy", 5 | "esHost": "localhost", 6 | "esPort": "9300", 7 | "esClusterName": "camunda_bpm_es_cluster", 8 | "transportClient": false, 9 | "properties": { 10 | "es.node.local" : false, 11 | "es.path.logs" : "${es.path.logs}", 12 | "es.path.data" : "${es.path.data}", 13 | "es.path.work" : "${es.path.work}", 14 | "es.index.number_of_shards" : "1", 15 | "es.index.number_of_replicas" : "0" 16 | } 17 | } -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/camunda-bpm-elasticsearch.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": "camundabpm", 3 | "type": "processinstance", 4 | "indexingStrategy": "org.camunda.bpm.elasticsearch.index.ElasticSearchDefaultIndexStrategy", 5 | "esHost": "localhost", 6 | "esPort": "9300", 7 | "esClusterName": "camunda_bpm_es_cluster", 8 | "transportClient": false, 9 | "properties": { 10 | "es.node.local" : true, 11 | "es.network.host" : "_local_", 12 | "es.path.logs" : "${es.path.logs}", 13 | "es.path.data" : "${es.path.data}", 14 | "es.path.work" : "${es.path.work}", 15 | "es.index.number_of_shards" : "1", 16 | "es.index.number_of_replicas" : "0", 17 | "es.index.store.type" : "memory", 18 | "es.index.store.fs.memory.enabled" : "true" 19 | } 20 | } -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/dashboards/resources/DateHistogramBucketPair.java: -------------------------------------------------------------------------------- 1 | package org.camunda.bpm.cockpit.plugin.dashboards.resources; 2 | 3 | /** 4 | * Created by hawky4s on 12.08.14. 5 | */ 6 | public class DateHistogramBucketPair { 7 | 8 | protected Number key; 9 | protected long docCount; 10 | 11 | public DateHistogramBucketPair(Number key, long docCount) { 12 | this.key = key; 13 | this.docCount = docCount; 14 | } 15 | 16 | public Number getKey() { 17 | return key; 18 | } 19 | 20 | public void setKey(Number key) { 21 | this.key = key; 22 | } 23 | 24 | public long getDocCount() { 25 | return docCount; 26 | } 27 | 28 | public void setDocCount(long docCount) { 29 | this.docCount = docCount; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoricDetailEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | public interface HistoricDetailEventMixIn { 20 | } 21 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoricTaskInstanceEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | public interface HistoricTaskInstanceEventMixIn { 20 | } 21 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoricProcessInstanceEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | public interface HistoricProcessInstanceEventMixIn { 20 | } 21 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoricScopeInstanceEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | public interface HistoricScopeInstanceEventMixIn { 20 | } 21 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoricActivityInstanceEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | public interface HistoricActivityInstanceEventMixIn { 20 | } 21 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | handlers = java.util.logging.ConsoleHandler 18 | .level = FINE 19 | java.util.logging.ConsoleHandler.level=FINE 20 | 21 | org.apache.ibatis.level=FINE 22 | 23 | javax.activation.level=INFO 24 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoricFormPropertyEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | public interface HistoricFormPropertyEventMixIn extends HistoricDetailEventMixIn { 20 | } 21 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoricVariableUpdateEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | public interface HistoricVariableUpdateEventMixIn extends HistoricDetailEventMixIn { 20 | } 21 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/dashboards/resources/AggregationsResult.java: -------------------------------------------------------------------------------- 1 | package org.camunda.bpm.cockpit.plugin.dashboards.resources; 2 | 3 | import org.elasticsearch.search.aggregations.Aggregation; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by hawky4s on 12.08.14. 10 | */ 11 | public class AggregationsResult { 12 | 13 | private Map> dateHistogramBuckets; 14 | private long totalHits; 15 | 16 | public void setDateHistogramBuckets(Map> dateHistogramBuckets) { 17 | this.dateHistogramBuckets = dateHistogramBuckets; 18 | } 19 | 20 | public Map> getDateHistogramBuckets() { 21 | return dateHistogramBuckets; 22 | } 23 | 24 | public void setTotalHits(long totalHits) { 25 | this.totalHits = totalHits; 26 | } 27 | 28 | public long getTotalHits() { 29 | return totalHits; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/test/resources/camunda.cfg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/HistoryEventMixIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | 20 | import com.fasterxml.jackson.annotation.JsonFilter; 21 | import com.fasterxml.jackson.annotation.JsonIgnore; 22 | 23 | @JsonFilter("HistoryEventMixIn") 24 | public interface HistoryEventMixIn { 25 | 26 | @JsonIgnore Object getPersistentState(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/ProcessDataContainer.java: -------------------------------------------------------------------------------- 1 | package org.camunda.bpm.elasticsearch; 2 | 3 | import org.camunda.bpm.engine.runtime.VariableInstance; 4 | 5 | import java.util.List; 6 | 7 | public class ProcessDataContainer { 8 | 9 | private String pid; 10 | private String name; 11 | private List variables; 12 | 13 | public ProcessDataContainer() {} 14 | 15 | public ProcessDataContainer(String pid) { 16 | this.pid = pid; 17 | } 18 | 19 | public ProcessDataContainer(String pid, String name) { 20 | this(pid); 21 | this.name = name; 22 | this.variables = null; 23 | } 24 | 25 | public ProcessDataContainer(String pid, String name, List variables) { 26 | this(pid, name); 27 | this.variables = variables; 28 | } 29 | 30 | public String getPid() { 31 | return pid; 32 | } 33 | 34 | public void setPid(String pid) { 35 | this.pid = pid; 36 | } 37 | 38 | public List getVariables() { 39 | return variables; 40 | } 41 | 42 | public void setVariables(List variables) { 43 | this.variables = variables; 44 | } 45 | 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/handler/ElasticSearchHistoryEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.handler; 18 | 19 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 20 | import org.camunda.bpm.engine.impl.history.handler.HistoryEventHandler; 21 | 22 | import java.util.List; 23 | 24 | public abstract class ElasticSearchHistoryEventHandler implements HistoryEventHandler { 25 | 26 | public abstract void handleEvent(HistoryEvent historyEvent); 27 | 28 | public void handleEvents(List historyEvents) { 29 | for (HistoryEvent historyEvent : historyEvents) { 30 | handleEvent(historyEvent); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/dashboards/DashboardsPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 nico.rehwaldt. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.cockpit.plugin.dashboards; 18 | 19 | import java.util.HashSet; 20 | import java.util.Set; 21 | 22 | import org.camunda.bpm.cockpit.plugin.dashboards.resources.DashboardsRootResource; 23 | import org.camunda.bpm.cockpit.plugin.spi.impl.AbstractCockpitPlugin; 24 | 25 | /** 26 | * 27 | * @author nico.rehwaldt 28 | */ 29 | public class DashboardsPlugin extends AbstractCockpitPlugin { 30 | 31 | public static final String ID = "dashboards"; 32 | 33 | @Override 34 | public String getId() { 35 | return ID; 36 | } 37 | 38 | @Override 39 | public Set> getResourceClasses() { 40 | HashSet> classes = new HashSet>(); 41 | 42 | classes.add(DashboardsRootResource.class); 43 | 44 | return classes; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/session/ElasticSearchSessionFactory.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.elasticsearch.session; 14 | 15 | import org.camunda.bpm.elasticsearch.index.ElasticSearchIndexStrategy; 16 | import org.camunda.bpm.engine.impl.interceptor.Session; 17 | import org.camunda.bpm.engine.impl.interceptor.SessionFactory; 18 | 19 | /** 20 | * @author Daniel Meyer 21 | * 22 | */ 23 | public class ElasticSearchSessionFactory implements SessionFactory { 24 | 25 | protected ElasticSearchIndexStrategy indexingStrategy; 26 | 27 | public ElasticSearchSessionFactory(ElasticSearchIndexStrategy indexingStrategy) { 28 | this.indexingStrategy = indexingStrategy; 29 | } 30 | 31 | public Class getSessionType() { 32 | return ElasticSearchSession.class; 33 | } 34 | 35 | public Session openSession() { 36 | return new ElasticSearchSession(indexingStrategy); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/pages/search.js: -------------------------------------------------------------------------------- 1 | ngDefine('dashboards.pages.search', [ 2 | 'angular', 3 | 'require', 4 | ], function(module, angular, require) { 5 | 6 | var Controller = ['$scope', '$http', 'Uri', '$compile', 7 | function($scope, $http, Uri, $compile) { 8 | 9 | $scope.searchString = ""; 10 | $scope.includeVariables = true; 11 | $scope.includeTasks = true; 12 | $scope.includeActivities = false; 13 | 14 | $scope.searchResults = []; 15 | 16 | $scope.doSearch = function() { 17 | 18 | $http({ 19 | method: 'GET', 20 | url: Uri.appUri("plugin://dashboards/default/search"), 21 | params: { 22 | query: $scope.searchString, 23 | includeVariables: $scope.includeVariables, 24 | includeTasks: $scope.includeTasks, 25 | includeActivities: $scope.includeActivities 26 | } 27 | }).success(function(data) { 28 | $scope.searchResults = data; 29 | }); 30 | 31 | }; 32 | 33 | $scope.clear = function() { 34 | $scope.searchResults = []; 35 | $scope.searchString = ""; 36 | }; 37 | 38 | }]; 39 | 40 | var ViewConfig = [ 'ViewsProvider', function(ViewsProvider) { 41 | ViewsProvider.registerDefaultView('cockpit.dashboard', { 42 | id: 'search', 43 | priority: 20, 44 | label: 'Seach', 45 | controller: Controller, 46 | url: require.toUrl('./search.html') 47 | }); 48 | }]; 49 | 50 | module 51 | .config(ViewConfig); 52 | }); 53 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/query/bool_all.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "filtered": { 4 | "query": { 5 | "match_all": {} 6 | }, 7 | "filter": { 8 | "bool": { 9 | "should": [ 10 | { 11 | "nested": { 12 | "path": "variables", 13 | "query": { 14 | "query_string": { 15 | "fields": ["variables.*"], 16 | "query": "$myValue", 17 | "use_dis_max" : true, 18 | "lenient" : true 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "nested": { 25 | "path": "activities", 26 | "query": { 27 | "query_string": { 28 | "fields": ["activities.*"], 29 | "query": "$myValue", 30 | "use_dis_max" : true, 31 | "lenient" : true 32 | } 33 | } 34 | } 35 | }, 36 | { 37 | "nested": { 38 | "path": "tasks", 39 | "query": { 40 | "query_string": { 41 | "fields": ["tasks.*"], 42 | "query": "$myValue", 43 | "use_dis_max" : true, 44 | "lenient" : true 45 | } 46 | } 47 | } 48 | } 49 | ] 50 | } 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/handler/ElasticSearchTransactionAwareCompositeEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.handler; 18 | 19 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 20 | import org.camunda.bpm.engine.impl.history.handler.DbHistoryEventHandler; 21 | 22 | public class ElasticSearchTransactionAwareCompositeEventHandler extends ElasticSearchHistoryEventHandler { 23 | 24 | protected DbHistoryEventHandler dbHistoryEventHandler = new DbHistoryEventHandler(); 25 | protected ElasticSearchTransactionAwareHistoryEventHandler elasticSearchTransactionAwareHistoryEventHandler = new ElasticSearchTransactionAwareHistoryEventHandler(); 26 | 27 | @Override 28 | public void handleEvent(HistoryEvent historyEvent) { 29 | dbHistoryEventHandler.handleEvent(historyEvent); 30 | elasticSearchTransactionAwareHistoryEventHandler.handleEvent(historyEvent); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/dashboards/resources/SearchResult.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.cockpit.plugin.dashboards.resources; 14 | 15 | /** 16 | * @author Daniel Meyer 17 | * 18 | */ 19 | public class SearchResult { 20 | 21 | protected String processInstanceId; 22 | protected String processDefinitionId; 23 | protected String processDefinitionName; 24 | 25 | public String getProcessInstanceId() { 26 | return processInstanceId; 27 | } 28 | public void setProcessInstanceId(String processInstanceId) { 29 | this.processInstanceId = processInstanceId; 30 | } 31 | public String getProcessDefinitionId() { 32 | return processDefinitionId; 33 | } 34 | public void setProcessDefinitionId(String processDefinitionId) { 35 | this.processDefinitionId = processDefinitionId; 36 | } 37 | public String getProcessDefinitionName() { 38 | return processDefinitionName; 39 | } 40 | public void setProcessDefinitionName(String processDefinitionName) { 41 | this.processDefinitionName = processDefinitionName; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/session/ElasticSearchSession.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.elasticsearch.session; 14 | 15 | import java.util.LinkedList; 16 | import java.util.List; 17 | 18 | import org.camunda.bpm.elasticsearch.index.ElasticSearchIndexStrategy; 19 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 20 | import org.camunda.bpm.engine.impl.interceptor.Session; 21 | 22 | /** 23 | * @author Daniel Meyer 24 | * 25 | */ 26 | public class ElasticSearchSession implements Session { 27 | 28 | protected ElasticSearchIndexStrategy indexingStrategy; 29 | 30 | protected List historyEvents = new LinkedList(); 31 | 32 | public ElasticSearchSession(ElasticSearchIndexStrategy indexingStrategy) { 33 | this.indexingStrategy = indexingStrategy; 34 | } 35 | 36 | public void addHistoryEvent(HistoryEvent historyEvent) { 37 | historyEvents.add(historyEvent); 38 | } 39 | 40 | public void flush() { 41 | indexingStrategy.executeRequest(historyEvents); 42 | } 43 | 44 | public void close() { 45 | 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/dashboards/resources/DashboardsRootResource.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.cockpit.plugin.dashboards.resources; 14 | 15 | import javax.ws.rs.Path; 16 | import javax.ws.rs.PathParam; 17 | 18 | import org.camunda.bpm.cockpit.plugin.dashboards.DashboardsPlugin; 19 | import org.camunda.bpm.cockpit.plugin.resource.AbstractCockpitPluginRootResource; 20 | 21 | @Path("plugin/" + DashboardsPlugin.ID) 22 | public class DashboardsRootResource extends AbstractCockpitPluginRootResource { 23 | 24 | public DashboardsRootResource() { 25 | super(DashboardsPlugin.ID); 26 | } 27 | 28 | @Path("{engineName}"+SearchResource.PATH) 29 | public SearchResource search(@PathParam("engineName") String engineName) { 30 | return subResource(new SearchResource(engineName), engineName); 31 | } 32 | 33 | @Path("{engineName}"+ProcessInstanceHistogramResource.PATH) 34 | public ProcessInstanceHistogramResource dateHistogram(@PathParam("engineName") String engineName) { 35 | return subResource(new ProcessInstanceHistogramResource(engineName), engineName); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/query/HistoryEventsQueryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.query; 18 | 19 | import org.camunda.bpm.elasticsearch.AbstractElasticSearchTest; 20 | import org.camunda.bpm.elasticsearch.ProcessDataContainer; 21 | import org.camunda.bpm.elasticsearch.TestDataGenerator; 22 | import org.camunda.bpm.engine.test.ProcessEngineRule; 23 | import org.junit.Ignore; 24 | import org.junit.Rule; 25 | import org.junit.Test; 26 | 27 | import java.util.HashMap; 28 | 29 | public class HistoryEventsQueryTest extends AbstractElasticSearchTest { 30 | 31 | @Ignore 32 | @Test 33 | public void queryShouldFindProcessInstanceViaVariableValue() { 34 | HashMap stringProcessDataContainerHashMap = TestDataGenerator.startInvoiceProcess(processEngineRule.getProcessEngine(), 10); 35 | 36 | // flushAndRefresh(); 37 | 38 | // QueryBuilders.boolQuery().must(QueryBuilders.nestedQuery("")) 39 | // SearchRequestBuilder srb = client.prepareSearch().setQuery(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/query/querystring_all.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "filtered": { 4 | "query": { 5 | "match": {} 6 | }, 7 | "filter": { 8 | "bool": { 9 | "should": [ 10 | { 11 | "nested": { 12 | "path": "variables", 13 | "query": { 14 | "query_string": { 15 | "fields": ["variables.*"], 16 | "query": "somebody", 17 | "use_dis_max" : true, 18 | "lenient" : true 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "nested": { 25 | "path": "activities", 26 | "query": { 27 | "query_string": { 28 | "fields": ["activities.*"], 29 | "query": "somebody", 30 | "use_dis_max" : true, 31 | "lenient" : true 32 | } 33 | } 34 | } 35 | }, 36 | { 37 | "nested": { 38 | "path": "tasks", 39 | "query": { 40 | "query_string": { 41 | "fields": ["tasks.*"], 42 | "query": "somebody", 43 | "use_dis_max" : true, 44 | "lenient" : true 45 | } 46 | } 47 | } 48 | } 49 | ] 50 | } 51 | } 52 | } 53 | }, 54 | "facets" : { 55 | "histo1" : { 56 | "date_histogram" : { 57 | "key_field" : "endTime", 58 | "interval" : "day" 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/pages/processDefinition.js: -------------------------------------------------------------------------------- 1 | ngDefine('dashboards.pages.processDefinition', [ 2 | 'angular', 3 | 'require' 4 | ], function(module, angular, require) { 5 | 6 | var Controller = ['$scope', 'processDefinition', 'Views', 7 | function($scope, processDefinition, Views) { 8 | 9 | $scope.processDefinition = processDefinition; 10 | 11 | $scope.exportedVars = { read: [ 'processDefinition' ] }; 12 | $scope.dashboardProviders = Views.getProviders({ component: 'dashboard.processDefinition.view' }); 13 | 14 | }]; 15 | 16 | var RouteConfig = [ '$routeProvider', function($routeProvider) { 17 | $routeProvider.when('/process-definition/:processDefinitionId/dashboard', { 18 | templateUrl: require.toUrl('./process-definition.html'), 19 | controller: Controller, 20 | authentication: 'required', 21 | resolve: { 22 | processDefinition: [ 'ResourceResolver', 'ProcessDefinitionResource', 23 | function(ResourceResolver, ProcessDefinitionResource) { 24 | return ResourceResolver.getByRouteParam('processDefinitionId', { 25 | name: 'process definition', 26 | resolve: function(id) { 27 | return ProcessDefinitionResource.get({ id : id }); 28 | } 29 | }); 30 | }] 31 | }, 32 | reloadOnSearch: false 33 | }); 34 | }]; 35 | 36 | var ViewConfig = [ 'ViewsProvider', function(ViewsProvider) { 37 | ViewsProvider.registerDefaultView('cockpit.processDefinition.view', { 38 | id: 'dashboard', 39 | priority: 20, 40 | label: 'Dashboard' 41 | }); 42 | }]; 43 | 44 | module 45 | .config(RouteConfig) 46 | .config(ViewConfig); 47 | }); 48 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/index/ElasticSearchIndexStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.index; 18 | 19 | import org.camunda.bpm.elasticsearch.ElasticSearchHistoryEventDispatcher; 20 | import org.camunda.bpm.elasticsearch.jackson.JsonTransformer; 21 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 22 | import org.elasticsearch.client.Client; 23 | 24 | import java.util.List; 25 | 26 | public abstract class ElasticSearchIndexStrategy { 27 | 28 | protected ElasticSearchHistoryEventDispatcher dispatcher = new ElasticSearchHistoryEventDispatcher(); 29 | protected JsonTransformer transformer = new JsonTransformer(); 30 | protected Client esClient; 31 | 32 | public abstract void executeRequest(List historyEvents); 33 | 34 | public abstract void executeRequest(HistoryEvent historyEvent); 35 | 36 | public void setDispatcher(ElasticSearchHistoryEventDispatcher dispatcher) { 37 | this.dispatcher = dispatcher; 38 | } 39 | 40 | public void setEsClient(Client esClient) { 41 | this.esClient = esClient; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | camunda BPM - ElasticSearch extension 2 | =========================== 3 | 4 | [![Build Status](https://travis-ci.org/camunda/camunda-bpm-elasticsearch.svg?branch=master)](https://travis-ci.org/camunda/camunda-bpm-elasticsearch) 5 | [![Build Status](https://drone.io/github.com/camunda/camunda-bpm-elasticsearch/status.png)](https://drone.io/github.com/camunda/camunda-bpm-elasticsearch/latest) 6 | [![Stories in Ready](https://badge.waffle.io/camunda/camunda-bpm-elasticsearch.png?label=ready&title=Ready)](https://waffle.io/camunda/camunda-bpm-elasticsearch) 7 | 8 | camunda-bpm-elasticsearch combines the camunda-bpm platform with the powerful search capabilities of ElasticSearch. 9 | It comes with a process engine plugin which indexes all generated history events through ElasticSearch. 10 | To use the indexed data, a cockpit plugin is also provided to allow querying and retrieval of process instances through ElasticSearch. 11 | 12 | Documentation 13 | ------------- 14 | 15 | Read the [User Guide](docs/userguide.md). 16 | 17 | Components (Modules) 18 | -------------------- 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
ModuleDescription
elasticsearch-cockpit-pluginIntegration of ElasticSearch with camunda BPM cockpit as a cockpit plugin.
elasticsearch-engine-integrationIntegration of ElasticSearch with camunda BPM engine as a process engine plugin.
elasticsearch-jboss-moduleProduces in its target directory a folder named modules with all required libraries to use with JBoss 7.x.
elasticsearch-lib-moduleProduces in its target directory a folder with all required libraries to drop into Tomcat's lib directory.
36 | 37 | -------------------------------------------------------------------------------- /elasticsearch-commons/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 4.0.0 22 | 23 | 24 | org.camunda.bpm.extension.elasticsearch 25 | camunda-bpm-elasticsearch 26 | 1.0.0-SNAPSHOT 27 | 28 | 29 | elasticsearch-commons 30 | camunda bpm - elasticsearch - commons 31 | 32 | 33 | 34 | org.elasticsearch 35 | elasticsearch 36 | 37 | 38 | 39 | com.fasterxml.jackson.core 40 | jackson-databind 41 | 42 | 43 | 44 | com.google.guava 45 | guava 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/handler/ElasticSearchTransactionAwareHistoryEventHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.handler; 18 | 19 | import org.camunda.bpm.elasticsearch.session.ElasticSearchSession; 20 | import org.camunda.bpm.engine.impl.context.Context; 21 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 22 | 23 | /** 24 | * {@link ElasticSearchHistoryEventHandler} implementation which adds the event to the current {@link ElasticSearchSession}. 25 | * The ElasticSearchSession is opened once per command and batches all events fired until the session is closed. 26 | * 27 | * @author Christian Lipphardt 28 | * @author Daniel Meyer 29 | * 30 | */ 31 | public class ElasticSearchTransactionAwareHistoryEventHandler extends ElasticSearchHistoryEventHandler { 32 | 33 | public void handleEvent(HistoryEvent historyEvent) { 34 | 35 | // get or create current ElasticSearchSession 36 | ElasticSearchSession elasticSearchSession = Context.getCommandContext() 37 | .getSession(ElasticSearchSession.class); 38 | 39 | // add event to elastic search session. 40 | elasticSearchSession.addHistoryEvent(historyEvent); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/pages/search.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 |
16 |

Search Results

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 32 | 35 | 36 | 37 |
IdProcess
28 | 29 | {{processInstance.processInstanceId}} 30 | 31 | 33 | {{processInstance.processDefinitionName}} 34 |
38 |
39 | 40 | 61 | 62 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/example/invoice/service/ArchiveInvoiceService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* Licensed under the Apache License, Version 2.0 (the "License"); 18 | * you may not use this file except in compliance with the License. 19 | * You may obtain a copy of the License at 20 | * 21 | * http://www.apache.org/licenses/LICENSE-2.0 22 | * 23 | * Unless required by applicable law or agreed to in writing, software 24 | * distributed under the License is distributed on an "AS IS" BASIS, 25 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 | * See the License for the specific language governing permissions and 27 | * limitations under the License. 28 | */ 29 | package org.camunda.bpm.example.invoice.service; 30 | 31 | import org.camunda.bpm.engine.delegate.DelegateExecution; 32 | import org.camunda.bpm.engine.delegate.JavaDelegate; 33 | 34 | import java.util.logging.Logger; 35 | 36 | /** 37 | *

This is an empty service implementation illustrating how to use a plain 38 | * Java Class as a BPMN 2.0 Service Task delegate.

39 | */ 40 | public class ArchiveInvoiceService implements JavaDelegate { 41 | 42 | private final Logger LOGGER = Logger.getLogger(ArchiveInvoiceService.class.getName()); 43 | 44 | public void execute(DelegateExecution execution) throws Exception { 45 | 46 | LOGGER.info("\n\n ... Now archiving invoice " + execution.getProcessInstanceId() +"\n"); 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/ElasticSearchHistoryEventDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch; 18 | 19 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 20 | 21 | public class ElasticSearchHistoryEventDispatcher { 22 | 23 | public static final String DEFAULT_DISPATCH_INDEX = ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM; 24 | public static final String DEFAULT_DISPATCH_TYPE = ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM; 25 | 26 | 27 | protected String getDispatchTargetIndexForHistoryEvent(HistoryEvent historyEvent) { 28 | return null; 29 | } 30 | 31 | public String getDispatchTargetIndex(HistoryEvent historyEvent) { 32 | String dispatchTargetTypeForHistoryEvent = getDispatchTargetIndexForHistoryEvent(historyEvent); 33 | if (dispatchTargetTypeForHistoryEvent != null) { 34 | return dispatchTargetTypeForHistoryEvent; 35 | } else { 36 | return DEFAULT_DISPATCH_INDEX; 37 | } 38 | } 39 | 40 | protected String getDispatchTargetTypeForHistoryEvent(HistoryEvent historyEvent) { 41 | return null; 42 | } 43 | 44 | public String getDispatchTargetType(HistoryEvent historyEvent) { 45 | String dispatchTargetForHistoryEvent = getDispatchTargetTypeForHistoryEvent(historyEvent); 46 | if (dispatchTargetForHistoryEvent != null) { 47 | return dispatchTargetForHistoryEvent; 48 | } else { 49 | return DEFAULT_DISPATCH_TYPE; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /elasticsearch-jboss-module/src/main/modules/org/camunda/bpm/jboss/camunda-jboss-subsystem/main/module.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/camunda.cfg.remote.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/camunda.cfg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/ElasticSearchClientProvider.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.cockpit.plugin; 14 | 15 | import java.util.List; 16 | 17 | import org.camunda.bpm.elasticsearch.ElasticSearchClient; 18 | import org.camunda.bpm.elasticsearch.ElasticSearchHistoryPlugin; 19 | import org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration; 20 | import org.camunda.bpm.engine.ProcessEngine; 21 | import org.camunda.bpm.engine.impl.ProcessEngineImpl; 22 | import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin; 23 | import org.elasticsearch.client.Client; 24 | 25 | /** 26 | * @author Daniel Meyer 27 | * 28 | */ 29 | public class ElasticSearchClientProvider { 30 | 31 | protected static ElasticSearchClient cachedClient = null; 32 | 33 | public static Client getClient(ProcessEngine processEngine) { 34 | 35 | if(cachedClient == null) { 36 | createClient(processEngine); 37 | } 38 | 39 | return cachedClient.get(); 40 | } 41 | 42 | protected static void createClient(ProcessEngine processEngine) { 43 | List processEnginePlugins = ((ProcessEngineImpl) processEngine).getProcessEngineConfiguration() 44 | .getProcessEnginePlugins(); 45 | 46 | // check whether process enigne has elastic search plugin configured 47 | for (ProcessEnginePlugin processEnginePlugin : processEnginePlugins) { 48 | if (processEnginePlugin instanceof ElasticSearchHistoryPlugin) { 49 | ElasticSearchHistoryPlugin historyPlugin = (ElasticSearchHistoryPlugin) processEnginePlugin; 50 | cachedClient = historyPlugin.getElasticSearchClient(); 51 | break; 52 | } 53 | } 54 | 55 | if(cachedClient == null) { 56 | // create new client from classpath configuration 57 | ElasticSearchHistoryPluginConfiguration elasticSearchPluginConfiguration = ElasticSearchHistoryPluginConfiguration.readConfigurationFromClasspath(); 58 | cachedClient = new ElasticSearchClient(elasticSearchPluginConfiguration); 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/AbstractElasticSearchActiveMQTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch; 18 | 19 | import org.apache.activemq.ActiveMQConnectionFactory; 20 | import org.apache.activemq.broker.BrokerService; 21 | import org.apache.activemq.broker.TransportConnector; 22 | import org.apache.activemq.broker.region.policy.PolicyEntry; 23 | import org.apache.activemq.broker.region.policy.PolicyMap; 24 | import org.junit.After; 25 | import org.junit.Before; 26 | 27 | import javax.jms.Connection; 28 | import java.net.URI; 29 | 30 | public class AbstractElasticSearchActiveMQTest { // extends AbstractElasticSearchTest { 31 | 32 | private BrokerService broker; 33 | private TransportConnector connector; 34 | private Connection connection; 35 | 36 | @Before 37 | public void setup() throws Exception { 38 | broker = createBroker(); 39 | connector = new TransportConnector(); 40 | connector.setUri(new URI("vm://localhost")); 41 | broker.addConnector(connector); 42 | broker.start(); 43 | 44 | ActiveMQConnectionFactory connFactory = 45 | new ActiveMQConnectionFactory(connector.getConnectUri() + "?jms.prefetchPolicy.all=1"); 46 | connection = connFactory.createConnection(); 47 | connection.start(); 48 | } 49 | 50 | @After 51 | public void tearDown() throws Exception { 52 | connector.stop(); 53 | connection.close(); 54 | broker.stop(); 55 | } 56 | 57 | protected BrokerService createBroker() { 58 | BrokerService brokerService = new BrokerService(); 59 | brokerService.setPersistent(false); 60 | brokerService.setUseJmx(false); 61 | 62 | PolicyMap policyMap = new PolicyMap(); 63 | PolicyEntry policy = new PolicyEntry(); 64 | policy.setConsumersBeforeDispatchStarts(2); 65 | policy.setTimeBeforeDispatchStarts(1000); 66 | policyMap.setDefaultEntry(policy); 67 | 68 | brokerService.setDestinationPolicy(policyMap); 69 | 70 | return brokerService; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/entity/EntityFilterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.entity; 18 | 19 | import com.fasterxml.jackson.core.JsonProcessingException; 20 | import org.camunda.bpm.elasticsearch.jackson.JsonTransformer; 21 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 22 | import org.junit.After; 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | 26 | import java.io.IOException; 27 | import java.util.Map; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | import static org.junit.Assert.assertFalse; 31 | 32 | public class EntityFilterTest { 33 | 34 | private HistoryEvent historyEvent; 35 | private JsonTransformer jsonTransformer; 36 | 37 | @Before 38 | public void setUp() { 39 | jsonTransformer = new JsonTransformer(); 40 | 41 | historyEvent = new HistoryEvent(); 42 | historyEvent.setId("id"); 43 | historyEvent.setExecutionId("ExecutionId"); 44 | historyEvent.setProcessDefinitionId("processDefinitionId"); 45 | historyEvent.setProcessInstanceId("processInstanceId"); 46 | historyEvent.setEventType(HistoryEvent.ACTIVITY_EVENT_TYPE_START); 47 | 48 | assertEquals(HistoryEvent.class, historyEvent.getPersistentState()); 49 | } 50 | 51 | @After 52 | public void tearDown() { 53 | jsonTransformer = null; 54 | } 55 | 56 | @Test 57 | public void shouldTransformHistoryEventToJsonAndApplyMixInFilter() throws JsonProcessingException { 58 | String json = jsonTransformer.transformToJson(historyEvent); 59 | 60 | assertFalse(json.contains(HistoryEvent.class.getName())); 61 | } 62 | 63 | @Test 64 | public void shouldTransformJsonToMapAndApplyMixInFilter() throws IOException { 65 | String json = jsonTransformer.transformToJson(historyEvent); 66 | assertFalse(json.contains(HistoryEvent.class.getName())); 67 | 68 | Map jsonMap = jsonTransformer.transformJsonToMap(json); 69 | assertFalse(jsonMap.containsKey("")); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /elasticsearch-jboss-module/src/main/modules/org/camunda/bpm/elasticsearch/main/module.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/index/ElasticSearchBulkIndexStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.index; 18 | 19 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 20 | import org.elasticsearch.action.bulk.BulkItemResponse; 21 | import org.elasticsearch.action.bulk.BulkRequestBuilder; 22 | import org.elasticsearch.action.bulk.BulkResponse; 23 | import org.elasticsearch.action.update.UpdateRequestBuilder; 24 | import org.elasticsearch.common.unit.TimeValue; 25 | 26 | import java.io.IOException; 27 | import java.util.List; 28 | import java.util.logging.Level; 29 | 30 | public class ElasticSearchBulkIndexStrategy extends ElasticSearchDefaultIndexStrategy { 31 | 32 | @Override 33 | public void executeRequest(List historyEvents) { 34 | BulkRequestBuilder bulkRequestBuilder = esClient.prepareBulk(); 35 | try { 36 | for (HistoryEvent historyEvent : historyEvents) { 37 | UpdateRequestBuilder updateRequestBuilder = prepareUpdateRequest(historyEvent); 38 | bulkRequestBuilder.add(updateRequestBuilder); 39 | } 40 | 41 | BulkResponse bulkResponse; 42 | if (WAIT_FOR_RESPONSE > 0) { 43 | bulkResponse = bulkRequestBuilder.get(TimeValue.timeValueSeconds(WAIT_FOR_RESPONSE)); 44 | } else { 45 | bulkResponse = bulkRequestBuilder.get(); 46 | } 47 | 48 | if (bulkResponse.hasFailures()) { 49 | LOGGER.severe("Error while executing bulk request: " + bulkResponse.buildFailureMessage()); 50 | } 51 | 52 | if (LOGGER.isLoggable(Level.FINEST)) { 53 | for (BulkItemResponse bulkItemResponse : bulkResponse) { 54 | LOGGER.finest("[" + bulkItemResponse.getIndex() + 55 | "][" + bulkItemResponse.getType() + 56 | "][" + bulkItemResponse.getOpType() + 57 | "] process instance with id '" + bulkItemResponse.getId() + "'"); 58 | } 59 | } 60 | } catch (IOException e) { 61 | LOGGER.log(Level.SEVERE, e.getMessage(), e); 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/cfg/ElasticSearchHistoryPluginConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.cfg; 18 | 19 | 20 | import com.fasterxml.jackson.core.JsonProcessingException; 21 | import com.fasterxml.jackson.databind.ObjectMapper; 22 | import org.camunda.bpm.elasticsearch.index.ElasticSearchDefaultIndexStrategy; 23 | import org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration; 24 | import org.junit.Test; 25 | 26 | import static org.junit.Assert.assertEquals; 27 | import static org.junit.Assert.assertFalse; 28 | import static org.junit.Assert.assertTrue; 29 | 30 | public class ElasticSearchHistoryPluginConfigurationTest { 31 | 32 | @Test 33 | public void writeElasticSearchHistoryPluginConfiguration() throws JsonProcessingException { 34 | ObjectMapper objectMapper = new ObjectMapper(); 35 | 36 | String config = objectMapper.writeValueAsString(new ElasticSearchHistoryPluginConfiguration()); 37 | System.out.println(config); 38 | } 39 | 40 | @Test 41 | public void readElasticSearchHistoryPluginConfiguration() { 42 | ElasticSearchHistoryPluginConfiguration historyPluginConfiguration = ElasticSearchHistoryPluginConfiguration.readConfigurationFromClasspath(); 43 | assertEquals("camundabpm", historyPluginConfiguration.getIndex()); 44 | assertEquals("processinstance", historyPluginConfiguration.getType()); 45 | assertEquals(ElasticSearchDefaultIndexStrategy.class.getName(), historyPluginConfiguration.getIndexingStrategy()); 46 | 47 | assertEquals("localhost", historyPluginConfiguration.getEsHost()); 48 | assertEquals("9300", historyPluginConfiguration.getEsPort()); 49 | assertEquals("camunda_bpm_es_cluster", historyPluginConfiguration.getEsClusterName()); 50 | assertFalse(historyPluginConfiguration.isTransportClient()); 51 | 52 | // check properties 53 | assertEquals("_local_", historyPluginConfiguration.getProperties().get("es.network.host")); 54 | assertTrue((Boolean) historyPluginConfiguration.getProperties().get("es.node.local")); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/pages/activityMonitor.js: -------------------------------------------------------------------------------- 1 | ngDefine('dashboards.pages.activityMonitor', [ 2 | 'angular', 3 | 'require', 4 | '../lib/freewall', 5 | '../lib/d3.min', 6 | '../lib/nv.d3.min', 7 | 'module:nvd3:../lib/angular-nvd3' 8 | ], function(module, angular, require) { 9 | 10 | var Controller = ['$scope', '$http', 'Uri', '$compile', '$timeout', 11 | function($scope, $http, Uri, $compile, $timeout) { 12 | 13 | $('head').append(''); 14 | 15 | $scope.interval = '1s'; 16 | $scope.timeframe = undefined; 17 | $scope.options = { 18 | chart: { 19 | type: 'stackedAreaChart', 20 | height: 400, 21 | margin : { 22 | top: 20, 23 | right: 20, 24 | bottom: 60, 25 | left: 40 26 | }, 27 | x: function(bucket){return bucket.key;}, 28 | y: function(bucket){return bucket.docCount;}, 29 | useVoronoi: false, 30 | clipEdge: true, 31 | transitionDuration: 1, 32 | useInteractiveGuideline: true, 33 | xAxis: { 34 | showMaxMin: true, 35 | tickFormat: function(d) { 36 | return d3.time.format('%x')(new Date(d)); 37 | } 38 | }, 39 | yAxis: { 40 | tickFormat: function(d){ 41 | return d3.format(',.2f')(d); 42 | } 43 | } 44 | } 45 | }; 46 | 47 | 48 | $scope.getHistogramData = function() { 49 | 50 | 51 | $http({ 52 | method: 'GET', 53 | url: Uri.appUri("plugin://dashboards/default/histogram/processinstance"), 54 | params: { 55 | interval: $scope.interval, 56 | timeframe: $scope.timeframe 57 | } 58 | }).success(function(data) { 59 | histogramData = []; 60 | 61 | 62 | var values = []; 63 | 64 | 65 | $scope.data = []; 66 | var ended = { "key": "Ended Process Instances", "values": [] }; 67 | $scope.data.push(ended); 68 | 69 | angular.forEach(data.dateHistogramBuckets.ended, function(bucket) { 70 | $scope.data[0].values.push(bucket); 71 | }, values); 72 | 73 | $timeout($scope.getHistogramData, 2000); 74 | }); 75 | 76 | }; 77 | 78 | $scope.getHistogramData(); 79 | }]; 80 | 81 | var ViewConfig = [ 'ViewsProvider', function(ViewsProvider) { 82 | ViewsProvider.registerDefaultView('cockpit.dashboard', { 83 | id: 'activity-monitor', 84 | priority: 19, 85 | label: 'Activity Monitor', 86 | controller: Controller, 87 | url: require.toUrl('./activity-monitor.html') 88 | }); 89 | }]; 90 | 91 | module 92 | .config(ViewConfig); 93 | }); 94 | -------------------------------------------------------------------------------- /elasticsearch-lib-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 4.0.0 22 | 23 | 24 | org.camunda.bpm.extension.elasticsearch 25 | camunda-bpm-elasticsearch 26 | 1.0.0-SNAPSHOT 27 | 28 | 29 | elasticsearch-lib-module 30 | camunda bpm - elasticsearch - tomcat 31 | 32 | 33 | 34 | org.camunda.bpm.extension.elasticsearch 35 | elasticsearch-engine-integration 36 | ${project.version} 37 | provided 38 | 39 | 40 | org.elasticsearch 41 | elasticsearch 42 | 43 | 44 | 45 | 46 | 47 | lib 48 | 49 | true 50 | 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-dependency-plugin 56 | 2.8 57 | 58 | 59 | copy-dependencies 60 | prepare-package 61 | 62 | copy-dependencies 63 | 64 | 65 | ${project.build.directory}/lib/ 66 | false 67 | false 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/util/ClassUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.util; 18 | 19 | import org.camunda.bpm.engine.ClassLoadingException; 20 | import org.camunda.bpm.engine.ProcessEngineException; 21 | import org.camunda.bpm.engine.impl.util.ClassLoaderUtil; 22 | 23 | public class ClassUtil { 24 | 25 | public static T createInstance(Class clazz) { 26 | try { 27 | return clazz.newInstance(); 28 | 29 | } catch (InstantiationException e) { 30 | throw new ProcessEngineException("Could not instantiate class", e); 31 | } catch (IllegalAccessException e) { 32 | throw new ProcessEngineException("IllegalAccessException while instantiating class", e); 33 | } 34 | } 35 | 36 | @SuppressWarnings("unchecked") 37 | public static Class loadClass(String className, ClassLoader customClassloader, Class clazz) { 38 | try { 39 | if(customClassloader != null) { 40 | return (Class) customClassloader.loadClass(className); 41 | }else { 42 | return (Class) ClassUtil.loadClass(className); 43 | } 44 | 45 | } catch (ClassNotFoundException e) { 46 | throw new ProcessEngineException("Could not load configuration class", e); 47 | 48 | } catch (ClassCastException e) { 49 | throw new ProcessEngineException("Custom class of wrong type. Must extend "+clazz.getName(), e); 50 | 51 | } 52 | } 53 | 54 | public static Class loadClass(String className) { 55 | Class clazz = null; 56 | ClassLoader classLoader = null; 57 | 58 | Throwable throwable = null; 59 | 60 | try { 61 | ClassLoader contextClassloader = ClassLoaderUtil.getContextClassloader(); 62 | if(contextClassloader != null) { 63 | clazz = Class.forName(className, true, contextClassloader); 64 | } 65 | } catch(Throwable t) { 66 | if(throwable == null) { 67 | throwable = t; 68 | } 69 | } 70 | if(clazz == null) { 71 | try { 72 | clazz = Class.forName(className, true, ClassUtil.class.getClassLoader()); 73 | } catch(Throwable t) { 74 | if(throwable == null) { 75 | throwable = t; 76 | } 77 | } 78 | } 79 | if(clazz == null) { 80 | throw new ClassLoadingException(className, throwable); 81 | } 82 | return clazz; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /elasticsearch-commons/src/main/java/org/camunda/bpm/elasticsearch/util/JsonHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.util; 18 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import com.fasterxml.jackson.databind.type.MapType; 21 | import com.fasterxml.jackson.databind.type.TypeFactory; 22 | 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | import java.util.Scanner; 28 | 29 | public class JsonHelper { 30 | 31 | private static ObjectMapper objectMapper = new ObjectMapper(); 32 | 33 | public static T readJsonFromClasspath(Class clazz, String fileName) { 34 | InputStream inputStream = null; 35 | 36 | try { 37 | inputStream = IoUtil.getResourceAsStream(fileName); 38 | if (inputStream == null) { 39 | throw new RuntimeException("File '" + fileName + "' not found!"); 40 | } 41 | 42 | T typedJson = objectMapper.readValue(inputStream, clazz); 43 | 44 | return typedJson; 45 | } catch (IOException e) { 46 | throw new RuntimeException("Unable to load json [" + fileName + "] from classpath", e); 47 | } finally { 48 | IoUtil.closeSilently(inputStream); 49 | } 50 | } 51 | 52 | public static Map readJsonFromClasspathAsMap(String fileName) { 53 | InputStream inputStream = null; 54 | 55 | try { 56 | inputStream = IoUtil.getResourceAsStream(fileName); 57 | if (inputStream == null) { 58 | throw new RuntimeException("File '" + fileName + "' not found!"); 59 | } 60 | 61 | MapType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class); 62 | HashMap mapping = objectMapper.readValue(inputStream, type); 63 | 64 | return mapping; 65 | } catch (IOException e) { 66 | throw new RuntimeException("Unable to load json [" + fileName + "] from classpath", e); 67 | } finally { 68 | IoUtil.closeSilently(inputStream); 69 | } 70 | } 71 | 72 | public static String readJsonFromClasspathAsString(String fileName) { 73 | InputStream inputStream = null; 74 | 75 | try { 76 | inputStream = IoUtil.getResourceAsStream(fileName); 77 | if (inputStream == null) { 78 | throw new RuntimeException("File '" + fileName + "' not found!"); 79 | } 80 | 81 | Scanner s = new java.util.Scanner(inputStream, "UTF-8").useDelimiter("\\A"); 82 | return s.hasNext() ? s.next() : null; 83 | } finally { 84 | IoUtil.closeSilently(inputStream); 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /elasticsearch-commons/src/main/java/org/camunda/bpm/elasticsearch/util/IoUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.util; 18 | 19 | import com.google.common.io.Files; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.OutputStream; 25 | import java.nio.charset.Charset; 26 | 27 | public class IoUtil { 28 | 29 | public static final Charset DEFAULT_UTF_8_CHARSET = Charset.forName("UTF-8"); 30 | 31 | public static void writeToFile(String content, String fileName) { 32 | writeToFile(content.getBytes(DEFAULT_UTF_8_CHARSET), fileName, true); 33 | } 34 | 35 | public static void writeToFile(String content, String fileName, boolean createFile) { 36 | writeToFile(content.getBytes(DEFAULT_UTF_8_CHARSET), fileName, createFile); 37 | } 38 | 39 | public static void writeToFile(byte[] content, String fileName, boolean createFile) { 40 | File file = new File(fileName); 41 | try { 42 | if (createFile) { 43 | Files.createParentDirs(file); 44 | file.createNewFile(); 45 | } 46 | 47 | Files.write(content, file); 48 | } catch (IOException e) { 49 | // nop 50 | } 51 | } 52 | 53 | public static InputStream getResourceAsStream(String name) { 54 | InputStream resourceStream = null; 55 | 56 | // Try the current Thread context classloader 57 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 58 | resourceStream = classLoader.getResourceAsStream(name); 59 | if(resourceStream == null) { 60 | // Finally, try the classloader for this class 61 | classLoader = IoUtil.class.getClassLoader(); 62 | resourceStream = classLoader.getResourceAsStream(name); 63 | } 64 | 65 | return resourceStream; 66 | } 67 | 68 | /** 69 | * Closes the given stream. The same as calling {@link InputStream#close()}, but 70 | * errors while closing are silently ignored. 71 | */ 72 | public static void closeSilently(InputStream inputStream) { 73 | try { 74 | if(inputStream != null) { 75 | inputStream.close(); 76 | } 77 | } catch(IOException ignore) { 78 | // Exception is silently ignored 79 | } 80 | } 81 | 82 | /** 83 | * Closes the given stream. The same as calling {@link java.io.OutputStream#close()}, but 84 | * errors while closing are silently ignored. 85 | */ 86 | public static void closeSilently(OutputStream outputStream) { 87 | try { 88 | if(outputStream != null) { 89 | outputStream.close(); 90 | } 91 | } catch(IOException ignore) { 92 | // Exception is silently ignored 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/JsonTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.core.JsonProcessingException; 21 | import com.fasterxml.jackson.databind.JavaType; 22 | import com.fasterxml.jackson.databind.ObjectMapper; 23 | import com.fasterxml.jackson.databind.type.CollectionType; 24 | import com.fasterxml.jackson.databind.type.MapType; 25 | import com.fasterxml.jackson.databind.type.SimpleType; 26 | import com.fasterxml.jackson.databind.type.TypeFactory; 27 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 28 | 29 | import java.io.IOException; 30 | import java.util.ArrayList; 31 | import java.util.HashMap; 32 | import java.util.List; 33 | import java.util.Map; 34 | 35 | public class JsonTransformer { 36 | 37 | protected ObjectMapper mapper = new ObjectMapper(); 38 | 39 | public JsonTransformer() { 40 | configureJsonMapper(null); 41 | } 42 | 43 | public JsonTransformer(HashMap, Class> mixInFilters) { 44 | configureJsonMapper(mixInFilters); 45 | } 46 | 47 | protected void configureJsonMapper(HashMap, Class> mixInFilters) { 48 | //mapper.configure(WRITE_DATE_KEYS_AS_TIMESTAMPS, true); 49 | 50 | // serialize only non null values 51 | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 52 | // allow filtering of entities 53 | mapper.registerModule(new JacksonMixInFilterModule(mixInFilters)); 54 | mapper.setFilters(JacksonMixInFilterModule.getCustomFilterProvider()); 55 | } 56 | 57 | public String transformToJson(HistoryEvent historyEvent) throws JsonProcessingException { 58 | return mapper.writeValueAsString(historyEvent); 59 | } 60 | 61 | public byte[] transformToBytes(HistoryEvent historyEvent) throws JsonProcessingException { 62 | return mapper.writeValueAsBytes(historyEvent); 63 | } 64 | 65 | public Map transformJsonToMap(String json) throws IOException { 66 | MapType mapType = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class); 67 | return mapper.readValue(json, mapType); 68 | } 69 | 70 | public List> transformJsonToList(String json) throws IOException { 71 | JavaType javaType = MapType.construct(HashMap.class, SimpleType.construct(String.class), SimpleType.construct(Object.class)); 72 | 73 | CollectionType listType = TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, javaType); 74 | return mapper.readValue(json, listType); 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/develop/resources/WEB-INF/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/index/HistoryEventsIndexingTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.index; 18 | 19 | import org.camunda.bpm.elasticsearch.AbstractElasticSearchTest; 20 | import org.camunda.bpm.elasticsearch.ProcessDataContainer; 21 | import org.camunda.bpm.elasticsearch.TestDataGenerator; 22 | import org.camunda.bpm.elasticsearch.util.IoUtil; 23 | import org.elasticsearch.action.search.SearchRequestBuilder; 24 | import org.elasticsearch.action.search.SearchResponse; 25 | import org.elasticsearch.index.query.FilterBuilders; 26 | import org.elasticsearch.index.query.FilteredQueryBuilder; 27 | import org.elasticsearch.index.query.QueryBuilders; 28 | import org.elasticsearch.search.SearchHit; 29 | import org.elasticsearch.search.SearchHits; 30 | import org.junit.Test; 31 | 32 | import java.io.IOException; 33 | import java.util.ArrayList; 34 | import java.util.HashMap; 35 | import java.util.Map; 36 | 37 | import static org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM; 38 | import static org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM; 39 | import static org.junit.Assert.assertEquals; 40 | import static org.junit.Assert.assertNotNull; 41 | 42 | public class HistoryEventsIndexingTest extends AbstractElasticSearchTest { 43 | 44 | @Test 45 | public void testIndexingSingleInvoice() throws IOException { 46 | HashMap processesById = TestDataGenerator.startInvoiceProcess(processEngineRule.getProcessEngine(), 1); 47 | 48 | String[] pids = processesById.keySet().toArray(new String[0]); 49 | 50 | // elasticsearch ////////////////////////////// 51 | 52 | flushAndRefresh(); 53 | 54 | FilteredQueryBuilder query = QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter("processInstanceId", pids[0])); 55 | 56 | SearchRequestBuilder searchRequestBuilder = client.prepareSearch(ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM) 57 | .setQuery(query); 58 | 59 | IoUtil.writeToFile(searchRequestBuilder.toString(), this.getClass().getSimpleName() + ".json", true); 60 | 61 | SearchResponse searchResponse = searchRequestBuilder.get(); 62 | SearchHits hits = searchResponse.getHits(); 63 | assertEquals(1, hits.totalHits()); 64 | 65 | SearchHit hit = hits.getAt(0); 66 | assertEquals(pids[0], hit.getId()); 67 | assertEquals(ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM, hit.getType()); 68 | 69 | Map source = hit.getSource(); 70 | assertNotNull(source.get("startTime")); 71 | assertNotNull(source.get("endTime")); 72 | ArrayList variables = (ArrayList) source.get("variables"); 73 | assertEquals(5, variables.size()); 74 | ArrayList tasks = (ArrayList) source.get("tasks"); 75 | assertEquals(9, tasks.size()); 76 | ArrayList activities = (ArrayList) source.get("activities"); 77 | assertEquals(19, activities.size()); 78 | 79 | logger.info(searchResponse.toString()); 80 | 81 | // for (SearchHit searchHit : searchResponse.getHits()) { 82 | // logger.info(searchHit.sourceAsString()); 83 | // } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/index/HistoryEventsMappingTest.java: -------------------------------------------------------------------------------- 1 | package org.camunda.bpm.elasticsearch.index; 2 | 3 | import com.github.tlrx.elasticsearch.test.annotations.ElasticsearchIndex; 4 | import com.github.tlrx.elasticsearch.test.annotations.ElasticsearchMapping; 5 | import org.camunda.bpm.elasticsearch.AbstractElasticSearchTest; 6 | import org.camunda.bpm.elasticsearch.ProcessDataContainer; 7 | import org.camunda.bpm.elasticsearch.TestDataGenerator; 8 | import org.camunda.bpm.elasticsearch.util.IoUtil; 9 | import org.elasticsearch.action.search.SearchRequestBuilder; 10 | import org.elasticsearch.action.search.SearchResponse; 11 | import org.elasticsearch.index.query.FilterBuilders; 12 | import org.elasticsearch.index.query.FilteredQueryBuilder; 13 | import org.elasticsearch.index.query.QueryBuilders; 14 | import org.elasticsearch.search.SearchHit; 15 | import org.elasticsearch.search.SearchHits; 16 | import org.junit.Test; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | import static org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM; 24 | import static org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM; 25 | import static org.junit.Assert.assertEquals; 26 | import static org.junit.Assert.assertNotNull; 27 | 28 | public class HistoryEventsMappingTest extends AbstractElasticSearchTest { 29 | 30 | @Test 31 | // @ElasticsearchIndex( 32 | // indexName = ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM, 33 | // cleanAfter = true, 34 | // mappings = @ElasticsearchMapping(typeName = ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM, properties = { 35 | // @Elasticsearch 36 | // })) 37 | public void testIndexingSingleInvoice() throws IOException { 38 | HashMap processesById = TestDataGenerator.startInvoiceProcess(processEngineRule.getProcessEngine(), 1); 39 | 40 | String[] pids = processesById.keySet().toArray(new String[0]); 41 | 42 | // elasticsearch ////////////////////////////// 43 | 44 | flushAndRefresh(); 45 | 46 | showMappings(ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM); 47 | 48 | FilteredQueryBuilder query = QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter("processInstanceId", pids[0])); 49 | 50 | SearchRequestBuilder searchRequestBuilder = client.prepareSearch(ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM) 51 | .setQuery(query); 52 | 53 | IoUtil.writeToFile(searchRequestBuilder.toString(), this.getClass().getSimpleName() + ".json", true); 54 | 55 | SearchResponse searchResponse = searchRequestBuilder.get(); 56 | SearchHits hits = searchResponse.getHits(); 57 | assertEquals(1, hits.totalHits()); 58 | 59 | 60 | SearchHit hit = hits.getAt(0); 61 | assertEquals(pids[0], hit.getId()); 62 | assertEquals(ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM, hit.getType()); 63 | 64 | Map source = hit.getSource(); 65 | assertNotNull(source.get("startTime")); 66 | assertNotNull(source.get("endTime")); 67 | ArrayList variables = (ArrayList) source.get("variables"); 68 | assertEquals(5, variables.size()); 69 | ArrayList tasks = (ArrayList) source.get("tasks"); 70 | assertEquals(9, tasks.size()); 71 | ArrayList activities = (ArrayList) source.get("activities"); 72 | assertEquals(19, activities.size()); 73 | 74 | logger.info(searchResponse.toString()); 75 | 76 | // for (SearchHit searchHit : searchResponse.getHits()) { 77 | // logger.info(searchHit.sourceAsString()); 78 | // } 79 | 80 | showMappings(ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM); 81 | 82 | assertMappings(ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM); 83 | // TODO: write assertions for mapping 84 | } 85 | 86 | protected void assertMappings(String esDefaultIndexNameCamundaBpm) { 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/jackson/JacksonMixInFilterModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.jackson; 18 | 19 | import com.fasterxml.jackson.annotation.JsonFilter; 20 | import com.fasterxml.jackson.core.Version; 21 | import com.fasterxml.jackson.databind.module.SimpleModule; 22 | import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; 23 | import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; 24 | import org.camunda.bpm.engine.impl.history.event.*; 25 | 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | 29 | public class JacksonMixInFilterModule extends SimpleModule { 30 | 31 | protected HashMap, Class> customMixInFilters; 32 | 33 | public JacksonMixInFilterModule(HashMap, Class> customMixInFilters) { 34 | super("ElasticSearchHistoryEntityMixInFilterModule", Version.unknownVersion()); 35 | this.customMixInFilters = customMixInFilters; 36 | } 37 | 38 | @Override 39 | public void setupModule(SetupContext context) { 40 | setupMixIns(context, getDefaultMixInFilters()); 41 | 42 | if (customMixInFilters != null) { 43 | setupMixIns(context, customMixInFilters); 44 | } 45 | 46 | super.setupModule(context); 47 | } 48 | 49 | public static String getJsonFilterAnnotationValue(Class clazz) { 50 | JsonFilter jsonFilterAnnotation = (JsonFilter) clazz.getAnnotation(JsonFilter.class); 51 | if (jsonFilterAnnotation != null) { 52 | return jsonFilterAnnotation.value(); 53 | } 54 | 55 | return null; 56 | } 57 | 58 | protected void setupMixIns(SetupContext context, HashMap, Class> mixInFilters) { 59 | for (Map.Entry, Class> mixInFilter : mixInFilters.entrySet()) { 60 | context.setMixInAnnotations(mixInFilter.getKey(), mixInFilter.getValue()); 61 | } 62 | } 63 | 64 | public static SimpleFilterProvider getCustomFilterProvider() { 65 | SimpleFilterProvider filterProvider = new SimpleFilterProvider(); 66 | for (Map.Entry, Class> mixInFilter : getDefaultMixInFilters().entrySet()) { 67 | String jsonFilterId = getJsonFilterAnnotationValue(mixInFilter.getValue()); 68 | if (jsonFilterId != null) { 69 | SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept(""); 70 | // TODO: add extension mechanism to declare filter values via ElasticSearchHistoryPluginConfiguration 71 | filterProvider.addFilter(jsonFilterId, filter); 72 | } 73 | } 74 | 75 | return filterProvider; 76 | } 77 | 78 | public static HashMap, Class> getDefaultMixInFilters() { 79 | HashMap, Class> mixInFilters = new HashMap, Class>(); 80 | 81 | mixInFilters.put(HistoryEvent.class, HistoryEventMixIn.class); 82 | mixInFilters.put(HistoricScopeInstanceEvent.class, HistoricScopeInstanceEventMixIn.class); // introduced with 7.0.x 83 | mixInFilters.put(HistoricProcessInstanceEventEntity.class, HistoricProcessInstanceEventMixIn.class); 84 | mixInFilters.put(HistoricTaskInstanceEventEntity.class, HistoricTaskInstanceEventMixIn.class); 85 | mixInFilters.put(HistoricActivityInstanceEventEntity.class, HistoricActivityInstanceEventMixIn.class); 86 | mixInFilters.put(HistoricDetailEventEntity.class, HistoricDetailEventMixIn.class); 87 | mixInFilters.put(HistoricVariableUpdateEventEntity.class, HistoricVariableUpdateEventMixIn.class); 88 | mixInFilters.put(HistoricFormPropertyEventEntity.class, HistoricFormPropertyEventMixIn.class); 89 | 90 | return mixInFilters; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/resources/mapping/processinstance.json: -------------------------------------------------------------------------------- 1 | { 2 | "processinstance" : { 3 | "dynamic_templates": [ 4 | { 5 | "id_fields_template": { 6 | "match": "id", 7 | "match_mapping_type": "string", 8 | "mapping": { 9 | "type": "string", 10 | "index": "not_analyzed" 11 | } 12 | } 13 | }, 14 | { 15 | "id_fields_template": { 16 | "match": "*Id", 17 | "match_mapping_type": "string", 18 | "mapping": { 19 | "type": "string", 20 | "index": "not_analyzed" 21 | } 22 | } 23 | }, 24 | { 25 | "key_fields_template": { 26 | "match_mapping_type": "string", 27 | "match": "*Key", 28 | "mapping": { 29 | "type": "multi_field", 30 | "fields": { 31 | "{name}": { 32 | "type": "{dynamic_type}", "index": "analyzed" 33 | }, 34 | "raw": { 35 | "type": "{dynamic_type}", "index": "not_analyzed" 36 | } 37 | } 38 | } 39 | } 40 | }, 41 | { 42 | "key_fields_template": { 43 | "match_mapping_type": "string", 44 | "match": "*Name", 45 | "mapping": { 46 | "type": "multi_field", 47 | "fields": { 48 | "{name}": { 49 | "type": "{dynamic_type}", "index": "analyzed" 50 | }, 51 | "raw": { 52 | "type": "{dynamic_type}", "index": "not_analyzed" 53 | } 54 | } 55 | } 56 | } 57 | }, 58 | { 59 | "time_fields_template": { 60 | "match_mapping_type": "long", 61 | "match": "*Time", 62 | "mapping": { 63 | "type": "date" 64 | } 65 | } 66 | }, 67 | { 68 | "timestamp_field_template": { 69 | "match_mapping_type": "long", 70 | "match": "timestamp", 71 | "mapping": { 72 | "type": "date" 73 | } 74 | } 75 | } 76 | ], 77 | "properties": { 78 | 79 | "id": { 80 | "type": "string", 81 | "index": "not_analyzed" 82 | }, 83 | "processInstanceId": { 84 | "type": "string", 85 | "index": "not_analyzed" 86 | }, 87 | "executionId": { 88 | "type": "string", 89 | "index": "not_analyzed" 90 | }, 91 | "processDefinitionId": { 92 | "type": "multi_field", 93 | "fields": { 94 | "processDefinitionId": { "type": "string", "index": "not_analyzed" }, 95 | "analyzed": { "type": "string", "index": "analyzed" } 96 | } 97 | }, 98 | "eventType": { 99 | "type": "string", 100 | "index": "not_analyzed" 101 | }, 102 | 103 | 104 | "businessKey": { 105 | "type": "multi_field", 106 | "fields": { 107 | "businessKey": { "type": "string", "index": "analyzed" }, 108 | "raw": { "type": "string", "index": "not_analyzed" } 109 | } 110 | }, 111 | "startUserId": { 112 | "type": "multi_field", 113 | "fields": { 114 | "startUserId": { "type": "string", "index": "analyzed" }, 115 | "raw": { "type": "string", "index": "not_analyzed" } 116 | } 117 | }, 118 | "superProcessInstanceId": { 119 | "type": "string", 120 | "index": "not_analyzed" 121 | }, 122 | "deleteReason": { 123 | "type": "multi_field", 124 | "fields": { 125 | "deleteReason": { "type": "string", "index": "analyzed" }, 126 | "raw": { "type": "string", "index": "not_analyzed" } 127 | } 128 | }, 129 | "startTime": { 130 | "type": "date" 131 | }, 132 | "endTime": { 133 | "type": "date" 134 | }, 135 | "durationInMillis": { 136 | "type": "long" 137 | }, 138 | "startActivityId": { 139 | "type": "string", 140 | "index": "not_analyzed" 141 | }, 142 | "endActivityId": { 143 | "type": "string", 144 | "index": "not_analyzed" 145 | }, 146 | 147 | 148 | "activities": { 149 | "type": "nested" 150 | }, 151 | "tasks": { 152 | "type": "nested" 153 | }, 154 | "variables": { 155 | "type": "nested" 156 | } 157 | 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /elasticsearch-commons/src/main/java/org/camunda/bpm/elasticsearch/ElasticSearchClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch; 18 | 19 | import org.elasticsearch.client.Client; 20 | import org.elasticsearch.client.transport.TransportClient; 21 | import org.elasticsearch.common.settings.ImmutableSettings; 22 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 23 | import org.elasticsearch.node.Node; 24 | import org.elasticsearch.node.NodeBuilder; 25 | 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | import java.util.logging.Level; 29 | import java.util.logging.Logger; 30 | 31 | public class ElasticSearchClient { 32 | 33 | protected static final Logger LOGGER = Logger.getLogger(ElasticSearchClient.class.getName()); 34 | 35 | protected Client esClient; 36 | protected Node esNode; 37 | 38 | protected ElasticSearchHistoryPluginConfiguration historyPluginConfiguration; 39 | 40 | public ElasticSearchClient(ElasticSearchHistoryPluginConfiguration historyPluginConfiguration) { 41 | this.historyPluginConfiguration = historyPluginConfiguration; 42 | this.esClient = init(); 43 | } 44 | 45 | protected Client init() { 46 | Client client = null; 47 | 48 | ImmutableSettings.Builder settingsBuilder = ImmutableSettings.builder() 49 | .put("cluster.name", historyPluginConfiguration.getEsClusterName()); 50 | 51 | if (historyPluginConfiguration.isTransportClient()) { 52 | // sniff for rest of cluster settingsBuilder.put("client.transport.sniff", true); 53 | addCustomESProperties(settingsBuilder, historyPluginConfiguration.getProperties()); 54 | 55 | TransportClient transportClient = new TransportClient(settingsBuilder).addTransportAddress( 56 | new InetSocketTransportAddress(historyPluginConfiguration.getEsHost(), Integer.parseInt(historyPluginConfiguration.getEsPort()))); 57 | LOGGER.info("Successfully connected to " + transportClient.connectedNodes()); 58 | client = transportClient; 59 | } else { 60 | if (esNode == null) { 61 | // initialize default settings 62 | settingsBuilder 63 | .put("node.name", "rocking-camunda-bpm-history") 64 | .put("node.client", true) // make node a client, so it won't become a master 65 | .put("node.local", false) 66 | .put("node.data", false) 67 | .put("node.http.enabled", true); 68 | // .put("discovery.zen.ping.multicast.enabled", false) 69 | // .put("discovery.zen.ping.unicast.hosts", "127.0.0.1:9300"); 70 | 71 | addCustomESProperties(settingsBuilder, historyPluginConfiguration.getProperties()); 72 | 73 | esNode = NodeBuilder.nodeBuilder() 74 | .loadConfigSettings(true) 75 | .settings(settingsBuilder) 76 | .build(); 77 | 78 | if (LOGGER.isLoggable(Level.INFO)) { 79 | LOGGER.info("Initialized node with settings: " + esNode.settings().getAsMap().toString()); 80 | } 81 | 82 | esNode.start(); 83 | } 84 | 85 | client = esNode.client(); 86 | } 87 | 88 | return client; 89 | } 90 | 91 | public void dispose() { 92 | if (esClient != null) { 93 | esClient.close(); 94 | } 95 | if (esNode != null) { 96 | esNode.close(); 97 | } 98 | } 99 | 100 | public Client get() { 101 | if (esClient == null) { 102 | esClient = init(); 103 | } 104 | return esClient; 105 | } 106 | 107 | public void set(Client esClient) { 108 | this.esClient = esClient; 109 | } 110 | 111 | protected void addCustomESProperties(ImmutableSettings.Builder settingsBuilder, HashMap properties) { 112 | for (Map.Entry property : properties.entrySet()) { 113 | if (property.getKey().toLowerCase().startsWith("es.")) { 114 | settingsBuilder.put(property.getKey().substring(3), property.getValue()); 115 | } 116 | } 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /elasticsearch-jboss-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 20 | 21 | 4.0.0 22 | 23 | 24 | org.camunda.bpm.extension.elasticsearch 25 | camunda-bpm-elasticsearch 26 | 1.0.0-SNAPSHOT 27 | 28 | 29 | elasticsearch-jboss-module 30 | camunda bpm - elasticsearch - jboss 31 | 32 | 33 | 34 | org.camunda.bpm.extension.elasticsearch 35 | elasticsearch-engine-integration 36 | ${project.version} 37 | provided 38 | 39 | 40 | org.elasticsearch 41 | elasticsearch 42 | 43 | 44 | 45 | 46 | 47 | jboss 48 | 49 | true 50 | 51 | 52 | ${project.build.directory} 53 | 54 | 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-dependency-plugin 59 | 2.8 60 | 61 | 62 | copy-dependencies 63 | prepare-package 64 | 65 | copy-dependencies 66 | 67 | 68 | ${project.build.directory}/modules/org/camunda/bpm/elasticsearch/main/ 69 | false 70 | false 71 | true 72 | 73 | 74 | 75 | 76 | 77 | maven-resources-plugin 78 | 2.6 79 | 80 | 81 | copy-modules 82 | prepare-package 83 | 84 | copy-resources 85 | 86 | 87 | ${project.build.directory}/modules 88 | 89 | 90 | src/main/modules 91 | true 92 | 93 | 94 | 95 | 96 | 97 | copy-standalone-xml 98 | prepare-package 99 | 100 | copy-resources 101 | 102 | 103 | ${project.build.directory}/standalone 104 | 105 | 106 | src/main/standalone 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/resources/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | vm://localhost 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 59 | 63 | 64 | 65 | 66 | 68 | 69 | 70 | 72 | 73 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | 83 | 84 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/util/ElasticSearchHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.util; 18 | 19 | import org.elasticsearch.action.ActionRequest; 20 | import org.elasticsearch.action.ActionResponse; 21 | import org.elasticsearch.client.Client; 22 | import org.elasticsearch.common.bytes.BytesArray; 23 | import org.elasticsearch.common.io.stream.BytesStreamOutput; 24 | import org.elasticsearch.common.xcontent.XContentBuilder; 25 | import org.elasticsearch.common.xcontent.XContentFactory; 26 | 27 | import java.io.IOException; 28 | import java.util.Map; 29 | import java.util.logging.Logger; 30 | 31 | public class ElasticSearchHelper { 32 | 33 | protected static final Logger LOGGER = Logger.getLogger(ElasticSearchHelper.class.getName()); 34 | 35 | public static void checkIndex(Client esClient, String indexName) { 36 | if (!checkIndexExists(esClient, indexName)) { 37 | if (createIndex(esClient, indexName)) { 38 | LOGGER.info("Index [" + indexName + "] not found. Creating new index [" + indexName + "]"); 39 | } else { 40 | throw new RuntimeException("Unable to create index [" + indexName + "] in Elasticsearch."); 41 | } 42 | } else { 43 | LOGGER.info("Index [" + indexName + "] already exists in Elasticsearch."); 44 | } 45 | } 46 | 47 | public static boolean createIndex(Client esClient, String indexName) { 48 | return esClient.admin().indices().prepareCreate(indexName).get().isAcknowledged(); 49 | } 50 | 51 | public static void checkTypeAndMapping(Client esClient, String indexName, String typeName) { 52 | Map mapping = 53 | JsonHelper.readJsonFromClasspathAsMap("mapping/" + typeName + ".json"); 54 | checkTypeAndMapping(esClient, indexName, typeName, mapping); 55 | } 56 | 57 | public static void checkTypeAndMapping(Client esClient, String indexName, String typeName, Map mapping) { 58 | if (!checkTypeExists(esClient, indexName, typeName)) { 59 | if (mapping == null) { 60 | throw new RuntimeException("No mapping provided."); 61 | } 62 | 63 | if (updateMappingForType(esClient, indexName, typeName, mapping)) { 64 | LOGGER.info("Created mapping for [" + indexName + "]/[" + typeName + "]"); 65 | } else { 66 | throw new RuntimeException("Could not define mapping for ["+ indexName +"]/["+ typeName +"]"); 67 | } 68 | } 69 | } 70 | 71 | public static boolean checkIndexExists(Client esClient, String indexName) { 72 | return esClient.admin().indices().prepareExists(indexName).get().isExists(); 73 | } 74 | 75 | public static boolean checkTypeExists(Client esClient, String index, String type) { 76 | return esClient.admin().indices().prepareExists(index, type).get().isExists(); 77 | } 78 | 79 | public static boolean updateMappingForType(Client esClient, String indexName, String typeName, Map mapping) { 80 | return esClient.admin().indices().preparePutMapping(indexName).setType(typeName).setSource(mapping).get().isAcknowledged(); 81 | } 82 | 83 | public static String convertRequestToJson(ActionRequest request) throws IOException { 84 | BytesStreamOutput bytesStreamOutput = new BytesStreamOutput(); 85 | request.writeTo(bytesStreamOutput); 86 | 87 | XContentBuilder builder = XContentFactory.jsonBuilder(bytesStreamOutput); 88 | builder.prettyPrint(); 89 | 90 | // builder.startObject(); 91 | // builder.endObject(); 92 | BytesArray bytesArray = builder.bytes().toBytesArray(); 93 | return new String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length()); 94 | } 95 | 96 | public static String convertResponseToJson(ActionResponse response) throws IOException { 97 | BytesStreamOutput bytesStreamOutput = new BytesStreamOutput(); 98 | response.writeTo(bytesStreamOutput); 99 | 100 | XContentBuilder builder = XContentFactory.jsonBuilder(bytesStreamOutput); 101 | builder.prettyPrint(); 102 | 103 | // builder.startObject(); 104 | // builder.endObject(); 105 | return builder.bytes().toUtf8(); 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/develop/java/org/camunda/bpm/extension/elasticsearch/cockpit/demodata/DemoDataGenerator.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.extension.elasticsearch.cockpit.demodata; 14 | 15 | import static org.camunda.bpm.engine.authorization.Authorization.ANY; 16 | import static org.camunda.bpm.engine.authorization.Authorization.AUTH_TYPE_GRANT; 17 | import static org.camunda.bpm.engine.authorization.Permissions.ALL; 18 | 19 | import java.util.List; 20 | import java.util.Random; 21 | import java.util.Timer; 22 | import java.util.TimerTask; 23 | 24 | import org.camunda.bpm.engine.AuthorizationService; 25 | import org.camunda.bpm.engine.IdentityService; 26 | import org.camunda.bpm.engine.ProcessEngine; 27 | import org.camunda.bpm.engine.authorization.Groups; 28 | import org.camunda.bpm.engine.authorization.Resource; 29 | import org.camunda.bpm.engine.authorization.Resources; 30 | import org.camunda.bpm.engine.identity.Group; 31 | import org.camunda.bpm.engine.identity.User; 32 | import org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity; 33 | import org.camunda.bpm.engine.task.Task; 34 | import org.springframework.beans.factory.InitializingBean; 35 | 36 | /** 37 | * @author Daniel Meyer 38 | * 39 | */ 40 | public class DemoDataGenerator implements InitializingBean { 41 | 42 | private static final int maxInstances = 10; 43 | 44 | protected ProcessEngine processEngine; 45 | 46 | public void afterPropertiesSet() throws Exception { 47 | 48 | System.out.println("Generating demo data"); 49 | 50 | scheduleInstanceStart(); 51 | 52 | // ensure admin user exists 53 | IdentityService identityService = processEngine.getIdentityService(); 54 | User user = identityService.createUserQuery().userId("demo").singleResult(); 55 | if(user == null) { 56 | User newUser = identityService.newUser("demo"); 57 | newUser.setPassword("demo"); 58 | identityService.saveUser(newUser); 59 | System.out.println("Created used 'demo', password 'demo'"); 60 | AuthorizationService authorizationService = processEngine.getAuthorizationService(); 61 | 62 | // create group 63 | if(identityService.createGroupQuery().groupId(Groups.CAMUNDA_ADMIN).count() == 0) { 64 | Group camundaAdminGroup = identityService.newGroup(Groups.CAMUNDA_ADMIN); 65 | camundaAdminGroup.setName("camunda BPM Administrators"); 66 | camundaAdminGroup.setType(Groups.GROUP_TYPE_SYSTEM); 67 | identityService.saveGroup(camundaAdminGroup); 68 | } 69 | 70 | // create ADMIN authorizations on all built-in resources 71 | for (Resource resource : Resources.values()) { 72 | if(authorizationService.createAuthorizationQuery().groupIdIn(Groups.CAMUNDA_ADMIN).resourceType(resource).resourceId(ANY).count() == 0) { 73 | AuthorizationEntity userAdminAuth = new AuthorizationEntity(AUTH_TYPE_GRANT); 74 | userAdminAuth.setGroupId(Groups.CAMUNDA_ADMIN); 75 | userAdminAuth.setResource(resource); 76 | userAdminAuth.setResourceId(ANY); 77 | userAdminAuth.addPermission(ALL); 78 | authorizationService.saveAuthorization(userAdminAuth); 79 | } 80 | } 81 | 82 | processEngine.getIdentityService() 83 | .createMembership("demo", Groups.CAMUNDA_ADMIN); 84 | } 85 | } 86 | 87 | 88 | 89 | protected void scheduleInstanceStart() { 90 | new Timer(true).schedule(new TimerTask() { 91 | public void run() { 92 | 93 | // start some process instances 94 | int rand = new Random().nextInt(maxInstances); 95 | for (int i = 0; i < rand; i++) { 96 | processEngine.getRuntimeService().startProcessInstanceByKey("generatedFormsQuickstart"); 97 | } 98 | 99 | // complete some process instances 100 | rand = new Random().nextInt(maxInstances); 101 | List tasks = processEngine.getTaskService().createTaskQuery() 102 | .listPage(0, rand); 103 | for (Task task : tasks) { 104 | processEngine.getTaskService().complete(task.getId()); 105 | } 106 | 107 | // reschedule 108 | scheduleInstanceStart(); 109 | } 110 | }, 1000); 111 | } 112 | 113 | 114 | 115 | public void setProcessEngine(ProcessEngine processEngine) { 116 | this.processEngine = processEngine; 117 | } 118 | 119 | public ProcessEngine getProcessEngine() { 120 | return processEngine; 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /elasticsearch-commons/src/main/java/org/camunda/bpm/elasticsearch/ElasticSearchHistoryPluginConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch; 18 | 19 | import org.camunda.bpm.elasticsearch.util.JsonHelper; 20 | 21 | import java.util.HashMap; 22 | 23 | public class ElasticSearchHistoryPluginConfiguration { 24 | 25 | public static final String ES_CAM_BPM_CONFIGURATION = "camunda-bpm-elasticsearch.json"; 26 | 27 | public static final String ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM = "camundabpm"; 28 | public static final String ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM = "processinstance"; 29 | 30 | public static final String ES_DEFAULT_HOST = "localhost"; 31 | public static final String ES_DEFAULT_PORT_NODE_CLIENT = "9300"; 32 | public static final String ES_DEFAULT_PORT_TRANSPORT_CLIENT = "9300"; 33 | public static final String ES_DEFAULT_CLUSTER_NAME = "elasticsearch"; 34 | 35 | private String index; 36 | private String type; 37 | private String indexingStrategy; 38 | 39 | private String esHost; 40 | private String esPort; 41 | private String esClusterName; 42 | private boolean transportClient = false; 43 | private HashMap properties = new HashMap(); 44 | private String eventHandler; 45 | 46 | public String getIndex() { 47 | if (index == null) { 48 | index = ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM; 49 | } 50 | return index; 51 | } 52 | 53 | public void setIndex(String index) { 54 | this.index = index; 55 | } 56 | 57 | public String getType() { 58 | if (type == null) { 59 | type = ES_DEFAULT_TYPE_NAME_CAMUNDA_BPM; 60 | } 61 | return type; 62 | } 63 | 64 | public void setType(String type) { 65 | this.type = type; 66 | } 67 | 68 | public String getIndexingStrategy() { 69 | return indexingStrategy; 70 | } 71 | 72 | public void setIndexingStrategy(String indexingStrategy) { 73 | this.indexingStrategy = indexingStrategy; 74 | } 75 | 76 | public String getEsHost() { 77 | if (esHost == null) { 78 | esHost = ES_DEFAULT_HOST; 79 | } 80 | return esHost; 81 | } 82 | 83 | public void setEsHost(String esHost) { 84 | this.esHost = esHost; 85 | } 86 | 87 | public String getEsPort() { 88 | if (esPort == null) { 89 | if (isTransportClient()) { 90 | esPort = ES_DEFAULT_PORT_TRANSPORT_CLIENT; 91 | } else { 92 | esPort = ES_DEFAULT_PORT_NODE_CLIENT; 93 | } 94 | } 95 | return esPort; 96 | } 97 | 98 | public void setEsPort(String esPort) { 99 | this.esPort = esPort; 100 | } 101 | 102 | public String getEsClusterName() { 103 | if (esClusterName == null) { 104 | esClusterName = ES_DEFAULT_CLUSTER_NAME; 105 | } 106 | return esClusterName; 107 | } 108 | 109 | public void setEsClusterName(String esClusterName) { 110 | this.esClusterName = esClusterName; 111 | } 112 | 113 | public boolean isTransportClient() { 114 | return transportClient; 115 | } 116 | 117 | public void setTransportClient(boolean transportClient) { 118 | this.transportClient = transportClient; 119 | } 120 | 121 | public HashMap getProperties() { 122 | return properties; 123 | } 124 | 125 | public void setProperties(HashMap properties) { 126 | this.properties = properties; 127 | } 128 | 129 | public String getEventHandler() { 130 | return eventHandler; 131 | } 132 | 133 | public void setEventHandler(String eventHandler) { 134 | this.eventHandler = eventHandler; 135 | } 136 | 137 | public void validate() { 138 | StringBuilder sb = new StringBuilder(); 139 | 140 | if (getEsClusterName() == null || getEsClusterName().isEmpty()) { 141 | 142 | } 143 | if (getEsHost() == null || getEsHost().isEmpty()) { 144 | 145 | } 146 | if (getEsPort() == null || getEsPort().isEmpty()) { 147 | 148 | } 149 | if (getIndex() == null || getIndex().isEmpty()) { 150 | 151 | } 152 | if (getType() == null || getType().isEmpty()) { 153 | 154 | } 155 | if (getIndexingStrategy() == null || getIndexingStrategy().isEmpty()) { 156 | 157 | } 158 | if (getEventHandler() == null || getEventHandler().isEmpty()) { 159 | 160 | } 161 | } 162 | 163 | public static ElasticSearchHistoryPluginConfiguration readConfigurationFromClasspath() { 164 | return readConfigurationFromClasspath(ES_CAM_BPM_CONFIGURATION); 165 | } 166 | 167 | public static ElasticSearchHistoryPluginConfiguration readConfigurationFromClasspath(String fileName) { 168 | return JsonHelper.readJsonFromClasspath(ElasticSearchHistoryPluginConfiguration.class, fileName); 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/dashboards/resources/SearchResource.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.cockpit.plugin.dashboards.resources; 14 | import static org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM; 15 | 16 | import java.util.ArrayList; 17 | import java.util.HashSet; 18 | import java.util.List; 19 | import java.util.Set; 20 | import java.util.logging.Logger; 21 | 22 | import javax.ws.rs.GET; 23 | import javax.ws.rs.QueryParam; 24 | 25 | import org.camunda.bpm.cockpit.plugin.ElasticSearchClientProvider; 26 | import org.camunda.bpm.cockpit.plugin.resource.AbstractCockpitPluginResource; 27 | import org.camunda.bpm.engine.repository.ProcessDefinition; 28 | import org.elasticsearch.action.search.SearchRequestBuilder; 29 | import org.elasticsearch.action.search.SearchResponse; 30 | import org.elasticsearch.client.Client; 31 | import org.elasticsearch.index.query.FilterBuilder; 32 | import org.elasticsearch.index.query.FilterBuilders; 33 | import org.elasticsearch.index.query.FilteredQueryBuilder; 34 | import org.elasticsearch.index.query.QueryBuilders; 35 | import org.elasticsearch.search.SearchHit; 36 | import org.elasticsearch.search.SearchHits; 37 | 38 | /** 39 | * @author Daniel Meyer 40 | * 41 | */ 42 | public class SearchResource extends AbstractCockpitPluginResource { 43 | 44 | private final static Logger LOG = Logger.getLogger(SearchResource.class.getName()); 45 | 46 | public static final String PATH = "/search"; 47 | 48 | public SearchResource(String engineName) { 49 | super(engineName); 50 | } 51 | 52 | @GET 53 | public List doSearch( 54 | @QueryParam("query") String query, 55 | @QueryParam("includeVariables") boolean includeVariables, 56 | @QueryParam("includeActivities") boolean includeActivities, 57 | @QueryParam("includeTasks") boolean includeTasks 58 | ) { 59 | 60 | Client client = ElasticSearchClientProvider.getClient(getProcessEngine()); 61 | 62 | List filters = new ArrayList(); 63 | if(includeVariables) { 64 | filters.add(FilterBuilders.nestedFilter("variables", QueryBuilders.queryString(query).field("variables.*").lenient(true).useDisMax(true))); 65 | } 66 | if(includeActivities) { 67 | filters.add(FilterBuilders.nestedFilter("activities", QueryBuilders.queryString(query).field("activities.*").lenient(true).useDisMax(true))); 68 | } 69 | if(includeTasks) { 70 | filters.add(FilterBuilders.nestedFilter("tasks", QueryBuilders.queryString(query).field("tasks.*").lenient(true).useDisMax(true))); 71 | } 72 | 73 | FilteredQueryBuilder elasticSearchQuery = QueryBuilders.filteredQuery( 74 | QueryBuilders.matchAllQuery(), 75 | FilterBuilders.boolFilter().should( 76 | filters.toArray(new FilterBuilder[0]) 77 | ) 78 | ); 79 | 80 | SearchRequestBuilder searchRequestBuilder = client.prepareSearch(ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM) 81 | .setQuery(elasticSearchQuery) 82 | .setFetchSource(false) 83 | .addField("processDefinitionId") 84 | .setSize(20); 85 | 86 | System.out.println(searchRequestBuilder); 87 | 88 | SearchResponse searchResponse = searchRequestBuilder.get(); 89 | SearchHits hits = searchResponse.getHits(); 90 | 91 | List searchResults = new ArrayList(); 92 | Set processDefinitionIds = new HashSet(); 93 | for (SearchHit searchHit : hits.getHits()) { 94 | SearchResult searchResult = new SearchResult(); 95 | searchResult.setProcessInstanceId(searchHit.getId()); 96 | searchResult.setProcessDefinitionId((String) searchHit.getFields().get("processDefinitionId").getValue()); 97 | searchResults.add(searchResult); 98 | processDefinitionIds.add(searchResult.getProcessDefinitionId()); 99 | } 100 | 101 | // get process definition names 102 | List processDefinitions = getProcessEngine().getRepositoryService() 103 | .createProcessDefinitionQuery() 104 | .processDefinitionIdIn(processDefinitionIds.toArray(new String[0])) 105 | .list(); 106 | for (ProcessDefinition processDefinition : processDefinitions) { 107 | for (SearchResult searchResult : searchResults) { 108 | if(searchResult.getProcessDefinitionId().equals(processDefinition.getId())) { 109 | if(processDefinition.getName() == null || processDefinition.getName().isEmpty()) { 110 | searchResult.setProcessDefinitionName(processDefinition.getKey()); 111 | } else { 112 | searchResult.setProcessDefinitionName(processDefinition.getName()); 113 | } 114 | } 115 | } 116 | } 117 | return searchResults; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/entity/ElasticSearchProcessInstanceHistoryEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.entity; 18 | 19 | import org.camunda.bpm.engine.impl.history.event.HistoricActivityInstanceEventEntity; 20 | import org.camunda.bpm.engine.impl.history.event.HistoricProcessInstanceEventEntity; 21 | import org.camunda.bpm.engine.impl.history.event.HistoricTaskInstanceEventEntity; 22 | import org.camunda.bpm.engine.impl.history.event.HistoricVariableUpdateEventEntity; 23 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | /** 29 | * 30 | */ 31 | public class ElasticSearchProcessInstanceHistoryEntity extends HistoricProcessInstanceEventEntity { 32 | 33 | private List activities = null; 34 | private List tasks = null; 35 | private List variables = null; 36 | 37 | public ElasticSearchProcessInstanceHistoryEntity() { 38 | } 39 | 40 | public static ElasticSearchProcessInstanceHistoryEntity createFromHistoryEvent(HistoryEvent historyEvent) { 41 | ElasticSearchProcessInstanceHistoryEntity esHistoryEntity = new ElasticSearchProcessInstanceHistoryEntity(); 42 | 43 | esHistoryEntity.setId(historyEvent.getId()); // maybe use process instance id here? 44 | esHistoryEntity.setProcessInstanceId(historyEvent.getProcessInstanceId()); 45 | 46 | if (historyEvent instanceof HistoricProcessInstanceEventEntity) { 47 | HistoricProcessInstanceEventEntity pie = (HistoricProcessInstanceEventEntity) historyEvent; 48 | 49 | esHistoryEntity.setExecutionId(pie.getExecutionId()); 50 | esHistoryEntity.setProcessDefinitionId(pie.getProcessDefinitionId()); 51 | 52 | esHistoryEntity.setStartActivityId(pie.getStartActivityId()); 53 | esHistoryEntity.setEndActivityId(pie.getEndActivityId()); 54 | esHistoryEntity.setStartTime(pie.getStartTime()); 55 | esHistoryEntity.setEndTime(pie.getEndTime()); 56 | esHistoryEntity.setDurationInMillis(pie.getDurationInMillis()); 57 | 58 | esHistoryEntity.setBusinessKey(pie.getBusinessKey()); 59 | esHistoryEntity.setStartUserId(pie.getStartUserId()); 60 | esHistoryEntity.setDeleteReason(pie.getDeleteReason()); 61 | esHistoryEntity.setSuperProcessInstanceId(pie.getSuperProcessInstanceId()); 62 | 63 | } else if (historyEvent instanceof HistoricActivityInstanceEventEntity) { 64 | 65 | HistoricActivityInstanceEventEntity aie = (HistoricActivityInstanceEventEntity) historyEvent; 66 | esHistoryEntity.addHistoricActivityInstanceEvent(aie); 67 | 68 | } else if (historyEvent instanceof HistoricTaskInstanceEventEntity) { 69 | 70 | HistoricTaskInstanceEventEntity tie = (HistoricTaskInstanceEventEntity) historyEvent; 71 | esHistoryEntity.addHistoricTaskInstanceEvent(tie); 72 | 73 | } else if (historyEvent instanceof HistoricVariableUpdateEventEntity) { 74 | 75 | HistoricVariableUpdateEventEntity vue = (HistoricVariableUpdateEventEntity) historyEvent; 76 | esHistoryEntity.addHistoricVariableUpdateEvent(vue); 77 | 78 | } else { 79 | // unknown event - throw exception or return null? 80 | } 81 | 82 | return esHistoryEntity; 83 | } 84 | 85 | public List getVariables() { 86 | return variables; 87 | } 88 | 89 | public void setVariables(List variables) { 90 | this.variables = variables; 91 | } 92 | 93 | public void addHistoricVariableUpdateEvent(HistoricVariableUpdateEventEntity variableUpdateEvent) { 94 | if (variables == null) { 95 | variables = new ArrayList(); 96 | } 97 | variables.add(variableUpdateEvent); 98 | } 99 | 100 | public List getActivities() { 101 | return activities; 102 | } 103 | 104 | public void setActivities(List activities) { 105 | this.activities = activities; 106 | } 107 | 108 | public void addHistoricActivityInstanceEvent(HistoricActivityInstanceEventEntity activityInstanceEvent) { 109 | if (activities == null) { 110 | activities = new ArrayList(); 111 | } 112 | activities.add(activityInstanceEvent); 113 | } 114 | 115 | public List getTasks() { 116 | return tasks; 117 | } 118 | 119 | public void setTasks(List tasks) { 120 | this.tasks = tasks; 121 | } 122 | 123 | public void addHistoricTaskInstanceEvent(HistoricTaskInstanceEventEntity taskInstanceEvent) { 124 | if (tasks == null) { 125 | tasks = new ArrayList(); 126 | } 127 | tasks.add(taskInstanceEvent); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/java/org/camunda/bpm/cockpit/plugin/dashboards/resources/ProcessInstanceHistogramResource.java: -------------------------------------------------------------------------------- 1 | /* Licensed under the Apache License, Version 2.0 (the "License"); 2 | * you may not use this file except in compliance with the License. 3 | * You may obtain a copy of the License at 4 | * 5 | * http://www.apache.org/licenses/LICENSE-2.0 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.camunda.bpm.cockpit.plugin.dashboards.resources; 14 | 15 | import org.camunda.bpm.cockpit.plugin.ElasticSearchClientProvider; 16 | import org.camunda.bpm.cockpit.plugin.resource.AbstractCockpitPluginResource; 17 | import org.elasticsearch.action.search.SearchRequestBuilder; 18 | import org.elasticsearch.action.search.SearchResponse; 19 | import org.elasticsearch.action.search.SearchType; 20 | import org.elasticsearch.client.Client; 21 | import org.elasticsearch.index.query.*; 22 | import org.elasticsearch.search.aggregations.AggregationBuilders; 23 | import org.elasticsearch.search.aggregations.bucket.filter.Filter; 24 | import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder; 25 | import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram; 26 | import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramBuilder; 27 | 28 | import javax.ws.rs.GET; 29 | import javax.ws.rs.QueryParam; 30 | import java.util.*; 31 | import java.util.logging.Logger; 32 | 33 | import static org.camunda.bpm.elasticsearch.ElasticSearchHistoryPluginConfiguration.ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM; 34 | 35 | /** 36 | * @author Christian Lipphardt 37 | */ 38 | public class ProcessInstanceHistogramResource extends AbstractCockpitPluginResource { 39 | 40 | private final static Logger LOG = Logger.getLogger(ProcessInstanceHistogramResource.class.getName()); 41 | 42 | public static final String PATH = "/histogram/processinstance"; 43 | 44 | public ProcessInstanceHistogramResource(String engineName) { 45 | super(engineName); 46 | } 47 | 48 | @GET 49 | public AggregationsResult getDateHistogramAggregrations( 50 | @QueryParam("interval") String interval, 51 | @QueryParam("timeframe") String timeframe 52 | ) { 53 | 54 | Client client = ElasticSearchClientProvider.getClient(getProcessEngine()); 55 | 56 | DateHistogram.Interval dateInterval = null; 57 | switch (interval) { 58 | case "s": 59 | case "m": 60 | case "h": 61 | case "d": 62 | case "w": 63 | case "M": 64 | case "q": 65 | case "y": 66 | default: 67 | dateInterval = DateHistogram.Interval.SECOND; 68 | break; 69 | } 70 | 71 | // create buckets based on startTime 72 | DateHistogramBuilder histogramStartTime = AggregationBuilders.dateHistogram("dateHistogram") 73 | .minDocCount(0) 74 | .interval(dateInterval) 75 | .field("startTime"); 76 | // only get the running process instances 77 | FilterAggregationBuilder runningPIsAgg = AggregationBuilders.filter("running") 78 | .filter(FilterBuilders.missingFilter("endTime")); 79 | runningPIsAgg.subAggregation(histogramStartTime); 80 | 81 | // create buckets based on endTime 82 | DateHistogramBuilder histogramEndTime = AggregationBuilders.dateHistogram("dateHistogram") 83 | .minDocCount(0) 84 | .interval(dateInterval) 85 | .field("endTime"); 86 | // only get the ended process instances 87 | FilterAggregationBuilder endedPIsAgg = AggregationBuilders.filter("ended") 88 | .filter(FilterBuilders.existsFilter("endTime")); 89 | endedPIsAgg.subAggregation(histogramEndTime); 90 | 91 | 92 | SearchRequestBuilder searchRequestBuilder = client.prepareSearch(ES_DEFAULT_INDEX_NAME_CAMUNDA_BPM) 93 | .setQuery(QueryBuilders.matchAllQuery()) 94 | .addAggregation(runningPIsAgg) 95 | .addAggregation(endedPIsAgg) 96 | .setSearchType(SearchType.COUNT); 97 | 98 | System.out.println(searchRequestBuilder); 99 | 100 | SearchResponse searchResponse = searchRequestBuilder.get(); 101 | 102 | long totalHits = searchResponse.getHits().getTotalHits(); 103 | 104 | Filter running = searchResponse.getAggregations().get("running"); 105 | // long runningTotal = running.getDocCount(); 106 | 107 | DateHistogram runningDateHistogram = running.getAggregations().get("dateHistogram"); 108 | List runningDateHistogramBuckets = parseDateHistogramAggregation(runningDateHistogram); 109 | 110 | 111 | Filter ended = searchResponse.getAggregations().get("ended"); 112 | // long endedTotal = ended.getDocCount(); 113 | 114 | DateHistogram endedDateHistogram = ended.getAggregations().get("dateHistogram"); 115 | List endedDateHistogramBuckets = parseDateHistogramAggregation(endedDateHistogram); 116 | 117 | HashMap> dateHistogramBucketPairs = new HashMap<>(); 118 | dateHistogramBucketPairs.put("running", runningDateHistogramBuckets); 119 | dateHistogramBucketPairs.put("ended", endedDateHistogramBuckets); 120 | 121 | AggregationsResult aggregationsResult = new AggregationsResult(); 122 | aggregationsResult.setDateHistogramBuckets(dateHistogramBucketPairs); 123 | aggregationsResult.setTotalHits(totalHits); 124 | 125 | return aggregationsResult; 126 | } 127 | 128 | protected List parseDateHistogramAggregation(DateHistogram dateHistogram) { 129 | ArrayList dateHistogramBuckets = new ArrayList<>(); 130 | 131 | for (DateHistogram.Bucket bucket : dateHistogram.getBuckets()) { 132 | dateHistogramBuckets.add(new DateHistogramBucketPair(bucket.getKeyAsNumber(), bucket.getDocCount())); 133 | } 134 | 135 | return dateHistogramBuckets; 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 4.0.0 22 | 23 | 24 | org.camunda.bpm.extension.elasticsearch 25 | camunda-bpm-elasticsearch 26 | 1.0.0-SNAPSHOT 27 | 28 | 29 | elasticsearch-cockpit-plugin 30 | camunda bpm - elasticsearch - cockpit plugin 31 | 32 | 33 | 34 | org.camunda.bpm.extension.elasticsearch 35 | elasticsearch-engine-integration 36 | ${project.version} 37 | 38 | 39 | 40 | org.camunda.bpm.webapp 41 | camunda-webapp-core 42 | ${version.camunda-bpm} 43 | provided 44 | 45 | 46 | 47 | org.jboss.spec 48 | jboss-javaee-6.0 49 | pom 50 | provided 51 | 3.0.2.Final 52 | 53 | 54 | 55 | 56 | org.camunda.bpm 57 | camunda-engine 58 | provided 59 | 60 | 61 | com.h2database 62 | h2 63 | test 64 | 65 | 66 | junit 67 | junit 68 | test 69 | 70 | 71 | 72 | 73 | 74 | 75 | src/main/resources 76 | true 77 | 78 | 79 | 80 | 81 | 82 | 83 | develop 84 | 85 | 86 | org.camunda.bpm.webapp 87 | camunda-webapp-tomcat-standalone 88 | ${version.camunda-bpm} 89 | war 90 | 91 | 92 | 93 | 94 | 95 | org.mortbay.jetty 96 | jetty-maven-plugin 97 | 8.1.14.v20131031 98 | 99 | 100 | /camunda 101 | 102 | ${project.basedir}/src/main/resources 103 | ${project.basedir}/src/develop/resources 104 | 105 | 106 | 107 | 108 | 109 | org.codehaus.mojo 110 | build-helper-maven-plugin 111 | 1.9 112 | 113 | 114 | add-source 115 | generate-sources 116 | 117 | add-source 118 | 119 | 120 | 121 | src/develop/java 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | develop-ee 132 | 133 | 134 | org.camunda.bpm.webapp 135 | camunda-webapp-ee-tomcat-standalone 136 | ${version.camunda-bpm} 137 | war 138 | 139 | 140 | 141 | 142 | 143 | org.mortbay.jetty 144 | jetty-maven-plugin 145 | 8.1.14.v20131031 146 | 147 | 148 | /camunda 149 | 150 | ${project.basedir}/src/main/resources 151 | ${project.basedir}/src/develop/resources 152 | 153 | 154 | 155 | 156 | 157 | org.codehaus.mojo 158 | build-helper-maven-plugin 159 | 1.9 160 | 161 | 162 | add-source 163 | generate-sources 164 | 165 | add-source 166 | 167 | 168 | 169 | src/develop/java 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/TestDataGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch; 18 | 19 | import org.camunda.bpm.engine.ProcessEngine; 20 | import org.camunda.bpm.engine.RepositoryService; 21 | import org.camunda.bpm.engine.RuntimeService; 22 | import org.camunda.bpm.engine.TaskService; 23 | import org.camunda.bpm.engine.impl.test.ProcessEngineAssert; 24 | import org.camunda.bpm.engine.impl.util.ClockUtil; 25 | import org.camunda.bpm.engine.repository.Deployment; 26 | import org.camunda.bpm.engine.runtime.ProcessInstance; 27 | import org.camunda.bpm.engine.runtime.VariableInstance; 28 | import org.camunda.bpm.engine.task.Task; 29 | import org.elasticsearch.common.base.Charsets; 30 | import org.junit.Assert; 31 | 32 | import java.io.BufferedReader; 33 | import java.io.IOException; 34 | import java.io.InputStreamReader; 35 | import java.net.URL; 36 | import java.util.Date; 37 | import java.util.HashMap; 38 | import java.util.List; 39 | import java.util.Random; 40 | import java.util.logging.Logger; 41 | 42 | import static org.junit.Assert.assertEquals; 43 | 44 | public class TestDataGenerator { 45 | 46 | private static final Logger LOGGER = Logger.getLogger(TestDataGenerator.class.getName()); 47 | private static final Random RANDOM = new Random(); 48 | 49 | public static String getRandomString() { 50 | URL names = TestDataGenerator.class.getClassLoader().getResource("data/names.txt"); 51 | return randomString(names); 52 | } 53 | 54 | public static Double getRandomDouble() { 55 | return RANDOM.nextDouble() * 1000; 56 | } 57 | 58 | public static Long getRandomLong() { 59 | return RANDOM.nextLong(); 60 | } 61 | 62 | public static String randomString(URL nodeNames) { 63 | BufferedReader reader = null; 64 | try { 65 | reader = new BufferedReader(new InputStreamReader(nodeNames.openStream(), Charsets.UTF_8)); 66 | int numberOfNames = 0; 67 | while (reader.readLine() != null) { 68 | numberOfNames++; 69 | } 70 | reader.close(); 71 | reader = new BufferedReader(new InputStreamReader(nodeNames.openStream(), Charsets.UTF_8)); 72 | int number = ((new Random().nextInt(numberOfNames)) % numberOfNames); 73 | for (int i = 0; i < number; i++) { 74 | reader.readLine(); 75 | } 76 | return reader.readLine(); 77 | } catch (IOException e) { 78 | return null; 79 | } finally { 80 | try { 81 | if (reader != null) { 82 | reader.close(); 83 | } 84 | } catch (IOException e) { 85 | // ignore this exception 86 | } 87 | } 88 | } 89 | 90 | public static HashMap startInvoiceProcess(ProcessEngine processEngine, final int numberOfInstances) { 91 | return startInvoiceProcess(processEngine, numberOfInstances, false); 92 | } 93 | 94 | public static HashMap startInvoiceProcess(ProcessEngine processEngine, final int numberOfInstances, boolean addRandomTimeInterval) { 95 | RepositoryService repositoryService = processEngine.getRepositoryService(); 96 | RuntimeService runtimeService = processEngine.getRuntimeService(); 97 | TaskService taskService = processEngine.getTaskService(); 98 | 99 | Deployment deployment = repositoryService.createDeployment().addClasspathResource("invoice.bpmn").deploy(); 100 | Assert.assertNotNull(repositoryService.createDeploymentQuery().deploymentId(deployment.getId()).singleResult()); 101 | 102 | LOGGER.info("Creating " + numberOfInstances + " instances of 'invoice.bpmn' process."); 103 | 104 | 105 | HashMap variablesByProcessIds = new HashMap(numberOfInstances); 106 | 107 | for (int i = 0; i < numberOfInstances; i++) { 108 | if (addRandomTimeInterval) { 109 | ClockUtil.setCurrentTime(new Date(ClockUtil.getCurrentTime().getTime() + getRandomLong())); 110 | } 111 | 112 | HashMap variables = new HashMap(); 113 | variables.put(TestDataGenerator.getRandomString(), TestDataGenerator.getRandomString()); 114 | variables.put("long", TestDataGenerator.getRandomLong()); 115 | variables.put("double", TestDataGenerator.getRandomDouble()); 116 | 117 | ProcessInstance pi = runtimeService.startProcessInstanceByKey("invoice", variables); 118 | Assert.assertNotNull(pi); 119 | 120 | List tasks = taskService.createTaskQuery().processInstanceId(pi.getId()).list(); 121 | 122 | assertEquals(1, tasks.size()); 123 | assertEquals("assignApprover", tasks.get(0).getTaskDefinitionKey()); 124 | 125 | variables.clear(); 126 | String approver = TestDataGenerator.getRandomString(); 127 | variables.put("approver", approver); 128 | taskService.complete(tasks.get(0).getId(), variables); 129 | 130 | tasks = taskService.createTaskQuery().processInstanceId(pi.getId()).list(); 131 | 132 | assertEquals(1, tasks.size()); 133 | assertEquals("approveInvoice", tasks.get(0).getTaskDefinitionKey()); 134 | assertEquals(approver, tasks.get(0).getAssignee()); 135 | 136 | variables.clear(); 137 | variables.put("approved", Boolean.TRUE); 138 | taskService.complete(tasks.get(0).getId(), variables); 139 | 140 | tasks = taskService.createTaskQuery().processInstanceId(pi.getId()).list(); 141 | 142 | // retrieve all variables 143 | List variableInstances = runtimeService.createVariableInstanceQuery().processInstanceIdIn(pi.getProcessInstanceId()).list(); 144 | variablesByProcessIds.put(pi.getProcessInstanceId(), new ProcessDataContainer(pi.getProcessInstanceId(), pi.getBusinessKey(), variableInstances)); 145 | 146 | assertEquals(1, tasks.size()); 147 | assertEquals("prepareBankTransfer", tasks.get(0).getTaskDefinitionKey()); 148 | taskService.complete(tasks.get(0).getId()); 149 | 150 | ProcessEngineAssert.assertProcessEnded(processEngine, pi.getId()); 151 | } 152 | 153 | LOGGER.info("Created " + numberOfInstances + " instances of 'invoice.bpmn' process."); 154 | 155 | return variablesByProcessIds; 156 | } 157 | 158 | private TestDataGenerator() {} 159 | } 160 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 4.0.0 22 | 23 | 24 | org.camunda.bpm.extension.elasticsearch 25 | camunda-bpm-elasticsearch 26 | 1.0.0-SNAPSHOT 27 | 28 | 29 | elasticsearch-engine-integration 30 | camunda bpm - elasticsearch - integration 31 | 32 | 33 | ${project.build.directory}/es/log 34 | ${project.build.directory}/es/data 35 | ${project.build.directory}/es/work 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | com.github.tlrx 55 | elasticsearch-test 56 | test 57 | 58 | 59 | 60 | org.camunda.bpm.extension.elasticsearch 61 | elasticsearch-commons 62 | ${project.version} 63 | 64 | 65 | 66 | org.camunda.bpm 67 | camunda-engine 68 | provided 69 | 70 | 71 | 72 | com.fasterxml.uuid 73 | java-uuid-generator 74 | provided 75 | 76 | 77 | 78 | org.camunda.bpm.jboss 79 | camunda-jboss-subsystem 80 | provided 81 | 82 | 83 | 84 | org.codehaus.groovy 85 | groovy-all 86 | 2.3.2 87 | test 88 | 89 | 90 | 91 | 92 | com.h2database 93 | h2 94 | test 95 | 96 | 97 | 98 | junit 99 | junit 100 | test 101 | 102 | 103 | 104 | org.hamcrest 105 | hamcrest-all 106 | test 107 | 108 | 109 | 110 | org.apache.activemq 111 | activemq-all 112 | provided 113 | 114 | 115 | 116 | 117 | org.springframework.integration 118 | spring-integration-jms 119 | provided 120 | 121 | 122 | 123 | 124 | 125 | 126 | src/test/resources 127 | true 128 | 129 | 130 | 131 | 132 | 133 | org.apache.maven.plugins 134 | maven-surefire-plugin 135 | 136 | true 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | remote-es 145 | 146 | ${project.basedir}/elasticsearch/logs 147 | ${project.basedir}/elasticsearch/data 148 | ${project.basedir}/elasticsearch/work 149 | 150 | 151 | 152 | 153 | org.apache.maven.plugins 154 | maven-surefire-plugin 155 | 156 | 157 | **/cfg/** 158 | 159 | 160 | 161 | 162 | maven-antrun-plugin 163 | 1.4 164 | 165 | 166 | process-test-classes 167 | 168 | run 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.camunda 9 | camunda-release-parent 10 | 2.5 11 | 12 | 13 | 14 | org.camunda.bpm.extension.elasticsearch 15 | camunda-bpm-elasticsearch 16 | 1.0.0-SNAPSHOT 17 | pom 18 | 19 | camunda bpm - elasticsearch 20 | 21 | 22 | 1.4.4 23 | 1.2.1 24 | 25 | 4.9.0 26 | 2.4.1 27 | 17.0 28 | 29 | 7.2.0 30 | 5.9.0 31 | 32 | 4.11 33 | 34 | 3.1.2.RELEASE 35 | 2.2.5.RELEASE 36 | 37 | 1.7 38 | UTF-8 39 | 40 | 41 | 42 | elasticsearch-cockpit-plugin 43 | elasticsearch-engine-integration 44 | elasticsearch-jboss-module 45 | elasticsearch-lib-module 46 | elasticsearch-commons 47 | 48 | 49 | 50 | 51 | 52 | com.github.tlrx 53 | elasticsearch-test 54 | ${version.elasticsearch-test} 55 | test 56 | 57 | 58 | 59 | org.elasticsearch 60 | elasticsearch 61 | ${version.elasticsearch} 62 | 63 | 64 | 65 | org.hamcrest 66 | hamcrest-all 67 | 1.3 68 | test 69 | 70 | 71 | 72 | org.elasticsearch 73 | elasticsearch 74 | ${version.elasticsearch} 75 | test-jar 76 | test 77 | 78 | 79 | 80 | org.camunda.bpm 81 | camunda-engine 82 | ${version.camunda-bpm} 83 | 84 | 85 | com.fasterxml.uuid 86 | java-uuid-generator 87 | 3.1.2 88 | 89 | 90 | org.camunda.bpm.jboss 91 | camunda-jboss-subsystem 92 | ${version.camunda-bpm} 93 | 94 | 95 | com.h2database 96 | h2 97 | 1.3.168 98 | 99 | 100 | 101 | 102 | com.fasterxml.jackson.core 103 | jackson-core 104 | ${version.jackson} 105 | 106 | 107 | com.fasterxml.jackson.core 108 | jackson-databind 109 | ${version.jackson} 110 | 111 | 112 | 113 | junit 114 | junit 115 | ${version.junit} 116 | test 117 | 118 | 119 | 120 | 121 | org.apache.activemq 122 | activemq-all 123 | ${version.activemq} 124 | 125 | 126 | 127 | 128 | org.springframework.integration 129 | spring-integration-jms 130 | ${version.spring-it} 131 | 132 | 133 | 134 | 135 | org.springframework 136 | spring-core 137 | ${version.spring} 138 | 139 | 140 | org.springframework 141 | spring-context 142 | ${version.spring} 143 | 144 | 145 | org.springframework 146 | spring-context-support 147 | ${version.spring} 148 | 149 | 150 | org.springframework 151 | spring-beans 152 | ${version.spring} 153 | 154 | 155 | org.springframework 156 | spring-aspects 157 | ${version.spring} 158 | 159 | 160 | org.springframework 161 | spring-test 162 | ${version.spring} 163 | test 164 | 165 | 166 | 167 | com.google.guava 168 | guava 169 | ${version.guava} 170 | 171 | 172 | 173 | 174 | 175 | 176 | The Apache Software License, Version 2.0 177 | http://www.apache.org/licenses/LICENSE-2.0.txt 178 | 179 | 180 | 181 | 182 | 183 | Christian Lipphardt 184 | christian.lipphardt@camunda.com 185 | 186 | 187 | 188 | 189 | 190 | camunda-bpm-nexus 191 | https://app.camunda.com/nexus/content/groups/public/ 192 | 193 | true 194 | 195 | 196 | true 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | org.apache.maven.plugins 205 | maven-compiler-plugin 206 | 3.1 207 | 208 | ${version.java} 209 | ${version.java} 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/test/java/org/camunda/bpm/elasticsearch/AbstractElasticSearchTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch; 18 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import com.github.tlrx.elasticsearch.test.annotations.ElasticsearchAdminClient; 21 | import com.github.tlrx.elasticsearch.test.annotations.ElasticsearchClient; 22 | import com.github.tlrx.elasticsearch.test.annotations.ElasticsearchNode; 23 | import com.github.tlrx.elasticsearch.test.support.junit.runners.ElasticsearchRunner; 24 | import org.camunda.bpm.elasticsearch.util.ElasticSearchHelper; 25 | import org.camunda.bpm.engine.impl.ProcessEngineImpl; 26 | import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin; 27 | import org.camunda.bpm.engine.test.ProcessEngineRule; 28 | import org.elasticsearch.action.ShardOperationFailedException; 29 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; 30 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; 31 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus; 32 | import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; 33 | import org.elasticsearch.action.admin.indices.flush.FlushResponse; 34 | import org.elasticsearch.action.admin.indices.refresh.RefreshResponse; 35 | import org.elasticsearch.client.AdminClient; 36 | import org.elasticsearch.client.Client; 37 | import org.elasticsearch.client.Requests; 38 | import org.elasticsearch.cluster.metadata.IndexMetaData; 39 | import org.elasticsearch.cluster.metadata.MappingMetaData; 40 | import org.elasticsearch.common.collect.ImmutableOpenMap; 41 | import org.elasticsearch.common.hppc.cursors.ObjectCursor; 42 | import org.elasticsearch.node.Node; 43 | import org.elasticsearch.rest.RestStatus; 44 | import org.junit.Before; 45 | import org.junit.Rule; 46 | import org.junit.runner.RunWith; 47 | 48 | import java.io.IOException; 49 | import java.util.List; 50 | import java.util.Map; 51 | import java.util.logging.Logger; 52 | 53 | import static org.elasticsearch.client.Requests.clusterStateRequest; 54 | import static org.hamcrest.core.IsEqual.equalTo; 55 | import static org.junit.Assert.assertThat; 56 | 57 | @RunWith(ElasticsearchRunner.class) 58 | public abstract class AbstractElasticSearchTest { 59 | 60 | protected Logger logger = Logger.getLogger(AbstractElasticSearchTest.class.getName()); 61 | 62 | protected ObjectMapper mapper = new ObjectMapper(); 63 | 64 | @ElasticsearchNode(configFile = "config/elasticsearch-test.yml") 65 | protected Node elasticsearchNode; 66 | @ElasticsearchClient 67 | protected Client client; 68 | @ElasticsearchAdminClient 69 | protected AdminClient adminClient; 70 | 71 | @Rule 72 | public ProcessEngineRule processEngineRule = new ProcessEngineRule(); 73 | 74 | @Before 75 | public void initialize() { 76 | ElasticSearchHistoryPluginConfiguration historyPluginConfiguration = ElasticSearchHistoryPluginConfiguration.readConfigurationFromClasspath(); 77 | ElasticSearchHelper.checkIndex(client, historyPluginConfiguration.getIndex()); 78 | ElasticSearchHelper.checkTypeAndMapping(client, historyPluginConfiguration.getIndex(), historyPluginConfiguration.getType()); 79 | 80 | List processEnginePlugins = ((ProcessEngineImpl) processEngineRule.getProcessEngine()) 81 | .getProcessEngineConfiguration() 82 | .getProcessEnginePlugins(); 83 | for (ProcessEnginePlugin processEnginePlugin : processEnginePlugins) { 84 | if (processEnginePlugin instanceof ElasticSearchHistoryPlugin) { 85 | ElasticSearchHistoryPlugin plugin = (ElasticSearchHistoryPlugin) processEnginePlugin; 86 | plugin.setElasticSearchClient(client); 87 | } 88 | } 89 | } 90 | 91 | protected void showMappings(String... indices) throws IOException { 92 | ClusterStateResponse clusterStateResponse = adminClient.cluster() 93 | .state(clusterStateRequest() 94 | .blocks(true) 95 | .nodes(true) 96 | .indices(indices)) 97 | .actionGet(); 98 | 99 | for (IndexMetaData indexMetaData : clusterStateResponse.getState().getMetaData()) { 100 | printMapping(indexMetaData.getMappings()); 101 | } 102 | } 103 | 104 | protected void printMapping(ImmutableOpenMap mappedMetaData) { 105 | for (ObjectCursor metaDataEntry : mappedMetaData.values()) { 106 | try { 107 | Map sourceAsMap = metaDataEntry.value.getSourceAsMap(); 108 | logger.info(mapper.writeValueAsString(sourceAsMap)); 109 | } catch (IOException e) { 110 | // nop 111 | } 112 | } 113 | } 114 | 115 | /** 116 | * Waits for relocations and refreshes all indices in the cluster. 117 | * 118 | * @see #waitForRelocation() 119 | */ 120 | protected final RefreshResponse refresh() { 121 | waitForRelocation(); 122 | // TODO RANDOMIZE with flush? 123 | RefreshResponse actionGet = adminClient.indices().prepareRefresh().execute().actionGet(); 124 | // assertNoFailures(actionGet); 125 | return actionGet; 126 | } 127 | 128 | /** 129 | * Flushes and refreshes all indices in the cluster 130 | */ 131 | protected final void flushAndRefresh() { 132 | flush(true); 133 | refresh(); 134 | } 135 | 136 | /** 137 | * Flushes all indices in the cluster 138 | */ 139 | protected final FlushResponse flush() { 140 | return flush(true); 141 | } 142 | 143 | private FlushResponse flush(boolean ignoreNotAllowed) { 144 | waitForRelocation(); 145 | FlushResponse actionGet = adminClient.indices().prepareFlush().setForce(true).setFull(true).execute().actionGet(); 146 | if (ignoreNotAllowed) { 147 | for (ShardOperationFailedException failure : actionGet.getShardFailures()) { 148 | // assertThat("unexpected flush failure " + failure.reason(), failure.status(), equalTo(RestStatus.SERVICE_UNAVAILABLE)); 149 | } 150 | } else { 151 | // assertNoFailures(actionGet); 152 | } 153 | return actionGet; 154 | } 155 | 156 | /** 157 | * Waits for all relocating shards to become active using the cluster health API. 158 | */ 159 | public ClusterHealthStatus waitForRelocation() { 160 | return waitForRelocation(null); 161 | } 162 | 163 | /** 164 | * Waits for all relocating shards to become active and the cluster has reached the given health status 165 | * using the cluster health API. 166 | */ 167 | public ClusterHealthStatus waitForRelocation(ClusterHealthStatus status) { 168 | ClusterHealthRequest request = Requests.clusterHealthRequest().waitForRelocatingShards(0); 169 | if (status != null) { 170 | request.waitForStatus(status); 171 | } 172 | ClusterHealthResponse actionGet = adminClient.cluster() 173 | .health(request).actionGet(); 174 | if (actionGet.isTimedOut()) { 175 | // logger.info("waitForRelocation timed out (status={}), cluster state:\n{}\n{}", status, adminClient.cluster().prepareState().get().getState().prettyPrint(), adminClient.cluster().preparePendingClusterTasks().get().prettyPrint()); 176 | assertThat("timed out waiting for relocation", actionGet.isTimedOut(), equalTo(false)); 177 | } 178 | if (status != null) { 179 | assertThat(actionGet.getStatus(), equalTo(status)); 180 | } 181 | return actionGet.getStatus(); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /elasticsearch-engine-integration/src/main/java/org/camunda/bpm/elasticsearch/index/ElasticSearchDefaultIndexStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - Christian Lipphardt and camunda services GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.camunda.bpm.elasticsearch.index; 18 | 19 | import com.fasterxml.jackson.core.JsonProcessingException; 20 | import org.camunda.bpm.elasticsearch.entity.ElasticSearchProcessInstanceHistoryEntity; 21 | import org.camunda.bpm.elasticsearch.util.ElasticSearchHelper; 22 | import org.camunda.bpm.engine.impl.history.event.HistoricActivityInstanceEventEntity; 23 | import org.camunda.bpm.engine.impl.history.event.HistoricProcessInstanceEventEntity; 24 | import org.camunda.bpm.engine.impl.history.event.HistoricTaskInstanceEventEntity; 25 | import org.camunda.bpm.engine.impl.history.event.HistoricVariableUpdateEventEntity; 26 | import org.camunda.bpm.engine.impl.history.event.HistoryEvent; 27 | import org.elasticsearch.action.update.UpdateRequestBuilder; 28 | import org.elasticsearch.action.update.UpdateResponse; 29 | import org.elasticsearch.common.unit.TimeValue; 30 | import org.elasticsearch.script.ScriptService; 31 | 32 | import java.io.IOException; 33 | import java.util.HashMap; 34 | import java.util.List; 35 | import java.util.Map; 36 | import java.util.logging.Level; 37 | import java.util.logging.Logger; 38 | 39 | public class ElasticSearchDefaultIndexStrategy extends ElasticSearchIndexStrategy { 40 | 41 | protected static final Logger LOGGER = Logger.getLogger(ElasticSearchDefaultIndexStrategy.class.getName()); 42 | 43 | protected static final String ES_INDEX_UPDATE_SCRIPT = 44 | "if (isActivityInstanceEvent) { if (ctx._source.containsKey(\"activities\")) { ctx._source.activities += value } else { ctx._source.activities = value } };" + 45 | "if (isTaskInstanceEvent) { if (ctx._source.containsKey(\"tasks\")) { ctx._source.tasks += value } else { ctx._source.tasks = value } };" + 46 | "if (isVariableUpdateEvent) { if (ctx._source.containsKey(\"variables\")) { ctx._source.variables += value } else { ctx._source.variables = value } };"; 47 | protected static final int WAIT_FOR_RESPONSE = 5; 48 | 49 | public void executeRequest(List historyEvents) { 50 | for (HistoryEvent historyEvent : historyEvents) { 51 | executeRequest(historyEvent); 52 | } 53 | } 54 | 55 | public void executeRequest(HistoryEvent historyEvent) { 56 | try { 57 | if (filterEvents(historyEvent)) { 58 | return; 59 | } 60 | 61 | UpdateRequestBuilder updateRequestBuilder = prepareUpdateRequest(historyEvent); 62 | 63 | if (LOGGER.isLoggable(Level.FINE)) { 64 | LOGGER.fine(ElasticSearchHelper.convertRequestToJson(updateRequestBuilder.request())); 65 | } 66 | 67 | UpdateResponse updateResponse; 68 | if (WAIT_FOR_RESPONSE > 0) { 69 | updateResponse = updateRequestBuilder.get(TimeValue.timeValueSeconds(WAIT_FOR_RESPONSE)); 70 | } else { 71 | updateResponse = updateRequestBuilder.get(); 72 | } 73 | 74 | if (LOGGER.isLoggable(Level.FINE)) { 75 | LOGGER.fine("[" + updateResponse.getIndex() + 76 | "][" + updateResponse.getType() + 77 | "][update] process instance with id '" + updateResponse.getId() + "'"); 78 | LOGGER.log(Level.FINE, "Source: " + updateResponse.getGetResult().sourceAsString()); 79 | } 80 | } catch (IOException e) { 81 | LOGGER.log(Level.SEVERE, e.getMessage(), e); 82 | } 83 | } 84 | 85 | protected boolean filterEvents(HistoryEvent historyEvent) { 86 | if (historyEvent instanceof HistoricProcessInstanceEventEntity || 87 | historyEvent instanceof HistoricActivityInstanceEventEntity || 88 | historyEvent instanceof HistoricTaskInstanceEventEntity || 89 | historyEvent instanceof HistoricVariableUpdateEventEntity) { 90 | return false; 91 | } 92 | return true; 93 | } 94 | 95 | protected UpdateRequestBuilder prepareUpdateRequest(HistoryEvent historyEvent) throws IOException { 96 | UpdateRequestBuilder updateRequestBuilder = esClient.prepareUpdate() 97 | .setIndex(dispatcher.getDispatchTargetIndex(historyEvent)) 98 | .setId(historyEvent.getProcessInstanceId()); 99 | 100 | String dispatchTargetType = dispatcher.getDispatchTargetType(historyEvent); 101 | if (dispatchTargetType != null && !dispatchTargetType.isEmpty()) { 102 | updateRequestBuilder.setType(dispatchTargetType); 103 | } 104 | 105 | if (historyEvent instanceof HistoricProcessInstanceEventEntity) { 106 | prepareHistoricProcessInstanceEventUpdate(historyEvent, updateRequestBuilder); 107 | } else if (historyEvent instanceof HistoricActivityInstanceEventEntity || 108 | historyEvent instanceof HistoricTaskInstanceEventEntity || 109 | historyEvent instanceof HistoricVariableUpdateEventEntity) { 110 | updateRequestBuilder = prepareOtherHistoricEventsUpdateRequest(historyEvent, updateRequestBuilder); 111 | } else { 112 | // unknown event - insert... 113 | throw new IllegalArgumentException("Unknown event detected: '" + historyEvent + "'"); 114 | // LOGGER.warning("Unknown event detected: '" + historyEvent + "'"); 115 | } 116 | 117 | if (LOGGER.isLoggable(Level.FINE)) { 118 | updateRequestBuilder.setFields("_source"); 119 | } 120 | 121 | return updateRequestBuilder; 122 | } 123 | 124 | protected UpdateRequestBuilder prepareHistoricProcessInstanceEventUpdate(HistoryEvent historyEvent, UpdateRequestBuilder updateRequestBuilder) throws JsonProcessingException { 125 | ElasticSearchProcessInstanceHistoryEntity elasticSearchProcessInstanceHistoryEntity = 126 | ElasticSearchProcessInstanceHistoryEntity.createFromHistoryEvent(historyEvent); 127 | 128 | String event = transformer.transformToJson(elasticSearchProcessInstanceHistoryEntity); 129 | 130 | updateRequestBuilder.setDoc(event).setDocAsUpsert(true); 131 | 132 | return updateRequestBuilder; 133 | } 134 | 135 | protected UpdateRequestBuilder prepareOtherHistoricEventsUpdateRequest(HistoryEvent historyEvent, UpdateRequestBuilder updateRequestBuilder) throws IOException { 136 | HashMap scriptParams = new HashMap(); 137 | 138 | if (historyEvent instanceof HistoricActivityInstanceEventEntity) { 139 | scriptParams.put("isActivityInstanceEvent", true); 140 | scriptParams.put("isTaskInstanceEvent", false); 141 | scriptParams.put("isVariableUpdateEvent", false); 142 | } else if (historyEvent instanceof HistoricTaskInstanceEventEntity) { 143 | scriptParams.put("isActivityInstanceEvent", false); 144 | scriptParams.put("isTaskInstanceEvent", true); 145 | scriptParams.put("isVariableUpdateEvent", false); 146 | } else { 147 | scriptParams.put("isActivityInstanceEvent", false); 148 | scriptParams.put("isTaskInstanceEvent", false); 149 | scriptParams.put("isVariableUpdateEvent", true); 150 | } 151 | 152 | String eventJson = transformer.transformToJson(historyEvent); 153 | // needed otherwise the resulting json is not an array/list and the update script throws an error 154 | List> events = transformer.transformJsonToList("[" + eventJson + "]"); 155 | scriptParams.put("value", events); 156 | 157 | updateRequestBuilder.setScript(ES_INDEX_UPDATE_SCRIPT, ScriptService.ScriptType.INLINE) 158 | .setScriptParams(scriptParams); 159 | 160 | return updateRequestBuilder; 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /docs/userguide.md: -------------------------------------------------------------------------------- 1 | # Camunda BPM Elasticsearch User Guide 2 | 3 | ## Overview 4 | 5 | The Camunda BPM Elasticsearch extension is a community extension which allows you to use 6 | Elasticsearch as data store for Camunda history and audit data. 7 | 8 | ### Giving it a quick Try 9 | 10 | If you want to have a quick look at this project, you can start a running instance of Camunda BPM 11 | with Elasticsearch in the following way: 12 | 13 | * Cone the project using git: `git clone https://github.com/camunda/camunda-bpm-elasticsearch.git` 14 | * Build the project using maven: `mvn clean install -DskipTests` 15 | * Start the camunda Webapp from the commandline: 16 | 17 | ```bash 18 | cd elasticsearch-cockpit-plugin 19 | mvn clean jetty:run -Pdevelop 20 | ``` 21 | * go to [http://localhost:8080/camunda](http://localhost:8080/camunda) 22 | * Login with `demo:demo` 23 | 24 | In Cockpit you will see a couple of plugins which allow you to search through the process engine 25 | data using Elasticsearch. 26 | 27 | ### How it works 28 | 29 | The Camunda process engine produces a continuous event stream of auditing data (Read Userguide: 30 | [History][userguide:history_event_stream]). This event stream contains events about process instances 31 | being started, tasks being completed, variables being modified and so forth (check the Camunda BPM 32 | Userguide for a complete list of supported events). 33 | The Camunda Elasticsearch Extension implements the `HistoryEventHandler` SPI and stores all history 34 | events in Elasticsearch. Once the history data is stored in Elasticsearch, it can be queried in a 35 | flexible way. 36 | 37 | ### Components 38 | 39 | The Camunda Elasticsearch Extension is composed of two modules: a process engine plugin and a 40 | Cockpit plugin. 41 | 42 | #### The Process Engine Plugin 43 | 44 | The process engine plugin implements the `HistoryEventHandler` SPI and stores camunda history events 45 | in Elasticsearch. 46 | 47 | #### The Cockpit Plugin 48 | 49 | The Cockpit plugin enhances Camunda BPM Cockpit and provides different view for accessing the 50 | History Data stored in Elasticsearch. 51 | 52 | ##### The Quick Search View 53 | 54 | The Quick Seach View is a simple seach bar which allows full text search on all stored events. 55 | 56 | ![Quick Search Screenshot][quick-search-screenshot] 57 | 58 | ##### The Activity Monitoring View 59 | 60 | The Activity Monitoring View shows an histogram with the number of started and completed process 61 | instances over time. 62 | 63 | ## Installation & Configuration 64 | 65 | ### Supported Camunda BPM Version 66 | 67 | Currently camunda BPM 7.2.0 is required. 68 | 69 | ### Installing the Process Engine Integration 70 | 71 | The process engine integration needs to be added as [Process Engine Plugin][process-engine-plugin] 72 | to Camunda Process Engine. The setup depends on whether you use a *shared* or an *embedded* process 73 | engine. 74 | 75 | #### Installation with Embedded Process Engine 76 | 77 | In order to use the Elasticsearch Module with an embedded process engine you need to add it to the 78 | process engine classpath and configure the process engine to use the plugin. 79 | 80 | ##### Adding the Elasticsearch plugin to the classpath 81 | 82 | If your application uses Apache Maven, you need to add the following dependencies to your 83 | application: 84 | 85 | ```xml 86 | 87 | 88 | org.camunda.bpm.extension.elasticsearch 89 | elasticsearch-engine-integration 90 | 1.0.0-SNAPSHOT 91 | 92 | 93 | org.elasticsearch 94 | elasticsearch 95 | 1.3.1 96 | 97 | 98 | ``` 99 | 100 | ##### Spring based Configuration 101 | 102 | If you bootstrap your process engine using the Spring Framework, you can configure the Elasticsearch plugin using Spring: 103 | 104 | ```xml 105 | 106 | ... 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | ``` 117 | 118 | #### Installation with Shared Process Engine 119 | 120 | If you use a shared process engine, you need to add camunda Elasticsearch JAR files and all 121 | required Elasticsearch libraries to the process engine classpath and configure the plugin in 122 | `bpm-platform.xml` or `standalone.xml` (JBoss). 123 | 124 | ##### Installation in JBoss Application Server Distribution 125 | 126 | In order to install the Elasticsearch extension on JBoss Application Server with Camunda BPM 127 | subsystem, the following steps are necessary: 128 | 129 | * Download a pre-packaged distribution from [camunda.org](http://camunda.org/download/). 130 | * Unpack the Camunda distribution into a folder of your choice. 131 | * Clone the [camunda-bpm-elasticsearch][repository] repository using Git. 132 | * Build the repository by typing `mvn clean install` 133 | * Copy the modules from `elasticsearch-jboss-module/target/modules/` to the modules folder of your 134 | jboss distribution. 135 | * Inside the modules folder of your JBoss Application Server, edit the file 136 | `modules/org/camunda/bpm/jboss/camunda-jboss-subsystem/main/module.xm` and add a 137 | module dependency to the elasticsearch module: 138 | 139 | ```xml 140 | 141 | ... 142 | 143 | ... 144 | 145 | 146 | 147 | 148 | ``` 149 | 150 | * Edit the JBoss `standalone.xml` file and activate the Elasticsearch plugin: 151 | 152 | ```xml 153 | 154 | 155 | 156 | ... 157 | 158 | 159 | org.camunda.bpm.elasticsearch.ElasticSearchHistoryPlugin 160 | 161 | 162 | 163 | 164 | 165 | ``` 166 | 167 | ##### Installation in Tomcat Distribution 168 | 169 | In order to install the Elasticsearch process engine plugin in the Camunda Tomcat distribution, the 170 | following steps are necessary: 171 | 172 | * Download a pre-packaged distribution from [camunda.org](http://camunda.org/download/). 173 | * Unpack the camunda distribution into a folder of your choice. 174 | * Clone the [camunda-bpm-elasticsearch][repository] repository using Git. 175 | * Build the repository by typing `mvn clean install` 176 | * copy the libraries `elasticsearch-lib-module/target/lib/` to the apache tomcat `lib/` folder (the 177 | same folder in which the `camunda-engine.jar` file is located.). 178 | * Inside the apache tomcat configuration folder, edit the file named `bpm-platform.xml`: 179 | 180 | ```xml 181 | 182 | ... 183 | 184 | 185 | org.camunda.bpm.elasticsearch.ElasticSearchHistoryPlugin 186 | 187 | 188 | 189 | ``` 190 | 191 | ### Installing the Cockpit Plugin 192 | 193 | > TODO: this section needs to be improved 194 | 195 | In order to install the cockpit plugin you need to proceed as follows: 196 | 197 | * Build the cockpit plugin by cloning the repository and building it with maven 198 | * Copy the plugin jar file to the WEB-INF/lib folder of the camunda Webapplication 199 | 200 | [userguide:history_event_stream]: http://docs.camunda.org/latest/guides/user-guide/#process-engine-history-and-audit-event-log 201 | [quick-search-screenshot]: img/quick-search.png 202 | [process-engine-plugin]: http://docs.camunda.org/latest/guides/user-guide/#process-engine-process-engine-plugins 203 | [repository]: https://github.com/camunda/camunda-bpm-elasticsearch 204 | -------------------------------------------------------------------------------- /elasticsearch-cockpit-plugin/src/main/resources/plugin-webapp/dashboards/app/lib/nv.d3.min.css: -------------------------------------------------------------------------------- 1 | .chartWrap{margin:0;padding:0;overflow:hidden}.nvtooltip.with-3d-shadow,.with-3d-shadow .nvtooltip{-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nvtooltip{position:absolute;background-color:rgba(255,255,255,1);padding:1px;border:1px solid rgba(0,0,0,.2);z-index:10000;font-family:Arial;font-size:13px;text-align:left;pointer-events:none;white-space:nowrap;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.nvtooltip.with-transitions,.with-transitions .nvtooltip{transition:opacity 250ms linear;-moz-transition:opacity 250ms linear;-webkit-transition:opacity 250ms linear;transition-delay:250ms;-moz-transition-delay:250ms;-webkit-transition-delay:250ms}.nvtooltip.x-nvtooltip,.nvtooltip.y-nvtooltip{padding:8px}.nvtooltip h3{margin:0;padding:4px 14px;line-height:18px;font-weight:400;background-color:rgba(247,247,247,.75);text-align:center;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.nvtooltip p{margin:0;padding:5px 14px;text-align:center}.nvtooltip span{display:inline-block;margin:2px 0}.nvtooltip table{margin:6px;border-spacing:0}.nvtooltip table td{padding:2px 9px 2px 0;vertical-align:middle}.nvtooltip table td.key{font-weight:400}.nvtooltip table td.value{text-align:right;font-weight:700}.nvtooltip table tr.highlight td{padding:1px 9px 1px 0;border-bottom-style:solid;border-bottom-width:1px;border-top-style:solid;border-top-width:1px}.nvtooltip table td.legend-color-guide div{width:8px;height:8px;vertical-align:middle}.nvtooltip .footer{padding:3px;text-align:center}.nvtooltip-pending-removal{position:absolute;pointer-events:none}svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:block;width:100%;height:100%}svg text{font:400 12px Arial}svg .title{font:700 14px Arial}.nvd3 .nv-background{fill:#fff;fill-opacity:0}.nvd3.nv-noData{font-size:18px;font-weight:700}.nv-brush .extent{fill-opacity:.125;shape-rendering:crispEdges}.nvd3 .nv-legend .nv-series{cursor:pointer}.nvd3 .nv-legend .disabled circle{fill-opacity:0}.nvd3 .nv-axis{pointer-events:none}.nvd3 .nv-axis path{fill:none;stroke:#000;stroke-opacity:.75;shape-rendering:crispEdges}.nvd3 .nv-axis path.domain{stroke-opacity:.75}.nvd3 .nv-axis.nv-x path.domain{stroke-opacity:0}.nvd3 .nv-axis line{fill:none;stroke:#e5e5e5;shape-rendering:crispEdges}.nvd3 .nv-axis .zero line,.nvd3 .nv-axis line.zero{stroke-opacity:.75}.nvd3 .nv-axis .nv-axisMaxMin text{font-weight:700}.nvd3 .x .nv-axis .nv-axisMaxMin text,.nvd3 .x2 .nv-axis .nv-axisMaxMin text,.nvd3 .x3 .nv-axis .nv-axisMaxMin text{text-anchor:middle}.nv-brush .resize path{fill:#eee;stroke:#666}.nvd3 .nv-bars .negative rect{zfill:brown}.nvd3 .nv-bars rect{zfill:#4682b4;fill-opacity:.75;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-bars rect.hover{fill-opacity:1}.nvd3 .nv-bars .hover rect{fill:#add8e6}.nvd3 .nv-bars text{fill:rgba(0,0,0,0)}.nvd3 .nv-bars .hover text{fill:rgba(0,0,0,1)}.nvd3 .nv-multibar .nv-groups rect,.nvd3 .nv-multibarHorizontal .nv-groups rect,.nvd3 .nv-discretebar .nv-groups rect{stroke-opacity:0;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-multibar .nv-groups rect:hover,.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,.nvd3 .nv-discretebar .nv-groups rect:hover{fill-opacity:1}.nvd3 .nv-discretebar .nv-groups text,.nvd3 .nv-multibarHorizontal .nv-groups text{font-weight:700;fill:rgba(0,0,0,1);stroke:rgba(0,0,0,0)}.nvd3.nv-pie path{stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-pie .nv-slice text{stroke:#000;stroke-width:0}.nvd3.nv-pie path{stroke:#fff;stroke-width:1px;stroke-opacity:1}.nvd3.nv-pie .hover path{fill-opacity:.7}.nvd3.nv-pie .nv-label{pointer-events:none}.nvd3.nv-pie .nv-label rect{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-groups path.nv-line{fill:none;stroke-width:1.5px}.nvd3 .nv-groups path.nv-line.nv-thin-line{stroke-width:1px}.nvd3 .nv-groups path.nv-area{stroke:none}.nvd3 .nv-line.hover path{stroke-width:6px}.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point{fill-opacity:0;stroke-opacity:0}.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point{fill-opacity:.5!important;stroke-opacity:.5!important}.with-transitions .nvd3 .nv-groups .nv-point{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-scatter .nv-groups .nv-point.hover,.nvd3 .nv-groups .nv-point.hover{stroke-width:7px;fill-opacity:.95!important;stroke-opacity:.95!important}.nvd3 .nv-point-paths path{stroke:#aaa;stroke-opacity:0;fill:#eee;fill-opacity:0}.nvd3 .nv-indexLine{cursor:ew-resize}.nvd3 .nv-distribution{pointer-events:none}.nvd3 .nv-groups .nv-point.hover{stroke-width:20px;stroke-opacity:.5}.nvd3 .nv-scatter .nv-point.hover{fill-opacity:1}.nvd3.nv-stackedarea path.nv-area{fill-opacity:.7;stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-stackedarea path.nv-area.hover{fill-opacity:.9}.nvd3.nv-stackedarea .nv-groups .nv-point{stroke-opacity:0;fill-opacity:0}.nvd3.nv-linePlusBar .nv-bar rect{fill-opacity:.75}.nvd3.nv-linePlusBar .nv-bar rect:hover{fill-opacity:1}.nvd3.nv-bullet{font:10px sans-serif}.nvd3.nv-bullet .nv-measure{fill-opacity:.8}.nvd3.nv-bullet .nv-measure:hover{fill-opacity:1}.nvd3.nv-bullet .nv-marker{stroke:#000;stroke-width:2px}.nvd3.nv-bullet .nv-markerTriangle{stroke:#000;fill:#fff;stroke-width:1.5px}.nvd3.nv-bullet .nv-tick line{stroke:#666;stroke-width:.5px}.nvd3.nv-bullet .nv-range.nv-s0{fill:#eee}.nvd3.nv-bullet .nv-range.nv-s1{fill:#ddd}.nvd3.nv-bullet .nv-range.nv-s2{fill:#ccc}.nvd3.nv-bullet .nv-title{font-size:14px;font-weight:700}.nvd3.nv-bullet .nv-subtitle{fill:#999}.nvd3.nv-bullet .nv-range{fill:#bababa;fill-opacity:.4}.nvd3.nv-bullet .nv-range:hover{fill-opacity:.7}.nvd3.nv-sparkline path{fill:none}.nvd3.nv-sparklineplus g.nv-hoverValue{pointer-events:none}.nvd3.nv-sparklineplus .nv-hoverValue line{stroke:#333;stroke-width:1.5px}.nvd3.nv-sparklineplus,.nvd3.nv-sparklineplus g{pointer-events:all}.nvd3 .nv-hoverArea{fill-opacity:0;stroke-opacity:0}.nvd3.nv-sparklineplus .nv-xValue,.nvd3.nv-sparklineplus .nv-yValue{stroke-width:0;font-size:.9em;font-weight:400}.nvd3.nv-sparklineplus .nv-yValue{stroke:#f66}.nvd3.nv-sparklineplus .nv-maxValue{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-sparklineplus .nv-minValue{stroke:#d62728;fill:#d62728}.nvd3.nv-sparklineplus .nv-currentValue{font-weight:700;font-size:1.1em}.nvd3.nv-ohlcBar .nv-ticks .nv-tick{stroke-width:2px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover{stroke-width:4px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive{stroke:#2ca02c}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative{stroke:#d62728}.nvd3.nv-historicalStockChart .nv-axis .nv-axislabel{font-weight:700}.nvd3.nv-historicalStockChart .nv-dragTarget{fill-opacity:0;stroke:none;cursor:move}.nvd3 .nv-brush .extent{fill-opacity:0!important}.nvd3 .nv-brushBackground rect{stroke:#000;stroke-width:.4;fill:#fff;fill-opacity:.7}.nvd3.nv-indentedtree .name{margin-left:5px}.nvd3.nv-indentedtree .clickable{color:#08C;cursor:pointer}.nvd3.nv-indentedtree span.clickable:hover{color:#005580;text-decoration:underline}.nvd3.nv-indentedtree .nv-childrenCount{display:inline-block;margin-left:5px}.nvd3.nv-indentedtree .nv-treeicon{cursor:pointer}.nvd3.nv-indentedtree .nv-treeicon.nv-folded{cursor:pointer}.nvd3 .background path{fill:none;stroke:#ccc;stroke-opacity:.4;shape-rendering:crispEdges}.nvd3 .foreground path{fill:none;stroke:#4682b4;stroke-opacity:.7}.nvd3 .brush .extent{fill-opacity:.3;stroke:#fff;shape-rendering:crispEdges}.nvd3 .axis line,.axis path{fill:none;stroke:#000;shape-rendering:crispEdges}.nvd3 .axis text{text-shadow:0 1px 0 #fff}.nvd3 .nv-interactiveGuideLine{pointer-events:none}.nvd3 line.nv-guideline{stroke:#ccc} --------------------------------------------------------------------------------