com.prowidesoftware.swift.model.SwiftBlock2Output.java Source code

Java tutorial

Introduction

Here is the source code for com.prowidesoftware.swift.model.SwiftBlock2Output.java

Source

/*******************************************************************************
 * Copyright (c) 2016 Prowide Inc.
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as 
 *     published by the Free Software Foundation, either version 3 of the 
 *     License, or (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 *     
 *     Check the LGPL at <http://www.gnu.org/licenses/> for more details.
 *******************************************************************************/
package com.prowidesoftware.swift.model;

import java.io.Serializable;

import org.apache.commons.lang.Validate;

/**
 * Base class for SWIFT <b>Application Header Block (block 2)
 * for OUTPUT (from SWIFT)</b>.<br>
 * This block is used to construct messages that have been 
 * <i>output</i> from the SWIFT network. From the application point
 * of view, it correspond to the <i>RECEIVED</i> messages.<br><br>
 * 
 * <p>It's value is fixed-length and continuous with no field delimiters. 
 * This class contains its elements as individual attributes for 
 * easier management of the block value.</p>
 * 
 * <p>For a received message, a message being output from SWIFT, the 
 * SwiftBlock2Output includes explicit information regarding the MIR. 
 * This is sometimes confusing because it is an output block with an 
 * input reference. The important thing to understand here is that the 
 * MIR information is related to the original sender of the message that 
 * has been received. The attributes of this header (block 2 output) are 
 * explicitly documented as MIR information by SWIFT.</p>
 * 
 * <p>The MOR itself could be created combining information from block 1 
 * and 2 but it usually does not make sense.</p>
 * 
 * @author www.prowidesoftware.com
 * @since 4.0
 * @see MIR
 */
//TODO: add parameter checks (Validate.*) and complete javadocs 
public class SwiftBlock2Output extends SwiftBlock2 implements Serializable {
    private static final long serialVersionUID = 6067091531833134527L;
    @SuppressWarnings("unused")
    private static final transient java.util.logging.Logger log = java.util.logging.Logger
            .getLogger(SwiftBlock2.class.getName());

    /** 
     * String of 4 characters containing the input time with respect to the sender
     */
    private String senderInputTime;

    /**
     * Date part of the MIR in YYMMDD format.
     */
    private String MIRDate;

    /**
     * String of 12 characters containing the logical terminal field of the MIR
     * (address of the sender of the message).
     * 
     */
    private String MIRLogicalTerminal;

    /**
     * String of 4 characters containing the session number field of the MIR.
     * 
     */
    private String MIRSessionNumber;

    /**
     * String of 6 characters containing the sequence number field of the MIR.
     * 
     */
    private String MIRSequenceNumber;

    /**
     * String of 6 characters containing the Output date local 
     * to the receiver, written in the following format: YYMMDD
     */
    private String receiverOutputDate;

    /**
     * String of 4 characters containing the Output time local 
     * to the receiver, written in the following format: HHMM
     */
    private String receiverOutputTime;

    /**
     * Constructor for specific values
     * 
     * @param messageType the message type
     * @param senderInputTime the input time
     * @param MIRDate date
     * @param MIRLogicalTerminal logical terminal
     * @param MIRSessionNumber session number
     * @param MIRSequenceNumber message sequence number
     * @param receiverOutputDate receiver date
     * @param receiverOutputTime receiver time
     * @param messagePriority the message priority (S=system, U=urgent, N=normal)
     */
    public SwiftBlock2Output(final String messageType, final String senderInputTime, final String MIRDate,
            final String MIRLogicalTerminal, final String MIRSessionNumber, final String MIRSequenceNumber,
            final String receiverOutputDate, final String receiverOutputTime, final String messagePriority) {
        super();
        this.messageType = messageType;
        this.senderInputTime = senderInputTime;
        this.MIRDate = MIRDate;
        this.MIRLogicalTerminal = MIRLogicalTerminal;
        this.MIRSessionNumber = MIRSessionNumber;
        this.MIRSequenceNumber = MIRSequenceNumber;
        this.receiverOutputDate = receiverOutputDate;
        this.receiverOutputTime = receiverOutputTime;
        this.messagePriority = messagePriority;
    }

    /**
     * Creates the block with lenient false, meaning it expects a fixed length value.
     * Example of supported values:<br> 
     * "O1001200970103BANKBEBBAXXX22221234569701031201N" or "2:O1001200970103BANKBEBBAXXX22221234569701031201N"
     * 
     * @param value a fixed length string of 46 (starting with 'O') or 49 (starting with '2:O') characters containing the blocks value
     * @throws IllegalArgumentException if parameter is not 47 or 49 characters 
     * @see #SwiftBlock2Output(String, boolean)
     */
    public SwiftBlock2Output(final String value) {
        this(value, false);
    }

    /**
      * Creates a block 2 output object setting attributes by parsing the string argument containing the blocks value. 
     * This value can be in different flavors because some fields are optional.<br>
     * 
     * @param value string containing the entire blocks value
     * @param lenient if true the value will be parsed with a best effort heuristic, if false it will throw a IllegalArgumentException if the value has an invalid total size
     * @see #setValue(String, boolean)
     * @since 7.7
     */
    public SwiftBlock2Output(final String value, boolean lenient) {
        super();
        this.setValue(value, lenient);
    }

    /**
     * Default Constructor
     */
    public SwiftBlock2Output() {
        super();
    }

    /**
     * Sets the input time with respect to the sender
     * 
     * @param senderInputTime 4 numbers HHMM
     */
    public void setSenderInputTime(final String senderInputTime) {
        this.senderInputTime = senderInputTime;
    }

    /**
     * Returns the input time with respect to the sender
     * 
     * @return 4 numbers HHMM
     */
    public String getSenderInputTime() {
        return senderInputTime;
    }

    /**
     * Sets the date the sender sent the message to SWIFT,
     * from the MIR field
     * 
     * @param MIRDate 6 numbers with date in format YYMMDD
     */
    public void setMIRDate(final String MIRDate) {
        this.MIRDate = MIRDate;
    }

    /**
     * Gets the date the sender sent the message to SWIFT,
     * from the MIR field, in the format YYMMDD
     * 
     * @return String with 6 numbers
     */
    public String getMIRDate() {
        return this.MIRDate;
    }

    /**
     * Sets the the full LT address of the sender of the message.
     * 
     * @param MIRLogicalTerminal 12 characters full LT address
     */
    public void setMIRLogicalTerminal(final String MIRLogicalTerminal) {
        this.MIRLogicalTerminal = MIRLogicalTerminal;
    }

    /**
     * Sets the the full LT address of the sender of the message.
     * 
     * @see LogicalTerminalAddress#getSenderLogicalTerminalAddress()
     * @param MIRLogicalTerminal 12 characters full LT address
     * @since 7.6
     */
    public void setMIRLogicalTerminal(final LogicalTerminalAddress MIRLogicalTerminal) {
        this.MIRLogicalTerminal = MIRLogicalTerminal.getSenderLogicalTerminalAddress();
    }

    /**
     * Creates a full LT address using the parameter BIC code and a default LT identifier,
     * and sets the resulting address as MIR logical terminal address.
     * 
     * @see #setMIRLogicalTerminal(LogicalTerminalAddress)
     * @param bic
     * @since 7.6
     */
    public void setSender(final BIC bic) {
        setMIRLogicalTerminal(new LogicalTerminalAddress(bic.getBic11()));
    }

    /**
     * Completes if necessary and sets the LT address of the sender
     * as MIR logical terminal address.<br />
      * The sender addresses will be filled with proper default LT identifier and branch codes if not provided.
     * 
     * @see #setMIRLogicalTerminal(LogicalTerminalAddress)
     * @since 7.6
     */
    public void setSender(final String sender) {
        setMIRLogicalTerminal(new LogicalTerminalAddress(sender));
    }

    /**
     * Gets the the full LT address of the sender of the 
     * message, from the MIR field, for example: BANKBEBBAXXX
     * 
     * @return LT address
     */
    public String getMIRLogicalTerminal() {
        return this.MIRLogicalTerminal;
    }

    /**
     * Gets the sender's BIC code.<br />
     * For output message the sender address is contained in this block2
     * and not in the header block 1 as for input messages.
     * 
     * @return sender BIC address
     * @see BIC
     * @since 7.6
     */
    public BIC getSenderBIC() {
        return new BIC(this.MIRLogicalTerminal);
    }

    /**
     * Sets the session number field of the MIR
     * 
     * @param MIRSessionNumber 4 numbers
     */
    public void setMIRSessionNumber(final String MIRSessionNumber) {
        this.MIRSessionNumber = MIRSessionNumber;
    }

    /**
     * Gets the date the sender session number,
     * from the MIR field, in the format NNNN
     * 
     * @return 4 numbers
     */
    public String getMIRSessionNumber() {
        return this.MIRSessionNumber;
    }

    /**
     * Sets the sequence number field of the MIR
     * 
     * @param MIRSequenceNumber 6 numbers
     */
    public void setMIRSequenceNumber(final String MIRSequenceNumber) {
        this.MIRSequenceNumber = MIRSequenceNumber;
    }

    /**
     * Gets the date the sender sequence number,
     * from the MIR field, in the format NNNNNN
     *      
     * @return 6 numbers
     */
    public String getMIRSequenceNumber() {
        return MIRSequenceNumber;
    }

    /**
     * Gets the full MIR (Message Input Reference) string of 28 
     * characters containing the sender's date, LT address,
     * session and sequence:<br>
     * for example YYMMDDBANKBEBBAXXX2222123456<br>
     * @return a String with MIR, returns <code>null</code> if all MIR components are <code>null</code> 
     */
    public String getMIR() {
        if (MIRDate == null && MIRLogicalTerminal == null && MIRSessionNumber == null
                && MIRSequenceNumber == null) {
            return null;
        }
        final StringBuilder v = new StringBuilder();
        if (MIRDate != null) {
            v.append(MIRDate);
        }
        if (MIRLogicalTerminal != null) {
            v.append(MIRLogicalTerminal);
        }
        if (MIRSessionNumber != null) {
            v.append(MIRSessionNumber);
        }
        if (MIRSequenceNumber != null) {
            v.append(MIRSequenceNumber);
        }
        return v.toString();
    }

    /**
     * Sets the full MIR (Message Input Reference) from a fixed length (28 characters) string containing the complete MIR value.<br>
     * 
     * @param mir complete MIR string value, a fixed length (28 characters) string containing the MIR value
     * @throws IllegalArgumentException if parameter has an invalid total size.
     * @see #setMIR(String, boolean) 
     */
    public void setMIR(final String mir) {
        setMIR(mir, false);
    }

    /**
     * Sets the MIR (Message Input Reference) attributes by parsing the string argument containing the complete MIR value.<br /> 
     * For example YYMMDDBANKBEBBAXXX2222123456<br>
     * 
     * @param mir complete MIR string
     * @param lenient if true the value will be parsed with a best effort heuristic, if false it will throw a IllegalArgumentException if the value has an invalid total size
     */
    public void setMIR(final String mir, boolean lenient) {
        if (!lenient) {
            Validate.notNull(mir);
            Validate.isTrue(mir.length() == 28,
                    "expected a 28 characters string for MIR value and found a " + mir.length() + " string:" + mir);
        }
        if (mir != null) {
            final StringBuilder sb = new StringBuilder(mir);

            int offset = 0;
            int len;

            len = 6;
            this.setMIRDate(String.valueOf(sb.subSequence(offset, offset + len)));
            offset += len;

            len = 12;
            this.setMIRLogicalTerminal(String.valueOf(sb.subSequence(offset, offset + len)));
            offset += len;

            len = 4;
            this.setMIRSessionNumber(String.valueOf(sb.subSequence(offset, offset + len)));
            offset += len;

            if (lenient) {
                //get all remaining text
                this.setMIRSequenceNumber(String.valueOf(sb.subSequence(offset, mir.length())));
            } else {
                len = 6;
                this.setMIRSequenceNumber(String.valueOf(sb.subSequence(offset, offset + len)));
                offset += len;
            }
        }
    }

    /**
     * Sets the Output date local to the receiver, written in the following format: YYMMDD
     * 
     * @param receiverOutputDate 6 characters in format YYMMDD
     */
    public void setReceiverOutputDate(final String receiverOutputDate) {
        this.receiverOutputDate = receiverOutputDate;
    }

    /**
     * Gets the Output date local to the receiver
     * 
     * @return 6 characters in format YYMMDD
     */
    public String getReceiverOutputDate() {
        return receiverOutputDate;
    }

    /**
     * Sets the Output time local to the receiver, written in the following format: HHMM
     * 
     * @param receiverOutputTime String with 4 numbers
     */
    public void setReceiverOutputTime(final String receiverOutputTime) {
        this.receiverOutputTime = receiverOutputTime;
    }

    /**
     * Gets the Output time local to the receiver, written in the following format: HHMM
     * 
     * @return String with 4 numbers
     */
    public String getReceiverOutputTime() {
        return receiverOutputTime;
    }

    /**
     * Tell if this block is empty or not.
     * This block is considered to be empty if all its attributes are set to <code>null</code>.
     * @return <code>true</code> if all fields are <code>null</code> and false in other case
     */
    public boolean isEmpty() {
        return messageType == null && senderInputTime == null && getMIR() == null && receiverOutputDate == null
                && receiverOutputTime == null && messagePriority == null;
    }

    /**
     * Gets the fixed length block 2 value, as a result of
     * concatenating its individual elements as follow:<br>
     * Message Type +
     * Sender Input Time +
     * MIR +
     * Receiver Output Date +
     * Receiver Output Time +
     * Message Priority.
     */
    public String getValue() {
        if (isEmpty()) {
            return null;
        }
        final StringBuilder v = new StringBuilder("O");
        if (messageType != null) {
            v.append(messageType);
        }
        if (senderInputTime != null) {
            v.append(senderInputTime);
        }
        if (getMIR() != null) {
            v.append(getMIR());
        }
        if (receiverOutputDate != null) {
            v.append(receiverOutputDate);
        }
        if (receiverOutputTime != null) {
            v.append(receiverOutputTime);
        }
        if (messagePriority != null) {
            v.append(messagePriority);
        }
        return v.toString();
    }

    /**
     * @see #getValue()
     */
    public String getBlockValue() {
        return getValue();
    }

    /**
     * Sets the block's attributes by parsing the fixed length string argument.<br>
     * 
     * @param value a fixed length (between 46 and 49) string containing the blocks' value
     * @throws IllegalArgumentException if parameter has an invalid total size.
     * @see #setValue(String, boolean) 
     */
    public void setValue(final String value) {
        setValue(value, false);
    }

    /**
     * Sets the block's attributes by parsing the string argument containing the blocks value.<br /> 
     * This value can be in different flavors because some fields are optional.<br />
     * Example of supported values:<br />
     * <pre>
     *   "O1001200970103BANKBEBBAXXX22221234569701031201" (46) or
     *   "2:O1001200970103BANKBEBBAXXX22221234569701031201" (48)   // used for service/system messages
     *   "O1001200970103BANKBEBBAXXX22221234569701031201N" (47) or
     *   "2:O1001200970103BANKBEBBAXXX22221234569701031201N" (49)
     * </pre><br />
     * 
     * @param value string containing the entire blocks value
     * @param lenient if true the value will be parsed with a best effort heuristic, if false it will throw a IllegalArgumentException if the value has an invalid total size
     */
    public void setValue(final String value, boolean lenient) {
        if (lenient) {
            //leave all attributes as null (cleaning defaults)
            clean();
        } else {
            // check parameters
            Validate.notNull(value, "value must not be null");
        }

        if (value != null) {

            int slen = value.length();

            if (!lenient) {
                // check parameters
                Validate.notNull(value, "value must not be null");
                Validate.isTrue(slen == 46 || slen == 48 || slen == 47 || slen == 49,
                        "expected a string value of 46 and up to 49 chars and obtained a " + slen
                                + " chars string: '" + value + "'");
            }

            // figure out the starting point and check the input value has proper optional
            int offset = 0;
            if (value.startsWith("2:")) { // accept 2:...
                offset = 2;
            }

            slen -= offset;
            if (!lenient) {
                if (slen != 46 && slen != 47) {
                    throw new IllegalArgumentException("Value must match: O<mt><time><mir><date><time>[<pri>]");
                }
                if (Character.toUpperCase(value.charAt(offset)) != 'O') {
                    throw new IllegalArgumentException("Value must match: O<mt><time><mir><date><time>[<pri>]");
                }
            }
            offset++; // skip the output mark

            // separate value fragments
            int len = 3;
            this.setMessageType(this.getValuePart(value, offset, len));
            offset += len;

            len = 4;
            this.setSenderInputTime(this.getValuePart(value, offset, len));
            offset += len;

            len = 28;
            this.setMIR(this.getValuePart(value, offset, len), lenient);
            offset += len;

            len = 6;
            this.setReceiverOutputDate(this.getValuePart(value, offset, len));
            offset += len;

            len = 4;
            this.setReceiverOutputTime(this.getValuePart(value, offset, len));
            offset += len;

            if (lenient) {
                //get all remaining text
                this.setMessagePriority(this.getValuePart(value, offset));
            } else {
                len = 1;
                this.setMessagePriority(this.getValuePart(value, offset, len));
                offset += len; // optional (system messages)
            }

        }
    }

    /**
     * @see #setValue(String)
     */
    public void setBlockValue(final String value) {
        setValue(value);
    }

    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + ((MIRDate == null) ? 0 : MIRDate.hashCode());
        result = prime * result + ((MIRLogicalTerminal == null) ? 0 : MIRLogicalTerminal.hashCode());
        result = prime * result + ((MIRSequenceNumber == null) ? 0 : MIRSequenceNumber.hashCode());
        result = prime * result + ((MIRSessionNumber == null) ? 0 : MIRSessionNumber.hashCode());
        result = prime * result + ((messagePriority == null) ? 0 : messagePriority.hashCode());
        result = prime * result + ((messageType == null) ? 0 : messageType.hashCode());
        result = prime * result + ((receiverOutputDate == null) ? 0 : receiverOutputDate.hashCode());
        result = prime * result + ((receiverOutputTime == null) ? 0 : receiverOutputTime.hashCode());
        result = prime * result + ((senderInputTime == null) ? 0 : senderInputTime.hashCode());
        return result;
    }

    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (!super.equals(obj)) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final SwiftBlock2Output other = (SwiftBlock2Output) obj;
        if (MIRDate == null) {
            if (other.MIRDate != null) {
                return false;
            }
        } else if (!MIRDate.equals(other.MIRDate)) {
            return false;
        }
        if (MIRLogicalTerminal == null) {
            if (other.MIRLogicalTerminal != null) {
                return false;
            }
        } else if (!MIRLogicalTerminal.equals(other.MIRLogicalTerminal)) {
            return false;
        }
        if (MIRSequenceNumber == null) {
            if (other.MIRSequenceNumber != null) {
                return false;
            }
        } else if (!MIRSequenceNumber.equals(other.MIRSequenceNumber)) {
            return false;
        }
        if (MIRSessionNumber == null) {
            if (other.MIRSessionNumber != null) {
                return false;
            }
        } else if (!MIRSessionNumber.equals(other.MIRSessionNumber)) {
            return false;
        }
        if (messagePriority == null) {
            if (other.messagePriority != null) {
                return false;
            }
        } else if (!messagePriority.equals(other.messagePriority)) {
            return false;
        }
        if (messageType == null) {
            if (other.messageType != null) {
                return false;
            }
        } else if (!messageType.equals(other.messageType)) {
            return false;
        }
        if (receiverOutputDate == null) {
            if (other.receiverOutputDate != null) {
                return false;
            }
        } else if (!receiverOutputDate.equals(other.receiverOutputDate)) {
            return false;
        }
        if (receiverOutputTime == null) {
            if (other.receiverOutputTime != null) {
                return false;
            }
        } else if (!receiverOutputTime.equals(other.receiverOutputTime)) {
            return false;
        }
        if (senderInputTime == null) {
            if (other.senderInputTime != null) {
                return false;
            }
        } else if (!senderInputTime.equals(other.senderInputTime)) {
            return false;
        }
        return true;
    }

    /**
     * @since 7.5
     */
    public String toJson() {
        final StringBuilder sb = new StringBuilder();
        sb.append("{ \n");

        sb.append(" \"messageType\" : \"").append(messageType).append("\", \n");
        sb.append(" \"senderInputTime\" : \"").append(senderInputTime).append("\", \n");
        sb.append(" \"MIRDate\" : \"").append(MIRDate).append("\", \n");
        sb.append(" \"MIRLogicalTerminal\" : \"").append(MIRLogicalTerminal).append("\", \n");
        sb.append(" \"MIRSessionNumber\" : \"").append(MIRSessionNumber).append("\", \n");
        sb.append(" \"MIRSequenceNumber\" : \"").append(MIRSequenceNumber).append("\", \n");
        sb.append(" \"receiverOutputDate\" : \"").append(receiverOutputDate).append("\", \n");
        sb.append(" \"receiverOutputTime\" : \"").append(receiverOutputTime).append("\", \n");
        sb.append(" \"messagePriority\" : \"").append(messagePriority).append("\" \n");

        sb.append("} ");
        return sb.toString();
    }

    /**
     * Generic getter for block attributes based on qualified names from {@link SwiftBlock2OutputField}
     * @param field field to get
     * @return field value or <code>null</code> if attribute is not set
     * @since 7.7
     */
    public String field(SwiftBlock2OutputField field) {
        switch (field) {
        case MessageType:
            return getMessageType();
        case MessagePriority:
            return getMessagePriority();
        case SenderInputTime:
            return getSenderInputTime();
        case MIRDate:
            return getMIRDate();
        case MIRLogicalTerminal:
            return getMIRLogicalTerminal();
        case MIRSessionNumber:
            return getMIRSessionNumber();
        case MIRSequenceNumber:
            return getMIRSequenceNumber();
        case ReceiverOutputDate:
            return getReceiverOutputDate();
        case ReceiverOutputTime:
            return getReceiverOutputTime();
        }
        return null;
    }

    /**
     * Generic setter for block attributes based on qualified names from {@link SwiftBlock2OutputField}
     * @param field field to get
     * @param value content to set
     * @since 7.8
     */
    public void setField(SwiftBlock2OutputField field, final String value) {
        switch (field) {
        case MessageType:
            setMessageType(value);
            break;
        case MessagePriority:
            setMessagePriority(value);
            break;
        case SenderInputTime:
            setSenderInputTime(value);
            break;
        case MIRDate:
            setMIRDate(value);
            break;
        case MIRLogicalTerminal:
            setMIRLogicalTerminal(value);
            break;
        case MIRSessionNumber:
            setMIRSessionNumber(value);
            break;
        case MIRSequenceNumber:
            setMIRSequenceNumber(value);
            break;
        case ReceiverOutputDate:
            setReceiverOutputDate(value);
            break;
        case ReceiverOutputTime:
            setReceiverOutputTime(value);
            break;
        }
    }
}