Hi Luis,
Welcome, again I think, first yes there are lots of things to think about and this is a good starting point.
A set of predefined, single source parameters that you want to use for all processes…for example:
- email server attributes
- database server attributes
- etc.
As you will have noted parameters are process based and not global so in this sense don’t work. If I want to change the email server address then I only want to do it once not everywhere (for every process using live update).
For some reason this is still not built in when it should be…
OK, that’s part 1 gripe out of the way.
My second gripe is the use of BDO/M. It’s not always necessary. And in this case I feel it is definitely not required.
You have to ask yourself what are you using these parameters for, you don’t say that in your post but I will use my example of email server attributes. These will never be shown on the screen (except in the configuration form) and will only be used by the process. Therefore not suitable for BDO/M just use them in the process as process variables.
Try not to over thing the use of BDO/M, when it is Business Data, sure use it if the data meets the explicit requirements of a BDO/M, i.e.
- You are recommended to use business data instead of process data for any data that has meaning outside of one single process.
- The business data objects are stored in a database that can be accessed by all applications and processes in a tenant.
- There is no need to import data from an external system or write it back after a change. The data is automatically stored persistently.
In my example of email server attributes I have two points that fail the BDM requirements:
Do my email server Attributes have meaning outside one process, tricky as this is a yes and no answer. Yes because I will use them, but more specifically because I will not base any business decision on them. They are what they are, they are fixed, unchangeable, unmodifiable, and do not form part of a process/business decision…
I do NOT want my email server parameters stored in all processes and made available to the all processes. Here for every process I would be saving a copy of the attributes in each process. Not what I need, and as Anna has found out will increase the size of database needlessly. Invoices can be stored and used by other processes, but my email attributes will not so attributes fail the test for a BDO/M.
So gripe 2 is use BDO/M appropriately, if there is any question of not meeting the requirement of a BDO/M then reconsider using a BDO/M.
gripe 3 is simple, I would like to see global parameters that act like a BDO/M but are not saved at all, which would suit the need for global parameters.
I will give you an example of how to do parameters, not database, but parameters file which will fit your needs:
- create pool variable for emParms as type map
- create a new connector Development->Connectors->New Definition
- give it a name getEMParmsfromProperties
- Next->Next->Next to Outputs
- Add a output emParms as type java.util.map
- Finish
- Development->Connectors->New Implementation
- Click the definition getEMParmsfromProperties
- Next
- Add the Class name to the end of the package name-> org.mycompany.connector.getEMParmsfromProperties otherwise you end up overwriting previous packages.
- Finish
Here you can now write your code to get your parameters from your source and return them as a map to your process
Here is some very bad sample code to
- find the parameters file (under webapps/companyname/parameters folder)
- Open the properties file
- read the parameters
- and save as a map.
NOTE: this code will not run as is, you have to write it as your own…
Note also that I use jasypt java library for de/encrypting our properties file…very important. Not necessary but very important.
You could rewrite this for SQL as required.
You then add this connector assigning the return to the previously created pool variable and then gain access to the data by referring to the returned map elements.
emParms.get("dbHost") etc.
Hope this helps,
regards
Seán
package org.mycompany.connector.DeleteImpl;
import org.bonitasoft.engine.connector.ConnectorException;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.properties.EncryptableProperties;
import java.util.regex.Pattern;
import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
/**
*The connector execution will follow the steps
-
1 - setInputParameters() → the connector receives input parameters values
-
2 - validateInputParameters() → the connector can validate input parameters values
-
3 - connect() → the connector can establish a connection to a remote server (if necessary)
-
4 - executeBusinessLogic() → execute the connector
-
5 - getOutputParameters() → output are retrieved from connector
-
6 - disconnect() → the connector can close connection to remote server (if any)
*/
public class DeleteImpl extends
AbstractDeleteImpl {
String propertiesDir = “/webapps/???/properties/”;
Map<String, String> dbParms = new HashMap<String, String>();
@Override
protected void executeBusinessLogic() throws ConnectorException{
//preample code - preparation
String catalinaHome = System.getProperty("CATALINA_HOME");
// allow for no catalina home or path in groovy runs from \bin\bootstrap.jar
// with Java ?
String catalinaPath = System.getProperty("CATALINA_PATH");
if (catalinaHome == null && catalinaPath == null){
String strClassPath = System.getProperty("java.class.path");
//20150201 new version to get to webapps - START
if (strClassPath.indexOf(";") != 0 ){
//strClassPath is concatenated and must be reduced to one dir
String[] catHome = strClassPath.split(Pattern.quote(";"));
for (String singleCatHome : catHome){
if (singleCatHome.indexOf("bin") != 0){
String noBin = singleCatHome.substring(0, singleCatHome.indexOf("bin"));
File f = new File(noBin+"webapps");
if (f.exists() && f.isDirectory()) {
catalinaHome = noBin;
break;
}
}
}
}
else{
//strClassPath is not concated and is OK?
}
//20150201 new version to get to webapps - END
}
else if (catalinaHome == null && catalinaPath != null){
catalinaHome = catalinaPath;
}
else { // we have a CatalinaHome - but is it concatenated?
if (catalinaHome.indexOf(";") != 0 ){
//catalinaHome is concatenated and must be reduced to one dir
String[] catHome = catalinaHome.split(Pattern.quote(";"));
for (String singleCatHome : catHome){
if (singleCatHome.indexOf("webapps") != 0){
catalinaHome = singleCatHome;
break;
}
}
}
else{
//catalinaHome is not concated and is OK
}
}
String propertiesFile = propertiesDir+"????DBEncrypted.properties";
//set encryption
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("");
Properties propsEnc = new EncryptableProperties(encryptor);
//inputs
//none
//outputs
//sometimes added as global parms as in here
initializeOutputs();
//TODO execute your business logic here
try{
try{
propsEnc.load(new FileInputStream(new File(catalinaHome + propertiesFile)));
}
catch(Exception e0){
propertiesFile = propertiesDir+"????DB.properties";
try{
propsEnc.load(new FileInputStream(new File(catalinaHome + propertiesFile)));
}
catch(Exception e1){
}
}
try{
dbParms.put("dbType", propsEnc.getProperty("?????????Parms.dbType"));
dbParms.put("dbHost", propsEnc.getProperty("?????????Parms.dbHost"));
dbParms.put("dbPort", propsEnc.getProperty("?????????Parms.dbPort"));
dbParms.put("dbDatabase", propsEnc.getProperty("?????????Parms.dbDatabase"));
dbParms.put("dbUser", propsEnc.getProperty("?????????Parms.dbUser"));
dbParms.put("dbPassword", propsEnc.getProperty("?????????Parms.dbPassword"));
dbParms.remove("Default Null Output");
//now to touch the database and make sure it is available
Connection con = null;
String url = "jdbc:postgresql://"+dbParms.get("dbHost")+":"+dbParms.get("dbPort")+"/"+dbParms.get("dbDatabase");
try {
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException ex1) {
dbParms.clear();
dbParms.put("Error", thisModule+": DB Connection Error (ex1): "+ex1.toString());
}
con = DriverManager.getConnection(url, dbParms.get("dbUser"),dbParms.get("dbPassword"));
} catch (SQLException ex2) {
dbParms.clear();
dbParms.put("Error", thisModule+": DB Connection Error (ex2): "+ex2.toString());
} finally {
try {
if (con != null) {
con.close();
}
} catch (SQLException ex3) {
logger.severe(thisModule+": DB Connection Error (ex3): dbParms="+dbParms);
dbParms.clear();
dbParms.put("Error", thisModule+": DB Connection Error (ex3): "+ex3.toString());
logger.severe(thisModule+": DB Connection Error (ex3): "+ex3.toString());
logger.severe(thisModule+": DB Connection Error (ex3):(catalinaHome): "+catalinaHome);
}
}
}
catch(Exception ex4){
logger.severe(thisModule+": DB Connection Error (ex4): dbParms="+dbParms);
dbParms.clear();
dbParms.put("Error", "dbParms Setting Failed (ex4): "+ex4.toString());
logger.severe(thisModule+": dbParms Setting Failed (ex4): Parameter failure, one or more parms is invalid."+ex4.toString());
logger.severe(thisModule+": DB Connection Error (ex4):(catalinaHome): "+catalinaHome);
}
}
catch(Exception ex5){
logger.severe(thisModule+": DB Connection Error (ex5): dbParms="+dbParms);
dbParms.clear();
dbParms.put("Error", "ResourceBundle get Messages Failed (ex5): "+ex5.toString());
logger.severe(thisModule+": ResourceBundle get Messages Failed: "+ex5.getMessage());
logger.severe(thisModule+": DB Connection Error (ex5):(catalinaHome): "+catalinaHome);
}
if(debug){d++; dumpDataOutputs();}
//WARNING : Set the output of the connector execution. If outputs are not set, connector fails
setDbParms(dbParms);
}
private void dumpDataOutputs(){
logger.info(thisModule+": Ending: dataOutputs: "+dbParms);
logger.info(thisModule+": End");
}
private void initializeOutputs(){
//set default outputs
dbParms.put("Default Null Output", "Default Null Output");
setDbParms(dbParms);
}
@Override
public void connect() throws ConnectorException{
//[Optional] Open a connection to remote server
}
@Override
public void disconnect() throws ConnectorException{
//[Optional] Close connection to remote server
}
}