Skip to content

Commit

Permalink
First release
Browse files Browse the repository at this point in the history
BonitaCommand
BonitaCommandApiAccessor to create your own command using the Public API
  • Loading branch information
pierre-yves-monnet committed Apr 24, 2019
1 parent f182090 commit 67d14cf
Show file tree
Hide file tree
Showing 4 changed files with 944 additions and 0 deletions.
27 changes: 27 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bonitasoft.command</groupId>
<artifactId>bonita-commanddeployment</artifactId>
<version>1.1.0</version>
<name>bonita-commanddeployment</name>
<dependencies>


<dependency>
<groupId>org.bonitasoft.engine</groupId>
<artifactId>bonita-client</artifactId>
<version>7.6.0</version>
</dependency>
<dependency>
<groupId>org.bonitasoft.engine</groupId>
<artifactId>bonita-server</artifactId>
<version>7.6.0</version>
</dependency>

<dependency>
<groupId>com.bonitasoft.log.event</groupId>
<artifactId>bonita-event</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</project>
228 changes: 228 additions & 0 deletions src/main/java/org/bonitasoft/command/BonitaCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package org.bonitasoft.command;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.bonitasoft.engine.command.SCommandExecutionException;
import org.bonitasoft.engine.command.SCommandParameterizationException;
import org.bonitasoft.engine.command.TenantCommand;
import org.bonitasoft.engine.service.TenantServiceAccessor;
import org.bonitasoft.log.event.BEvent;
import org.bonitasoft.log.event.BEvent.Level;
import org.bonitasoft.log.event.BEventFactory;

/* ******************************************************************************** */
/* */
/* Command Control */
/* */
/* this class is the main control for the command. */
/*
* your command must implement this command here. The implementation garantie:
* - to have the same object called (in the Command call, Bonita creates one new object for each
* call. the getinstance() must decide, you return the same object or a new one
* - manage the PING and any basic verb
* - has the same method as the BonitaCommandDeployment.callCommand
*/

public abstract class BonitaCommand extends TenantCommand {

static Logger logger = Logger.getLogger(BonitaCommand.class.getName());

static String logHeader = "BonitaCommand ~~~";

private static BEvent EVENT_INTERNAL_ERROR = new BEvent(BonitaCommand.class.getName(), 1, Level.ERROR,
"Internal error", "Internal error, check the log");

/* ******************************************************************************** */
/* */
/* the companion MilkCmdControlAPI call this API */
/* */
/* ******************************************************************************** */

/**
* this constant is defined too in MilkQuartzJob to have an independent JAR
*/
public static String cstVerb = "verb";
public static String cstVerbPing = "PING";
public static String cstVerbHelp = "HELP";

/**
* this constant is defined too in MilkQuartzJob to have an independent JAR
*/
public static String cstTenantId = "tenantId";
public static String cstParametersCommand = "parametersCmd";

public static String cstResultTimeInMs = "timeinms";
public static String cstResultListEvents = "listevents";

/* ******************************************************************************** */
/* */
/* Abstract method */
/* */
/* ******************************************************************************** */
/**
* Each command instanciate a new Object.
* if you want that the command use the same object, then return it a static object, else return a
* "this"
* The default implementation return the current object
*/

public BonitaCommand getInstance()
{
return this;
}

/**
*
*
*/
public static class ExecuteParameters {
/**
* the command may respect the Verb/Parameters protocole. Then, this is the verb
*/
public String verb;
public Map<String, Serializable> parametersCommand;
/**
* the original parameters
*/
public Map<String, Serializable> parameters;
/**
* tenant Id
*/
public long tenantId;


}



public static class ExecuteAnswer {

public List<BEvent> listEvents = new ArrayList<BEvent>();
public HashMap<String, Object> result = new HashMap<String, Object>();
/*
* the command may want to manage directly the serializatble. Then, it can do that, just
*/
public Serializable resultSerializable = null;
}

/**
* execute the command.
*
* @param verb : if the command respect the Verb / Parameter, then the verb of the command
* @param parametersCommand : if the command respect the Verb / Parameter, then the parameter of the command
* @param parameters : the original parameters of the command (so, if the command does not respect the verb/Parameter protocol, the original parameters
* @param tenantId
* @param serviceAccessor
* @return
*/
public abstract ExecuteAnswer executeCommand(ExecuteParameters executeParameters, TenantServiceAccessor serviceAccessor);

/**
* the command may return any help and instruction to the developper
*
* @param parameters
* @param tenantId
* @param serviceAccessor
* @return
*/
public String getHelp(Map<String, Serializable> parameters, long tenantId, TenantServiceAccessor serviceAccessor) {
return "No help available";
}

/* ******************************************************************************** */
/* */
/* the BonitaEngine Command API call this API */
/* */
/* ******************************************************************************** */

/**
* each call, the command create a new object.
* The singleton is then use, and decision is take that the method is responsible to save all
* change
*/
public Serializable execute(Map<String, Serializable> parameters, TenantServiceAccessor serviceAccessor)
throws SCommandParameterizationException, SCommandExecutionException {

BonitaCommand executableCmdControl = getInstance();
return executableCmdControl.executeSingleton(parameters, serviceAccessor);
}

/**
* Singleton object. All privates members are safe
*
* @param parameters
* @param serviceAccessor
* @return
* @throws SCommandParameterizationException
* @throws SCommandExecutionException
*/
private Serializable executeSingleton(Map<String, Serializable> parameters, TenantServiceAccessor serviceAccessor)
throws SCommandParameterizationException, SCommandExecutionException {

long currentTime = System.currentTimeMillis();
long startTime = System.currentTimeMillis();
ExecuteParameters executeParameters = new ExecuteParameters();
ExecuteAnswer executeAnswer = null;

try {

executeParameters.parameters = parameters;
executeParameters.verb = (String) parameters.get(cstVerb);
executeParameters.tenantId = (Long) parameters.get(cstTenantId);
executeParameters.parametersCommand = (Map<String,Serializable>) parameters.get(BonitaCommand.cstParametersCommand);

logger.info(logHeader + "BonitaCommand Verb[" + (executeParameters.verb==null ? null : executeParameters.verb.toString()) + "] Tenant[" + executeParameters.tenantId + "]");

// ------------------- ping ?
if (cstVerbPing.equals(executeParameters.verb)) {
// logger.info("CmdCreateMilk: ping");
executeAnswer = new ExecuteAnswer();
executeAnswer.result.put("ping", "hello world");
executeAnswer.result.put("status", "OK");
} else if (cstVerbHelp.equals(executeParameters.verb)) {
executeAnswer = new ExecuteAnswer();
executeAnswer.result.put("help", getHelp(parameters, executeParameters.tenantId, serviceAccessor));
}
else
{
executeAnswer= executeCommand( executeParameters, serviceAccessor);
}


} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
logger.severe("BonitaCommand: ~~~~~~~~~~ : ERROR " + e + " at " + exceptionDetails);
if (executeAnswer==null)
executeAnswer = new ExecuteAnswer();

executeAnswer.listEvents.add(new BEvent(EVENT_INTERNAL_ERROR, e.getMessage()));
} finally {
if (executeAnswer==null)
executeAnswer = new ExecuteAnswer();
executeAnswer.result.put(cstResultTimeInMs, System.currentTimeMillis() - currentTime);
executeAnswer.result.put(cstResultListEvents, BEventFactory.getHtml(executeAnswer.listEvents));
logger.info(logHeader + "BonitaCommand Verb[" + (executeParameters.verb == null ? "null" : executeParameters.verb.toString()) + "] Tenant["
+ executeParameters.tenantId + "] Error?" + BEventFactory.isError(executeAnswer.listEvents) + " in "
+ (System.currentTimeMillis() - startTime) + " ms");

}

// ------------------- service
//ProcessDefinitionService processDefinitionService = serviceAccessor.getProcessDefinitionService();
//ProcessInstanceService processInstanceService = serviceAccessor.getProcessInstanceService();
//SchedulerService schedulerService = serviceAccessor.getSchedulerService();
//EventInstanceService eventInstanceService = serviceAccessor.getEventInstanceService();
if (executeAnswer.resultSerializable !=null)
return executeAnswer.resultSerializable;
return executeAnswer.result;
}
}
134 changes: 134 additions & 0 deletions src/main/java/org/bonitasoft/command/BonitaCommandApiAccessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package org.bonitasoft.command;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Map;
import java.util.logging.Logger;

import org.bonitasoft.engine.api.APIAccessor;
import org.bonitasoft.engine.connector.ConnectorAPIAccessorImpl;
import org.bonitasoft.engine.service.TenantServiceAccessor;

/* ******************************************************************************** */
/* */
/* CommandAPI Control */
/* */
/* use this class if you want to have a ApiAccessor as parameters */
/* */
/* Note: to execute the method, a new thread has to be created, and the main command*/
/* thread has to wait. But if you don't want to wait, you can implement the */
/* method "waitAnswer" and return false */
/* ******************************************************************************** */

public abstract class BonitaCommandApiAccessor extends BonitaCommand {


/**
* implement this Method
* @param verb
* @param parameters
* @param tenantId
* @param apiAccessor
* @return
*/
public abstract ExecuteAnswer executeCommandApiAccessor(ExecuteParameters executeParameters, APIAccessor apiAccessor);


public boolean waitAnswer()
{ return true; };

/**
* you can implements method like getHelp
*/

/* ******************************************************************************** */
/* */
/** implementation */
/**
* this is in the command
*/

private class RunCommandApi implements Runnable
{
public Long lock = new Long(0);

ExecuteParameters executeParameters;
public BonitaCommandApiAccessor bonitaCommandAPI;
/**
* we copy the value to ensure at one moment, the BonitaCommandApi does not change it's mind...
*/
public boolean myParentWaits;

public ExecuteAnswer executeAnswer;

public void start() {
final Thread T = new Thread(this);
T.start();
}

public void run()
{
Logger logger = Logger.getLogger(RunCommandApi.class.getName());

// create the ApiAccessor
ConnectorAPIAccessorImpl apiAccessor = new ConnectorAPIAccessorImpl(executeParameters.tenantId);
try
{
executeAnswer = bonitaCommandAPI.executeCommandApiAccessor(executeParameters, apiAccessor);
}
catch(Exception e )
{
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();

logger.severe("GetAvailableHumanTaskList : error:"+e.getMessage()+" at "+exceptionDetails);


}

// notify my parent: it wait for me !
if (myParentWaits)
{
synchronized ( lock )
{
lock.notify();
}
}
}
} //-------------------------------- end RunCommandApi

/**
* command call this method.
* So, let's create a new thread, and wait for its return
*/
@Override
public final ExecuteAnswer executeCommand(ExecuteParameters executeParameters, TenantServiceAccessor serviceAccessor)
{
RunCommandApi runCommandApi = new RunCommandApi();
runCommandApi.executeParameters = executeParameters;
runCommandApi.bonitaCommandAPI = this;
runCommandApi.myParentWaits = waitAnswer();


runCommandApi.start();
if (runCommandApi.myParentWaits)
{
// synchronized is mandatory to wait
synchronized ( runCommandApi.lock )
{
try {
runCommandApi.lock.wait();
return runCommandApi.executeAnswer;
}
catch(InterruptedException e){
logger.severe("BonitaCommandAPI. error "+e.toString());
}
}
}
return new ExecuteAnswer();

}

}
Loading

0 comments on commit 67d14cf

Please sign in to comment.