/**************************************************************************** * Copyright (C) 2012 ecsec GmbH. * All rights reserved. * Contact: ecsec GmbH (info@ecsec.de) * * This file is part of the Open eCard App. * * GNU General Public License Usage * This file may be used under the terms of the GNU General Public * License version 3.0 as published by the Free Software Foundation * and appearing in the file LICENSE.GPL included in the packaging of * this file. Please review the following information to ensure the * GNU General Public License version 3.0 requirements will be met: * http://www.gnu.org/copyleft/gpl.html. * * Other Usage * Alternatively, this file may be used in accordance with the terms * and conditions contained in a signed written agreement between * you and ecsec GmbH. * ***************************************************************************/ package org.openecard.common.util; import iso.std.iso_iec._24727.tech.schema.IFDStatusType; import iso.std.iso_iec._24727.tech.schema.SlotStatusType; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Tobias Wich <tobias.wich@ecsec.de> */ public class IFDStatusDiff { private static final Logger _logger = LoggerFactory.getLogger(IFDStatusDiff.class); private final List<IFDStatusType> expected; private List<IFDStatusType> result; private List<IFDStatusType> deleted; public IFDStatusDiff(List<IFDStatusType> expected) { this.expected = expected; } public static IFDStatusDiff diff(List<IFDStatusType> expected, List<IFDStatusType> others, boolean withNew) { IFDStatusDiff diff = new IFDStatusDiff(expected); diff.diff(others, withNew); return diff; } public void diff(List<IFDStatusType> others, boolean withNew) { result = new LinkedList<IFDStatusType>(); deleted = new LinkedList<IFDStatusType>(expected); for (IFDStatusType next : others) { String nextName = next.getIFDName(); if (expectedContains(nextName)) { // check for terminal connection IFDStatusType other = expectedGet(nextName); Boolean otherCard = other.isConnected(); boolean otherCardB = (otherCard == null) ? false : otherCard.booleanValue(); Boolean thisCard = next.isConnected(); boolean thisCardB = (thisCard == null) ? false : thisCard.booleanValue(); if (thisCardB != otherCardB) { result.add(next); } else { // check for card insertions or removals if (other.getSlotStatus().size() == next.getSlotStatus().size()) { for (SlotStatusType nextSlot : next.getSlotStatus()) { BigInteger thisSlotIdx = nextSlot.getIndex(); SlotStatusType otherSlot = null; for (SlotStatusType nextOtherSlot : other.getSlotStatus()) { if (thisSlotIdx.equals(nextOtherSlot.getIndex())) { otherSlot = nextOtherSlot; break; } } // no equivalent slot, only occurs on evolving terminals ;-) if (otherSlot == null) { result.add(next); break; } // compare card status of slot if (nextSlot.isCardAvailable() != otherSlot.isCardAvailable()) { result.add(next); break; } // compare if there are different cards in slot byte[] nextATR = nextSlot.getATRorATS(); byte[] otherATR = otherSlot.getATRorATS(); if (!(nextATR == null && otherATR == null) && !(IFDStatusDiff.arrayEquals(nextATR, otherATR))) { result.add(next); break; } } } } // delete card from deleted list deleted.remove(expectedGet(nextName)); } else if (withNew) { result.add(next); } } merge(deleted); } private static boolean arrayEquals(byte[] a, byte[] b) { if (a == null && b == null) { return false; } else { boolean result = Arrays.equals(a, b); return result; } } private IFDStatusType expectedGet(String ifdName) { for (IFDStatusType s : expected) { if (s.getIFDName().equals(ifdName)) { return s; } } return null; } private boolean expectedContains(String ifdName) { Boolean b = expectedGet(ifdName) != null; return b.booleanValue(); } private List<IFDStatusType> merge(List<IFDStatusType> deleted) { ArrayList<IFDStatusType> states = new ArrayList<IFDStatusType>(result.size() + deleted.size()); states.addAll(result); // transform all deleted terminals so it is clear they disappeared for (IFDStatusType next : deleted) { IFDStatusType s = new IFDStatusType(); s.setIFDName(next.getIFDName()); s.setConnected(Boolean.FALSE); // slots must be present too for (SlotStatusType nextST : next.getSlotStatus()) { SlotStatusType st = new SlotStatusType(); st.setIndex(nextST.getIndex()); st.setCardAvailable(Boolean.FALSE); s.getSlotStatus().add(st); } // add new deleted terminal type to states list states.add(s); } this.result = states; return states; } public boolean hasChanges() { if (this.result != null && !this.result.isEmpty()) { return true; } else { return false; } } public List<IFDStatusType> result() { return result; } }