Skip to content

BatchSynchronizationProcedure

This API is designed to compact and to clean implement a batch synchronization procedure giving the base behavior that a batch synchronization need to have

Implementation

Create the support item

It is suggested to use JoinTableSyncBatchItem as base for the support item, but is not required

@BatchQueryItem
public class TeamMemberBatchItem extends JoinTableSyncBatchItem<String, String> {

    public TeamMemberBatchItem(String teamId, String memberId) {
        super(teamId, memberId);
    }

}

Create the procedure

@BatchSyncProcedureImpl
public class TeamMemberBatchSyncProcedure extends BatchSynchronizationProcedure<String, String, TeamMemberBatchItem> {

    public TeamMemberBatchSyncProcedure(String owner, Collection<String> ownedItems, EntityManager entityManager) {
        super(owner, ownedItems, "team_members", entityManager);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected SyncBatchModel createModel() {
        // create the model
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected BatchQuery<TeamMemberBatchItem> createBatchQuery() {
        // create the query
    }

}

Usage

Use in a service

The inheritance with the EquinoxItemsHelper is required to properly provide the entityManager

import java.util.List;

@Service
public class TeamsService extends EquinoxItemsHelper {

    public void syncMembers(String teamId, List<String> members) {
        TeamMemberBatchSyncProcedure procedure = new TeamMemberBatchSyncProcedure(teamId, members, entityManager);
        // create the callback to retrieve the current data (required)
        procedure.setCurrentDataCallback(new BatchSynchronizationProcedure.CurrentDataCallback<String>() {
            @Override
            public Collection<String> retrieveCurrentData() {
                List<String> currentData = List.of();
                // custom logic to fill the list
                return currentData;
            }
        });

        // execute the procedure
        procedure.executeBatchSynchronization();
    }

}
import org.springframework.stereotype.Service

@Service
class TeamsService : EquinoxItemsHelper() {

    fun syncMembers(
        teamId: String,
        members: List<String>
    ) {
        val procedure = TeamMemberBatchSyncProcedure(
            teamId,
            members,
            entityManager
        )

        // create the callback to retrieve the current data (required)
        procedure.setCurrentDataCallback(object : BatchSynchronizationProcedure.CurrentDataCallback<String> {
            override fun retrieveCurrentData(): Collection<String> {
                val currentData: List<String> = listOf()
                // custom logic to fill the list
                return currentData
            }
        })

        // execute the procedure
        procedure.executeBatchSynchronization()
    }

}

Mirrored usage

If you have also a mirrored service of the TeamsService like for example MembersService and you need to sync the teams of a member you can use a dedicated converter to properly create the support item to use in the same sync procedure you created for the team's side (TeamMemberBatchSyncProcedure), this because the support item has a fixed constructor, but the owner entity changes related to the service where the procedure is invoked. You can do as follows:

import java.util.List;

@Service
public class MembersService extends EquinoxItemsHelper {

    public void syncTeams(String memberId, List<String> teams) {
        TeamMemberBatchSyncProcedure procedure = new TeamMemberBatchSyncProcedure(memberId, teams, entityManager);
        // create the callback to retrieve the current data (required)
        procedure.setCurrentDataCallback(new BatchSynchronizationProcedure.CurrentDataCallback<String>() {
            @Override
            public Collection<String> retrieveCurrentData() {
                List<String> currentData = List.of();
                // custom logic to fill the list
                return currentData;
            }
        });
        // create the converter to properly create the support item
        procedure.useConverter(teamsIds -> {
            List<TeamMemberBatchItem> teamMemberBatchItems = new ArrayList<>();
            for (String teamId : teamsIds)
                // the member identifier is fixed, meanwhile the team identifier changes
                teamMemberBatchItems.add(new TeamMemberBatchItem(teamId, memberId));
            return teamMemberBatchItems;
        });
        // execute the procedure
        procedure.executeBatchSynchronization();
    }

}
import org.springframework.stereotype.Service

@Service
class MembersService : EquinoxItemsHelper() {

    fun syncTeams(
        memberId: String,
        teams: List<String>
    ) {
        val procedure = TeamMemberBatchSyncProcedure(
            memberId,
            teams,
            entityManager
        )

        // create the callback to retrieve the current data (required)
        procedure.setCurrentDataCallback(object : BatchSynchronizationProcedure.CurrentDataCallback<String> {
            override fun retrieveCurrentData(): Collection<String> {
                val currentData: List<String> = listOf()
                // custom logic to fill the list
                return currentData
            }
        })

        // create the converter to properly create the support item
        procedure.useConverter { teamsIds ->
            val teamMemberBatchItems = ArrayList<TeamMemberBatchItem>()
            for (teamId in teamsIds) {
                // the member identifier is fixed, meanwhile the team identifier changes
                teamMemberBatchItems.add(TeamMemberBatchItem(teamId, memberId))
            }
            teamMemberBatchItems
        }

        // execute the procedure
        procedure.executeBatchSynchronization()
    }

}

Then use the converter in the procedure (if you need to use the converter you have to create a converter for both sides)

@BatchSyncProcedureImpl
public class TeamMemberBatchSyncProcedure extends BatchSynchronizationProcedure<String, String, TeamMemberBatchItem> {

    public TeamMemberBatchSyncProcedure(String owner, Collection<String> ownedItems, EntityManager entityManager) {
        super(owner, ownedItems, "team_members", entityManager);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected SyncBatchModel createModel() {
        return new SyncBatchModel() {
            @Override
            public Collection<TeamMemberBatchItem> getCurrentData() {
                // use the converter to convert the current data retrieved with the CurrentDataCallback
                return converter.convert(currentDataCallback.retrieveCurrentData());
            }

            @Override
            public String[] getDeletingColumns() {
                return new String[]{"team_id", "member_id"};
            }
        };
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected BatchQuery<TeamMemberBatchItem> createBatchQuery() {
        return new BatchQuery<>() {
            @Override
            public Collection<TeamMemberBatchItem> getData() {
                // use the converter 
                return converter.convert(ownedItems);
            }

            @Override
            @TableColumns(columns = {"team_id", "member_id"})
            public void prepareQuery(Query query, int index, Collection<TeamMemberBatchItem> items) {
                for (TeamMemberBatchItem element : items) {
                    query.setParameter(index++, element.getOwner());
                    query.setParameter(index++, element.getOwned());
                }
            }

            @Override
            public String[] getColumns() {
                return new String[]{"team_id", "member_id"};
            }
        };
    }

}
@BatchSyncProcedureImpl
class TeamMemberBatchSyncProcedure(
    owner: String,
    ownedItems: Collection<String>,
    entityManager: EntityManager
) : BatchSynchronizationProcedure<String, String, TeamMemberBatchItem>(
    owner,
    ownedItems,
    "team_members",
    entityManager
) {

    /**
     * {@inheritDoc}
     */
    override fun createModel(): SyncBatchModel {
        return object : SyncBatchModel() {
            override fun getCurrentData(): Collection<TeamMemberBatchItem> {
                // use the converter to convert the current data retrieved with the CurrentDataCallback
                return converter.convert(currentDataCallback.retrieveCurrentData())
            }

            override fun getDeletingColumns(): Array<String> {
                return arrayOf("team_id", "member_id")
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    override fun createBatchQuery(): BatchQuery<TeamMemberBatchItem> {
        return object : BatchQuery<TeamMemberBatchItem>() {
            override fun getData(): Collection<TeamMemberBatchItem> {
                // use the converter
                return converter.convert(ownedItems)
            }

            @TableColumns(columns = ["team_id", "member_id"])
            override fun prepareQuery(
                query: Query,
                index: Int,
                items: Collection<TeamMemberBatchItem>
            ) {
                var idx = index
                for (element in items) {
                    query.setParameter(idx++, element.owner)
                    query.setParameter(idx++, element.owned)
                }
            }

            override fun getColumns(): Array<String> {
                return arrayOf("team_id", "member_id")
            }
        }
    }

}