package de.persosim.simulator.cardobjects; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import de.persosim.simulator.exception.AccessDeniedException; import de.persosim.simulator.exception.LifeCycleChangeException; import de.persosim.simulator.exception.ObjectNotModifiedException; import de.persosim.simulator.secstatus.SecStatus; /** * Abstract superclass for most/all CardObjects. This implements handling of * bidirectional parent/child relation. * * @author amay * */ public abstract class AbstractCardObject implements CardObject { private CardObject parent; private List<CardObject> children = new ArrayList<>(); protected transient SecStatus securityStatus; private Iso7816LifeCycleState lifeCycleState = Iso7816LifeCycleState.CREATION; @Override public void setSecStatus(SecStatus securityStatus) throws AccessDeniedException { if (this.securityStatus != null && !lifeCycleState.isPersonalizationPhase()) { throw new AccessDeniedException("The security status can not be set after leaving the personalization phase"); } this.securityStatus = securityStatus; // forward the SecStatus to all children for (CardObject curChild : getChildren()) { curChild.setSecStatus(securityStatus); } } @Override public CardObject getParent() { return parent; } @Override public Collection<CardObject> getChildren() { return children; } /** * Add new child to the collection. * <p/> * This method also sets the SecStatus of the new child. If the new child is * of type AbstractCardObject also the parent is set. Overriding this method * requires calling {@link #addChild(CardObject)} of super or handling * setting of the security status for the object. Additionally the * implementation must be able to handle the {@link SecStatus} variable * being <code>null</code>. * * @param newChild * child to add to the collection * @throws AccessDeniedException */ public void addChild(CardObject newChild) throws AccessDeniedException { children.add(newChild); if (newChild instanceof AbstractCardObject) { ((AbstractCardObject) newChild).parent = this; } try { newChild.setSecStatus(securityStatus); } catch (AccessDeniedException e) { throw new ObjectNotModifiedException("A new child should have security access restriction that allows setting the security status"); } } @Override public CardObject removeChild(CardObject child) throws AccessDeniedException { if (children.contains(child)) { children.remove(child); if (child instanceof AbstractCardObject) { ((AbstractCardObject) child).parent = null; } return child; } return null; } @Override public Iso7816LifeCycleState getLifeCycleState() { return lifeCycleState; } @Override public void updateLifeCycleState(Iso7816LifeCycleState state) throws AccessDeniedException { if (lifeCycleState.isPersonalizationPhase() && state.equals(Iso7816LifeCycleState.OPERATIONAL_ACTIVATED)){ lifeCycleState = state; return; } switch (getLifeCycleState()) { case INITIALISATION: if (state.equals(Iso7816LifeCycleState.OPERATIONAL_ACTIVATED)) { lifeCycleState = state; return; } break; case CREATION: if(state.equals(Iso7816LifeCycleState.INITIALISATION) || state.equals(Iso7816LifeCycleState.OPERATIONAL_ACTIVATED)){ lifeCycleState = state; return; } break; case OPERATIONAL_ACTIVATED: if(state.equals(Iso7816LifeCycleState.OPERATIONAL_DEACTIVATED) || state.equals(Iso7816LifeCycleState.TERMINATION)){ lifeCycleState = state; return; } break; case OPERATIONAL_DEACTIVATED: if(state.equals(Iso7816LifeCycleState.OPERATIONAL_ACTIVATED) || state.equals(Iso7816LifeCycleState.TERMINATION)){ lifeCycleState = state; return; } break; default: break; } throw new LifeCycleChangeException("Change is not allowed.", lifeCycleState, state); } @Override public Collection<CardObject> findChildren(CardObjectIdentifier... cardObjectIdentifiers) { if(cardObjectIdentifiers.length == 0) {throw new IllegalArgumentException("must provide at least 1 identifier");} Collection<CardObject> matchingChildren = new ArrayList<>(); // check the immediate children of the current DF for (CardObject curChild : getChildren()) { if (CardObjectUtils.matches(curChild, cardObjectIdentifiers)) { matchingChildren.add(curChild); } } // if no fitting child has been found, collection is empty return matchingChildren; } @Override public Collection<CardObjectIdentifier> getAllIdentifiers() { HashSet<CardObjectIdentifier> set = new HashSet<>(); return set; } }