// count the actual values in the structure
int count = 0;
for (Item item = group.getFirstChild(); item != null; item = item.getNext()) {
// get the schema customization information
SchemaCustom custom = ((SchemaExtension)item.getSchemaComponent().getSchema().getExtension()).getCustom();
// handle inlining of references
if (item instanceof ReferenceItem) {
// first make sure the definition has been checked for inlining
ReferenceItem reference = (ReferenceItem)item;
DefinitionItem definition = reference.getDefinition();
checkInline(definition, depth + 1, defs);
if (definition.isInline()) {
// convert the reference to an inline copy of the definition
item = reference.inlineReference();
if (s_logger.isDebugEnabled()) {
s_logger.debug(SchemaUtils.getIndentation(depth) + "converted reference to "
+ SchemaUtils.describeComponent(definition.getSchemaComponent()) + " to inline group");
}
}
}
// handle actual item count, and inlining of child group (may be new, from converted reference)
if (item instanceof GroupItem) {
// check count for nested group
GroupItem grpitem = (GroupItem)item;
int grpcount = computeComplexity(grpitem, depth + 1, defs);
// avoid inlining if an enumeration, or an extension reference; or the nested group is optional or a
// collection and has more than one item (or a single item which is itself optional or a collection,
// which will be counted as multiple items); or the main group is a choice, and the nested group is a
// compositor with more than one element, and the first element is optional (or the first element child
// of that element, if inlined) - but allow override from customizations
boolean inline = true;
ComponentExtension exten = grpitem.getComponentExtension();
if (exten.isSeparateClass()) {
inline = false;
} else {
if (grpitem.isEnumeration()) {
inline = false;
} else if (grpitem.isCollection() || grpitem.isOptional()) {
if (grpcount > 1) {
inline = false;
} else {
// must be single child, but block inlining if that child is optional or an element or
// attribute with simple value (since we need an object for the optional part, separate
// from the simple value)
Item child;
GroupItem childgrp = grpitem;
boolean named = false;
while ((child = childgrp.getFirstChild()) instanceof GroupItem) {
childgrp = (GroupItem)child;
if (childgrp.isOptional()) {
inline = false;
break;
}
if (!named && childgrp.isTopmost()) {
int type = childgrp.getSchemaComponent().type();
named = type == SchemaBase.ATTRIBUTE_TYPE || type == SchemaBase.ELEMENT_TYPE;
}
}
if (named && child instanceof ValueItem) {
inline = false;
}
}
} else if (grpcount > 1 && group.getSchemaComponent().type() == SchemaBase.CHOICE_TYPE) {
// assume no inlining, but dig into structure to make sure first non-inlined element is required
inline = false;
Item child = grpitem.getFirstChild();
while (!child.isOptional()) {
if (child.getSchemaComponent().type() == SchemaBase.ELEMENT_TYPE &&
!(child instanceof GroupItem && ((GroupItem)child).isInline())) {
// required element with simple value or separate class, safe to inline
inline = true;
break;
} else if (child instanceof GroupItem) {
child = ((GroupItem)child).getFirstChild();
if (child == null) {
// empty group, safe to inline
inline = true;
break;
}
} else {
// required reference item, safe to inline
inline = true;
break;
}
}
}
}
if (inline) {
// inline the group
if (!grpitem.isInline()) {
grpitem.setInline(true);
}
count += grpcount;
if (s_logger.isDebugEnabled()) {
s_logger.debug(SchemaUtils.getIndentation(depth) + "inlining "
+ (grpitem instanceof DefinitionItem ? "definition " : "group ")
+ SchemaUtils.describeComponent(grpitem.getSchemaComponent()) + " with item count " +
count);
}
} else {
// force separate class for group
grpitem.setInline(false);
count++;
}
} else {
count++;
}
// bump up the complexity if the item is repeated (optionally inlining collection wrappers)
if (!custom.isNullCollectionAllowed() && item.isCollection()) {
count++;
}
}
return count > 1 ? 2 : count;
}