SchemaParticleImpl partImpl = (SchemaParticleImpl)contentModel;
if (partImpl.hasTransitionNotes())
return;
QNameSetBuilder start = new QNameSetBuilder();
QNameSetBuilder excludenext = new QNameSetBuilder();
boolean deterministic = true;
SchemaParticle[] children = null;
boolean canskip = (partImpl.getMinOccurs().signum() == 0);
switch (partImpl.getParticleType())
{
case SchemaParticle.ELEMENT:
// compute start and excludeNext; canskip is already correct
if (partImpl.hasTransitionRules())
start.addAll(partImpl.acceptedStartNames());
else
start.add(partImpl.getName());
break;
case SchemaParticle.WILDCARD:
// compute start and excludeNext; canskip is already correct
start.addAll(partImpl.getWildcardSet());
break;
case SchemaParticle.SEQUENCE:
children = ensureStateMachine(partImpl.getParticleChildren());
// adjust canskip if all children are skippable
canskip = true;
for (int i = 0; canskip && i < children.length; i++)
{
if (!(children[i]).isSkippable())
canskip = false;
}
// bubble up nondeterministic bit
for (int i = 0; deterministic && i < children.length; i++)
{
if (!((SchemaParticleImpl)children[i]).isDeterministic())
deterministic = false;
}
// verify deterministic and compute excludeNext set
for (int i = 1; i < children.length; i++)
{
excludenext.addAll(((SchemaParticleImpl)children[i - 1]).getExcludeNextSet());
if (deterministic && !excludenext.isDisjoint((children[i]).acceptedStartNames()))
deterministic = false;
if ((children[i]).isSkippable())
excludenext.addAll((children[i]).acceptedStartNames());
else
excludenext.clear();
}
// next, compute start set
for (int i = 0; i < children.length; i++)
{
start.addAll((children[i]).acceptedStartNames());
if (!(children[i]).isSkippable())
break;
}
break;
case SchemaParticle.CHOICE:
children = ensureStateMachine(partImpl.getParticleChildren());
// adjust canskip if any children are skippable
canskip = false;
for (int i = 0; !canskip && i < children.length; i++)
{
if ((children[i]).isSkippable())
canskip = true;
}
// bubble up nondeterministic bit
for (int i = 0; deterministic && i < children.length; i++)
{
if (!((SchemaParticleImpl)children[i]).isDeterministic())
deterministic = false;
}
// compute start and excludeNext sets, verify deterministic
for (int i = 0; i < children.length; i++)
{
if (deterministic && !start.isDisjoint((children[i]).acceptedStartNames()))
deterministic = false;
start.addAll((children[i]).acceptedStartNames());
excludenext.addAll(((SchemaParticleImpl)children[i]).getExcludeNextSet());
}
break;
case SchemaParticle.ALL:
children = ensureStateMachine(partImpl.getParticleChildren());
// adjust canskip if all children are skippable
canskip = true;
for (int i = 0; !canskip && i < children.length; i++)
{
if (!(children[i]).isSkippable())
canskip = false;
}
// bubble up nondeterministic bit
for (int i = 0; deterministic && i < children.length; i++)
{
if (!((SchemaParticleImpl)children[i]).isDeterministic())
deterministic = false;
}
// compute start and excludeNext sets, verify deterministic
for (int i = 0; i < children.length; i++)
{
if (deterministic && !start.isDisjoint((children[i]).acceptedStartNames()))
deterministic = false;
start.addAll((children[i]).acceptedStartNames());
excludenext.addAll(((SchemaParticleImpl)children[i]).getExcludeNextSet());
}
if (canskip)
excludenext.addAll(start);
break;
default:
// wildcard, all cases nyi
throw new IllegalStateException("Unrecognized schema particle");
}
// apply looping logic
BigInteger minOccurs = partImpl.getMinOccurs();
BigInteger maxOccurs = partImpl.getMaxOccurs();
boolean canloop = (maxOccurs == null || maxOccurs.compareTo(BigInteger.ONE) > 0);
boolean varloop = (maxOccurs == null || minOccurs.compareTo(maxOccurs) < 0);
if (canloop && deterministic && !excludenext.isDisjoint(start))
{
// we have a possible looping nondeterminism.
// let's take some time now to see if it's actually caused
// by non-unique-particle-attribute or not.
QNameSet suspectSet = excludenext.intersect(start);
// compute the set of all particles that could start this group
Map startMap = new HashMap();
particlesMatchingStart(partImpl, suspectSet, startMap, new QNameSetBuilder());
// compute the set of all particles that could have been repeated rather than ending this group
Map afterMap = new HashMap();
particlesMatchingAfter(partImpl, suspectSet, afterMap, new QNameSetBuilder(), true);
// see if we can find a member of after that is not a member of start
// if we can, then particle attribution is not unique
deterministic = afterMapSubsumedByStartMap(startMap, afterMap);
}
if (varloop)
excludenext.addAll(start);
canskip = canskip || minOccurs.signum() == 0;
partImpl.setTransitionRules(start.toQNameSet(), canskip);
partImpl.setTransitionNotes(excludenext.toQNameSet(), deterministic);
}