All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.prowidesoftware.swift.model.SwiftBlock1 Maven / Gradle / Ivy

There is a newer version: SRU2024-10.2.3
Show newest version
/*
 * Copyright 2006-2023 Prowide
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.prowidesoftware.swift.model;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.prowidesoftware.swift.model.mt.ServiceIdType;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;
import java.util.logging.Level;
import org.apache.commons.lang3.Validate;

/**
 * Base class for SWIFT Basic Header Block (block 1).
 * It contains information about the source of the message.
*

* The basic header block is fixed-length and continuous with * no field delimiters. This class contains its * elements as individual attributes for easier management * of the block value.
* This block is mandatory for all SWIFT messages. * * @author sebastian * @since 4.0 */ // TODO: add parameter checks (Validate.*) and complete javadocs public class SwiftBlock1 extends SwiftValueBlock implements Serializable { /** * Constant for FIN messages in application id * * @since 4.1 */ public static final transient String APPLICATION_ID_FIN = "F"; /** * Constant for GPA (General Purpose Application) messages in application id * * @since 4.1 */ public static final transient String APPLICATION_ID_GPA = "A"; /** * Constant for Logins and so messages in application id * * @since 4.1 */ public static final transient String APPLICATION_ID_LOGINS = "L"; private static final transient java.util.logging.Logger log = java.util.logging.Logger.getLogger(SwiftBlock1.class.getName()); private static final long serialVersionUID = 4229511645041690763L; /** * String of 1 character containing the Application ID as follows:
* F = FIN (financial application)
* A = GPA (general purpose application)
* L = GPA (for logins, and so on)
* This designates the application that has established the * association used to convey the message. You always use F for FIN messages. * It is set by default to F (FIN messages). */ private String applicationId = "F"; /** * String of 2 characters containing Service ID as follows:
* 01 = GPA/FIN Message (system and user-to-user)
* 02 = GPA Login
* 03 = GPA Select
* 05 = FIN Quit
* 06 = GPA Logout
* 12 = GPA System Remove AP Request
* 13 = GPA System Abort AP Confirmation
* 14 = GPA System Remove LT Request
* 15 = GPA System Abort LT Confirmation
* 21 = GPA/FIN Message (ACK/NAK/UAK/UNK)
* 22 = GPA Login ACK (LAK)
* 23 = GPA Select ACK (SAK)
* 25 = FIN Quit ACK
* 26 = GPA Logout ACK
* 33 = GPA User Abort AP Request
* 35 = GPA User Abort LT Request
* 42 = GPA Login NAK (LNK)
* 43 = GPA Select NAK (SNK) * It is set by default to 01 (FIN messages). */ private String serviceId = "01"; /** * The Logical Terminal address of the sender for messages * sent or the receiver for messages received from the * SWIFT network.
* Identifies a logical channel connection to SWIFT, and the network uses it * for addressing. It is composed by the BIC code, an optional terminal * identifier (A, B or C) if the institution has more than one terminal or an X, * and the branch code (padded with "X" if no branch is used). * For example BFOOARBSAXXX or BFOOARBSXXXX. * . */ private String logicalTerminal; /** * Session number. 4 characters. It is generated by the user's computer. * As appropriate, the current application session number based * on the Login. It is padded with zeros. */ private String sessionNumber = "0000"; /** * Sequence number is a 6 characters string that is generated by the * user's computer.
* For all FIN messages with a Service Identifier of 01 or 05, * this number is the next expected sequence number appropriate to * the direction of the transmission.
* For FIN messages with a Service Identifier of 21 or 25, * the sequence number is that of the acknowledged service message.
* It is padded with zeros. */ private String sequenceNumber = "000000"; /** * Constructor for specific values * * @param applicationId the application id * @param serviceId the service id * @param logicalTerminal the logical terminal name * @param sessionNumber the session number * @param sequenceNumber the message sequence number */ public SwiftBlock1( final String applicationId, final String serviceId, final String logicalTerminal, final String sessionNumber, final String sequenceNumber) { this.applicationId = applicationId; this.serviceId = serviceId; this.logicalTerminal = logicalTerminal; this.sessionNumber = sessionNumber; this.sequenceNumber = sequenceNumber; } /** * Default constructor */ public SwiftBlock1() {} /** * Creates the block with lenient false, meaning it expects a fixed length value. * Example of supported values:
* "F01BANKBEBBXXXX2222123456" or "1:F01BANKBEBBAXXX2222123456" * * @param value a fixed length string of 25 or 27 (which must start with '1:') characters containing the blocks value * @throws IllegalArgumentException if parameter is not 25 or 27 characters * @see #SwiftBlock1(String, boolean) */ public SwiftBlock1(final String value) { this(value, false); } /** * Creates a block 1 object setting attributes by parsing the fixed string argument;
* * @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 SwiftBlock1(final String value, boolean lenient) { this.setValue(value, lenient); } /** * Copy constructor * * @param block an existing block1 to copy * @since 7.10.4 */ public SwiftBlock1(SwiftBlock1 block) { this( block.getApplicationId(), block.getServiceId(), block.getLogicalTerminal(), block.getSessionNumber(), block.getSequenceNumber()); } /** * This method deserializes the JSON data into an block 1 object. * @param json json representation * @return block 1 object * @see #toJson() * @since 7.9.8 */ public static SwiftBlock1 fromJson(String json) { final Gson gson = new GsonBuilder().create(); return gson.fromJson(json, SwiftBlock1.class); } /** * Sets the block number. * * @param blockNumber the block number to set * @throws IllegalArgumentException if parameter blockName is not the integer 1 * @since 5.0 */ @Override protected void setBlockNumber(final Integer blockNumber) { // sanity check Objects.requireNonNull(blockNumber, "parameter 'blockNumber' cannot be null"); Validate.isTrue(blockNumber == 1, "blockNumber must be 1"); } /** * Sets the block name. Will cause an exception unless setting block number to 1. * * @param blockName the block name to set * @throws IllegalArgumentException if parameter blockName is not the string "1" * @since 5.0 */ @Override protected void setBlockName(final String blockName) { // sanity check Objects.requireNonNull(blockName, "parameter 'blockName' cannot be null"); Validate.isTrue(blockName.compareTo("1") == 0, "blockName must be string '1'"); } /** * Returns the block number (the value 1 as an integer) * * @return Integer containing the block's number */ @Override public Integer getNumber() { return 1; } /** * Returns the block name (the value 1 as a string) * * @return block name * @since 5.0 */ @Override public String getName() { return "1"; } /** * Gets the application ID field in block 1 * * @return application ID field in block 1 */ public String getApplicationId() { return applicationId; } /** * Sets the applicationId * * @param applicationId String of 1 character containing the Application ID (F, A or L) */ public void setApplicationId(final String applicationId) { this.applicationId = applicationId; } /** * Gets the service ID field in block 1 * * @return service ID field in block 1 */ public String getServiceId() { return serviceId; } /** * Sets the Service ID * * @param serviceId string of 2 characters containing Service ID (01, 02, 03, etc...) */ public void setServiceId(final String serviceId) { this.serviceId = serviceId; } /** * Sets the logical terminal address from the parameter BIC. *

If the LT identifier is not provided, "A" will be set as default. If the branch code is not provided XXX will be used as default. *

The implementation assumes the message is outgoing, and if the full logical terminal address is provided with an "X" as LT identifier, it wil be replaced by and "A". * * @param sender a BIC8, BIC11 or full 12 character length logical terminal address * @see #setLogicalTerminal(LogicalTerminalAddress) * @since 6.4 */ public void setSender(final String sender) { setLogicalTerminal(new LogicalTerminalAddress(sender)); } /** * Gets the BIC code from the LT address.
* * @return the BIC object * @since 7.6 */ public BIC getBIC() { return new BIC(this.logicalTerminal); } /** * Gets the The Logical Terminal address of the sender for messages * sent or the receiver for messages received from the SWIFT network. * * @return the 12 characters logical terminal address */ public String getLogicalTerminal() { return logicalTerminal; } /** * Sets the The Logical Terminal address with the parameter as it is given without any modification. * *

Beware for an outgoing message the LT identifier cannot be X and the branch code must be padded with XXX if not present in * the BIC address. The complete logical terminal address must always be a 12 characters length alphanumeric string * * @param logicalTerminal should be a fixed at 12 character length string; with the BIC address, LT identifier and branch code. */ public void setLogicalTerminal(final String logicalTerminal) { this.logicalTerminal = logicalTerminal; } /** * Sets the LT address.
* *

The implementation assumes the message is outgoing, and will tamper the LT identifier if necessary (changing an "X" LT identifier by and "A"). * * @param logicalTerminal the logical terminal address to set * @see LogicalTerminalAddress#getSenderLogicalTerminalAddress() * @since 7.6 */ public void setLogicalTerminal(final LogicalTerminalAddress logicalTerminal) { this.logicalTerminal = logicalTerminal.getSenderLogicalTerminalAddress(); } /** * Sets the logical terminal address from the parameter BIC code with "A" as default LT identifier and XXX as default branch code. * * @param bic a BIC code * @see #setLogicalTerminal(LogicalTerminalAddress) * @since 7.6 */ public void setLogicalTerminal(final BIC bic) { setLogicalTerminal(new LogicalTerminalAddress(bic.getBic11())); } /** * Gets the session number in block 1 * * @return session number in block 1 */ public String getSessionNumber() { return sessionNumber; } /** * Sets the Session number. It is generated by the user's computer. * As appropriate, the current application session number based * on the Login. It is padded with zeros. * * @param sessionNumber 4 numbers. */ public void setSessionNumber(final String sessionNumber) { this.sessionNumber = sessionNumber; } /** * Gets the sequence number field in block 1 * * @return sequence number field in block 1 */ public String getSequenceNumber() { return sequenceNumber; } /** * Sets the Sequence number that is generated by the * user's computer.
* For all FIN messages with a Service Identifier of 01 or 05, * this number is the next expected sequence number appropriate to * the direction of the transmission.
* For FIN messages with a Service Identifier of 21 or 25, * the sequence number is that of the acknowledged service message.
* It is padded with zeros. * * @param sequenceNumber 6 numbers */ public void setSequenceNumber(final String sequenceNumber) { this.sequenceNumber = sequenceNumber; } /** * Tell if this block is empty or not. * This block is considered to be empty if all its attributes are set to null. * * @return true if all fields are null and false in other case */ @Override public boolean isEmpty() { return applicationId == null && serviceId == null && logicalTerminal == null && sessionNumber == null && sequenceNumber == null; } /** * Gets the fixed length block 1 value, as a result of * concatenating its individual elements as follow:
* Application ID Service ID + * Logical terminal (LT) address + * Session number + * Sequence number.
* Notice that this method does not return the "1:" string. */ @Override public String getValue() { if (isEmpty()) { return null; } final StringBuilder v = new StringBuilder(); if (applicationId != null) { v.append(applicationId); } if (serviceId != null) { v.append(serviceId); } if (logicalTerminal != null) { v.append(logicalTerminal); } if (sessionNumber != null) { v.append(sessionNumber); } if (sequenceNumber != null) { v.append(sequenceNumber); } return v.toString(); } /** * Sets the block's attributes by parsing the fixed length string argument. * * @param value a fixed length string containing the blocks' value (25 or 24 characters when '1:' is not indicated; 26 or 27 characters when starting string '1:' is included) * @throws IllegalArgumentException if parameter is not between 24 and 27 characters. * @see #setValue(String, boolean) */ @Override public void setValue(final String value) { setValue(value, false); } /** * @see #getValue() */ @Override public String getBlockValue() { return getValue(); } /** * @see #setValue(String) */ @Override public void setBlockValue(final String value) { setValue(value); } /** * Sets the block's attributes by parsing string argument with its content
* This value can be in different flavors because some fields are optional.
* For example "F01BANKBEBBAXXX2222123456" or "1:F01BANKBEBBAXXX2222123456". * * @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 Objects.requireNonNull(value, "value must not be null"); } if (value != null) { int offset = 0; int slen = value.length(); // figure out the starting point if (value.startsWith("1")) { if (!lenient) { Validate.isTrue( value.startsWith("1:"), "expected '1:' at the beginning of value and found '" + value.charAt(0) + "'"); Validate.isTrue( slen == 26 || slen == 27, "block value " + value + " cannot be parsed because it has an invalid size, expected 26 or 27 and found " + value.length()); } offset = 2; } else { if (!lenient) { Validate.isTrue( slen == 24 || slen == 25, "block value " + value + " cannot be parsed because it has an invalid size, expected 24 or 25 and found " + value.length()); } } // separate value fragments int len = 1; this.setApplicationId(this.getValuePart(value, offset, len)); offset += len; len = 2; this.setServiceId(this.getValuePart(value, offset, len)); offset += len; // LT address must be fixed to 12 characters padding both the LT id and the branch with X if necessary len = 12; this.setLogicalTerminal(this.getValuePart(value, offset, len)); offset += len; len = 4; this.setSessionNumber(this.getValuePart(value, offset, len)); offset += len; if (lenient) { // get all remaining text this.setSequenceNumber(this.getValuePart(value, offset)); } else { // get text between size boundaries len = 6; this.setSequenceNumber(this.getValuePart(value, offset, len)); } } } /** * Sets all attributes to null * * @since 6.4 */ public void clean() { applicationId = null; serviceId = null; logicalTerminal = null; sessionNumber = null; sequenceNumber = null; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; SwiftBlock1 that = (SwiftBlock1) o; return Objects.equals(applicationId, that.applicationId) && Objects.equals(serviceId, that.serviceId) && Objects.equals(logicalTerminal, that.logicalTerminal) && Objects.equals(sessionNumber, that.sessionNumber) && Objects.equals(sequenceNumber, that.sequenceNumber); } @Override public int hashCode() { return Objects.hash(super.hashCode(), applicationId, serviceId, logicalTerminal, sessionNumber, sequenceNumber); } /** * Get a json representation of this object. *

* Example:
*

     * {
     * "applicationId": "F",
     * "serviceId": "01",
     * "logicalTerminal": "FOOSEDR0AXXX",
     * "sessionNumber": "0000",
     * "sequenceNumber": "000000"
     * }
     *  
* * @return json representation * @since 7.5 */ public String toJson() { final Gson gson = new GsonBuilder().create(); return gson.toJson(this); } /** * Generic getter for block attributes based on qualified names from {@link SwiftBlock1Field} * * @param field field to get * @return field value or null if attribute is not set * @since 7.7 */ public String field(SwiftBlock1Field field) { switch (field) { case ApplicationId: return getApplicationId(); case ServiceId: return getServiceId(); case LogicalTerminal: return getLogicalTerminal(); case SessionNumber: return getSessionNumber(); case SequenceNumber: return getSequenceNumber(); default: return null; } } /** * Generic setter for block attributes based on qualified names from {@link SwiftBlock1Field} * * @param field field to set * @param value content to set * @since 7.8 */ public void setField(SwiftBlock1Field field, final String value) { switch (field) { case ApplicationId: setApplicationId(value); break; case ServiceId: setServiceId(value); break; case LogicalTerminal: setLogicalTerminal(value); break; case SessionNumber: setSessionNumber(value); break; case SequenceNumber: setSequenceNumber(value); break; default: log.warning("don't know how to set " + field + " to block1"); break; } } /** * Maps the service id to the service id enumeration * * @return the mapped enumeration or null if service id not present or cannot be mapped * @since 7.8.3 */ public ServiceIdType getServiceIdType() { try { return ServiceIdType.valueOf("_" + this.serviceId); } catch (Exception e) { final String text = "Block1 serviceId contains an invalid value [" + this.serviceId + "]. The expected values are " + Arrays.toString(ServiceIdType.values()); log.warning(text); log.log(Level.FINEST, text, e); return null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy