geronimo-xbean-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dblev...@apache.org
Subject svn commit: r1038273 - in /geronimo/xbean/trunk/xbean-finder/src: main/java/org/apache/xbean/finder/ test/java/org/apache/xbean/finder/
Date Tue, 23 Nov 2010 18:49:33 GMT
Author: dblevins
Date: Tue Nov 23 18:49:32 2010
New Revision: 1038273

URL: http://svn.apache.org/viewvc?rev=1038273&view=rev
Log:
XBEAN-160: Find subclasses
XBEAN-159: Find implementations
XBEAN-158: Reduced memory footprint via singly-linked lists

Added:
    geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/SingleLinkedList.java
  (with props)
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderDepthTest.java
  (with props)
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SingleLinkedListTest.java
  (with props)
Modified:
    geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AbstractFinder.java
    geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java

Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AbstractFinder.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AbstractFinder.java?rev=1038273&r1=1038272&r2=1038273&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AbstractFinder.java
(original)
+++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/AbstractFinder.java
Tue Nov 23 18:49:32 2010
@@ -31,6 +31,7 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -47,7 +48,7 @@ import org.objectweb.asm.signature.Signa
  */
 public abstract class AbstractFinder {
     private final Map<String, List<Info>> annotated = new HashMap<String,
List<Info>>();
-    protected final List<ClassInfo> classInfos = new ArrayList<ClassInfo>();
+    protected final Map<String, ClassInfo> classInfos = new HashMap<String, ClassInfo>();
     private final List<String> classesNotLoaded = new ArrayList<String>();
     private final int ASM_FLAGS = ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES;
 
@@ -55,6 +56,98 @@ public abstract class AbstractFinder {
 
     protected abstract Class<?> loadClass(String fixedName) throws ClassNotFoundException;
 
+    /**
+     * The link() method must be called to successfully use the findSubclasses and findImplementations
methods
+     * @return
+     * @throws IOException
+     */
+    public AbstractFinder link() throws IOException {
+        for (ClassInfo classInfo : classInfos.values().toArray(new ClassInfo[classInfos.size()]))
{
+
+            linkParent(classInfo);
+        }
+
+        for (ClassInfo classInfo : classInfos.values().toArray(new ClassInfo[classInfos.size()]))
{
+
+            linkInterfaces(classInfo);
+        }
+
+        return this;
+    }
+
+    private void linkParent(ClassInfo classInfo) throws IOException {
+        if (classInfo.superType == null) return;
+        if (classInfo.superType.equals("java.lang.Object")) return;
+        
+        ClassInfo parentInfo = classInfo.superclassInfo;
+
+        if (parentInfo == null) {
+
+            parentInfo = classInfos.get(classInfo.superType);
+
+            if (parentInfo == null) {
+
+                if (classInfo.clazz != null) {
+                    readClassDef(((Class<?>) classInfo.clazz).getSuperclass());
+                } else {
+                    readClassDef(classInfo.superType);
+                }
+
+                parentInfo = classInfos.get(classInfo.superType);
+
+                if (parentInfo == null) return;
+                
+                linkParent(parentInfo);
+            }
+
+            classInfo.superclassInfo = parentInfo;
+        }
+
+        if (!parentInfo.subclassInfos.contains(classInfo)) {
+            parentInfo.subclassInfos.add(classInfo);
+        }
+    }
+
+    private void linkInterfaces(ClassInfo classInfo) throws IOException {
+        final List<ClassInfo> infos = new ArrayList<ClassInfo>();
+
+        if (classInfo.clazz != null){
+            final Class<?>[] interfaces = classInfo.clazz.getInterfaces();
+
+            for (Class<?> clazz : interfaces) {
+                ClassInfo interfaceInfo = classInfos.get(clazz.getName());
+
+                if (interfaceInfo == null){
+                    readClassDef(clazz);
+                }
+
+                interfaceInfo = classInfos.get(clazz.getName());
+
+                if (interfaceInfo != null) {
+                    infos.add(interfaceInfo);
+                }
+            }
+        } else {
+            for (String className : classInfo.interfaces) {
+                ClassInfo interfaceInfo = classInfos.get(className);
+
+                if (interfaceInfo == null){
+                    readClassDef(className);
+                }
+
+                interfaceInfo = classInfos.get(className);
+
+                if (interfaceInfo != null) {
+                    infos.add(interfaceInfo);
+                }
+            }
+        }
+
+        for (ClassInfo info : infos) {
+            linkInterfaces(info);
+        }
+    }
+
     public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
         List<Info> infos = annotated.get(annotation.getName());
         return infos != null && !infos.isEmpty();
@@ -138,7 +231,7 @@ public abstract class AbstractFinder {
             }
         }
         boolean annClassFound;
-        List<ClassInfo> tempClassInfos = new ArrayList<ClassInfo>(classInfos);
+        List<ClassInfo> tempClassInfos = new ArrayList<ClassInfo>(classInfos.values());
         do {
             annClassFound = false;
             for (int pos = 0; pos < tempClassInfos.size(); pos++) {
@@ -266,7 +359,7 @@ public abstract class AbstractFinder {
     public List<Class> findClassesInPackage(String packageName, boolean recursive)
{
         classesNotLoaded.clear();
         List<Class> classes = new ArrayList<Class>();
-        for (ClassInfo classInfo : classInfos) {
+        for (ClassInfo classInfo : classInfos.values()) {
             try {
                 if (recursive && classInfo.getPackageName().startsWith(packageName)){
                     classes.add(classInfo.get());
@@ -280,20 +373,201 @@ public abstract class AbstractFinder {
         return classes;
     }
 
+    public <T> List<Class<? extends T>> findSubclasses(Class<T> clazz)
{
+        if (clazz == null) throw new NullPointerException("class cannot be null");
+
+        classesNotLoaded.clear();
+
+        final ClassInfo classInfo = classInfos.get(clazz.getName());
+
+        List<Class<? extends T>> found = new ArrayList<Class<? extends
T>>();
+        List<Class<? extends T>> found2 = new LinkedList<Class<? extends
T>>();
+
+        if (classInfo == null) return found;
+
+        findSubclasses(classInfo, found);
+
+        return found;
+    }
+
+    private <T> void findSubclasses(ClassInfo classInfo, List<Class<? extends
T>> found) {
+
+        for (ClassInfo subclassInfo : classInfo.subclassInfos) {
+
+            try {
+                found.add(subclassInfo.get());
+            } catch (ClassNotFoundException e) {
+                classesNotLoaded.add(subclassInfo.getName());
+            }
+
+            findSubclasses(subclassInfo, found);
+        }
+    }
+
+    private <T> List<Class<? extends T>> _findSubclasses(Class<T>
clazz) {
+        if (clazz == null) throw new NullPointerException("class cannot be null");
+
+        List<Class<? extends T>> classes = new ArrayList<Class<? extends
T>>();
+
+
+        for (ClassInfo classInfo : classInfos.values()) {
+
+            try {
+
+                if (clazz.getName().equals(classInfo.superType)) {
+
+                    if (clazz.isAssignableFrom(classInfo.get())) {
+
+                        classes.add(classInfo.get());
+
+                        classes.addAll(_findSubclasses(classInfo.get()));
+                    }
+                }
+
+            } catch (ClassNotFoundException e) {
+                classesNotLoaded.add(classInfo.getName());
+            }
+
+        }
+
+        return classes;
+    }
+
+    public <T> List<Class<? extends T>> findImplementations(Class<T>
clazz) {
+        if (clazz == null) throw new NullPointerException("class cannot be null");
+        if (!clazz.isInterface()) new IllegalArgumentException("class must be an interface");
+        classesNotLoaded.clear();
+
+        final String interfaceName = clazz.getName();
+
+        // Collect all interfaces extending the main interface (recursively)
+        // Collect all implementations of interfaces
+        // i.e. all *directly* implementing classes
+        List<ClassInfo> infos = collectImplementations(interfaceName);
+
+        // Collect all subclasses of implementations
+        List<Class<? extends T>> classes = new ArrayList<Class<? extends
T>>();
+        for (ClassInfo info : infos) {
+            try {
+                final Class<? extends T> impl = (Class<? extends T>) info.get();
+
+                if (clazz.isAssignableFrom(impl)) {
+                    classes.add(impl);
+
+                    // Optimization: Don't need to call this method if parent class was already
searched
+
+
+
+                    classes.addAll(_findSubclasses(impl));
+                }
+
+            } catch (ClassNotFoundException e) {
+                classesNotLoaded.add(info.getName());
+            }
+        }
+        return classes;
+    }
+
+    private List<ClassInfo> collectImplementations(String interfaceName) {
+        final List<ClassInfo> infos = new ArrayList<ClassInfo>();
+
+        for (ClassInfo classInfo : classInfos.values()) {
+
+            if (classInfo.interfaces.contains(interfaceName)) {
+
+                infos.add(classInfo);
+
+                try {
+
+                    final Class clazz = classInfo.get();
+
+                    if (clazz.isInterface() && !clazz.isAnnotation()) {
+
+                        infos.addAll(collectImplementations(classInfo.name));
+
+                    }
+                    
+                } catch (ClassNotFoundException ignore) {
+                    // we'll deal with this later
+                }
+            }
+        }
+        return infos;
+    }
+
     protected List<Info> getAnnotationInfos(String name) {
         List<Info> infos = annotated.get(name);
         if (infos == null) {
-            infos = new ArrayList<Info>();
+            infos = new SingleLinkedList<Info>();
             annotated.put(name, infos);
         }
         return infos;
     }
 
+    protected void readClassDef(String className) {
+        if (!className.endsWith(".class")) {
+            className = className.replace('.', '/') + ".class";
+        }
+        try {
+            URL resource = getResource(className);
+            if (resource != null) {
+                InputStream in = resource.openStream();
+                try {
+                    readClassDef(in);
+                } finally {
+                    in.close();
+                }
+            } else {
+                new Exception("Could not load " + className).printStackTrace();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+
     protected void readClassDef(InputStream in) throws IOException {
         ClassReader classReader = new ClassReader(in);
         classReader.accept(new InfoBuildingVisitor(), ASM_FLAGS);
     }
 
+    protected void readClassDef(Class clazz) {
+        List<Info> infos = new ArrayList<Info>();
+
+        Package aPackage = clazz.getPackage();
+        if (aPackage != null){
+            final PackageInfo info = new PackageInfo(aPackage);
+            for (AnnotationInfo annotation : info.getAnnotations()) {
+                List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
+                if (!annotationInfos.contains(info)) {
+                    annotationInfos.add(info);
+                }
+            }
+        }
+
+        ClassInfo classInfo = new ClassInfo(clazz);
+        infos.add(classInfo);
+        classInfos.put(clazz.getName(), classInfo);
+        for (Method method : clazz.getDeclaredMethods()) {
+            infos.add(new MethodInfo(classInfo, method));
+        }
+
+        for (Constructor constructor : clazz.getConstructors()) {
+            infos.add(new MethodInfo(classInfo, constructor));
+        }
+
+        for (Field field : clazz.getDeclaredFields()) {
+            infos.add(new FieldInfo(classInfo, field));
+        }
+
+        for (Info info : infos) {
+            for (AnnotationInfo annotation : info.getAnnotations()) {
+                List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
+                annotationInfos.add(info);
+            }
+        }
+    }
+
     public class Annotatable {
         private final List<AnnotationInfo> annotations = new ArrayList<AnnotationInfo>();
 
@@ -343,17 +617,35 @@ public abstract class AbstractFinder {
         public Package get() throws ClassNotFoundException {
             return (pkg != null)?pkg:info.get().getPackage();
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            PackageInfo that = (PackageInfo) o;
+
+            if (name != null ? !name.equals(that.name) : that.name != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return name != null ? name.hashCode() : 0;
+        }
     }
 
     public class ClassInfo extends Annotatable implements Info {
         private String name;
-        private final List<MethodInfo> methods = new ArrayList<MethodInfo>();
-        private final List<MethodInfo> constructors = new ArrayList<MethodInfo>();
+        private final List<MethodInfo> methods = new SingleLinkedList<MethodInfo>();
+        private final List<MethodInfo> constructors = new SingleLinkedList<MethodInfo>();
         private String superType;
-        private final List<String> interfaces = new ArrayList<String>();
-        private final List<FieldInfo> fields = new ArrayList<FieldInfo>();
+        private ClassInfo superclassInfo;
+        private final List<ClassInfo> subclassInfos = new SingleLinkedList<ClassInfo>();
+        private final List<String> interfaces = new SingleLinkedList<String>();
+        private final List<FieldInfo> fields = new SingleLinkedList<FieldInfo>();
         private Class<?> clazz;
-        private ClassNotFoundException notFound;
 
         public ClassInfo(Class clazz) {
             super(clazz);
@@ -361,6 +653,9 @@ public abstract class AbstractFinder {
             this.name = clazz.getName();
             Class superclass = clazz.getSuperclass();
             this.superType = superclass != null ? superclass.getName(): null;
+            for (Class intrface : clazz.getInterfaces()) {
+                this.interfaces.add(intrface.getName());
+            }
         }
 
         public ClassInfo(String name, String superType) {
@@ -369,7 +664,7 @@ public abstract class AbstractFinder {
         }
 
         public String getPackageName(){
-        	  return name.substring(0,name.lastIndexOf("."));
+            return name.indexOf(".") > 0 ? name.substring(0, name.lastIndexOf(".")) :
"" ;
         }
 
         public List<MethodInfo> getConstructors() {
@@ -398,19 +693,16 @@ public abstract class AbstractFinder {
 
         public Class get() throws ClassNotFoundException {
             if (clazz != null) return clazz;
-            if (notFound != null) throw notFound;
             try {
                 String fixedName = name.replaceFirst("<.*>", "");
                 this.clazz = loadClass(fixedName);
                 return clazz;
             } catch (ClassNotFoundException notFound) {
                 classesNotLoaded.add(name);
-                this.notFound = notFound;
                 throw notFound;
             }
         }
 
-
         public String toString() {
             return name;
         }
@@ -544,6 +836,7 @@ public abstract class AbstractFinder {
             this.info = info;
         }
 
+        @Override
         public void visit(int version, int access, String name, String signature, String
superName, String[] interfaces) {
             if (name.endsWith("package-info")) {
                 info = new PackageInfo(javaName(name));
@@ -559,7 +852,7 @@ public abstract class AbstractFinder {
                     new SignatureReader(signature).accept(new GenericAwareInfoBuildingVisitor(GenericAwareInfoBuildingVisitor.TYPE.CLASS,
classInfo));
                 }
                 info = classInfo;
-                classInfos.add(classInfo);
+                classInfos.put(classInfo.getName(), classInfo);
             }
         }
 
@@ -567,6 +860,7 @@ public abstract class AbstractFinder {
             return (name == null)? null:name.replace('/', '.');
         }
 
+        @Override
         public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
             AnnotationInfo annotationInfo = new AnnotationInfo(desc);
             info.getAnnotations().add(annotationInfo);
@@ -574,6 +868,7 @@ public abstract class AbstractFinder {
             return new InfoBuildingVisitor(annotationInfo);
         }
 
+        @Override
         public FieldVisitor visitField(int access, String name, String desc, String signature,
Object value) {
             ClassInfo classInfo = ((ClassInfo) info);
             FieldInfo fieldInfo = new FieldInfo(classInfo, name, desc);
@@ -581,6 +876,7 @@ public abstract class AbstractFinder {
             return new InfoBuildingVisitor(fieldInfo);
         }
 
+        @Override
         public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions) {
             ClassInfo classInfo = ((ClassInfo) info);
             MethodInfo methodInfo = new MethodInfo(classInfo, name, desc);
@@ -588,6 +884,7 @@ public abstract class AbstractFinder {
             return new InfoBuildingVisitor(methodInfo);
         }
 
+        @Override
         public AnnotationVisitor visitParameterAnnotation(int param, String desc, boolean
visible) {
             MethodInfo methodInfo = ((MethodInfo) info);
             List<AnnotationInfo> annotationInfos = methodInfo.getParameterAnnotations(param);

Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java?rev=1038273&r1=1038272&r2=1038273&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java
(original)
+++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java
Tue Nov 23 18:49:32 2010
@@ -132,42 +132,13 @@ public class ClassFinder extends Abstrac
 
     public ClassFinder(List<Class> classes){
         this.classLoader = null;
-        List<Info> infos = new ArrayList<Info>();
-        List<Package> packages = new ArrayList<Package>();
         for (Class clazz : classes) {
-
             try {
-                Package aPackage = clazz.getPackage();
-                if (aPackage != null && !packages.contains(aPackage)){
-                    infos.add(new PackageInfo(aPackage));
-                    packages.add(aPackage);
-                }
-
-                ClassInfo classInfo = new ClassInfo(clazz);
-                infos.add(classInfo);
-                classInfos.add(classInfo);
-                for (Method method : clazz.getDeclaredMethods()) {
-                    infos.add(new MethodInfo(classInfo, method));
-                }
-
-                for (Constructor constructor : clazz.getConstructors()) {
-                    infos.add(new MethodInfo(classInfo, constructor));
-                }
-
-                for (Field field : clazz.getDeclaredFields()) {
-                    infos.add(new FieldInfo(classInfo, field));
-                }
+                readClassDef(clazz);
             } catch (NoClassDefFoundError e) {
                 throw new NoClassDefFoundError("Could not fully load class: " + clazz.getName()
+ "\n due to:" + e.getMessage() + "\n in classLoader: \n" + clazz.getClassLoader());
             }
         }
-
-        for (Info info : infos) {
-            for (AnnotationInfo annotation : info.getAnnotations()) {
-                List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
-                annotationInfos.add(info);
-            }
-        }
     }
 
     private static Collection<URL> getUrls(ClassLoader classLoader, boolean excludeParent)
throws IOException {
@@ -253,25 +224,4 @@ public class ClassFinder extends Abstrac
         return classNames;
     }
 
-    protected void readClassDef(String className) {
-        if (!className.endsWith(".class")) {
-            className = className.replace('.', '/') + ".class";
-        }
-        try {
-            URL resource = getResource(className);
-            if (resource != null) {
-                InputStream in = resource.openStream();
-                try {
-                    readClassDef(in);
-                } finally {
-                    in.close();
-                }
-            } else {
-                new Exception("Could not load " + className).printStackTrace();
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-
-    }
 }

Added: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/SingleLinkedList.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/SingleLinkedList.java?rev=1038273&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/SingleLinkedList.java
(added)
+++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/SingleLinkedList.java
Tue Nov 23 18:49:32 2010
@@ -0,0 +1,245 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.xbean.finder;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public class SingleLinkedList<E> implements List<E> {
+
+    private Entry<E> entry;
+    private int size = 0;
+
+    private class Entry<E> {
+
+        private E value;
+        private Entry next;
+
+        private Entry(E value, Entry next) {
+            this.value = value;
+            this.next = next;
+        }
+    }
+
+
+    public int size() {
+        return size;
+    }
+
+    public boolean isEmpty() {
+        return size() > 0;
+    }
+
+    public boolean contains(Object o) {
+        if (o == null) {
+            for (E e : this) {
+                if (null == e) return true;
+            }
+        } else {
+            for (E e : this) {
+                if (o.equals(e)) return true;
+            }
+        }
+
+        return false;
+    }
+
+    public Iterator<E> iterator() {
+        return values();
+    }
+
+    public Object[] toArray() {
+        final Object[] array = new Object[size];
+        return toArray(array);
+    }
+
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size) a = (T[]) Array.newInstance(a.getClass().getComponentType(),
size);
+        
+        Object[] array = a;
+        int i = 0;
+
+        for (E e : this) {
+            array[i++] = e;
+        }
+        
+        return (T[]) array;
+    }
+
+    public boolean add(E e) {
+        this.entry = new Entry(e, this.entry); 
+        size++;
+        return true;
+    }
+
+    public boolean remove(Object o) {
+        throw new UnsupportedOperationException("remove");
+    }
+
+    public boolean containsAll(Collection<?> c) {
+        throw new UnsupportedOperationException("containsAll");
+    }
+
+    public boolean addAll(Collection<? extends E> c) {
+        throw new UnsupportedOperationException("addAll");
+    }
+
+    public boolean addAll(int index, Collection<? extends E> c) {
+        throw new UnsupportedOperationException("addAll");
+    }
+
+    public boolean removeAll(Collection<?> c) {
+        throw new UnsupportedOperationException("removeAll");
+    }
+
+    public boolean retainAll(Collection<?> c) {
+        throw new UnsupportedOperationException("retainAll");
+    }
+
+    public void clear() {
+        this.entry = null;
+    }
+
+    public E get(int index) {
+        bounds(index);
+        int i = size;
+        for (E e : this) {
+            if (--i == index) return e;
+        }
+
+        throw new IllegalStateException("statement should not be reachable");
+    }
+
+    public E set(int index, E element) {
+        bounds(index);
+        int i = size;
+
+        for (Entry<E> entry : entries()) {
+            if (--i == index) {
+                final E old = entry.value;
+                entry.value = element;
+                return old;
+            }
+        }
+
+        throw new IllegalStateException("statement should not be reachable");
+    }
+
+    public void add(int index, E element) {
+        throw new UnsupportedOperationException("add");
+    }
+
+    public E remove(int index) {
+        throw new UnsupportedOperationException("remove");
+    }
+
+    public int indexOf(Object o) {
+        throw new UnsupportedOperationException("indexOf");
+    }
+
+    public int lastIndexOf(Object o) {
+        throw new UnsupportedOperationException("lastIndexOf");
+    }
+
+    public ListIterator<E> listIterator() {
+        throw new UnsupportedOperationException("listIterator");
+    }
+
+    public ListIterator<E> listIterator(int index) {
+        throw new UnsupportedOperationException("listIterator");
+    }
+
+    public List<E> subList(int fromIndex, int toIndex) {
+        throw new UnsupportedOperationException("subList");
+    }
+
+    private void bounds(int index) {
+        if (index >= size) throw new IndexOutOfBoundsException(index + " [size " + size
+ "]");
+        if (index < 0) throw new IndexOutOfBoundsException(index + " [size " + size +
"]");
+    }
+
+
+    private Iterator<E> values() {
+        return new Values<E>(this.entry);
+    }
+
+    private Entries entries() {
+        return new Entries(this.entry);
+    }
+    
+
+    private class Values<E> implements Iterator<E> {
+
+        private Entry<E> current;
+
+        private Values(Entry<E> current) {
+            this.current = current;
+        }
+
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        public E next() {
+            if (current == null) throw new NoSuchElementException();
+            
+            final E v = current.value;
+
+            this.current = current.next;
+
+            return v;
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException("remove");
+        }
+    }
+
+    private class Entries implements Iterator<Entry<E>>, Iterable<Entry<E>>
{
+        private Entry<E> current;
+
+        private Entries(Entry<E> current) {
+            this.current = current;
+        }
+
+        public Iterator<Entry<E>> iterator() {
+            return this;
+        }
+
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        public Entry<E> next() {
+            if (current == null) throw new NoSuchElementException();
+
+            final Entry<E> value = this.current;
+
+            this.current = current.next;
+
+            return value;
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException("remove");
+        }
+    }
+}

Propchange: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/SingleLinkedList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderDepthTest.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderDepthTest.java?rev=1038273&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderDepthTest.java
(added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderDepthTest.java
Tue Nov 23 18:49:32 2010
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.xbean.finder;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ClassFinderDepthTest extends TestCase {
+
+
+    public static interface Hue {
+    }
+
+    public static interface Saturation {
+    }
+
+    public static interface Brightness {
+    }
+
+    public static interface HSB extends Hue, Saturation, Brightness {
+    }
+
+    public static class Color implements HSB {
+    }
+
+    public static class Red extends Color {
+    }
+
+    public static class Crimson extends Red {
+    }
+
+    // added to ensure there are classes that shouldn't match
+
+    public static class Shape {
+    }
+
+    public static class Square extends Shape {
+    }
+
+    public void testFindSubclassesIncomplete() throws Exception {
+        final AbstractFinder finder = new ClassFinder(Crimson.class, Square.class).link();
+
+        assertSubclasses(finder, Color.class, Red.class, Crimson.class);
+        assertSubclasses(finder, Red.class, Crimson.class);
+        assertSubclasses(finder, Crimson.class);
+
+        assertSubclasses(finder, Shape.class, Square.class);
+        assertSubclasses(finder, Square.class);
+    }
+
+    public void testFindImplementations() throws Exception {
+        final AbstractFinder finder = new ClassFinder(Crimson.class, Square.class).link();
+
+        assertImplementations(finder, HSB.class, Color.class, Red.class, Crimson.class);
+        assertImplementations(finder, Hue.class, HSB.class, Color.class, Red.class, Crimson.class);
+    }
+
+    private void assertSubclasses(AbstractFinder finder, Class<?> clazz, Class... subclasses)
{
+        final List<Class<?>> classes = new ArrayList(finder.findSubclasses(clazz));
+
+        for (Class subclass : subclasses) {
+            assertContains(classes, subclass);
+        }
+        assertSize(classes, subclasses.length);
+    }
+
+    private void assertImplementations(AbstractFinder finder, Class<?> clazz, Class...
implementations) {
+        final List<Class<?>> classes = new ArrayList(finder.findImplementations(clazz));
+
+        for (Class subclass : implementations) {
+            assertContains(classes, subclass);
+        }
+        assertSize(classes, implementations.length);
+    }
+
+    private void assertSize(List<?> list, int size) {
+        assertEquals(size, list.size());
+    }
+
+    private void assertContains(List<Class<?>> classes, Class<?> clazz)
{
+        assertTrue("missing " + clazz.getSimpleName(), classes.contains(clazz));
+    }
+
+}

Propchange: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderDepthTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SingleLinkedListTest.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SingleLinkedListTest.java?rev=1038273&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SingleLinkedListTest.java
(added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SingleLinkedListTest.java
Tue Nov 23 18:49:32 2010
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.xbean.finder;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class SingleLinkedListTest extends TestCase {
+    private SingleLinkedList<String> list;
+    private List<String> expected;
+
+    @Override
+    protected void setUp() throws Exception {
+        list = new SingleLinkedList<String>();
+        list.add("one");
+        list.add("two");
+        list.add("three");
+        list.add("four");
+        list.add("five");
+
+        expected = Arrays.asList("five", "four", "three", "two", "one");
+    }
+
+    public void testIterator() throws Exception {
+        ArrayList<String> arrayList = new ArrayList<String>();
+        for (String s : list) {
+            arrayList.add(s);
+        }
+
+        assertEquals(expected, arrayList);
+    }
+
+    public void testArrayListConstructor() throws Exception {
+        ArrayList<String> arrayList = new ArrayList<String>(list);
+
+        assertEquals(expected, arrayList);
+    }
+
+    public void testLinkedListConstructor() throws Exception {
+        LinkedList<String> linkedList = new LinkedList<String>(list);
+
+        assertEquals(expected, linkedList);
+    }
+
+    public void testToArrayWithWrongSize() {
+        final String[] strings = list.toArray(new String[0]);
+
+        assertEquals(expected, Arrays.asList(strings));
+    }
+
+    public void testToArrayWithRightSize() {
+        final String[] strings = list.toArray(new String[5]);
+
+        assertEquals(expected, Arrays.asList(strings));
+    }
+
+    public void testToArray() {
+        final Object[] strings = list.toArray();
+
+        assertEquals(expected, Arrays.asList(strings));
+    }
+
+    public void testContains() {
+        assertTrue(list.contains("five"));
+        assertFalse(list.contains("foo"));
+    }
+
+    public void testContainsNull() {
+        assertFalse(list.contains(null));
+    }
+
+    public void testGet() {
+        int i = 0;
+        assertEquals("one", list.get(i++));
+        assertEquals("two", list.get(i++));
+        assertEquals("three", list.get(i++));
+        assertEquals("four", list.get(i++));
+        assertEquals("five", list.get(i++));
+    }
+
+    public void testGetInvalid() {
+
+        try {
+            list.get(-1);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+            // pass
+        }
+
+
+        try {
+            list.get(5);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+            // pass
+        }
+    }
+
+
+    public void testSet() {
+        int i = 0;
+        assertEquals("one", list.set(i++, "uno"));
+        assertEquals("two", list.set(i++, "dos"));
+        assertEquals("three", list.set(i++, "tres"));
+        assertEquals("four", list.set(i++, "quatro"));
+        assertEquals("five", list.set(i++, "cinco"));
+
+        i = 0;
+        assertEquals("uno", list.get(i++));
+        assertEquals("dos", list.get(i++));
+        assertEquals("tres", list.get(i++));
+        assertEquals("quatro", list.get(i++));
+        assertEquals("cinco", list.get(i++));
+    }
+
+    public void testSetInvalid() {
+
+        try {
+            list.set(-1, null);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+            // pass
+        }
+
+
+        try {
+            list.set(5, null);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+            // pass
+        }
+    }
+
+}

Propchange: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/SingleLinkedListTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message