org.openlegacy.terminal.support.binders.ScreenBinderLogic.java Source code

Java tutorial

Introduction

Here is the source code for org.openlegacy.terminal.support.binders.ScreenBinderLogic.java

Source

/*******************************************************************************
 * Copyright (c) 2014 OpenLegacy Inc.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     OpenLegacy Inc. - initial API and implementation
 *******************************************************************************/
package org.openlegacy.terminal.support.binders;

import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openlegacy.FieldFormatter;
import org.openlegacy.definitions.DynamicFieldDefinition;
import org.openlegacy.terminal.FieldComparator;
import org.openlegacy.terminal.ScreenEntity;
import org.openlegacy.terminal.ScreenPojoFieldAccessor;
import org.openlegacy.terminal.TerminalField;
import org.openlegacy.terminal.TerminalPosition;
import org.openlegacy.terminal.TerminalRow;
import org.openlegacy.terminal.TerminalSendAction;
import org.openlegacy.terminal.TerminalSession;
import org.openlegacy.terminal.TerminalSnapshot;
import org.openlegacy.terminal.definitions.ScreenEntityDefinition;
import org.openlegacy.terminal.definitions.ScreenFieldDefinition;
import org.openlegacy.terminal.definitions.ScreenTableDefinition;
import org.openlegacy.terminal.definitions.ScreenTableDefinition.DrilldownDefinition;
import org.openlegacy.terminal.definitions.ScreenTableDefinition.ScreenColumnDefinition;
import org.openlegacy.terminal.definitions.SimpleScreenFieldDefinition;
import org.openlegacy.terminal.exceptions.TerminalActionException;
import org.openlegacy.terminal.modules.table.DefaultTableDrilldownPerformer;
import org.openlegacy.terminal.providers.TablesDefinitionProvider;
import org.openlegacy.terminal.services.ScreenEntitiesRegistry;
import org.openlegacy.terminal.support.SnapshotUtils;
import org.openlegacy.terminal.table.ScreenTableDrilldownPerformer;
import org.openlegacy.terminal.utils.SimpleScreenPojoFieldAccessor;
import org.openlegacy.utils.ProxyUtil;
import org.openlegacy.utils.TypesUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.inject.Inject;

public class ScreenBinderLogic implements Serializable {

    private static final long serialVersionUID = 1L;

    @Inject
    private FieldFormatter fieldFormatter;

    @Inject
    private FieldComparator fieldComparator;

    @Inject
    private ScreenEntitiesRegistry screenEntitiesRegistry;

    @Inject
    private TablesDefinitionProvider tablesDefinitionProvider;

    @Inject
    private ApplicationContext applicationContext;

    private String descriptionFieldSuffix = "Description";

    private final static Log logger = LogFactory.getLog(ScreenBinderLogic.class);

    public void populatedFields(ScreenPojoFieldAccessor fieldAccessor, TerminalSnapshot terminalSnapshot,
            Collection<ScreenFieldDefinition> fieldMappingDefinitions) {

        for (ScreenFieldDefinition fieldMappingDefinition : fieldMappingDefinitions) {
            TerminalPosition position = retrievePosition(fieldMappingDefinition, terminalSnapshot);
            if (position == null) {
                logger.warn("A field was not found for field:" + fieldMappingDefinition.getName());
                continue;
            }
            TerminalField terminalField = terminalSnapshot.getField(position);
            if (terminalField == null) {
                logger.debug("A field mapping was not found " + fieldMappingDefinition.getName());
                continue;
            }
            if (terminalField.isHidden() && !terminalField.isEditable()) {
                logger.debug("A hidden field was not bound " + fieldMappingDefinition.getName());
                continue;
            }

            if (fieldMappingDefinition.getDynamicFieldDefinition() != null) {
                fieldMappingDefinition = (SimpleScreenFieldDefinition) SerializationUtils
                        .clone((Serializable) fieldMappingDefinition);
                ((SimpleScreenFieldDefinition) fieldMappingDefinition).setPosition(position);
                ((SimpleScreenFieldDefinition) fieldMappingDefinition)
                        .setEndPosition(terminalField.getEndPosition());
                ((SimpleScreenFieldDefinition) fieldMappingDefinition).setLength(terminalField.getLength());

            }

            String text = getText(fieldMappingDefinition, terminalSnapshot);

            String fieldName = fieldMappingDefinition.getName();
            boolean bind = isBindText(fieldMappingDefinition, text);
            if (bind && fieldAccessor.isWritable(fieldName)) {
                Class<?> javaType = fieldMappingDefinition.getJavaType();
                if (TypesUtil.isNumberOrString(javaType)) {
                    String content = fieldFormatter.format(text);
                    if (!content.equals(fieldMappingDefinition.getNullValue())) {
                        fieldAccessor.setFieldValue(fieldName, content);
                    }
                }
                fieldAccessor.setTerminalField(fieldName, terminalField);
                handleDescriptionField(fieldAccessor, terminalSnapshot, fieldMappingDefinition, fieldName);
            }
            TerminalPosition cursorPosition = terminalSnapshot.getCursorPosition();
            if (cursorPosition != null && cursorPosition.equals(position)) {
                fieldAccessor.setFocusField(fieldMappingDefinition.getName());
            }

        }
    }

    public static TerminalPosition retrievePosition(ScreenFieldDefinition fieldMappingDefinition,
            TerminalSnapshot terminalSnapshot) {
        DynamicFieldDefinition dynamicField = fieldMappingDefinition.getDynamicFieldDefinition();
        if (dynamicField != null) {
            return getDynamicPosition(dynamicField, terminalSnapshot);
        }

        TerminalPosition position = fieldMappingDefinition.getPosition();
        if (position == null) {
            throw (new TerminalActionException("No field position, static nor dynamic, was found for field: "
                    + fieldMappingDefinition.getName()));
        }
        return position;
    }

    private void handleDescriptionField(ScreenPojoFieldAccessor fieldAccessor, TerminalSnapshot terminalSnapshot,
            ScreenFieldDefinition fieldMappingDefinition, String fieldName) {
        ScreenFieldDefinition descriptionFieldDefinition = fieldMappingDefinition.getDescriptionFieldDefinition();
        if (descriptionFieldDefinition != null) {
            String descriptionText = getText(descriptionFieldDefinition, terminalSnapshot);
            String content = fieldFormatter.format(descriptionText);
            fieldAccessor.setFieldValue(fieldName + descriptionFieldSuffix, content);
        }
    }

    /**
     * Grab text from the snapshot according to the field definition Considers multy-line field as rectangle/line breakings
     * 
     * @param fieldMappingDefinition
     * @param terminalSnapshot
     * @return
     */
    private String getText(ScreenFieldDefinition fieldMappingDefinition, TerminalSnapshot terminalSnapshot) {

        int startRow = fieldMappingDefinition.getPosition().getRow();
        int endRow = fieldMappingDefinition.getEndPosition().getRow();
        int startColumn = fieldMappingDefinition.getPosition().getColumn();
        int endColumn = fieldMappingDefinition.getEndPosition().getColumn();
        int fieldColumnLength = (endColumn - startColumn) + 1;

        if (endRow == 0) {
            endRow = startRow;
        }
        String text = "";
        for (int currentRow = startRow; currentRow <= endRow; currentRow++) {
            TerminalRow row = terminalSnapshot.getRow(currentRow);
            TerminalField terminalField = null;

            // multy line
            if (currentRow > startRow) {
                String newLine = "\n";
                if (fieldMappingDefinition.isRectangle()) {
                    terminalField = terminalSnapshot.getField(currentRow, startColumn);
                    if (terminalField != null) {
                        if (fieldMappingDefinition.getLength() > 0
                                && fieldColumnLength != terminalField.getLength()) {
                            text = text + newLine
                                    + fieldFormatter.format(row.getText(startColumn, fieldColumnLength));
                        } else {
                            text = text + newLine + fieldFormatter.format(terminalField.getValue());
                        }
                    }
                    // breaking lines
                } else {
                    // 1st row = grab until the end of the row
                    if (currentRow == startRow) {
                        text = text + newLine + fieldFormatter.format(row.getText(startColumn,
                                terminalSnapshot.getSize().getColumns() - fieldColumnLength));
                        // last row - grab until end column
                    } else if (currentRow == endRow) {
                        text = text + newLine + fieldFormatter.format(row.getText(1, endColumn));
                        // middle row - grab all line
                    } else {
                        text = text + newLine + fieldFormatter.format(row.getText());
                    }
                }
                // single line
            } else {
                terminalField = terminalSnapshot.getField(currentRow, startColumn);
                if (terminalField != null) {
                    if (fieldMappingDefinition.getLength() > 0 && fieldColumnLength != terminalField.getLength()) {
                        text += row.getText(startColumn, fieldColumnLength);
                    } else {
                        text += fieldFormatter.format(terminalField.getValue());
                    }
                }
            }
        }

        return text;
    }

    /**
     * Convert a pojo to a sendAction modified fields. Main complexity is around breaking multy line fields to single terminal
     * fields
     * 
     * @param sendAction
     * @param terminalSnapshot
     * @param screenPojo
     * @param fieldMappingsDefinitions
     */
    @SuppressWarnings("unchecked")
    public void populateSendAction(TerminalSendAction sendAction, TerminalSnapshot terminalSnapshot,
            Object screenPojo, Collection<ScreenFieldDefinition> fieldMappingsDefinitions) {
        ScreenPojoFieldAccessor fieldAccessor = new SimpleScreenPojoFieldAccessor(screenPojo);

        List<TerminalField> modifiedfields = sendAction.getFields();

        for (ScreenFieldDefinition fieldMappingDefinition : fieldMappingsDefinitions) {

            final TerminalPosition fieldPosition = fieldMappingDefinition.getPosition();
            final String fieldName = fieldMappingDefinition.getName();

            if (!fieldAccessor.isExists(fieldName)) {
                continue;
            }

            if (screenPojo instanceof ScreenEntity) {
                ScreenEntity screenEntity = (ScreenEntity) screenPojo;
                if (fieldName.equalsIgnoreCase(screenEntity.getFocusField())) {
                    sendAction.setCursorPosition(fieldPosition);
                    if (logger.isDebugEnabled()) {
                        logger.debug(MessageFormat.format("Cursor was set at position {0} from field {1}",
                                fieldPosition, screenEntity.getFocusField()));
                    }
                } else {
                    final Map<String, ScreenTableDefinition> tableDefinitions = tablesDefinitionProvider
                            .getTableDefinitions(screenEntity.getClass());
                    for (Entry<String, ScreenTableDefinition> tableDefinitionEntry : tableDefinitions.entrySet()) {
                        final List<Object> rows = (List<Object>) fieldAccessor
                                .getFieldValue(tableDefinitionEntry.getKey());
                        // final ScreenTableDefinition tableDefinition = tableDefinitions.get(tableFieldName);
                        int rowNumber = 0;
                        for (Object row : rows) {
                            final ScreenPojoFieldAccessor rowAccessor = new SimpleScreenPojoFieldAccessor(row);
                            // If there is no focusField on this table, break out of search.
                            if (!rowAccessor.isExists("focusField")) {
                                break;
                            }
                            final ScreenTableDefinition tableDefinition = tableDefinitionEntry.getValue();
                            Object focusField = rowAccessor.getFieldValue("focusField");
                            if (focusField != null && focusField.toString().trim().length() > 0) {
                                if (tableDefinition.isScrollable()) {
                                    final List<Object> keys = new ArrayList<Object>();
                                    for (String keyField : tableDefinitionEntry.getValue().getKeyFieldNames()) {
                                        keys.add(rowAccessor.getFieldValue(keyField));
                                    }
                                    final DrilldownDefinition drilldownDefinition = tableDefinition
                                            .getDrilldownDefinition();
                                    final ScreenTableDrilldownPerformer screenTableDrilldownPerformer = applicationContext
                                            .getBean(DefaultTableDrilldownPerformer.class);
                                    final TerminalSession terminalSession = applicationContext
                                            .getBean(TerminalSession.class);
                                    screenTableDrilldownPerformer.drilldown(drilldownDefinition, terminalSession,
                                            screenEntity.getClass(), screenEntity.getClass(), null, keys.toArray());
                                } else {
                                    int screenRowNumber = tableDefinition.getStartRow() + rowNumber;
                                    Integer columnNumber = null;
                                    if (NumberUtils.isNumber(focusField.toString())) {
                                        columnNumber = Integer.valueOf(focusField.toString());
                                    } else {
                                        final ScreenColumnDefinition focusColumnDef = tableDefinition
                                                .getColumnDefinition(focusField.toString().trim());
                                        Assert.notNull(focusColumnDef, MessageFormat
                                                .format("column field to focus on {0}, not found", focusField));
                                        columnNumber = focusColumnDef.getStartColumn();
                                    }
                                    fieldAccessor.setFieldValue(ScreenEntity.FOCUS_FIELD,
                                            SnapshotUtils.toAbsolutePosition(screenRowNumber, columnNumber,
                                                    terminalSnapshot.getSize()));
                                    // The focus based on position is evaluated at the end of this method
                                }
                            }
                            rowNumber++;
                        }
                    }
                }
            }

            if (!fieldMappingDefinition.isEditable()) {
                continue;
            }

            Object fieldValue = fieldAccessor.getFieldValue(fieldName);

            // null - skip field assignment
            if (fieldValue == null) {
                if (fieldMappingDefinition.getDefaultValue() != null) {
                    fieldValue = fieldMappingDefinition.getDefaultValue();
                } else {
                    continue;
                }
            }

            // don't handle none string or number
            if (!TypesUtil.isNumberOrString(fieldValue.getClass())) {
                continue;
            }

            String initalValue = String.valueOf(fieldValue);

            // short-cuts..
            int startRow = fieldMappingDefinition.getPosition().getRow();
            int endRow = fieldMappingDefinition.getEndPosition().getRow();
            if (endRow == 0) {
                endRow = startRow;
            }
            int startColumn = fieldMappingDefinition.getPosition().getColumn();
            int endColumn = fieldMappingDefinition.getEndPosition().getColumn();

            int currentColumn = startColumn;

            int screenColumns = terminalSnapshot.getSize().getColumns();

            String leftoverValue = initalValue;
            // iterate through the field rows - typically 1 round (endRow = startRow)
            for (int currentRow = startRow; currentRow <= endRow; currentRow++) {

                String value = leftoverValue;
                if (endRow != startRow) {
                    if (fieldMappingDefinition.isRectangle()) {
                        int delta = endColumn - startColumn + 1;
                        if (leftoverValue.length() >= delta) {
                            value = leftoverValue.substring(0, delta);
                            leftoverValue = leftoverValue.substring(delta);
                        } else {
                            value = leftoverValue;
                            leftoverValue = "";
                        }
                    } else {
                        // 1st row
                        if (currentRow == startRow) {
                            value = leftoverValue.substring(0, screenColumns - startColumn + 2);
                            leftoverValue = leftoverValue.substring(screenColumns - startColumn + 2);
                        }
                        // last row
                        else if (currentRow == endRow) {
                            value = leftoverValue;
                            currentColumn = 1;
                        }
                        // middle row
                        else {
                            value = leftoverValue.substring(0, screenColumns);
                            leftoverValue = leftoverValue.substring(screenColumns);
                            currentColumn = 1;
                        }
                    }
                }

                // find the terminal field in this position
                TerminalField terminalField = terminalSnapshot.getField(currentRow, currentColumn);

                if (terminalField == null) {
                    if (logger.isDebugEnabled()) {
                        logger.debug(MessageFormat.format(
                                "Unable to find terminal field in position {0},{1} which matchees field {2} in {3}",
                                currentRow, currentColumn, fieldName, ProxyUtil.getObjectRealClass(screenPojo)));
                    }
                    continue;
                }

                if (terminalField.isEditable() && value != null) {
                    String terminalFieldValue = terminalField.getValue();
                    // in case the field is numeric, compare the terminal field old value in as number (in case of leading spaces)
                    if (fieldMappingDefinition.getJavaType() == Integer.class && !terminalField.isEmpty()) {
                        terminalFieldValue = Integer.valueOf(fieldFormatter.format(terminalFieldValue)).toString();
                    }
                    if (fieldMappingDefinition.getJavaType() == Long.class && !terminalField.isEmpty()) {
                        terminalFieldValue = Long.valueOf(fieldFormatter.format(terminalFieldValue)).toString();
                    }
                    boolean fieldModified = fieldComparator.isFieldModified(screenPojo, fieldName,
                            terminalFieldValue, value);
                    if (fieldMappingDefinition.isForceUpdate() || fieldModified) {
                        if (fieldMappingDefinition.isEditable()) {
                            if (value.equals(fieldMappingDefinition.getNullValue())) {
                                logger.debug(MessageFormat.format(
                                        "Skipping sending field {0} with value \"{1}\" from screen {2} as it matches null value",
                                        fieldName, value, screenPojo.getClass()));
                            } else {
                                terminalField.setValue(value);
                                modifiedfields.add(terminalField);
                                if (logger.isDebugEnabled()) {
                                    logger.debug(MessageFormat.format(
                                            "Field {0} was set with value \"{1}\" to send fields for screen {2}",
                                            fieldName, value, screenPojo.getClass()));
                                }
                            }

                        } else {
                            throw (new TerminalActionException(MessageFormat.format(
                                    "Field {0} in screen {1} was modified with value {2}, but is not defined as editable",
                                    fieldName, screenPojo, value)));

                        }
                    }

                }
            }

        }
        if (screenPojo instanceof ScreenEntity) {
            ScreenEntity screenEntity = (ScreenEntity) screenPojo;
            ScreenEntityDefinition screenEntityDefinition = screenEntitiesRegistry.get(screenEntity.getClass());
            String focusField = screenEntity.getFocusField();
            if (NumberUtils.isNumber(focusField)) {
                int columns = screenEntityDefinition.getScreenSize().getColumns();
                sendAction.setCursorPosition(SnapshotUtils.toPosition(Integer.parseInt(focusField), columns));
                if (logger.isDebugEnabled()) {
                    logger.debug(MessageFormat.format("Cursor was set at position {0}", focusField));
                }
            }
        }

    }

    public static TerminalPosition getDynamicPosition(DynamicFieldDefinition dynamicField,
            TerminalSnapshot terminalSnapshot) {
        boolean isEntireScreen = isDynamicFieldCoversEntireScreen(dynamicField);

        int rowStart = isEntireScreen ? 0 : dynamicField.getRow();
        int columnStart = isEntireScreen ? 0 : dynamicField.getColumn();
        int rowEnd = isEntireScreen ? terminalSnapshot.getSize().getRows() : dynamicField.getEndRow();
        int columnEnd = isEntireScreen ? terminalSnapshot.getSize().getColumns() : dynamicField.getEndColumn();
        int fieldOffset = dynamicField.getFieldOffset();
        String text = dynamicField.getText();

        for (int rowIndex = rowStart; rowIndex < rowEnd; rowIndex++) {

            TerminalRow row = terminalSnapshot.getRow(rowIndex);

            if (row == null) {
                continue;
            }

            List<TerminalField> fields = row.getFields();
            for (int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) {
                TerminalField field = fields.get(fieldIndex);
                if (field.getPosition().getColumn() < columnStart || field.getPosition().getColumn() > columnEnd) {
                    continue;
                }

                String fieldValue = field.getValue();
                if (!fieldValue.contains(text) && !fieldValue.matches(text)) {
                    continue;
                }

                int dynamicFieldIndex = fieldIndex + fieldOffset;

                if ((dynamicFieldIndex < 0) || dynamicFieldIndex > fields.size()) {
                    continue;
                }

                if (fields.size() <= dynamicFieldIndex) {
                    logger.error("Illegal dynamic field mapping. Check that offset is correct. Dynamic field label:"
                            + dynamicField.getText());
                    continue;
                }
                TerminalField requestedield = fields.get(dynamicFieldIndex);

                int requestedFieldColumn = requestedield.getPosition().getColumn();
                if (requestedFieldColumn > columnEnd || requestedFieldColumn < columnStart) {
                    continue;
                }

                return requestedield.getPosition();
            }

        }
        return null;
    }

    private static boolean isDynamicFieldCoversEntireScreen(DynamicFieldDefinition dynamicField) {
        return (dynamicField.getRow() == 0 && dynamicField.getColumn() == 0 && dynamicField.getEndRow() == 0
                && dynamicField.getEndColumn() == 0);
    }

    private static boolean isBindText(ScreenFieldDefinition screenFieldDefinition, String text) {
        String when = screenFieldDefinition.getWhenFilter();
        String unless = screenFieldDefinition.getUnlessFilter();
        if (when != null) {
            if (text.matches(when) == false) {
                return false;
            }
        }
        if (unless != null) {
            if (text.matches(unless) == true) {
                return false;
            }
        }
        return true;
    }

    public void setDescriptionFieldSuffix(String descriptionFieldSuffix) {
        this.descriptionFieldSuffix = descriptionFieldSuffix;
    }
}