As system evolves and gets a lot of changes, this section contains referencing code examples. Snippets below gets extracted from an actual project code, so these are always reliable. Use IDE, if needed, in order to search for specific classes or files.


Recommended approaches and samples may be always found here.

DrawIO diagrams:

Other samples:


Saving latest/last user request parameters

Let’s take interface filters, as example - use restoreRequestParams method in ru.bgcrm.struts.action.BaseAction

Saving a value:

// PzdcDoc snippet of: 'ru.bgcrm.struts.action.MessageAction', lines: 454 - 454

        restoreRequestParams(conSet.getConnection(), form, true, false, "messageTypeAdd");

Restoring a value:

// PzdcDoc snippet of: 'ru.bgcrm.struts.action.MessageAction', lines: 484 - 491

public ActionForward messageUpdate(DynActionForm form, Connection con) throws Exception {
    var type = getType(form.getParamInt("typeId"));

    // preserving message type for choosing in next usage of editor
    if (form.getId() <= 0) {
        form.setParam("messageTypeAdd", String.valueOf(type.getId()));
        restoreRequestParams(con, form, false, true, "messageTypeAdd");

Saving and restoring a value at once:

// PzdcDoc snippet of: 'ru.bgcrm.struts.action.ProcessLinkAction', lines: 53 - 57

// процессы, к которым привязана сущность
public ActionForward linkedProcessList(DynActionForm form, Connection con) throws Exception {
    ProcessLinkDAO processLinkDAO = new ProcessLinkDAO(con, form);

    restoreRequestParams(con, form, true, true, "open");

Feature flag for UI

Option stored in user personalization map. UI dropbox available in user profile settings.

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/profile/default.jsp', lines: 39 - 45 --%>

<c:set var="key" value="iface.buffer.behavior"/>
<ui:combo-single hiddenName="${key}" value="${ctxUser.personalizationMap.get(key, '1')}" widthTextValue="200px">
        <jsp:attribute name="valuesHtml">
                <li value="1">${l.l('Последний объект сверху')}</li>
                <li value="2">${l.l('Сохранять порядок объектов')}</li>

Stored values may be read in JSP pages using in the same ctxUser.personalizationMap way, but also available in JS like for this case.

// PzdcDoc snippet of: 'webapps/js/kernel.shell.js', lines: 444 - 445

if (($$.pers["iface.buffer.openOnLongPress"] || 0) === 1) {
        const debug = $$.debug("buffer");

Depicting element count on a tab

For example, showing associated processes count. Gets saved on the first call. Use ru.bgcrm.model.IfaceState class

Refreshing value:

// PzdcDoc snippet of: 'ru.bgcrm.struts.action.ProcessLinkAction', lines: 200 - 207

// проверка и обновление статуса вкладки, если нужно
if (Strings.isNotBlank(form.getParam(IfaceState.REQUEST_PARAM_IFACE_ID))) {
    IfaceState ifaceState = new IfaceState(form);
    IfaceState currentState = new IfaceState(Process.OBJECT_TYPE, id, form,
    new IfaceStateDAO(con).compareAndUpdateState(ifaceState, currentState, form);

Show in JSP:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/process/process/process_editor.jsp', lines: 86 - 100 --%>

        <c:if test="${processType.properties.configMap.getSok('1', false, 'show.tab.links.process', 'processShowProcessLinks') eq '1'}">
                <c:set var="ifaceId" value="link_process"/>
                <c:set var="ifaceState" value="${ifaceStateMap[ifaceId]}"/>

                <c:url var="url" value="/user/process/link.do">
                        <c:param name="action" value="linkProcessList"/>
                        <c:param name="id" value="${process.id}"/>
                        <c:param name="linkedReferenceName" value="linkedProcessList"/>
                        <c:param name="linkReferenceName" value="linkProcessList"/>
                        <c:param name="ifaceId" value="${ifaceId}"/>
                        <c:param name="ifaceState" value="${ifaceState.state}"/>

                $tabs.tabs( "add", "${url}", "${l.l('Связанные процессы')}${ifaceState.getFormattedState()}" );

Date and time format

When formatting date and time values in Java or JSP , use the following formats in order to keep unified approach and maintain independence from the current locale:

  • ymd - year, month, date;

  • ymdh - year, month, day, hour;

  • ymdhm - year, month, day, hour, minute;

  • ymdhms - year, month, day, hour, minute, second.

Java code uses ru.bgcrm.util.TimeUtils class for date formatting, this class also contains format constants.

The same functions may be used in JSP using tu prefix:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/parameter/edit.jsp', lines: 160 - 160 --%>

<input type="text" name="value" value="${tu.format(data.value, type)}" id="${focusFieldUiid}" ${changeAttrs} onclick="${getCommand}"/>

Configuration Java Beans

In order to speed up parsing and validation, use Java class objects inherited from ru.bgcrm.util.Config For example: ru.bgcrm.model.config.IsolationConfig. This configuration supports constructor with a validation flag, which allows to check syntax when saving.

Configuration bin can be also obtained in JSP:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/plugin/task/task_list.jsp', lines: 4 - 4 --%>

<c:set var="config" value="${ctxSetup.getConfig('ru.bgcrm.plugin.task.Config')}"/> 


Putting results into JSP and rendering a form;

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/process/process/link_process_list.jsp', lines: 91 - 99 --%>

<c:set var="uiid" value="${u:uiid()}"/>
<html:form action="/user/process/link" styleId="${uiid}">
        <div style="display: inline-block;" class="tt bold mt05 mb05">${l.l('К процессу привязаны')}:</div>

        <input type="hidden" name="action" value="linkProcessList"/>
        <input type="hidden" name="id" value="${form.id}"/>

        <ui:page-control nextCommand="; $$.ajax.load(this.form, $('#${uiid}').parent())"/>

Java action:

// PzdcDoc snippet of: 'ru.bgcrm.struts.action.ProcessLinkAction', lines: 191 - 193

// привязанные к процессу процессы
Pageable<Pair<String, Process>> searchResultLink = new Pageable<Pair<String, Process>>(form);
processLinkDao.searchLinkProcessList(searchResultLink, id, open);

File upload

JSP page:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/config/list.jsp', lines: 64 - 77 --%>

<c:set var="uploadFormId" value="${u:uiid()}"/>
<form id="${uploadFormId}" action="/admin/config.do" method="POST" enctype="multipart/form-data" name="form">
        <input type="hidden" name="action" value="licenseUpload"/>
        <input type="hidden" name="responseType" value="json"/>
        <input type="file" name="file" style="visibility: hidden; display: none;"/>
        <button type="button" class="btn-grey w100p mt1" onclick="$$.ajax.triggerUpload('${uploadFormId}');">${l.l('Загрузить файл лицензии')}</button>
        $(function () {
                $$.ajax.upload('${uploadFormId}', 'lic-upload-iframe', function () {
                        $$.ajax.load('${form.requestUrl}', $$.shell.$content(this));


// PzdcDoc snippet of: 'src/ru/bgcrm/struts/action/admin/ConfigAction.java', lines: 153 - 166

public ActionForward licenseUpload(DynActionForm form, ConnectionSet conSet) throws Exception {
    var file = form.getFile();

    byte[] data = IOUtils.toByteArray(file.getInputStream());

    String error = new License(new String(data, StandardCharsets.UTF_8)).getError();
    if (Utils.notBlankString(error))
        throw new BGMessageException(error);

    IOUtils.write(data, new FileOutputStream(License.FILE_NAME));

    return json(conSet, form);

UI Only

A simple dictionary with pagination, AJAX editor invocation: webapps/WEB-INF/jspf/admin/process/status/list.jsp

Sending AJAX for sending, exiting or restoring data in process type properties editor:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/process/type/properties.jsp', lines: 187 - 192 --%>

<div class="mt1">
        <button type="button" class="btn-grey mr1" onclick="$$.ajax.post($('#${formUiid}')[0], {toPostNames: ['config', 'matrix']}).done(() => $$.ajax.load('${editUrl}', $('#${formUiid}').parent()));">OK</button>
        <button type="button" class="btn-grey mr1" onclick="$$.ajax.load('${editUrl}', $('#${formUiid}').parent())">${l.l('Восстановить')}</button>

        <button type="button" class="btn-white ml1" onclick="$$.ajax.load('${form.returnUrl}', $('#${formUiid}').parent())">${l.l('К списку типов')}</button>

Recursive include:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/user/check_tree_item.jsp', lines: 44 - 51 --%>

                <c:if test="${not empty node.children}">
                                <c:forEach var="child" items="${node.children}">
<c:set var="node" value="${child}" scope="request" />
<jsp:include page="check_tree_item.jsp" />

Action execution result include:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/user/user/update.jsp', lines: 166 - 171 --%>

        <c:url var="url" value="/admin/user.do">
                <c:param name="action" value="userGroupList" />
                <c:param name="id" value="${form.id}" />
                <c:param name="objectType" value="user" />
        <c:import url="${url}" />

Flex layout, using constants from Java classes (defined in process_search_constants.jsp), print button close to a field:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/search/search.jsp', lines: 70 - 84 --%>

<div style="display: flex;">
                <%@ include file="process_search_constants.jsp"%>
                <ui:combo-single hiddenName="mode" style="width: 100%;">
                        <jsp:attribute name="valuesHtml">
                                <li value="${MODE_USER_CREATED}">${l.l('Cозданные мной')}</li>
                                <li value="${MODE_USER_CLOSED}">${l.l('Закрытые мной')}</li>
                                <li value="${MODE_USER_STATUS_CHANGED}">${l.l('Статус изменён мной')}</li>
        <div class="pl05">
                <ui:button type="out" onclick="this.form.elements['searchBy'].value='userId'; $$.ajax.load(this.form, '#searchResult');"/>
For some reason a class, containing included constant must not contain config word in package path.

Snap-in refresh upon moving back to it:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/log/log.jsp', lines: 17 - 24 --%>

        $(function () {
                const $log = $('#${uiid}').parent();
                $log.data('onShow', function () {
                        $$.ajax.load("/user/log.do", $log);

Sending AJAX request and showing progress indicator on button during execution:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/run/run.jsp', lines: 20 - 24 --%>

                <button class="btn-grey ml1 icon" type="button" onclick="
                        $$.ajax.post(this.form, {control: this})
                                .done(() => {
                                        alert(this.form.sync.value ? '${l.l('Класс выполнен, проверьте логи')}' : '${l.l('Класс запущен в отдельном потоке,\\nвывод в логах.')}')
                                })"><i class="ti-control-play"></i></button>

The same but for $$.ajax.load function:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/user/process/queue/filter.jsp', lines: 910 - 910 --%>

<ui:button type="out" styleClass="out" onclick="const $form = $('${selectorForm}'); processQueueMarkFilledFilters($form); $$.ajax.load($form, $('#processQueueData'), {control: this});"/>

Restore form parameter values:

<%-- PzdcDoc snippet of: 'webapps/WEB-INF/jspf/admin/directory/parameter/group/update.jsp', lines: 8 - 10 --%>

<html:form action="/admin/directory" styleClass="center500">
        <input type="hidden" name="action" value="parameterGroupUpdate"/>
        <html:hidden property="directoryId"/>