Added ability to implicitly cast instances from the Loader.
[jglob.git] / src / dolda / jglob / Loader.java
1 package dolda.jglob;
2
3 import java.util.*;
4 import java.io.*;
5 import java.net.*;
6 import java.lang.annotation.*;
7
8 public class Loader {
9     private final Class<? extends Annotation> an;
10     private final ClassLoader cl;
11
12     private Loader(Class<? extends Annotation> annotation, ClassLoader loader) {
13         this.an = annotation;
14         this.cl = loader;
15     }
16
17     public Iterable<String> names() {
18         return(new Iterable<String>() {
19                 public Iterator<String> iterator() {
20                     return(new Iterator<String>() {
21                             private Enumeration<URL> rls;
22                             private Iterator<String> cur = null;
23
24                             private Iterator<String> parse(URL url) {
25                                 try {
26                                     List<String> buf = new LinkedList<String>();
27                                     InputStream in = url.openStream();
28                                     try {
29                                         BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"));
30                                         String ln;
31                                         while((ln = r.readLine()) != null) {
32                                             ln = ln.trim();
33                                             if(ln.length() < 1)
34                                                 continue;
35                                             buf.add(ln);
36                                         }
37                                         return(buf.iterator());
38                                     } finally {
39                                         in.close();
40                                     }
41                                 } catch(IOException e) {
42                                     throw(new GlobAccessException(e));
43                                 }
44                             }
45
46                             public boolean hasNext() {
47                                 if((cur == null) || !cur.hasNext()) {
48                                     if(rls == null) {
49                                         try {
50                                             rls = cl.getResources("META-INF/glob/" + an.getName());
51                                         } catch(IOException e) {
52                                             throw(new GlobAccessException(e));
53                                         }
54                                     }
55                                     if(!rls.hasMoreElements())
56                                         return(false);
57                                     URL u = rls.nextElement();
58                                     cur = parse(u);
59                                 }
60                                 return(true);
61                             }
62
63                             public String next() {
64                                 if(!hasNext())
65                                     throw(new NoSuchElementException());
66                                 String ret = cur.next();
67                                 return(ret);
68                             }
69
70                             public void remove() {throw(new UnsupportedOperationException());}
71                         });
72                 }
73             });
74     }
75
76     public Iterable<Class<?>> classes() {
77         return(new Iterable<Class<?>>() {
78                 public Iterator<Class<?>> iterator() {
79                     return(new Iterator<Class<?>>() {
80                             private final Iterator<String> names = names().iterator();
81                             private Class<?> n = null;
82
83                             public boolean hasNext() {
84                                 while(n == null) {
85                                     if(!names.hasNext())
86                                         return(false);
87                                     String nm = names.next();
88                                     Class<?> c;
89                                     try {
90                                         c = cl.loadClass(nm);
91                                     } catch(ClassNotFoundException e) {
92                                         continue;
93                                     }
94                                     if(c.getAnnotation(an) == null)
95                                         continue;
96                                     n = c;
97                                 }
98                                 return(true);
99                             }
100
101                             public Class<?> next() {
102                                 if(!hasNext())
103                                     throw(new NoSuchElementException());
104                                 Class<?> r = n;
105                                 n = null;
106                                 return(r);
107                             }
108
109                             public void remove() {throw(new UnsupportedOperationException());}
110                         });
111                 }
112             });
113     }
114
115     public <T> Iterable<T> instances(final Class<T> cast) {
116         return(new Iterable<T>() {
117                 public Iterator<T> iterator() {
118                     return(new Iterator<T>() {
119                             private final Iterator<Class<?>> classes = classes().iterator();
120                             private T n = null;
121
122                             public boolean hasNext() {
123                                 while(n == null) {
124                                     if(!classes.hasNext())
125                                         return(false);
126                                     Class<?> cl = classes.next();
127                                     T inst;
128                                     try {
129                                         inst = cast.cast(cl.newInstance());
130                                     } catch(InstantiationException e) {
131                                         throw(new GlobInstantiationException(e));
132                                     } catch(IllegalAccessException e) {
133                                         throw(new GlobInstantiationException(e));
134                                     }
135                                     n = inst;
136                                 }
137                                 return(true);
138                             }
139
140                             public T next() {
141                                 if(!hasNext())
142                                     throw(new NoSuchElementException());
143                                 T r = n;
144                                 n = null;
145                                 return(r);
146                             }
147
148                             public void remove() {throw(new UnsupportedOperationException());}
149                         });
150                 }
151             });
152     }
153
154     public Iterable<?> instances() {
155         return(instances(Object.class));
156     }
157
158     public static Loader get(Class<? extends Annotation> annotation, ClassLoader loader) {
159         return(new Loader(annotation, loader));
160     }
161
162     public static Loader get(Class<? extends Annotation> annotation) {
163         return(get(annotation, annotation.getClassLoader()));
164     }
165 }