<< Click to Display Table of Contents >> Custom Replication |
Overview
Bizagi provides a Replication Wizard to assist in connecting to an external sources such as SQL Server and Oracle (for data-level integration).
For any data source other then SQL Server and Oracle, there is the possibility to override the methods and classes used by Bizagi in its Replication feature.
What you need to do
In order to use Bizagi's Replication for an external data source other than SQL Server or Oracle, the following steps are carried out:
1. Creating a custom Replication library.
Within this custom library, you will need to override Bizagi Replication's classes and methods (as described in the next section: Classes and methods to override).
2. Configuring the data provider in Bizagi to use this custom Replication library.
This configuration uses the Advanced Replication configuration in Bizagi.
Classes and methods to override
To customize Bizagi's Replication, it is necessary to develop an assembly that implements the following interfaces:
•ICustomProviderDA
•ICustomQueryDA
•ICustomReplicationDA
•IDatabaseProperties
Bizagi separates the operations for connection, disconnection and transactional management from the operations to query data from the external sources in the Provider and Entity interfaces.
Therefore, when creating a custom Replication library, Bizagi follows best practices for this management and implementation's design.
Provider Interface ICustomProviderDA
The class that invokes this interface must contain the following methods:
•void Init (Dictionary<string, string> metadata): In charge of taking the data supplied in the system configuration, such as server name, database name, user, password, etc. It receives a Dictionary<string, string> map that contains the data configured as system metadata.
•void OpenConnection(): This method is used to make the connection with the external system. In the case of a database, this is where you build the connection links and open a connection with the repository.
•void CloseConnection(): In charge of closing the connection with the external system.
•void BeginTransaction(): In charge of initiating a new transaction for the current operation in the system.
•void Commit(): Commits the current transaction in the reference system.
•void Rollback(): Carries out rollback of the current transaction in the reference system.
Provider Interface ICustomQueryDA
The class that invokes this interface must contain the following methods:
•void AddParameter (string parameterName, BizagiDataType dataType, int size, byte precision, byte scale, object value, ParameterDirection parameterDirection): In charge of adding a parameter to the query to be executed.
•void ClearParameters(): Removes the existing parameters in the query.
•DataSet RunQuery(string query, string tableName): used to query the values of the external data source. The logic is generally equivalent to making a query on the fields of the data object.
Entity Interface ICustomReplicationDA
The class that invokes this interface must contain the following methods:
•void Init(ICustomProviderDA provider): Initializes the connection with the system.
Parameter |
Description |
---|---|
provider |
Allows the conversion towards the object that invokes the ICustomProviderDA interface. |
•DataSet GetEntity(string entitySource, string[] columnList, string optionalSourceFilter): used to query the values of the external data source. The logic is generally equivalent to making a query on the fields of the data object applying optional filters.
Parameter |
Description |
---|---|
entitySource |
Name of the table to replicate in the data source. |
arrsColList |
Array that contains the name of the columns to query in the data source. |
optionalSourceFilter |
Contains the where clause to query in the data source. |
RETURNED DataSet |
A DataSet with the values for that entity. |
Constants Interfaces: IDatabaseProperties
Keep in mind Bizagi will build the query and its syntax.
According to this idea, make sure you define all the proper constants to be used in queries in the integrated Database engine.
Example
In this example, we will configure custom Replication for a MySQL database engine.
We will present an example of the Replication classes that implement the "ICustomProviderDA", "ICustomQueryDA" and "IReplicationEntDA" interfaces.
Take into account that the following code provides an illustration for the "GetEntity()" method implementation (to serve as a guide), but other methods are not included and would need further development. |
Creating a custom Replication library
In this specific example, in order to implement Replication classes that connect to a MySQL database, it is required to first download and install the MySQL Connector/NET component for that connection.
The following classes were developed with Microsoft Visual Studio. Within this .NET project, referencing the "MySql.Data.dll" assembly as installed by the MySQL Connector/Net component is required.
It is also necessary to reference the library BizAgi.EntityManager.Interfaces.CustomSource.dll of Bizagi.
This is found at the bin of the project's web application folder (by default at "C:\Bizagi\Projects\[PROJECT_NAME]\WebApplication\bin\").
Class Interfaces ICustomProviderDA and ICustomQueryDA
using System;
using System.Data;
using BizAgi.EntityManager.Interfaces.CustomSource;
using MySql.Data.MySqlClient;
using System.Collections.Generic;
using System.Collections;
using System.Text;
namespace BizagiMySQL
{
public class CMySQLProvider : ICustomProviderDA, ICustomQueryDA
{
private Dictionary<string, string> _metadata;
private MySqlConnection _mySqlconn;
private bool _disposed;
//--- The array used to store the parameters to a stored procedure
private readonly List<CMySqlParameter> _params;
public CMySQLProvider()
{
_disposed = false;
_mySqlconn = null;
_params = new List<CMySqlParameter>();
}
#region IProviderVirtualDA2 Members
public void AddParameter(string parameterName, BizagiDataType dataType, int size, byte precision, byte scale, object value, ParameterDirection parameterDirection)
{
_params.Add(new CMySqlParameter(parameterName, dataType, size, precision, scale, value, parameterDirection));
}
public void ClearParameters()
{
_params.Clear();
}
public DataSet RunQuery(string query, string tableName)
{
MySqlCommand command = new MySqlCommand();
MySqlDataAdapter adapter = new MySqlDataAdapter();
DataSet ds = new DataSet();
command.Connection = this.GetConnection();
command.CommandText = ReplaceQueryParameters(query, _params);
command.CommandType = CommandType.Text;
GetParameters(command);
adapter.SelectCommand = command;
adapter.Fill(ds, tableName);
return ds;
}
public IDatabaseProperties Properties
{
get { return CMySqlDatabaseConstants.Instance; }
}
private void GetParameters(MySqlCommand oCmd)
{
//--- Get an enumerator for the parameter array list
IEnumerator oEnumerator = _params.GetEnumerator();
//--- Loop through the Parameters in the ArrayList
while (oEnumerator.MoveNext())
{
//--- Add the SQLParameter object to the SQLCommand object
oCmd.Parameters.Add(ConvertParameterToMySqlParameter((CMySqlParameter)oEnumerator.Current));
}
}
private MySqlParameter ConvertParameterToMySqlParameter(CMySqlParameter oP)
{
MySqlDbType dbType = oP.DataType;
//--- Instantiate a SqlParameter object
MySqlParameter mySqlParameter = new MySqlParameter(oP.ParameterName, dbType, oP.Size);
mySqlParameter.Value = oP.Value;
mySqlParameter.Direction = (ParameterDirection)oP.Direction;
mySqlParameter.Precision = oP.Precision;
mySqlParameter.Scale = oP.Scale;
mySqlParameter.SourceColumn = oP.SourceColumn;
mySqlParameter.SourceVersion = oP.UseCurrentSourceColumnValue ? DataRowVersion.Current : DataRowVersion.Original;
return mySqlParameter;
}
/// <summary>
/// Replace parameter in the form '?', by parameters in the form ':ParamName'
/// </summary>
/// <param name="sQuery"></param>
/// <returns></returns>
private static string ReplaceQueryParameters(string sQuery, List<CMySqlParameter> alParams)
{
if (alParams != null && alParams.Count > 0)
{
char cInter = '?', cQuote = '\'', cAt = '@', cColon = ':';
string sParamToken = ":";
bool bInQuote = false; // indicates if current character is in ''
StringBuilder sbResp = new StringBuilder();
int _i = 0, _n = sQuery.Length, nNumParam = 0, nLastStrIndex = 0;
while (_i < _n)
{
if (bInQuote)
{
if (sQuery[_i] == cQuote)
{
if ((_i + 1) < _n && sQuery[_i + 1] == cQuote)
{
// "...''..." case, already in quote
_i += 2;
}
else
{
// "...'" case
bInQuote = false;
_i++;
}
}
else
{
_i++;
}
}
else
{
if (sQuery[_i] == cInter)
{
// "...?..." case
if (nNumParam >= alParams.Count)
{
// parameter doesn't exists
throw new Exception(string.Format("Parameter {0} doesn't exists in command: '{1}'", nNumParam, sQuery));
}
else
{
// get valid param name
string sValidParamName = GetValidParamName(((CMySqlParameter)alParams[nNumParam]).ParameterName, alParams, nNumParam - 1);
(alParams[nNumParam]).ParameterName = sValidParamName;
// replace parameter by name
sbResp.Append(sQuery.Substring(nLastStrIndex, _i - nLastStrIndex));
sbResp.Append(sParamToken + sValidParamName);
nLastStrIndex = _i + 1;
nNumParam++;
}
}
else if (sQuery[_i] == cAt)
{
// replace parameter by name
sbResp.Append(sQuery.Substring(nLastStrIndex, _i - nLastStrIndex));
sbResp.Append(cInter);
nLastStrIndex = _i + 1;
nNumParam++;
}
else if (sQuery[_i] == cQuote)
{
// "'..." case
bInQuote = true;
}
_i++;
}
}
sbResp.Append(sQuery.Substring(nLastStrIndex, _n - nLastStrIndex));
return sbResp.ToString();
}
return sQuery;
}
/// <summary>
/// Gets a valid parameter name, unique for first iMaxParamIndex parameters
/// </summary>
/// <param name="sParamName"></param>
/// <param name="alParams"></param>
/// <param name="iMaxParamIndex"></param>
/// <returns></returns>
private static string GetValidParamName(string sParamName, List<CMySqlParameter> alParams, int iMaxParamIndex)
{
int iMaxDbIdLength = CMySqlDatabaseConstants.Instance.MaxDbIdLength;
string sResp = (iMaxDbIdLength < sParamName.Length) ? sParamName.Substring(0, iMaxDbIdLength) : sParamName;
int iSuffix = 1;
while (IndexOfParam(sResp, alParams, iMaxParamIndex) != -1)
{
// find an unique name
string sSuffix = iSuffix.ToString();
sResp = (iMaxDbIdLength - sSuffix.Length < sParamName.Length) ? sParamName.Substring(0, iMaxDbIdLength - sSuffix.Length) : sParamName;
sResp += sSuffix;
iSuffix++;
}
return sResp;
}
private static int IndexOfParam(string sParamName, List<CMySqlParameter> alParams, int iMaxParamIndex)
{
int i = 0, n = iMaxParamIndex;
while (i < n)
{
if ((alParams[i]).ParameterName == sParamName)
{
n = i;
}
else
{
i++;
}
}
return (n == iMaxParamIndex) ? -1 : n;
}
#endregion
#region IProviderVirtualDA Members
public void Init(Dictionary<string, string> metadata)
{
this._metadata = metadata;
}
public void BeginTransaction()
{
}
public void Commit()
{
}
public void Rollback()
{
}
public void OpenConnection()
{
if (_mySqlconn == null)
{
//Verify all parameters are filled
if (!_metadata.ContainsKey("Server") || !_metadata.ContainsKey("Database") ||
!_metadata.ContainsKey("Username") || !_metadata.ContainsKey("Password"))
{
throw new CustomVirtualizationException("Incomplete metadata: connection parameters missing");
}
else
{
//Build the connection string with the parameters received from Bizagi Server
string sServer = _metadata["Server"];
string sDatabase = _metadata["Database"];
string sUsername = _metadata["Username"];
string sPassword = _metadata["Password"];
string sConn = "Server=" + sServer + ";Database=" + sDatabase + ";Uid=" + sUsername + ";Pwd=" + sPassword + ";";
_mySqlconn = new MySqlConnection(sConn);
_mySqlconn.Open();
}
}
}
public void CloseConnection()
{
if (_mySqlconn != null)
_mySqlconn.Close();
_mySqlconn = null;
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
if (!_disposed)
{
_disposed = true;
}
}
#endregion
#region internal methods
internal MySqlConnection GetConnection()
{
return this._mySqlconn;
}
internal DataSet ExecuteMySQLQuery(string sSQL)
{
DataSet ds = new DataSet();
MySqlCommand command = new MySqlCommand(sSQL, this.GetConnection());
MySqlDataAdapter adapter = new MySqlDataAdapter(command);
adapter.Fill(ds);
return ds;
}
internal DataSet ExecuteMySQLQuery(MySqlCommand command)
{
DataSet ds = new DataSet();
MySqlDataAdapter adapter = new MySqlDataAdapter(command);
adapter.Fill(ds);
return ds;
}
internal void ExecuteNonQueryMySQL(string sSQL)
{
MySqlCommand command = new MySqlCommand(sSQL, this.GetConnection());
command.ExecuteNonQuery();
}
/// <summary>
/// Initializes command with current connection and transaction
/// </summary>
internal MySqlCommand GetCommand()
{
MySqlCommand m_oledbCmd = new MySqlCommand();
m_oledbCmd.Connection = GetConnection();
m_oledbCmd.CommandType = CommandType.Text;
m_oledbCmd.Parameters.Clear();
return m_oledbCmd;
}
#endregion
}
}
Class Interface ICustomReplicationDA
using System;
using System.Data;
using System.Collections.Specialized;
using System.Text;
using BizAgi.EntityManager.Interfaces.CustomSource;
namespace BizagiMySQL
{
public class CMySQLReplication : ICustomReplicationDA
{
/// <summary>
/// Flag to show if object has been disposed
/// </summary>
protected bool m_bDisposed;
/// <summary>
/// Connection with the virtual System
/// </summary>
protected CMySQLProvider m_objSystem;
/// <summary>
/// Metadata used to initialize object, as collection of name-value pairs
/// </summary>
protected HybridDictionary m_htMetadata;
public CMySQLReplication()
{
m_bDisposed = false;
}
#region ICustomReplicationDA Members
public void Init(ICustomProviderDA provider)
{
m_objSystem = (CMySQLProvider)provider;
}
public DataSet GetEntity(string entitySource, string[] columnList, string optionalSourceFilter)
{
try
{
StringBuilder sbSQL = new StringBuilder();
sbSQL.Append(" SELECT ");
sbSQL.Append(string.Join(",", columnList));
sbSQL.Append(" FROM ");
sbSQL.Append(entitySource);
if (!string.IsNullOrWhiteSpace(optionalSourceFilter))
{
sbSQL.Append(" WHERE ");
sbSQL.Append(optionalSourceFilter);
}
DataSet ds = m_objSystem.ExecuteMySQLQuery(sbSQL.ToString());
return ds;
}
catch (Exception e)
{
throw new ApplicationException(e.Message);
}
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
if (!m_bDisposed)
{
// You should never close the connection within this method!!
m_bDisposed = true;
}
}
#endregion
}
}
Parameters Class
using BizAgi.EntityManager.Interfaces;
using BizAgi.EntityManager.Interfaces.CustomSource;
using MySql.Data.MySqlClient;
namespace BizagiMySQL {
using System.Data;
public class CMySqlParameter
{
private BizagiDataType dataType; //--- Provider-independent data type
private MySqlDbType dbDataType; //--- Provider-specific datatype of the parameter
private string paramName; //--- The Internal name of the parameter
private string originalParamName; //--- The Original o External name of the parameter
//-------------------------------------------------------------------------------------------------------
//--- Class Constructors
//--- Overloaded: Yes
//-------------------------------------------------------------------------------------------------------
public CMySqlParameter(string sParameterName, BizagiDataType BizagiDataType, int iSize, object oValue) {
ParameterName = sParameterName;
dataType = BizagiDataType;
dbDataType = getSqlDataType(BizagiDataType);
Size = iSize;
Value = oValue;
Direction = ParameterDirection.Input;
}
public CMySqlParameter (string sParameterName, BizagiDataType BizagiDataType, int iSize, object oValue, ParameterDirection eDirection) {
ParameterName = sParameterName;
dataType = BizagiDataType;
dbDataType = getSqlDataType(BizagiDataType);
Size = iSize;
Value = oValue;
Direction = eDirection;
}
public CMySqlParameter (string sParameterName, BizagiDataType BizagiDataType, int iSize, byte iPrecision, byte iScale, object oValue, ParameterDirection eDirection)
{
ParameterName = sParameterName;
dataType = BizagiDataType;
dbDataType = getSqlDataType(BizagiDataType);
Size = iSize;
Precision = iPrecision;
Scale = iScale;
Value = oValue;
Direction = eDirection;
}
public CMySqlParameter (string sParameterName, BizagiDataType BizagiDataType, int iSize, byte iPrecision, byte iScale, object oValue, ParameterDirection eDirection, string sSourceColumn, bool bUseCurrentSourceColumnValue)
{
ParameterName = sParameterName;
dataType = BizagiDataType;
dbDataType = getSqlDataType(BizagiDataType);
Size = iSize;
Precision = iPrecision;
Scale = iScale;
Value = oValue;
Direction = eDirection;
SourceColumn = sSourceColumn;
UseCurrentSourceColumnValue = bUseCurrentSourceColumnValue;
}
public ParameterDirection Direction { get; private set; }
public object Value { get; private set; }
public string SourceColumn { get; private set; }
public string ParameterName
{
get { return paramName; }
set
{
string sResult = value;
originalParamName = value;
paramName = sResult.Replace ("@","?");
}
}
//--
// Only for this IParameter implementation
// ReadOnly -- Return the original name of the parameter
//--
public string OriginalName
{
get { return originalParamName; }
}
public BizagiDataType Type
{
get { return dataType; }
set
{
dataType = value;
dbDataType = getSqlDataType(dataType);
}
}
public int Size { get; set; }
public byte Precision { get; set; }
public byte Scale { get; set; }
public bool UseCurrentSourceColumnValue { get; set; }
public MySqlDbType DataType
{
get { return dbDataType; }
}
private static MySqlDbType getSqlDataType(BizagiDataType BizagiDataType) {
MySqlDbType oDbType = MySqlDbType.Int32;
switch (BizagiDataType) {
case BizagiDataType.BigInt:
oDbType = MySqlDbType.Int64;
break;
case BizagiDataType.Int:
oDbType = MySqlDbType.Int32;
break;
case BizagiDataType.SmallInt:
oDbType = MySqlDbType.Int16;
break;
case BizagiDataType.TinyInt:
oDbType = MySqlDbType.Byte;
break;
case BizagiDataType.Boolean:
oDbType = MySqlDbType.Bit;
break;
case BizagiDataType.Decimal:
oDbType = MySqlDbType.Decimal;
break;
case BizagiDataType.Numeric:
oDbType = MySqlDbType.Float;
break;
case BizagiDataType.Money:
oDbType = MySqlDbType.Decimal;
break;
case BizagiDataType.Float:
oDbType = MySqlDbType.Float;
break;
case BizagiDataType.Real:
oDbType = MySqlDbType.Float;
break;
case BizagiDataType.DateTime:
oDbType = MySqlDbType.DateTime;
break;
case BizagiDataType.SmallDateTime:
oDbType = MySqlDbType.DateTime;
break;
case BizagiDataType.Char:
oDbType = MySqlDbType.VarChar;
break;
case BizagiDataType.VarChar:
oDbType = MySqlDbType.VarChar;
break;
case BizagiDataType.Text:
oDbType = MySqlDbType.Text;
break;
case BizagiDataType.Binary:
oDbType = MySqlDbType.Binary;
break;
case BizagiDataType.VarBinary:
oDbType = MySqlDbType.VarBinary;
break;
case BizagiDataType.Image:
oDbType = MySqlDbType.VarBinary;
break;
case BizagiDataType.Guid:
oDbType = MySqlDbType.Guid;
break;
case BizagiDataType.NChar:
oDbType = MySqlDbType.VarChar;
break;
case BizagiDataType.NVarChar:
oDbType = MySqlDbType.VarChar;
break;
case BizagiDataType.NText:
oDbType = MySqlDbType.Text;
break;
default:
break;
}
return oDbType;
}
}
}
Class Interface IDatabaseProperties
using BizAgi.EntityManager.Interfaces.CustomSource;
namespace BizagiMySQL
{
/// <summary>
/// Specific database constants
/// </summary>
public class CMySqlDatabaseConstants : IDatabaseProperties
{
#region Singleton
private static readonly CMySqlDatabaseConstants MySqlInstance = new CMySqlDatabaseConstants();
public static CMySqlDatabaseConstants Instance
{
get { return MySqlInstance; }
}
protected CMySqlDatabaseConstants() {}
#endregion
#region Fields / Properties
/// <summary>
/// Open character for enclose a name that is reserved word or has special characters
/// </summary>
private readonly string m_sQuotedNameOpenChar = "'";
public string QuotedNameOpenChar { get { return m_sQuotedNameOpenChar; } }
/// <summary>
/// Close character for enclose a name that is reserved word or has special characters
/// </summary>
private readonly string m_sQuotedNameCloseChar = "'";
public string QuotedNameCloseChar { get { return m_sQuotedNameCloseChar; } }
/// <summary>
/// Indicates if by default comparisons between strings are case sensitive
/// </summary>
private readonly bool m_bCaseSensitive = false;
public bool CaseSensitive { get { return m_bCaseSensitive; } }
internal int MaxDbIdLength
{
get { return 128; }
}
#endregion
}
}
Configuring the data provider in Bizagi
In this step, we may configure the System and data provider for Replication; by specifying which library will be used (the custom component we created previously).
Take into account that this configuration is done through the Advanced Replication configuration method, which require that the entities to be replicated are already created in Bizagi's data model. |
1. Click Systems in the Expert View of Bizagi.
Then either right-click the Systems element and select New System from the drop-down menu or click New System in the standard menu bar.
2. Enter a Name and Description for the new system and click the Enable data providers checkbox.
Click OK to save changes.
3. Click the plus sign (+) beside the newly created system.
Right-click the New Provider element.
4. In the New Provider window enter a Name, Display name and Description in the Provider Setup tab.
Check the Enable data replication option. Also check Enable data virtualization for this Provider (if it applies).
5. Select the Connection details tab and then click New Assembly.
6. Enter a Name, Display name, Namespace and Description.
Then click Select Assembly to select the .dll of the custom replication library previously built. Click OK in the New Assembly window.
7. Click the New Class button and in the New Class for Assembly window, enter the name of the class that implements the IProviderVirtualDA interface.
Click OK.
8. Now in the Provider Development Properties tab, include the connection properties by clicking the Metadata button to create a new Property-Value row.
Click OK on the New Provider window.
9. Expand the new provider element, select the Replicated Entities element and create a New Replication Class.
10. Select the assembly from the drop-down list In the New Class for Assembly window (if the Entity class is in the same assembly as the Provider class) or include a new one by clicking on New Assembly.
Click New Class and complete the necessary fields in the new window. Click OK to complete the Entity Class Configuration.
11. Right-click the new entity class element and select the Add Replication Schedule option.
12. In the Replication setup enter a Name, Display Name and a Description for the replication schedule.
Select the Schedule Properties tab and specify the frequency with which the information will be replicated from the data source.
For the setup presented in this tab, define the periodicity and frequency of execution according to the detail in this table below:
Schedule option |
Description |
Enable Schedule for this Replication |
Mark this option for Bizagi to execute the data replication from the external source. |
Periodicity |
Mark Daily, Weekly or Monthly to define how frequently will Bizagi execute the Replication schema. |
Every |
This option will change according to Periodicity's selection. •When Daily is marked: enter the number of days between repetitions of the execution. •When Weekly is marked: enter the number of weeks between repetitions of the execution. Also, select on which weekdays this schema will be executed. •When Monthly is marked: enter the number of months between repetitions of the execution as well. Additionally, select the day of the month in which this schema will be executed. |
Daily frequency |
Define if the execution happens once a day (and at which time), or if it should be executed every certain time (minutes or hours). |
Beginning |
Set a starting date for this schema to begin its execution. |
Schedule properties description
After the configuration is set for the start date of execution, click OK.
13. Right-click the schedule and select Add Entity to Replication.
14. In the Add Entity to Replication window, select the desired entity from the Parameter entities drop-down list. Then, type the external entity name in the External Source field. Next, from the list of attributes of the Bizagi entity, select one (or more) to be the business key (an attribute that has a unique value so that it can be used to differentiate one register form another).
Click OK to save this changes.
15. Select the replicated entity. Enter the corresponding external column (field) for each attribute of the replicated entity.
This is done by right-clicking on the attribute and selecting Properties.
In the Edit Attribute window, type down the external column's name and click OK.
Do this for each of the listed attributes in the replicated entity.
If your custom Replication library has references to other assemblies, it is necessary to copy them into the Scheduler folder for the Replication's execution. This folder is found by default at: "C:\Bizagi\Projects\[PROJECT_NAME]\Scheduler". |
At this point we completed the Replication setup using a custom component, to connect to a MySQL database.
Verifying Replication (Checkpoint)
Once Replication is set, you may choose to verify that its execution synchronizes the values for those Parameter Entities with the external table's columns.
There are two ways to do this: using the options in the Systems modules, or through the displayed entities information (Entities module).
Options displayed in the Systems module are useful for a Production or Test Environment.
Options presented in the Entities module will serve as a checkpoint during Replication configuration (in the Development Environment).
To view how to verify that the Replication was set up or is running properly, refer to Verifying Replication.