Skip to main content

How-To Implementing Neowise Methods

1. Introduction

This article describes the methods created and used for Neowise. We have several different types of method:

  • SEARCH_CONTENT
  • DOCUMENT_NAMES
  • DOCUMENT_CLONE
  • PUBLICATION_CLONE
  • DASHLET

(They are part of PluginMethod.MethodType enum.)

2. Method implementation

To create a new Neowise method, we need to add a new plug-in in a plug-in library project. A new plug-in should implement 4 methods:

  • String getMethodName(String lang)
  • List<GuiParameter> getParameters(Map<String,Object> params)
  • List<GuiParameter> updateParameters(Map<String,Object> params)
  • main method with proper method type

2.1 Method Name

The name of method visible in priint:suite is delivered by method getMethodName of the plugin.

The declaration of the method is as follows:

@PubServerMethod(label = "name", type = PluginMethod.MethodType.GENERIC, description = "plugin method called to obtain a translation of plugin label")
public String getMethodName(
@PubServerMethodParameter(name = "lang", defaultValue = PubPlannerPlugins.EN, listOfValues = {}) final String lang);

The method gets a string parameter representing current language of priint:suite instance. Thereby the developer can provide translation of the method name.

2.2 UI Dialog Methods

Most of the methods require additional parameters which should be set by user in the runtime. After choosing the method, the UI dialog is shown, rendered on the fly.

uiDialogMethods.png

  1. Method name
  2. Parameter
  3. Parameter
@PubServerMethod(label = "parameters", type = PluginMethod.MethodType.GENERIC, description = "plugin method called to obtain a list of parameters needed in gui")
public List<GuiParameter> getParameters(
@PubServerMethodParameter(name = "params") final Map<String, Object> params);

The method returns list of GuiParameter objects. Each element of the list represents one GUI component shown in dialog. The components are rendered from the top to the bottom, in order as they are in the list.

The GuiParameter object can represent the following UI components:

  • TEXTFIELD - text input

TEXTFIELD.png

  • POSITIVE_NUMBER_TEXTFIELD - text input in which the user can only input positive numbers

POSITIVE_NUMBER_TEXTFIELD.png

  • TEXTAREA - text area for longer text

TEXTAREA.png

  • COMBOBOX - dropdown with predefined values

COMBOBOX.png

  • CHECKBOX - checkbox for true/false values

CHECKBOX.png

  • LABEL - text that can be displayed next to the component

LABEL.png

  • REFRESHBUTTON - button for refreshing the UI

REFRESHBUTTON.png

  • LINKBUTTON - button with the link to a specific place in the application

img.png

  • MULTIPLE_COMBOBOX - dropdown with predefined values with the possibility of selecting multiple values

MULTIPLE_COMBOBOX.png

We have a few factory methods to easily create the components:

public static final GuiParameter getTextField(String label, String identifier, String value);
public static final GuiParameter getPositiveNumberTextField(String label, String identifier, String value);
public static final GuiParameter getTextArea(String label, String identifier, String value, int lines);
public static final GuiParameter getComboBox(String label, String identifier, String value, List<GuiParameterComboBoxItem> lovValues);
public static final GuiParameter getCheckBox(String label, String identifier, boolean value);
public static final GuiParameter getLabel(String label, String identifier);
public static final GuiParameter getRefreshButton(String label, String identifier);
public static final GuiParameter getLinkButton(String label, String identifier, String value);
public static final GuiParameter getMultipleComboBox(String label, String identifier, String value, List<GuiParameterComboBoxItem> lovValues);

The UI components have additionally 3 attributes:

  • mandatory (methods: isMandatory, setMandatory) - the value of field cannot be null.
  • editable (methods: isEditable, setEditable) - the field has content only to show the user (example: default prefix of the document name calculated by the method)
  • canChangeGUI - the method can cause creation of new components. Sometimes, it is necessary to show additional UI elements or change existing elements based on the values inside the plugin e.g. different text fields should be displayed based on the value chosen inside a combo-box.

We can also set height and width of component using methods:

  • setHeightInChars
  • setWidthInChars

Additionally, all plugins used in Neowise should implement the List<GuiParameter> updateParameters(Map<String, Object> params) method. The below example shows how to create dynamic UI in your plugins. The first step is to pass canChangeGUI parameter to your created element inside the getParameters method. In the below example checkbox element will be able to change the UI of the plugin:

@PubServerMethod(label = "parameters",
type = PluginMethod.MethodType.GENERIC,
description = "plugin method called to obtain a list of parameters needed in the UI")
public List<GuiParameter> getParameters(@PubServerMethodParameter(name = "params") final Map<String, Object> params) {
List<GuiParameter> parameters = new ArrayList<>();

boolean valueType = true;
if(params.get("exampleCheckbox") != null){
valueType = Boolean.parseBoolean(params.get("exampleCheckbox").toString());
}
// please note the last parameter (canChangeGUI) in the getCheckBox method is set to true.
// It lets the plugin know that this UI element will make changes to the existing UI.
GuiParameter checkBox = GuiParameter.getCheckBox("Example checkbox", "exampleCheckbox", valueType,true);
parameters.add(checkBox);

return parameters;
}

The parameter params contains the values returned in the getParameters method. The returned List<GuiParameter> contains all the elements you want to display after the UI is changed i.e. you will need to copy the existing elements if you want them to be visible after the UI is changed. The below example displays a text field only if the checkbox unchecked:

@PubServerMethod(label="parameters",
type=PluginMethod.MethodType.GENERIC,
description="plugin method called to obtain a list of parameters needed in the UI")
public List<GuiParameter> updateParameters(@PubServerMethodParameter(name="params") final Map<String,Object> params) {
List<GuiParameter> parameters = getParameters(params);

boolean valueType = true;
if(params.get("exampleCheckbox") != null){
valueType = Boolean.parseBoolean(params.get("exampleCheckbox").toString());
}

if (!valueType) {
parameters.add(GuiParameter.getTextField("Example additional UI element", "exampleAdditionalUIElement", ""));
return parameters;
}

return parameters;
}

Resulting initial UI:

chrome_VuMG14xGiF.png

After changing the value of the checkbox:

chrome_8jtUPTICtZ.png

3. Review of Method Types – Use Cases

3.1 SEARCH_CONTENT

Methods of this type, like p. 1.1, are used to search buckets for content tree in Neowise

3.2 DOCUMENT_NAMES

Methods of this type are used to generate new document names during the creation of new Documents.

They can also be used while duplicating a Document or Publication: documentNamesDuplicationUI.png

3.3 DOCUMENT_CLONE

This kind of method is used during duplication of the Document. The method implements the way of creating new Document based on the source.

documentCloneUi.png

3.4 PUBLICATION_CLONE

This kind of method is used during duplication of the Publication.

publicationCloneUI.png

3.5 DASHLET

The methods of this type are used to generate the data for the Dashlets that are shown inside the Dashboard window of Neowise. dashletUI.png

The getParameters and updateParameters methods must be defined as it is now possible to configure the parameters for the Dashlets from the UI. Additionally, the getParameters method and the method used to get the data must use the following method from the com.priint.pubserver.dashboard.interfaces.DashletServiceLocal:

List<ChartParam> mergedParameters = dashletServiceLocal.getParametersByUserProjectDashlet(sessionInfo.getLogin(), sessionInfo.getDataSetLabel(),chartId);

4. Sample Implementations

4.1 SEARCH_CONTENT - Bucket search by label

This plugin will help users find the right bucket by providing the label. Additionally, it will allow to choose the entity (combobox) and will provide the possibility to search only the first level of buckets (checkbox ).

The method building UI – getParameters() – looks as follows:

@PubServerMethod(label="parameters",
type=PluginMethod.MethodType.GENERIC,
description="plugin method called to obtain a list of parameters needed in gui")
public List<GuiParameter> getParameters(@PubServerMethodParameter(name="params") final Map<String,Object> params) {

List<GuiParameter> result = new ArrayList<GuiParameter>();
GuiParameter entityLabel = GuiParameter.getTextField("LABEL", ENTITY_LABEL, params.containsKey(ENTITY_LABEL)?(String)params.get(ENTITY_LABEL):"");
entityLabel.getTranslations().put(PubPlannerPlugins.DE, "Bezeichnung");
entityLabel.getTranslations().put(PubPlannerPlugins.EN, "Label");
result.add(entityLabel);

List<GuiParameterComboBoxItem> lovValues = new ArrayList<GuiParameterComboBoxItem>();
GuiParameterComboBoxItem emptyComboItem = new GuiParameterComboBoxItem("- No selection -", "-1");
lovValues.add(emptyComboItem);
String entityModelIdentifier = (String)params.get(ENTITY_MODEL_IDENTIFIER);
EntityModel entityModel = Utils.getEntityModel(entityModelIdentifier);
boolean onlyRoots = params.containsKey(ONLY_ROOTS) && Boolean.parseBoolean((String)params.get(ONLY_ROOTS));
Map<String, String> entities = Utils.getEntityBucketNames(entityModel, onlyRoots);
Map<String, String> sortedEntities = entities.entrySet().stream()
.sorted(Map.Entry.<String, String>comparingByValue())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
sortedEntities.forEach((key, value)->{
GuiParameterComboBoxItem comboItem = new GuiParameterComboBoxItem(value, key);
lovValues.add(comboItem);
});

List <GuiParameter>hBoxChildren = new ArrayList();
GuiParameter entitiesCombo = GuiParameter.getComboBox("Entity", ENTITY_IDENTIFIER, null, lovValues);
if (params.containsKey(ENTITY_IDENTIFIER) && params.get(ENTITY_IDENTIFIER)!= null && !(params.get(ENTITY_IDENTIFIER).toString()).isEmpty()) {
entitiesCombo.setValue(params.get(ENTITY_IDENTIFIER).toString());
}else{
entitiesCombo.setValue("-1");
}
entitiesCombo.setHeightInChars(1);
entitiesCombo.setWidthInChars(55);
entitiesCombo.getTranslations().put(PubPlannerPlugins.EN, "Entity");
entitiesCombo.getTranslations().put(PubPlannerPlugins.DE, "Entität");
hBoxChildren.add(entitiesCombo);

GuiParameter onlyRootsCB = GuiParameter.getCheckBox("search only first level", ONLY_ROOTS, onlyRoots);
onlyRootsCB.setCanChangeGUI(true);
onlyRootsCB.getTranslations().put(PubPlannerPlugins.DE, "nur oberste Ebene durchsuchen");
onlyRootsCB.getTranslations().put(PubPlannerPlugins.EN, "search only first level");
onlyRootsCB.setHeightInChars(1);
hBoxChildren.add(onlyRootsCB);

GuiParameter hBox = GuiParameter.getHorizontalPanel("hbox", hBoxChildren);
hBox.setWidthInChars(60);
result.add(hBox);

return result;
}

The main method, annotated with type as SEARCH_CONTENT, uses EntityManager to search bucket by label. It also uses available parameters from UI, located in map of parameters:

  • PubPlannerPlugins.ParameterNames.SESSIONID
@SuppressWarnings("unchecked")
@PubServerMethod(label="SearchBucketByLabel",
type=PluginMethod.MethodType.SEARCH_CONTENT,
description="plugin method called to search buckets")
public List<Bucket> searchBuckets(@PubServerMethodParameter(name="parameters") final Map<String,Object> parameters) throws ServerException {
List<Bucket> result = new ArrayList<>();
String sessionId = (String)parameters.get(PubPlannerPlugins.ParameterNames.SESSIONID.toString());
String entityModelIdentifier = (String)parameters.get(ENTITY_MODEL_IDENTIFIER);
String entityIdentifier = parameters.containsKey(ENTITY_IDENTIFIER) && parameters.get(ENTITY_IDENTIFIER)!= null && !parameters.get(ENTITY_IDENTIFIER).equals("-1")? parameters.get(ENTITY_IDENTIFIER).toString():"";
String entityLabel = parameters.containsKey(ENTITY_LABEL)?(String)parameters.get(ENTITY_LABEL):"";
try{
boolean onlyRoots = parameters.containsKey(ONLY_ROOTS) && Boolean.parseBoolean((String)parameters.get(ONLY_ROOTS));
List<EntityBucket> bucketEntities = Utils.getBucketsEntitiesList(entityModelIdentifier, onlyRoots);
if(bucketEntities != null && !bucketEntities.isEmpty()) {
for (EntityBucket entityBucket:bucketEntities) {
if(entityIdentifier.isEmpty() || entityBucket.getIdentifier().equals(entityIdentifier)){
List<Bucket> subRes = serviceLocator.getEntityManager(sessionId).getBuckets(sessionId, entityModelIdentifier, entityBucket.getIdentifier(), entityLabel);
result.addAll(subRes.stream().filter((bucket -> {
return ((onlyRoots && (bucket.getParentBucketId() == null || bucket.getParentBucketId().equals(""))) || !onlyRoots) ;
})).collect(toList()));
}
}
}
}catch (EntityManagerException e){
throw new ServerException(1, SearchByLabel.this, e.getLocalizedMessage());
}
return result;
}

4.2 DOCUMENT_NAMES

In this case, we want to provide mechanism to generate document names for larger amount of documents. Let’s assume we want to let the user enter the start value. The getParameters() method can be like this:

public List<GuiParameter> getParameters(
@PubServerMethodParameter(name = "params") final Map<String, Object> params) {
List<GuiParameter> result = new ArrayList<GuiParameter>();
GuiParameter countFrom = GuiParameter.getTextField("Count from", "countFromID", "");
countFrom.getTranslations().put(PubPlannerPlugins.DE, "Zähler ab");
countFrom.getTranslations().put(PubPlannerPlugins.EN, "Count from");
countFrom.setMandatory(true);
result.add(countFrom);
return result;
}

The main method can be as follows:

  @PubServerMethod(label="automatic count from",
type=PluginMethod.MethodType.DOCUMENT_NAMES,
description="plugin method called to obtain a list document names")
public List<String> getDocumentNames(@PubServerMethodParameter(name="parameters") final Map<String,Object> parameters) throws ServerException {
List<String> result = new ArrayList<String>();
String howMany = (String)parameters.get(PubPlannerPlugins.ParameterNames.COUNT.toString());
String countFrom = (String)parameters.get("countFromId");

int docCount = Integer.parseInt(howMany);
int iCountFrom = Integer.parseInt(countFrom);
int iCountTo = docCount+iCountFrom;
for (int i = iCountFrom; i < iCountTo; i++) {
String docName = String.format("%04d", i);
result.add(docName);
}
return result;
}

Note: PubPlannerPlugins.ParameterNames.COUNT is a key of the object (in the map params) containing number of documents to create.

createDocument.png

4.3 DOCUMENT_CLONE

We want to provide a mechanism of cloning(duplicating) documents. We need to create a plugin with proper method. In this case the default implementation will be described.

To perform cloning operation, we will use CometServer4ServiceLocator to access some EJB:

private CometServer4ServiceLocator.ServiceLocatorEnum serviceLocator = CometServer4ServiceLocator.ServiceLocatorEnum.INSTANCE;

The UI dialog contains only one component – it is a checkbox to select if we want to duplicate document using masterdocument (document template):

copyUsingMasterDoc.png

The method building dialog – getParameters() – looks as follows:

//identifier of GUI component using as key in map of parameters
private static final String USE_MASTERDOCUMENT= "USE_MASTERDOCUMENT";

@PubServerMethod(label = "parameters", type = PluginMethod.MethodType.GENERIC, description = "plugin method called to obtain a list of parameters needed in gui")
public List<GuiParameter> getParameters(
@PubServerMethodParameter(name = "params") final Map<String, Object> params) {

List<GuiParameter> result = new ArrayList<GuiParameter>();

GuiParameter useMasterDocument = GuiParameter.getCheckBox("Using Masterdocument", USE_MASTERDOCUMENT, false);
useMasterDocument.getTranslations().put(PubPlannerPlugins.DE, "Musterdokumente verwenden");
useMasterDocument.getTranslations().put(PubPlannerPlugins.EN, "Using Masterdocument");
useMasterDocument.setMandatory(true);
try {
InDesignServerSettings settings = serviceLocator.getInDesignServerSettings();
if (null != settings) {
useMasterDocument.setValue(settings.isUseMasterDocument() + "");
}
} catch (Exception e) {
e.printStackTrace();
}
result.add(useMasterDocument);
return result;
}

The main method, annotated with type as DOCUMENT_CLONE, uses CometData bean to duplicate document. It also uses available parameters from main dialog, located in map of parameters:

  • PubPlannerPlugins.ParameterNames.SESSIONID
  • PubPlannerPlugins.ParameterNames.SOURCEDOCUEMNTS
  • PubPlannerPlugins.ParameterNames.NAMESOFDOCUMENTS
  • PubPlannerPlugins.ParameterNames.TARGETPUBLICATIONS
@PubServerMethod(label="StandardDocumentClone",
type=PluginMethod.MethodType.DOCUMENT_CLONE,
description="plugin method called to clone documents")
public Boolean cloneDocuments(@PubServerMethodParameter(name="parameters") final Map<String,Object> parameters) throws ServerException {

Boolean result = Boolean.TRUE;

String sessionId = (String)parameters.get(PubPlannerPlugins.ParameterNames.SESSIONID.toString());

List<String>sourceDocuments = (List<String>)parameters.get(PubPlannerPlugins.ParameterNames.SOURCEDOCUEMNTS.toString());

List<String>newDocumentNames = (List<String>)parameters.get(PubPlannerPlugins.ParameterNames.NAMESOFDOCUMENTS.toString());

List<String>targetPublications = (List<String>)parameters.get(PubPlannerPlugins.ParameterNames.TARGETPUBLICATIONS.toString());

if (targetPublications != null && !targetPublications.isEmpty()){
for (String publicationID:targetPublications){
if (sourceDocuments != null && !sourceDocuments.isEmpty()){
int index = 0;
for (String documentID:sourceDocuments){
String newName = "";
if (newDocumentNames != null && !newDocumentNames.isEmpty()){
newName = (String)newDocumentNames.get(0);
if (index <newDocumentNames.size()){
newName = (String)newDocumentNames.get(index);
}
}
index++;
serviceLocator.getCometDataLocal().
duplicateTreeElement(sessionId, "document",
documentID, publicationID, newName, parameters);
}
}
}
}
return result;
}

4.4 PUBLICATION_CLONE

It is similar to DOCUMENT_CLONE. In this example, the UI dialog stays the same, the user can decide whether the Document Template should be used. It also uses CometServer4ServiceLocator to access some EJB.

private CometServer4ServiceLocator.ServiceLocatorEnum serviceLocator = CometServer4ServiceLocator.ServiceLocatorEnum.INSTANCE;
@PubServerMethod(label="clonePublications",
type=PluginMethod.MethodType.PUBLICATION_CLONE,
description="plugin method called to clone documents")
public Boolean clonePublications(@PubServerMethodParameter(name="parameters") final Map<String,Object> parameters) throws ServerException {
Boolean result = Boolean.TRUE;

String sessionId = (String)parameters.get(PubPlannerPlugins.ParameterNames.SESSIONID.toString());

List<String>sourcePublications = (List<String>)parameters.get(PubPlannerPlugins.ParameterNames.SOURCEDOCUEMNTS.toString());

List<String>targetPublications = (List<String>)parameters.get(PubPlannerPlugins.ParameterNames.TARGETPUBLICATIONS.toString());

String newPublicationName="";
if (targetPublications != null && !targetPublications.isEmpty()){
for (String publicationID:targetPublications){
if (sourcePublications != null && !sourcePublications.isEmpty()){
for (String pubID:sourcePublications){
PucPublication[] pucPublications = serviceLocator.getCometDataLocal().
getPucPublications(sessionId, pubID,"","","","");
if (pucPublications!=null && pucPublications.length>0 ) {
newPublicationName = pucPublications[0].getLabel()!=null ?
"dup "+pucPublications[0].getLabel() : "";
} else {
newPublicationName = "";
}
serviceLocator.getCometDataLocal().
duplicateTreeElement(sessionId, "publication",
pubID, publicationID, newPublicationName, parameters);
}
}
}
}
return result;
}

4.5 DASHLET - Process User Task Timeliness Pie Chart

The method getData from the below class returns the timeliness of User Tasks for given process.

 @Stateless(mappedName = ProcessUserTaskTimelinessPieChart.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class ProcessUserTaskTimelinessPieChart extends PluginControlDefault {

public static final String MAPPED_NAME = "com.priint.pubserver.plugins.dashlets.ProcessUserTaskTimelinessPieChart";

BpmServiceLocal bpmServiceLocal;
DashletServiceLocal dashletServiceLocal;
private static final String CHART_ID_PARAM = "chartIdentifier";
private static final String PROCESS_ID_PARAM = "processId";

private final CometServer4ServiceLocator.ServiceLocatorEnum cs4Locator;
private CometServer4ServiceLocator.ServiceLocatorEnum getServiceLocator(){
return cs4Locator;
}
public ProcessUserTaskTimelinessPieChart() {
this(CometServer4ServiceLocator.ServiceLocatorEnum.INSTANCE);
}
public ProcessUserTaskTimelinessPieChart(final CometServer4ServiceLocator.ServiceLocatorEnum cs4Locator) {
super();
this.cs4Locator = cs4Locator;
}
@PubServerMethod(label="parameters",
type=PluginMethod.MethodType.GENERIC,
description="plugin method called to obtain a list of parameters needed in gui")
public List getParameters(@PubServerMethodParameter(name="params") final Map<String,Object> params) {
dashletServiceLocal = Utils.getDashletServiceLocal();
String sessionId = (String)params.get(PubPlannerPlugins.ParameterNames.SESSIONID.toString());
String chartId = (String)params.get(CHART_ID_PARAM);
AtomicReference processId = new AtomicReference<>("");
List result = new ArrayList<>();
try{
SessionInfo sessionInfo = SessionInfo.requireNormalSession(sessionId, TeamUserTaskTimelinessPieChart.class.getSimpleName());
List mergedParameters = dashletServiceLocal.getParametersByUserProjectDashlet(sessionInfo.getLogin(), sessionInfo.getDataSetLabel(),chartId);
mergedParameters.stream().forEach(chartParam -> {
if(chartParam.getName().equals(PROCESS_ID_PARAM)){
processId.set(chartParam.getValues()!=null && !chartParam.getValues().isEmpty()?chartParam.getValues().get(0).getValue():"");
}
});

bpmServiceLocal = Utils.getBpmServiceLocal();
List processes = bpmServiceLocal.getProcessDefinitionList();
List lovValues = new ArrayList<>();
Set distinctedProcess = new HashSet<>();
processes.stream().forEach(process->{
if (!distinctedProcess.contains(process.getKey())){
distinctedProcess.add(process.getKey());
GuiParameterComboBoxItem comboItem = new GuiParameterComboBoxItem(process.getName(), process.getKey());
lovValues.add(comboItem);
}

});
GuiParameter processCombo = GuiParameter.getComboBox(TranslationUtils.getDashboardsTranslation("process", sessionInfo.getLanguage()), PROCESS_ID_PARAM, null, lovValues);
processCombo.setMandatory(true);
if (processId.get()!=null && !processId.get().isEmpty()) {
processCombo.setValue(processId.get());
}else{
processCombo.setValue("-1");
}

processCombo.setHeightInChars(1);
processCombo.setWidthInChars(55);
result.add(processCombo);

}catch(Exception e) {

}
return result;
}

@Lock(LockType.READ)
@PubServerMethod(label="parameters",
type=PluginMethod.MethodType.GENERIC,
description="plugin method called to obtain a list of parameters needed in gui")
public List updateParameters(@PubServerMethodParameter(name="params") final Map<String,Object> params) {
return getParameters(params);
}

@PubServerMethod(label="name",
type=PluginMethod.MethodType.GENERIC,
description="plugin method called to obtain a translation of plugin label")
public String getMethodName(@PubServerMethodParameter(name="lang", defaultValue=PubPlannerPlugins.EN, listOfValues={}) final String lang) throws InvalidSessionException {
return TranslationUtils.getDashboardsTranslation("ProcessUserTaskTimelinessPieChart", lang);
}
@PubServerMethod(label="ProcessUserTaskTimelinessPieChart",
type= PluginMethod.MethodType.DASHLET,
description="plugin method called to generate data for Pie chart overview tasks timelines for given Process")
public PieChartData getData(@PubServerMethodParameter(name="parameters") final Map<String,Object> parameters) throws ServerException {
dashletServiceLocal = Utils.getDashletServiceLocal();
String sessionId = (String)parameters.get(PubPlannerPlugins.ParameterNames.SESSIONID.toString());
String chartId = (String)parameters.get(CHART_ID_PARAM);
SessionInfo sessionInfo = SessionInfo.requireNormalSession(sessionId, ProcessUserTaskTimelinessPieChart.class.getSimpleName());

PieChartData result = new PieChartData();
AtomicReference processIdentifierParam = new AtomicReference<>("");
List mergedParameters = dashletServiceLocal.getParametersByUserProjectDashlet(sessionInfo.getLogin(), sessionInfo.getDataSetLabel(),chartId);
mergedParameters.stream().forEach(chartParam -> {
if(chartParam.getName().equals(PROCESS_ID_PARAM)){
processIdentifierParam.set(chartParam.getValues()!=null && !chartParam.getValues().isEmpty()?chartParam.getValues().get(0).getValue():"");
}
});
String name = TranslationUtils.getDashboardsTranslation("wrongProcessParam", sessionInfo.getLanguage())
.replace("{Unparametrized title}", TranslationUtils.getDashboardsTranslation("ProcessUserTaskTimelinessPieChart", sessionInfo.getLanguage()));
String processIdParamValue = processIdentifierParam.get();
if(null != processIdParamValue && !processIdParamValue.isEmpty()) {
bpmServiceLocal = Utils.getBpmServiceLocal();
TaskQueryDto taskQuery = new TaskQueryDto();
taskQuery.addProcessVariable(ProcessVariableOperator.eq, "project", Utils.getProject(getSessionId()));
taskQuery.setSorting(new ArrayList<>());
taskQuery.setProcessDefinitionKey(processIdParamValue);
List taskList = bpmServiceLocal.getTaskList("0", "100000", taskQuery);
if(taskList!=null && !taskList.isEmpty())
result = TaskUtils.mapToTaskTimelinesPieChartData(getSessionId(), taskList);
try {
ProcessDefinition process = bpmServiceLocal.getProcessDefinitionByKey(processIdParamValue);
if (process != null) {
name = TranslationUtils.getDashboardsTranslation("ParametrizedProcessUserTaskTimelinessPieChart", sessionInfo.getLanguage())
.replace("{name}", "\"" + process.getName() + "\"");
}
}catch(Exception e){}
}
result.setName(name);
return result;
}
}