提交 569d1211 编写于 作者: J Joram Barrez

Fix for running reports on JDK 6 (version of Rhino in JDK 6 is too old)

上级 473c3937
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.explorer.reporting;
import java.util.HashMap;
import java.util.Map;
/**
* @author Joram Barrez
*/
public class Dataset {
protected String type;
protected String description;
protected String xaxis;
protected String yaxis;
protected Map<String, Number> data = new HashMap<String, Number>();
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Map<String, Number> getData() {
return data;
}
public String getXaxis() {
return xaxis;
}
public void setXaxis(String xaxis) {
this.xaxis = xaxis;
}
public String getYaxis() {
return yaxis;
}
public void setYaxis(String yaxis) {
this.yaxis = yaxis;
}
public void setData(Map<String, Number> data) {
this.data = data;
}
public void add(String key, Number value) {
data.put(key, value);
}
}
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.activiti.explorer.reporting;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.ActivitiException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
/**
* @author Joram Barrez
*/
public class ReportData {
protected String title;
protected List<Dataset> datasets = new ArrayList<Dataset>();
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<Dataset> getDatasets() {
return datasets;
}
public void setDatasets(List<Dataset> datasets) {
this.datasets = datasets;
}
public void addDataset(Dataset dataset) {
datasets.add(dataset);
}
public Dataset newDataset() {
Dataset dataset = new Dataset();
addDataset(dataset);
return dataset;
}
public String toString() {
try {
return new String(toBytes(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new ActivitiException("Could not convert report data to json", e);
}
}
public byte[] toBytes() {
try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE, false);
objectMapper.configure(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES, false);
objectMapper.configure(SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);
return objectMapper.writeValueAsBytes(this);
} catch (Exception e) {
throw new ActivitiException("Could not convert report data to json", e);
}
}
}
......@@ -21,8 +21,6 @@ import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
......
......@@ -20,7 +20,7 @@
targetRef="generateDataset" />
<scriptTask id="generateDataset" name="Execute script"
scriptFormat="JavaScript" activiti:autoStoreVariables="false">
scriptFormat="js" activiti:autoStoreVariables="false">
<script><![CDATA[
importPackage(java.sql);
......@@ -28,6 +28,8 @@
importPackage(java.util);
importPackage(org.activiti.explorer.reporting);
var reportData = new ReportData();
var month = execution.getVariable("month");
var employee = execution.getVariable("employee");
......@@ -52,17 +54,15 @@
}
}
var counts = {};
for (var i=firstDay; i<=lastDay; i++) {
counts[i + ""] = 0;
}
var counts = new Array();
var reportData = {};
reportData.datasets = [];
if (firstDay != null && lastDay != null && firstDay != lastDay) {
for (var i=firstDay; i<=lastDay; i++) {
counts[i] = 0;
}
// Fetch counts for day
var result = ReportingUtil.executeSelectSqlQuery("SELECT END_TIME_ FROM ACT_HI_TASKINST where END_TIME_ is not null and month(END_TIME_) = " + (month + 1) + " and ASSIGNEE_ = '" + employee + "'");
while (result.next()) { // process results one row at a time
var timestamp = result.getTimestamp(1);
......@@ -71,24 +71,26 @@
cal.setTime(timestamp);
var day = cal.get(Calendar.DAY_OF_MONTH);
var previousCount = counts[day + ""];
counts[day + ""] = previousCount + 1;
var previousCount = counts[day];
counts[day] = counts[day] + 1;
}
// Create data set
var dataset = {};
var dataset = reportData.newDataset();
dataset.type = "lineChart";
dataset.description = "Daily productivity overview for " + employee;
dataset.xaxis = "Day of month";
dataset.yaxis = "Number of completed tasks";
dataset.data = counts;
reportData.datasets.push(dataset);
execution.setVariable("reportData", new java.lang.String(JSON.stringify(reportData)).getBytes("UTF-8"));
for (var i=firstDay; i<=lastDay; i++) {
dataset.add(i + "", counts[i]);
}
} else if (firstDay != null && lastDay != null && firstDay == lastDay) {
for (var i=0; i<=24; i++) {
counts[i] = 0;
}
// Fetch counts for hours
var result = ReportingUtil.executeSelectSqlQuery("SELECT END_TIME_ FROM ACT_HI_TASKINST where END_TIME_ is not null and month(END_TIME_) = " + (month + 1) + " and ASSIGNEE_ = '" + employee + "'");
while (result.next()) { // process results one row at a time
......@@ -98,26 +100,23 @@
cal.setTime(timestamp);
var hour = cal.get(Calendar.HOUR_OF_DAY);
var previousCount = counts[hour + ""];
counts[hour + ""] = previousCount + 1;
var previousCount = counts[hour];
counts[hour] = counts[hour] + 1;
}
// Create data set
var dataset = {};
var dataset = reportData.newDataset();
dataset.type = "lineChart";
dataset.description = "Hourly productivity overview for " + employee;
dataset.xaxis = "Hour of day";
dataset.yaxis = "Number of completed tasks";
dataset.data = counts;
reportData.datasets.push(dataset);
execution.setVariable("reportData", new java.lang.String(JSON.stringify(reportData)).getBytes("UTF-8"));
for (var i=0; i<=24; i++) {
dataset.add(i + "", counts[i]);
}
}
} else {
reportData.data = {};
execution.setVariable("reportData", new java.lang.String(JSON.stringify(reportData)).getBytes("UTF-8"));
}
execution.setVariable("reportData", reportData.toBytes());
]]></script>
</scriptTask>
......
......@@ -11,7 +11,7 @@
<startEvent id="startevent1" name="Start" />
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="generateDataset" />
<scriptTask id="generateDataset" name="Execute script" scriptFormat="JavaScript" activiti:autoStoreVariables="false">
<scriptTask id="generateDataset" name="Execute script" scriptFormat="js" activiti:autoStoreVariables="false">
<script><![CDATA[
importPackage(java.sql);
......@@ -26,9 +26,10 @@
firstLineResult.next();
var firstLineCount = firstLineResult.getLong(1) - escalatedCount;
/* JDK 7 only
var reportData = {};
var dataset = {};
var dataset = {};
dataset.description = "Helpdesk process: issues solved in first line vs escalation needed";
dataset.type = "pieChart";
reportData.datasets = [];
......@@ -41,6 +42,22 @@
reportData.datasets.push(dataset);
execution.setVariable("reportData", new java.lang.String(JSON.stringify(reportData)).getBytes("UTF-8"));
*/
/* JDK 6+ */
var reportData = new ReportData();
var dataset = reportData.newDataset();
dataset.description = "Helpdesk process: issues solved in first line vs escalation needed";
dataset.type = "pieChart";
if (escalatedCount > 0 || firstLineCount > 0) {
dataset.add("First line solved", firstLineCount);
dataset.add("Escalation needed", escalatedCount);
}
execution.setVariable("reportData", reportData.toBytes());
]]></script>
</scriptTask>
<sequenceFlow id="flow3" sourceRef="generateDataset" targetRef="theEnd" />
......
......@@ -11,7 +11,7 @@
<startEvent id="startevent1" name="Start" />
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="generateDataset" />
<scriptTask id="generateDataset" name="Execute script" scriptFormat="JavaScript" activiti:autoStoreVariables="false">
<scriptTask id="generateDataset" name="Execute script" scriptFormat="js" activiti:autoStoreVariables="false">
<script><![CDATA[
importPackage(java.sql);
......@@ -20,6 +20,8 @@
var result = ReportingUtil.executeSelectSqlQuery("SELECT PD.NAME_, PD.VERSION_ , count(*) FROM ACT_HI_PROCINST PI inner join ACT_RE_PROCDEF PD on PI.PROC_DEF_ID_ = PD.ID_ group by PROC_DEF_ID_");
/* JDK 7 only
var reportData = {};
reportData.datasets = [];
......@@ -35,18 +37,36 @@
dataset.data[name + " (v" + version + ")"] = count;
}
reportData.datasets.push(dataset);
// We also include a list view of the same data
var dataset2 = {};
dataset2.type="list";
dataset2.description = "List overview of process instances";
dataset2.data = dataset.data;
reportData.datasets.push(dataset2);
// We want to store the results as bytes as the string size is limited in the variables table
execution.setVariable("reportData", new java.lang.String(JSON.stringify(reportData)).getBytes("UTF-8"));
*/
/* JDK 6+ */
var reportData = new ReportData;
var dataset = reportData.newDataset();
dataset.type = "pieChart";
dataset.description = "Process instance overview (" + new java.util.Date() + ")";
while (result.next()) { // process results one row at a time
var name = result.getString(1);
var version = result.getLong(2);
var count = result.getLong(3);
dataset.add(name + " (v" + version + ")", count);
}
var dataset2 = reportData.newDataset();
dataset2.type="list";
dataset2.description = "List overview of process instances";
dataset2.data = dataset.data;
execution.setVariable("reportData", reportData.toBytes());
]]></script>
</scriptTask>
<sequenceFlow id="flow3" sourceRef="generateDataset" targetRef="theEnd" />
......
......@@ -19,7 +19,7 @@
</startEvent>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="generateDataset" />
<scriptTask id="generateDataset" name="Execute script" scriptFormat="JavaScript" activiti:autoStoreVariables="false">
<scriptTask id="generateDataset" name="Execute script" scriptFormat="js" activiti:autoStoreVariables="false">
<script><![CDATA[
importPackage(java.sql);
......@@ -30,6 +30,8 @@
var result = ReportingUtil.executeSelectSqlQuery("select NAME_, avg(DURATION_) from ACT_HI_TASKINST where PROC_DEF_ID_ = '" + processDefinition.getId() + "' and END_TIME_ is not null group by NAME_");
/* JDK 7
var reportData = {};
reportData.datasets = [];
......@@ -46,6 +48,24 @@
reportData.datasets.push(dataset);
execution.setVariable("reportData", new java.lang.String(JSON.stringify(reportData)).getBytes("UTF-8"));
*/
/* JDK 6+ */
var reportData = new ReportData();
var dataset = reportData.newDataset();
dataset.type = execution.getVariable("chartType");
dataset.description = "Average task duration (in seconds) for process definition '" + processDefinition.getName() + "' (version " + processDefinition.getVersion() + ")";
while (result.next()) { // process results one row at a time
var name = result.getString(1);
var val = result.getLong(2) / 1000;
dataset.add(name, val);
}
execution.setVariable("reportData", reportData.toBytes());
]]></script>
</scriptTask>
<sequenceFlow id="flow3" sourceRef="generateDataset" targetRef="theEnd" />
......
......@@ -6,7 +6,7 @@ STATUS=$?
if [ $STATUS -eq 0 ]
then
cd modules/activiti-webapp-explorer2
mvn clean package jetty:run
mvn clean install jetty:run
else
echo "Build failure in dependent project. Cannot boot Activiti Explorer."
fi
\ No newline at end of file
......@@ -303,11 +303,11 @@
<listitem>
<para><emphasis role="bold">type</emphasis>Each dataset has a type. This type will be used
to determine how the data will be rendered. Currently supported values are:
<emphasis role="bold">pieChart, lineChart, barChart and list</emphasis></para>.
<emphasis role="bold">pieChart, lineChart, barChart and list.</emphasis></para>
</listitem>
<listitem>
<para><emphasis role="bold">description</emphasis>: each chart can have an optional description
that will be shown in the report</para>.
that will be shown in the report.</para>
</listitem>
<listitem>
<para><emphasis role="bold">x- and yaxis</emphasis>: only usable for type <emphasis>lineChart</emphasis>.
......@@ -331,6 +331,16 @@
contains only a script task (besides start and end) that generates the json dataset using javascript. Altough all of the
examples in Explorer use scripting, this can very well be done using Java service tasks. The end result of
running the process should just be the <emphasis>reportData</emphasis> variable that contains the data.
</para>
<para>
<emphasis role="bold">Important note:</emphasis> The following example only works on JDK 7+.
The reason for this is that the javascript engine (<emphasis>Rhino</emphasis>) that is shipped
with older JDK versions isn't advanced enough to cope with some constructs needed to write
scripts like the one below. See below for a JDK 6+ compliant example.
</para>
<para>
<programlisting>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;definitions xmlns=&quot;http://www.omg.org/spec/BPMN/20100524/MODEL&quot;
......@@ -381,6 +391,9 @@
&lt;/definitions&gt;
</programlisting>
</para>
<para>
Besides the typical XML linea at the top of the process xml, the main difference is that the
<emphasis>targetNamespace</emphasis> is set to <emphasis role="bold">activiti-report</emphasis>,
adding the category with the same name to the deployed process definition.
......@@ -401,6 +414,61 @@
a byte array is unlimited in size while the string is not. That is why the javascript string
must be converted to a Java string which has the capability to get the byte representation.
</para>
<para>
The same process which is compatible with JDK 6 (and higher) looks a bit different. The native
json capabilities cannot be used, hence some helper classes (<emphasis>ReportData</emphasis> and <emphasis>Dataset</emphasis>)
are provided:
<programlisting>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;definitions xmlns=&quot;http://www.omg.org/spec/BPMN/20100524/MODEL&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:activiti=&quot;http://activiti.org/bpmn&quot;
xmlns:bpmndi=&quot;http://www.omg.org/spec/BPMN/20100524/DI&quot; xmlns:omgdc=&quot;http://www.omg.org/spec/DD/20100524/DC&quot;
xmlns:omgdi=&quot;http://www.omg.org/spec/DD/20100524/DI&quot; typeLanguage=&quot;http://www.w3.org/2001/XMLSchema&quot;
expressionLanguage=&quot;http://www.w3.org/1999/XPath&quot;
targetNamespace=&quot;activiti-report&quot;&gt;
&lt;process id=&quot;process-instance-overview-report&quot; name=&quot;Process Instance Overview&quot; isExecutable=&quot;true&quot;&gt;
&lt;startEvent id=&quot;startevent1&quot; name=&quot;Start&quot; /&gt;
&lt;sequenceFlow id=&quot;flow1&quot; sourceRef=&quot;startevent1&quot; targetRef=&quot;generateDataset&quot; /&gt;
&lt;scriptTask id=&quot;generateDataset&quot; name=&quot;Execute script&quot; scriptFormat=&quot;js&quot; activiti:autoStoreVariables=&quot;false&quot;&gt;
&lt;script&gt;&lt;![CDATA[
importPackage(java.sql);
importPackage(java.lang);
importPackage(org.activiti.explorer.reporting);
var result = ReportingUtil.executeSelectSqlQuery(&quot;SELECT PD.NAME_, PD.VERSION_ , count(*) FROM ACT_HI_PROCINST PI inner join ACT_RE_PROCDEF PD on PI.PROC_DEF_ID_ = PD.ID_ group by PROC_DEF_ID_&quot;);
<emphasis role="bold">
var reportData = new ReportData;
var dataset = reportData.newDataset();
dataset.type = &quot;pieChart&quot;;
dataset.description = &quot;Process instance overview (&quot; + new java.util.Date() + &quot;)&quot;
</emphasis>
while (result.next()) { // process results one row at a time
var name = result.getString(1);
var version = result.getLong(2);
var count = result.getLong(3);
<emphasis role="bold">dataset.add(name + &quot; (v&quot; + version + &quot;)&quot;, count);</emphasis>
}
execution.setVariable(&quot;reportData&quot;, reportData.toBytes());
]]&gt;&lt;/script&gt;
&lt;/scriptTask&gt;
&lt;sequenceFlow id=&quot;flow3&quot; sourceRef=&quot;generateDataset&quot; targetRef=&quot;theEnd&quot; /&gt;
&lt;endEvent id=&quot;theEnd&quot; /&gt;
&lt;/process&gt;
&lt;/definitions&gt;
</programlisting>
</para>
</section>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册