AbstractFEC.java
package com.tradecloud.domain.model.fec;
import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.event.DealsEvent;
import com.tradecloud.domain.exception.ConfirmationException;
import com.tradecloud.domain.helper.XMLHelper;
import com.tradecloud.domain.model.ActualExposure;
import com.tradecloud.domain.model.ForexGroup;
import com.tradecloud.domain.model.Money;
import com.tradecloud.domain.model.audit.AuditEvent;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.treasury.TreasuryBank;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.Type;
import org.joda.time.LocalDate;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.math.BigDecimal;
import java.util.*;
@MappedSuperclass
@Table(name = "fec")
public abstract class AbstractFEC extends PersistenceBase implements IFEC, ActualExposure {
private static final long serialVersionUID = 1L;
@Embedded
protected BankReference bankReference;
@Embedded
protected InternalReference internalReference;
@Embedded
@AttributeOverrides({@AttributeOverride(name = "currency", column = @Column(name = "amount_currency")),
@AttributeOverride(name = "value", column = @Column(name = "amount_value", precision = 19, scale = 6))})
protected Money amount;
@Embedded
@AttributeOverrides({@AttributeOverride(name = "currency", column = @Column(name = "unlinked_amount_currency")),
@AttributeOverride(name = "value", column = @Column(name = "unlinked_amount_value", precision = 19, scale = 6))})
protected Money unlinkedAmount;
@Column(name = "maturity_date")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
protected LocalDate maturityDate;
@Embedded
protected BankDetails bankDetails;
@Embedded
@AttributeOverrides({@AttributeOverride(name = "currency", column = @Column(name = "spot_rate_currency")),
@AttributeOverride(name = "value", column = @Column(name = "spot_rate_value", precision = 19, scale = 6))})
protected Money spotRate;
@Embedded
@AttributeOverrides({@AttributeOverride(name = "currency", column = @Column(name = "forward_rate_currency")),
@AttributeOverride(name = "value", column = @Column(name = "forward_rate_value", precision = 19, scale = 6))})
protected Money forwardRate;
@Embedded
@AttributeOverrides({@AttributeOverride(name = "currency", column = @Column(name = "costing_rate_currency")),
@AttributeOverride(name = "value", column = @Column(name = "costing_rate_value", precision = 19, scale = 6))})
protected Money costingRate;
protected boolean confirmed;
protected Date confirmedDateTime;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_fec")
protected FEC parent;
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@OrderBy("confirmedDateTime desc")
@Fetch(FetchMode.SUBSELECT)
private List<FEC> fecLegs = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "extensionPreDeliverPair_id")
protected FEC extensionPreDeliverPair;
@Enumerated(value = EnumType.STRING)
@Column(name = "type", nullable = false, insertable = false, updatable = false)
// this will be readonly as it is declared as a @DiscriminatorColumn in FEC
protected FECType type;
@Column(name = "deal_date")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
protected LocalDate dealDate;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "organisationalunit_id")
protected OrganisationalUnit organisationalUnit;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "forexgroup_id")
protected ForexGroup forexGroup;
//@Enumerated(EnumType.STRING)
@Type(type = "com.tradecloud.domain.infrastructure.persistence.userTypes.FECTransactionTypeUserType")
protected FECTransactionType fecTransactionType;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SUBSELECT)
@XmlElementWrapper(name = "DealsEvents")
@XmlElement(name = "DealsEvent")
@OrderBy("createDateTime")
protected List<DealsEvent> events = new LinkedList<DealsEvent>();
@Override
public String getStateAsXML() {
StringBuilder builder = new StringBuilder();
builder.append("<fec>");
// builder.append("<ForexGroup>").append(forexGroup == null ? "" : forexGroup.getName()).append("</ForexGroup>");
builder.append("<ForexGroup>").append(XMLHelper.getForexGroupXML(forexGroup)).append("</ForexGroup>");
builder.append("<fecReference>").append(getId()).append("</fecReference>");
builder.append("<bankReference>").append((bankReference == null) ? "" : XMLHelper.encodeToXMLString(bankReference.getReference()))
.append("</bankReference>");
builder.append("<internalReference>")
.append((internalReference == null) ? "" : XMLHelper.encodeToXMLString(internalReference.getReference()))
.append("</internalReference>");
builder.append("<maturityDate>").append(maturityDate).append("</maturityDate>");
builder.append("<dealDate>").append(dealDate == null ? LocalDate.now() : dealDate).append("</dealDate>");
builder.append("<amount>").append(XMLHelper.getMoneyXML(amount)).append("</amount>");
builder.append("<unlinkedAmount>").append(XMLHelper.getMoneyXML(unlinkedAmount)).append("</unlinkedAmount>");
builder.append("<localCurrencyAmount>").append(XMLHelper.getLocalCurrencyXML(forwardRate.getValue(), amount.getValue()))
.append("</localCurrencyAmount>");
builder.append("<spotRate>").append(XMLHelper.getMoneyXML(spotRate)).append("</spotRate>");
builder.append("<forwardRate>").append(XMLHelper.getMoneyXML(forwardRate)).append("</forwardRate>");
builder.append("<bankDetails>").append(XMLHelper.getBankDetailsXML(bankDetails)).append("</bankDetails>");
builder.append("<confirmed>").append(confirmed).append("</confirmed>");
builder.append("<matured>").append(isMatured()).append("</matured>");
builder.append("<linkedAmount>").append(XMLHelper.getMoneyXML(calculateLinkedAmount())).append("</linkedAmount>");
builder.append("<status>").append(XMLHelper.encodeToXMLString(status().getStatusName())).append("</status>");
builder.append("<division>").append(XMLHelper.getOrganisationalUnitXML(organisationalUnit)).append("</division>");
builder.append("<fecTransactionType>").append((getFecTransactionType() == null) ? "" :
XMLHelper.encodeToXMLString(getFecTransactionType().getName())).append("</fecTransactionType>");
builder.append("</fec>");
return builder.toString();
}
public String getStateAsXMLWithStringFields() {
StringBuilder builder = new StringBuilder();
builder.append("<fec>");
builder.append("<ForexGroup>").append(XMLHelper.getForexGroupXML(forexGroup)).append("</ForexGroup>");
builder.append("<fecReference>").append(getId()).append("</fecReference>");
builder.append("<bankReference>").append((bankReference == null) ? "" : XMLHelper.encodeToXMLString(bankReference.getReference()))
.append("</bankReference>");
builder.append("<internalReference>")
.append((internalReference == null) ? "" : XMLHelper.encodeToXMLString(internalReference.getReference()))
.append("</internalReference>");
builder.append("<maturityDate>").append(maturityDate).append("</maturityDate>");
builder.append("<dealDate>").append(dealDate == null ? LocalDate.now() : dealDate).append("</dealDate>");
builder.append("<amount>").append(XMLHelper.getMoneyXML(amount, 2)).append("</amount>");
builder.append("<unlinkedAmount>").append(XMLHelper.getMoneyXML(unlinkedAmount)).append("</unlinkedAmount>");
builder.append("<localCurrencyAmount>").append(XMLHelper.getLocalCurrencyXML(forwardRate.getValue(), amount.getValue()))
.append("</localCurrencyAmount>");
builder.append("<spotRate>").append(XMLHelper.getMoneyXML(spotRate, 4)).append("</spotRate>");
builder.append("<forwardRate>").append(XMLHelper.getMoneyXML(forwardRate, 4)).append("</forwardRate>");
builder.append("<bankDetails>").append(XMLHelper.getBankDetailsXML(bankDetails)).append("</bankDetails>");
builder.append("<confirmed>").append(confirmed).append("</confirmed>");
builder.append("<matured>").append(isMatured()).append("</matured>");
builder.append("<linkedAmount>").append(XMLHelper.getMoneyXML(calculateLinkedAmount())).append("</linkedAmount>");
builder.append("<status>").append(XMLHelper.encodeToXMLString(status().getStatusName())).append("</status>");
builder.append("<division>").append(XMLHelper.getOrganisationalUnitXML(organisationalUnit)).append("</division>");
builder.append("<fecTransactionType>").append((getFecTransactionType() == null) ? "" :
XMLHelper.encodeToXMLString(getFecTransactionType().getName())).append("</fecTransactionType>");
builder.append("</fec>");
return builder.toString();
}
@Override
public Money calculateLinkedAmount() {
if (amount != null && unlinkedAmount != null) {
return amount != null ? amount.subtract(unlinkedAmount) : new Money(BigDecimal.ZERO, amount.getCurrency());
}
return null;
}
@Override
public void checkConfirmation(boolean appendFecTypeToMessage, Confirmation confirmation) {
String fecType = "";
if (appendFecTypeToMessage) {
fecType = confirmation.getConfirmationType().getDescription() + " ";
}
validate(confirmation.getForwardRate().getValue(), this.forwardRate.getValue(), "Confirmation failure : " + fecType
+ "Forward Rate value mismatch.");
validate(confirmation.getForwardRate().getCurrency(), this.forwardRate.getCurrency(), "Confirmation failure : " + fecType
+ "Forward Rate currency mismatch.");
validate(confirmation.getSpotRate().getValue(), this.spotRate.getValue(), "Confirmation failure : " + fecType + "Spot Rate value mismatch.");
validate(confirmation.getSpotRate().getCurrency(), this.spotRate.getCurrency(), "Confirmation failure : " + fecType
+ "Spot Rate currency mismatch.");
validate(confirmation.getAmount().getValue(), this.amount.getValue(), "Confirmation failure : " + fecType + "Amount value mismatch.");
validate(confirmation.getAmount().getCurrency(), this.amount.getCurrency(), "Confirmation failure : " + fecType
+ "Amount currency mismatch.");
validate(confirmation.getMaturityDate(), this.maturityDate, "Confirmation failure : " + fecType + "Maturity Date mismatch.");
if (confirmation.getOrganisationalUnit() != null) {
validate(confirmation.getOrganisationalUnit().getCode(), this.organisationalUnit.getCode(), "Confirmation failure : " + fecType
+ " OrganisationalUnit mismatch.");
}
if (confirmation.getForexGroup() != null) {
validate(confirmation.getForexGroup(), this.forexGroup, "Confirmation failure : " + fecType + "forex group mismatch.");
}
if (this.forwardRate.getValue().compareTo(this.spotRate.getValue()) < 0) {
throw new ConfirmationException("Confirmation failure: the Forward Rate (" + forwardRate + ") " + "may not be less than the Spot Rate ("
+ spotRate + ")");
}
if (this.forwardRate.getValue().compareTo(BigDecimal.ZERO) == 0) {
throw new ConfirmationException("Confirmation failure: Forward Rate may not be zero");
}
if (this.spotRate.getValue().compareTo(BigDecimal.ZERO) == 0) {
throw new ConfirmationException("Confirmation failure: Spot Rate may not be zero");
}
}
/**
* Override if necessary.
*
* @return
*/
public boolean isMatured() {
return (confirmed && (!maturityDate.isAfter(new LocalDate())));
}
@Override
public FECStatusType status() {
if (!confirmed) {
return FECStatusType.ESTABLISHED;
} else if (!maturityDate.isAfter(new LocalDate())) {
return FECStatusType.MATURED;
} else {
return FECStatusType.CONFIRMED;
}
}
public FECStatusType getStatus() {
return status();
}
private void validate(Object first, Object second, String message) {
if (!first.equals(second)) {
throw new ConfirmationException(message);
}
}
@Override
public StringBuilder getAuditEventsAsXML(List<AuditEvent> events) {
StringBuilder builder = new StringBuilder();
builder.append("<stateHistory>");
builder.append(getStateAsXML());
builder.append("<auditEvents>");
for (AuditEvent event : events) {
builder.append(event.getStateAsXML());
}
builder.append("</auditEvents>");
builder.append("</stateHistory>");
return builder;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!HibernateUtils.proxyClassEquals(this, obj)) {
return false;
}
final AbstractFEC other = (AbstractFEC) obj;
return new EqualsBuilder().append(this.bankReference, other.getBankReference()).isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(this.bankReference).toHashCode();
}
@Override
public Money getAmount() {
return amount;
}
@Override
public OrganisationalUnit getDivision() {
return organisationalUnit;
}
@Override
public void setDivision(OrganisationalUnit organisationalUnit) {
this.organisationalUnit = organisationalUnit;
}
@Override
public OrganisationalUnit getOrganisationalUnit() {
return organisationalUnit;
}
public void setOrganisationalUnit(OrganisationalUnit organisationalUnit) {
this.organisationalUnit = organisationalUnit;
}
@Override
public ForexGroup getForexGroup() {
return forexGroup;
}
@Override
public void setForexGroup(ForexGroup forexGroup) {
this.forexGroup = forexGroup;
}
@Override
public BankReference getBankReference() {
return bankReference;
}
public void setBankReference(BankReference bankReference) {
this.bankReference = bankReference;
}
@Override
public InternalReference getInternalReference() {
return internalReference;
}
public void setInternalReference(InternalReference internalReference) {
this.internalReference = internalReference;
}
@Override
public Money getUnlinkedAmount() {
return unlinkedAmount;
}
@Override
public void setUnlinkedAmount(Money unlinkedAmount) {
this.unlinkedAmount = unlinkedAmount;
}
@Override
public LocalDate getMaturityDate() {
return maturityDate;
}
public void setMaturityDate(LocalDate maturityDate) {
this.maturityDate = maturityDate;
}
@Override
public BankDetails getBankDetails() {
return bankDetails;
}
public void setBankDetails(BankDetails bankDetails) {
this.bankDetails = bankDetails;
}
@Override
public Money getSpotRate() {
return spotRate;
}
public void setSpotRate(Money spotRate) {
this.spotRate = spotRate;
}
@Override
public Money getForwardRate() {
return forwardRate;
}
public void setForwardRate(Money forwardRate) {
this.forwardRate = forwardRate;
}
@Override
public boolean isConfirmed() {
return confirmed;
}
@Override
public FEC getParent() {
return parent;
}
@Override
public void setParent(FEC parent) {
this.parent = parent;
parent.addLeg((FEC) this);
}
@Override
public void addLeg(FEC ifec) {
fecLegs.add(ifec);
}
public FECType getType() {
return type;
}
public void setType(FECType type) {
this.type = type;
}
@Override
public LocalDate getDealDate() {
return dealDate;
}
public void setDealDate(LocalDate dealDate) {
this.dealDate = dealDate;
}
public void setAmount(Money amount) {
this.amount = amount;
}
public FECTransactionType getFecTransactionType() {
return fecTransactionType;
}
public void setFecTransactionType(FECTransactionType fecTransactionType) {
this.fecTransactionType = fecTransactionType;
}
@Override
public void unConfirm() {
confirmed = false;
confirmedDateTime = null;
}
@Override
public Currency getCurrency() {
return amount.getCurrency();
}
@Override
public Money getCostingRate() {
return costingRate;
}
@Override
public void setCostingRate(Money costingRate) {
this.costingRate = costingRate;
}
public FEC getExtensionPreDeliverPair() {
return extensionPreDeliverPair;
}
public void setExtensionPreDeliverPair(FEC extensionPreDeliverPair) {
this.extensionPreDeliverPair = extensionPreDeliverPair;
}
public Date getConfirmedDateTime() {
return confirmedDateTime;
}
public List<FEC> getFecLegs() {
return fecLegs;
}
public List<DealsEvent> getEvents() {
return events;
}
public void setEvents(List<DealsEvent> events) {
this.events = events;
}
@Override
public TreasuryBank getBank() {
return bankDetails.getTreasuryBank();
}
@Override
public void updateCurrency(com.tradecloud.domain.common.Currency dtoCurrency) {
this.amount = Money.valueOf(this.amount.getValue(), Currency.getInstance(dtoCurrency.getCode()));
this.unlinkedAmount = Money.valueOf(this.unlinkedAmount.getValue(), Currency.getInstance(dtoCurrency.getCode()));
}
}