/* * Copyright 2008 (C) Tom Parker <thpr@users.sourceforge.net> * * This library 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 2.1 of the License, or (at your option) * any later version. * * This library 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. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package pcgen.rules.persistence.util; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; import pcgen.rules.persistence.token.CDOMPrimaryToken; import pcgen.rules.persistence.token.CDOMToken; /** * An Iterator that increments across the CDOMPrimaryTokens in a given * TokenFamily. This is primarily used when items are "unparsed" (converted to * LST), since it is necessary to increment across ALL tokens in order to be * able to ensure that the object is fully written to a persistent format. * * Note that this Iterator "corrects" for the fact that parent classes can also * be used, meaning if an LST Token is registered against CDOMObject.class it * can be used on Race.class or Ability.class, etc. * * @param <C> * The Class of object for which this TokenFamilyIterator is * iterating over tokens (will be the class of the object being * loaded, such as Race or Ability) */ public class TokenFamilyIterator<C> implements Iterator<CDOMPrimaryToken<? super C>> { /** * The Object class, "cached" due to common use */ private static final Class<Object> OBJECT_CLASS = Object.class; /** * The next token to be returned by this TokenFamilyIterator (Note: is only * validly containing the next token when needNewToken is false) */ private CDOMPrimaryToken<? super C> nextToken = null; /** * True if nextToken has been used and needs to be refreshed */ private boolean needNewToken = true; /** * The "acting" class for which tokens are being retrieved. This can be * either the class being loaded (e.g. Race) or a parent Class (e.g. * CDOMObject). */ private Class<?> actingClass; /** * The underlying Iterator that is incrementing across the CDOMTokens in the * actingClass. */ private Iterator<CDOMToken<?>> subIterator; /** * The token names that have been used. This is necessary since a specific * class (e.g. Race) can have a "local" version of a token. If that local * version exists, then we MUST skip the version that is "more global" when * we do this Iterator, otherwise this Iterator will provide tokens that are * designed to be unreachable (And thus will produce errors) */ private final Set<String> used = new HashSet<>(); /** * Constructs a new TokenFamilyIterator for the given Class * * @param cl * The Class for which this TokenFamilyIterator will return * CDOMTokens. */ public TokenFamilyIterator(Class<C> cl) { actingClass = cl; subIterator = TokenFamily.CURRENT.getTokens(cl).iterator(); } /** * Returns the next CDOMPrimaryToken * * @see java.util.Iterator#next() */ @Override public CDOMPrimaryToken<? super C> next() { setNext(); if (nextToken == null) { throw new NoSuchElementException(); } needNewToken = true; return nextToken; } /** * Sets nextToken to be "valid", in the sense of determining the next token * that this TokenFamilyIterator needs to return */ private void setNext() { if (needNewToken) { nextToken = getNext(); if (nextToken != null) { String tokenName = nextToken.getTokenName(); if (used.contains(tokenName)) { /* * Don't use a super-class token in write */ needNewToken = true; setNext(); } else { used.add(nextToken.getTokenName()); } } } } /** * Returns the next eligible CDOMPrimaryToken. * * Note the eligible token may not be valid for use if it is a token for a * parent class and there was a more specific token already defined. * * @return The next eligible CDOMPrimaryToken */ private CDOMPrimaryToken<? super C> getNext() { needNewToken = false; while (subIterator.hasNext()) { CDOMToken<?> tok = subIterator.next(); if (tok instanceof CDOMPrimaryToken) { @SuppressWarnings("unchecked") CDOMPrimaryToken<? super C> pt = (CDOMPrimaryToken<? super C>) tok; return pt; } } if (OBJECT_CLASS.equals(actingClass)) { return null; } actingClass = actingClass.getSuperclass(); subIterator = TokenFamily.CURRENT.getTokens(actingClass).iterator(); return getNext(); } /** * @see java.util.Iterator#hasNext() */ @Override public boolean hasNext() { setNext(); return nextToken != null; } /** * Unsupported * * @see java.util.Iterator#remove() */ @Override public void remove() { throw new UnsupportedOperationException( "Iterator does not support remove"); } }