/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.napile.idea.thermit.dom;
import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.napile.idea.thermit.AntIntrospector;
import org.napile.idea.thermit.ReflectedProject;
import org.napile.idea.thermit.ThermitClasses;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.PomTarget;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.xml.Convert;
import com.intellij.util.xml.Converter;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomTarget;
import com.intellij.util.xml.DummyEvaluatedXmlName;
import com.intellij.util.xml.EvaluatedXmlName;
import com.intellij.util.xml.GenericAttributeValue;
import com.intellij.util.xml.XmlName;
import com.intellij.util.xml.reflect.CustomDomChildrenDescription;
import com.intellij.util.xml.reflect.DomAttributeChildDescription;
import com.intellij.util.xml.reflect.DomExtender;
import com.intellij.util.xml.reflect.DomExtension;
import com.intellij.util.xml.reflect.DomExtensionsRegistrar;
import com.intellij.util.xml.reflect.DomGenericInfo;
/**
* @author Eugene Zhuravlev
* Date: Apr 9, 2010
*/
public class AntDomExtender extends DomExtender<AntDomElement>
{
private static final Logger LOG = Logger.getInstance("#org.napile.idea.thermit.dom.AntDomExtender");
private static final Key<Class> ELEMENT_IMPL_CLASS_KEY = Key.create("_element_impl_class_");
private static final Key<Boolean> IS_TASK_CONTAINER = Key.create("_task_container_");
private static final Map<String, Class<? extends AntDomElement>> TAG_MAPPING = new HashMap<String, Class<? extends AntDomElement>>();
static
{
TAG_MAPPING.put("property", AntDomProperty.class);
TAG_MAPPING.put("dirname", AntDomDirname.class);
TAG_MAPPING.put("fileset", AntDomFileSet.class);
TAG_MAPPING.put("dirset", AntDomDirSet.class);
TAG_MAPPING.put("filelist", AntDomFileList.class);
TAG_MAPPING.put("pathelement", AntDomPathElement.class);
TAG_MAPPING.put("path", AntDomPath.class);
TAG_MAPPING.put("classpath", AntDomClasspath.class);
TAG_MAPPING.put("typedef", AntDomTypeDef.class);
TAG_MAPPING.put("taskdef", AntDomTaskdef.class);
TAG_MAPPING.put("presetdef", AntDomPresetDef.class);
TAG_MAPPING.put("macrodef", AntDomMacroDef.class);
TAG_MAPPING.put("scriptdef", AntDomScriptDef.class);
TAG_MAPPING.put("antlib", AntDomAntlib.class);
TAG_MAPPING.put("thermit", AntDomAnt.class);
TAG_MAPPING.put("antcall", AntDomAntCall.class);
TAG_MAPPING.put("available", AntDomPropertyDefiningTaskWithDefaultValue.class);
TAG_MAPPING.put("condition", AntDomPropertyDefiningTaskWithDefaultValue.class);
TAG_MAPPING.put("uptodate", AntDomPropertyDefiningTaskWithDefaultValue.class);
TAG_MAPPING.put("checksum", AntDomChecksumTask.class);
TAG_MAPPING.put("loadfile", AntDomLoadFileTask.class);
TAG_MAPPING.put("whichresource", AntDomWhichResourceTask.class);
TAG_MAPPING.put("jarlib-resolve", AntDomPropertyDefiningTask.class);
TAG_MAPPING.put("p4counter", AntDomPropertyDefiningTask.class);
TAG_MAPPING.put("pathconvert", AntDomPropertyDefiningTask.class);
TAG_MAPPING.put("basename", AntDomBasenameTask.class);
TAG_MAPPING.put("length", AntDomLengthTask.class);
TAG_MAPPING.put("tempfile", AntDomTempFile.class);
TAG_MAPPING.put("exec", AntDomExecTask.class);
TAG_MAPPING.put("buildnumber", AntDomBuildnumberTask.class);
TAG_MAPPING.put("tstamp", AntDomTimestampTask.class);
TAG_MAPPING.put("format", AntDomTimestampTaskFormat.class);
TAG_MAPPING.put("input", AntDomInputTask.class);
}
public void registerExtensions(@NotNull final AntDomElement antDomElement, @NotNull DomExtensionsRegistrar registrar)
{
final XmlElement xmlElement = antDomElement.getXmlElement();
if(xmlElement instanceof XmlTag)
{
final XmlTag xmlTag = (XmlTag) xmlElement;
final String tagName = xmlTag.getName();
final AntDomProject antProject = antDomElement.getAntProject();
if(antProject == null)
{
return;
}
final ReflectedProject reflected = ReflectedProject.getProject(antProject.getClassLoader());
if(reflected.getProject() == null)
{
return;
}
final DomGenericInfo genericInfo = antDomElement.getGenericInfo();
AntIntrospector classBasedIntrospector = null;
final Hashtable<String, Class> coreTaskDefs = reflected.getTaskDefinitions();
final Hashtable<String, Class> coreTypeDefs = reflected.getDataTypeDefinitions();
final boolean isCustom = antDomElement instanceof AntDomCustomElement;
if("project".equals(tagName))
{
classBasedIntrospector = getIntrospector(reflected.getProject().getClass());
}
else if("target".equals(tagName))
{
classBasedIntrospector = getIntrospector(reflected.getTargetClass());
}
else
{
if(isCustom)
{
final AntDomCustomElement custom = (AntDomCustomElement) antDomElement;
final Class definitionClass = custom.getDefinitionClass();
if(definitionClass != null)
{
classBasedIntrospector = getIntrospector(definitionClass);
}
}
else
{
Class elemType = antDomElement.getChildDescription().getUserData(ELEMENT_IMPL_CLASS_KEY);
if(elemType == null)
{
if(coreTaskDefs != null)
{
elemType = coreTaskDefs.get(tagName);
}
}
if(elemType == null)
{
if(coreTypeDefs != null)
{
elemType = coreTypeDefs.get(tagName);
}
}
if(elemType != null)
{
classBasedIntrospector = getIntrospector(elemType);
}
}
}
AbstractIntrospector parentIntrospector = null;
if(classBasedIntrospector != null)
{
parentIntrospector = new ClassIntrospectorAdapter(classBasedIntrospector, coreTaskDefs, coreTypeDefs);
}
else
{
if(isCustom)
{
final AntDomNamedElement declaringElement = ((AntDomCustomElement) antDomElement).getDeclaringElement();
if(declaringElement instanceof AntDomMacroDef)
{
parentIntrospector = new MacrodefIntrospectorAdapter((AntDomMacroDef) declaringElement);
}
else if(declaringElement instanceof AntDomMacrodefElement)
{
parentIntrospector = new MacrodefElementOccurrenceIntrospectorAdapter((AntDomMacrodefElement) declaringElement)/*ContainerElementIntrospector.INSTANCE*/;
}
else if(declaringElement instanceof AntDomScriptDef)
{
parentIntrospector = new ScriptdefIntrospectorAdapter((AntDomScriptDef) declaringElement);
}
}
}
if(parentIntrospector != null)
{
defineAttributes(xmlTag, registrar, genericInfo, parentIntrospector);
if("project".equals(tagName) || parentIntrospector.isContainer())
{ // can contain any task or/and type definition
if(coreTaskDefs != null)
{
for(Map.Entry<String, Class> entry : coreTaskDefs.entrySet())
{
final DomExtension extension = registerChild(registrar, genericInfo, entry.getKey());
if(extension != null)
{
final Class type = entry.getValue();
if(type != null)
{
extension.putUserData(ELEMENT_IMPL_CLASS_KEY, type);
}
extension.putUserData(AntDomElement.ROLE, AntDomElement.Role.TASK);
}
}
}
if(coreTypeDefs != null)
{
for(Map.Entry<String, Class> entry : coreTypeDefs.entrySet())
{
final DomExtension extension = registerChild(registrar, genericInfo, entry.getKey());
if(extension != null)
{
final Class type = entry.getValue();
if(type != null)
{
extension.putUserData(ELEMENT_IMPL_CLASS_KEY, type);
}
extension.putUserData(AntDomElement.ROLE, AntDomElement.Role.DATA_TYPE);
}
}
}
registrar.registerCustomChildrenExtension(AntDomCustomElement.class, new AntCustomTagNameDescriptor());
}
else
{
final Iterator<String> nested = parentIntrospector.getNestedElementsIterator();
while(nested.hasNext())
{
final String nestedElementName = nested.next();
final DomExtension extension = registerChild(registrar, genericInfo, nestedElementName);
if(extension != null)
{
Class type = parentIntrospector.getNestedElementType(nestedElementName);
if(type != null && CommonClassNames.JAVA_LANG_OBJECT.equals(type.getName()))
{
type = null; // hack to support badly written tasks
}
if(type == null)
{
if(coreTypeDefs != null)
{
type = coreTypeDefs.get(nestedElementName);
}
}
if(type != null)
{
extension.putUserData(ELEMENT_IMPL_CLASS_KEY, type);
}
AntDomElement.Role role = AntDomElement.Role.DATA_TYPE;
if(coreTaskDefs != null && coreTaskDefs.containsKey(nestedElementName))
{
role = AntDomElement.Role.TASK;
}
else if(type != null && isAssignableFrom(ThermitClasses.Task, type))
{
role = AntDomElement.Role.TASK;
}
if(role != null)
{
extension.putUserData(AntDomElement.ROLE, role);
}
}
}
registrar.registerCustomChildrenExtension(AntDomCustomElement.class, new AntCustomTagNameDescriptor());
}
}
}
}
private static void defineAttributes(XmlTag xmlTag, DomExtensionsRegistrar registrar, DomGenericInfo genericInfo, AbstractIntrospector parentIntrospector)
{
final Map<String, Pair<Type, Class>> registeredAttribs = getStaticallyRegisteredAttributes(genericInfo);
// define attributes discovered by introspector and not yet defined statically
final Iterator<String> introspectedAttributes = parentIntrospector.getAttributesIterator();
while(introspectedAttributes.hasNext())
{
final String attribName = introspectedAttributes.next();
if(genericInfo.getAttributeChildDescription(attribName) == null)
{ // if not defined yet
final String _attribName = attribName.toLowerCase(Locale.US);
final Pair<Type, Class> types = registeredAttribs.get(_attribName);
Type type = types != null ? types.getFirst() : null;
Class converterClass = types != null ? types.getSecond() : null;
if(type == null)
{
type = String.class; // use String by default
final Class attributeType = parentIntrospector.getAttributeType(attribName);
if(attributeType != null)
{
// handle well-known types
if(File.class.isAssignableFrom(attributeType))
{
type = PsiFileSystemItem.class;
converterClass = AntPathConverter.class;
}
else if(Boolean.class.isAssignableFrom(attributeType))
{
type = Boolean.class;
converterClass = AntBooleanConverter.class;
}
}
}
LOG.assertTrue(type != null);
registerAttribute(registrar, attribName, type, converterClass);
if(types == null)
{ // augment the map if this was a newly added attribute
registeredAttribs.put(_attribName, new Pair<Type, Class>(type, converterClass));
}
}
}
// handle attribute case problems:
// additionaly register all attributes that exist in XML but differ from the registered ones only in case
for(XmlAttribute xmlAttribute : xmlTag.getAttributes())
{
final String existingAttribName = xmlAttribute.getName();
if(genericInfo.getAttributeChildDescription(existingAttribName) == null)
{
final Pair<Type, Class> pair = registeredAttribs.get(existingAttribName.toLowerCase(Locale.US));
if(pair != null)
{ // if such attribute should actually be here
registerAttribute(registrar, existingAttribName, pair.getFirst(), pair.getSecond());
}
}
}
}
private static void registerAttribute(DomExtensionsRegistrar registrar, String attribName, final @NotNull Type attributeType, final @Nullable Class converterType)
{
final DomExtension extension = registrar.registerGenericAttributeValueChildExtension(new XmlName(attribName), attributeType);
if(converterType != null)
{
try
{
extension.setConverter((Converter) converterType.newInstance());
}
catch(InstantiationException e)
{
LOG.info(e);
}
catch(IllegalAccessException e)
{
LOG.info(e);
}
}
}
private static Map<String, Pair<Type, Class>> getStaticallyRegisteredAttributes(final DomGenericInfo genericInfo)
{
final Map<String, Pair<Type, Class>> map = new HashMap<String, Pair<Type, Class>>();
for(DomAttributeChildDescription description : genericInfo.getAttributeChildrenDescriptions())
{
final Type type = description.getType();
if(type instanceof ParameterizedType)
{
final Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
if(typeArguments.length == 1)
{
String name = description.getXmlElementName();
final Type attribType = typeArguments[0];
Class<? extends Converter> converterType = null;
final Convert converterAnnotation = description.getAnnotation(Convert.class);
if(converterAnnotation != null)
{
converterType = converterAnnotation.value();
}
map.put(name.toLowerCase(Locale.US), new Pair<Type, Class>(attribType, converterType));
}
}
}
return map;
}
@Nullable
private static DomExtension registerChild(DomExtensionsRegistrar registrar, DomGenericInfo elementInfo, String childName)
{
if(elementInfo.getCollectionChildDescription(childName) == null)
{ // register if not yet defined statically
Class<? extends AntDomElement> modelClass = getModelClass(childName);
if(modelClass == null)
{
modelClass = AntDomElement.class;
}
return registrar.registerCollectionChildrenExtension(new XmlName(childName), modelClass);
}
return null;
}
@Nullable
public static AntIntrospector getIntrospector(Class c)
{
try
{
return AntIntrospector.getInstance(c);
}
catch(Throwable ignored)
{
ignored.printStackTrace();
}
return null;
}
@Nullable
private static Class<? extends AntDomElement> getModelClass(@NotNull String tagName)
{
return TAG_MAPPING.get(tagName.toLowerCase(Locale.US));
}
private static boolean isAssignableFrom(final String baseClassName, final Class clazz)
{
try
{
final ClassLoader loader = clazz.getClassLoader();
if(loader != null)
{
final Class baseClass = loader.loadClass(baseClassName);
return baseClass.isAssignableFrom(clazz);
}
}
catch(ClassNotFoundException ignored)
{
}
return false;
}
private static class AntCustomTagNameDescriptor extends CustomDomChildrenDescription.TagNameDescriptor
{
public Set<EvaluatedXmlName> getCompletionVariants(@NotNull DomElement parent)
{
if(!(parent instanceof AntDomElement))
{
return Collections.emptySet();
}
final AntDomElement element = (AntDomElement) parent;
final AntDomProject antDomProject = element.getAntProject();
if(antDomProject == null)
{
return Collections.emptySet();
}
final CustomAntElementsRegistry registry = CustomAntElementsRegistry.getInstance(antDomProject);
final Set<EvaluatedXmlName> result = new HashSet<EvaluatedXmlName>();
for(XmlName variant : registry.getCompletionVariants(element))
{
final String ns = variant.getNamespaceKey();
result.add(new DummyEvaluatedXmlName(variant, ns != null ? ns : ""));
}
return result;
}
@Nullable
public PomTarget findDeclaration(DomElement parent, @NotNull EvaluatedXmlName name)
{
final XmlName xmlName = name.getXmlName();
return doFindDeclaration(parent, xmlName);
}
@Nullable
public PomTarget findDeclaration(@NotNull DomElement child)
{
XmlName name = new XmlName(child.getXmlElementName(), child.getXmlElementNamespace());
return doFindDeclaration(child.getParent(), name);
}
@Nullable
private static PomTarget doFindDeclaration(DomElement parent, XmlName xmlName)
{
if(!(parent instanceof AntDomElement))
{
return null;
}
final AntDomElement parentElement = (AntDomElement) parent;
final AntDomProject antDomProject = parentElement.getAntProject();
if(antDomProject == null)
{
return null;
}
final CustomAntElementsRegistry registry = CustomAntElementsRegistry.getInstance(antDomProject);
final AntDomElement declaringElement = registry.findDeclaringElement(parentElement, xmlName);
if(declaringElement == null)
{
return null;
}
DomTarget target = DomTarget.getTarget(declaringElement);
if(target == null && declaringElement instanceof AntDomTypeDef)
{
final AntDomTypeDef typedef = (AntDomTypeDef) declaringElement;
final GenericAttributeValue<PsiFileSystemItem> resource = typedef.getResource();
if(resource != null)
{
target = DomTarget.getTarget(declaringElement, resource);
}
if(target == null)
{
final GenericAttributeValue<PsiFileSystemItem> file = typedef.getFile();
if(file != null)
{
target = DomTarget.getTarget(declaringElement, file);
}
}
}
return target;
}
}
private static abstract class AbstractIntrospector
{
@NotNull
public Iterator<String> getAttributesIterator()
{
return Collections.<String>emptyList().iterator();
}
@NotNull
public Iterator<String> getNestedElementsIterator()
{
return Collections.<String>emptyList().iterator();
}
public abstract boolean isContainer();
@Nullable
public Class getAttributeType(String attribName)
{
return null;
}
@Nullable
public Class getNestedElementType(String elementName)
{
return null;
}
}
private static class ClassIntrospectorAdapter extends AbstractIntrospector
{
private final AntIntrospector myIntrospector;
private final Map<String, Class> myCoreTaskDefs;
private final Map<String, Class> myCoreTypeDefs;
private List<String> myNestedElements;
private Map<String, Class> myNestedElementTypes;
private ClassIntrospectorAdapter(AntIntrospector introspector)
{
this(introspector, null, null);
}
public ClassIntrospectorAdapter(AntIntrospector introspector, Map<String, Class> coreTaskDefs, Map<String, Class> coreTypeDefs)
{
myIntrospector = introspector;
myCoreTaskDefs = coreTaskDefs != null ? coreTaskDefs : Collections.<String, Class>emptyMap();
myCoreTypeDefs = coreTypeDefs != null ? coreTypeDefs : Collections.<String, Class>emptyMap();
}
@NotNull
public Iterator<String> getAttributesIterator()
{
return new EnumerationToIteratorAdapter<String>(myIntrospector.getAttributes());
}
public Class getAttributeType(String attribName)
{
return myIntrospector.getAttributeType(attribName);
}
public boolean isContainer()
{
return myIntrospector.isContainer();
}
@NotNull
public Iterator<String> getNestedElementsIterator()
{
initNestedElements();
return myNestedElements.iterator();
}
public Class getNestedElementType(String attribName)
{
initNestedElements();
return myNestedElementTypes.get(attribName);
}
private void initNestedElements()
{
if(myNestedElements != null)
{
return;
}
myNestedElements = new ArrayList<String>();
myNestedElementTypes = new HashMap<String, Class>();
final Enumeration<String> nestedElements = myIntrospector.getNestedElements();
while(nestedElements.hasMoreElements())
{
final String elemName = nestedElements.nextElement();
myNestedElements.add(elemName);
myNestedElementTypes.put(elemName, myIntrospector.getElementType(elemName));
}
final Set<String> extensionPointTypes = myIntrospector.getExtensionPointTypes();
for(String extPoint : extensionPointTypes)
{
processEntries(extPoint, myCoreTaskDefs);
processEntries(extPoint, myCoreTypeDefs);
}
}
private void processEntries(String extPoint, final Map<String, Class> definitions)
{
for(Map.Entry<String, Class> entry : definitions.entrySet())
{
final String elementName = entry.getKey();
final Class taskClass = entry.getValue();
if(isAssignableFrom(extPoint, taskClass))
{
myNestedElements.add(elementName);
myNestedElementTypes.put(elementName, taskClass);
}
}
}
}
private static class MacrodefIntrospectorAdapter extends AbstractIntrospector
{
private final AntDomMacroDef myMacrodef;
private MacrodefIntrospectorAdapter(AntDomMacroDef macrodef)
{
myMacrodef = macrodef;
}
@NotNull
public Iterator<String> getAttributesIterator()
{
final List<AntDomMacrodefAttribute> macrodefAttributes = myMacrodef.getMacroAttributes();
if(macrodefAttributes.size() == 0)
{
return Collections.<String>emptyList().iterator();
}
final List<String> attribs = new ArrayList<String>(macrodefAttributes.size());
for(AntDomMacrodefAttribute attribute : macrodefAttributes)
{
final String attribName = attribute.getName().getRawText();
if(attribName != null)
{
attribs.add(attribName);
}
}
return attribs.iterator();
}
public boolean isContainer()
{
for(AntDomMacrodefElement element : myMacrodef.getMacroElements())
{
final GenericAttributeValue<Boolean> implicit = element.isImplicit();
if(implicit != null && Boolean.TRUE.equals(implicit.getValue()))
{
return true;
}
}
return false;
}
}
private static class MacrodefElementOccurrenceIntrospectorAdapter extends AbstractIntrospector
{
private final AntDomMacrodefElement myElement;
private volatile List<AbstractIntrospector> myContexts;
private volatile Map<String, Class> myChildrenMap;
private MacrodefElementOccurrenceIntrospectorAdapter(AntDomMacrodefElement element)
{
myElement = element;
}
public boolean isContainer()
{
final List<AbstractIntrospector> contexts = getContexts();
for(AbstractIntrospector context : contexts)
{
if(!context.isContainer())
{
return false;
}
}
return true;
}
@NotNull
public Iterator<String> getNestedElementsIterator()
{
return getNestedElementsMap().keySet().iterator();
}
public Class getNestedElementType(String elementName)
{
return getNestedElementsMap().get(elementName);
}
private Map<String, Class> getNestedElementsMap()
{
if(myChildrenMap != null)
{
return myChildrenMap;
}
final List<AbstractIntrospector> contexts = getContexts();
Map<String, Class> names = null;
for(AbstractIntrospector context : contexts)
{
if(context.isContainer())
{
continue;
}
final Set<String> set = new HashSet<String>();
for(Iterator<String> it = context.getNestedElementsIterator(); it.hasNext(); )
{
final String name = it.next();
set.add(name);
}
if(names == null)
{
names = new HashMap<String, Class>();
for(String s : set)
{
names.put(s, context.getNestedElementType(s));
}
}
else
{
names.keySet().retainAll(set);
}
}
final Map<String, Class> result = names == null ? Collections.<String, Class>emptyMap() : names;
return myChildrenMap = result;
}
private List<AbstractIntrospector> getContexts()
{
if(myContexts != null)
{
return myContexts;
}
final List<AbstractIntrospector> parents = new ArrayList<AbstractIntrospector>();
final AntDomMacroDef macroDef = myElement.getParentOfType(AntDomMacroDef.class, true);
if(macroDef != null)
{
final AntDomSequentialTask body = macroDef.getMacroBody();
if(body != null)
{
body.accept(new AntDomRecursiveVisitor()
{
public void visitAntDomCustomElement(AntDomCustomElement custom)
{
if(myElement.equals(custom.getDeclaringElement()))
{
final AntDomElement parent = custom.getParentOfType(AntDomElement.class, true);
if(parent != null)
{
final Class type = parent.getChildDescription().getUserData(ELEMENT_IMPL_CLASS_KEY);
if(type != null)
{
final AntIntrospector antIntrospector = AntIntrospector.getInstance(type);
if(antIntrospector != null)
{
parents.add(new ClassIntrospectorAdapter(antIntrospector));
}
}
}
}
}
});
}
}
return myContexts = parents;
}
}
private static class ScriptdefIntrospectorAdapter extends AbstractIntrospector
{
private final AntDomScriptDef myScriptDef;
private ScriptdefIntrospectorAdapter(AntDomScriptDef scriptDef)
{
myScriptDef = scriptDef;
}
@NotNull
public Iterator<String> getAttributesIterator()
{
final List<AntDomScriptdefAttribute> macrodefAttributes = myScriptDef.getScriptdefAttributes();
final List<String> attribs = new ArrayList<String>(macrodefAttributes.size());
for(AntDomScriptdefAttribute attribute : macrodefAttributes)
{
final String nameAttrib = attribute.getName().getRawText();
if(nameAttrib != null)
{
attribs.add(nameAttrib);
}
}
return attribs.iterator();
}
public boolean isContainer()
{
return false;
}
}
private static class ContainerElementIntrospector extends AbstractIntrospector
{
public static final ContainerElementIntrospector INSTANCE = new ContainerElementIntrospector();
public boolean isContainer()
{
return true;
}
}
private static class EnumerationToIteratorAdapter<T> implements Iterator<T>
{
private final Enumeration<T> myEnum;
public EnumerationToIteratorAdapter(Enumeration<T> enumeration)
{
myEnum = enumeration;
}
public boolean hasNext()
{
return myEnum.hasMoreElements();
}
public T next()
{
return myEnum.nextElement();
}
public void remove()
{
throw new UnsupportedOperationException("remove is not supported");
}
}
}