-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BonitaCommand BonitaCommandApiAccessor to create your own command using the Public API
- Loading branch information
1 parent
f182090
commit 67d14cf
Showing
4 changed files
with
944 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
228
src/main/java/org/bonitasoft/command/BonitaCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
134
src/main/java/org/bonitasoft/command/BonitaCommandApiAccessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.