1   package org.nnsoft.commons.bspi;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  import java.io.Closeable;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.InputStreamReader;
23  import java.io.Reader;
24  import java.net.URL;
25  import java.nio.charset.Charset;
26  import java.util.Enumeration;
27  import java.util.Iterator;
28  import java.util.LinkedHashMap;
29  import java.util.NoSuchElementException;
30  
31  
32  
33  
34  
35  final class ServiceClassIterator<S>
36      implements Iterator<Class<? extends S>>
37  {
38  
39      
40  
41  
42      private static final Charset UTF_8 = Charset.forName( "UTF-8" );
43  
44      
45  
46  
47      private final Class<S> service;
48  
49      
50  
51  
52      private final ClassLoader classLoader;
53  
54      private final Enumeration<URL> serviceResources;
55  
56      
57  
58  
59      private final LinkedHashMap<String, Class<? extends S>> providerTypes;
60  
61      private Iterator<String> pending = null;
62  
63      private String nextName = null;
64  
65      
66  
67  
68  
69  
70  
71      public ServiceClassIterator( Class<S> service, ClassLoader classLoader, Enumeration<URL> serviceResources,
72                                   LinkedHashMap<String, Class<? extends S>> providerTypes )
73      {
74          this.service = service;
75          this.classLoader = classLoader;
76          this.serviceResources = serviceResources;
77          this.providerTypes = providerTypes;
78      }
79  
80      
81  
82  
83      public boolean hasNext()
84      {
85          if ( nextName != null )
86          {
87              return true;
88          }
89  
90          while ( ( pending == null ) || !pending.hasNext() )
91          {
92              if ( !serviceResources.hasMoreElements() )
93              {
94                  return false;
95              }
96              pending = parseServiceFile( serviceResources.nextElement() );
97          }
98  
99          nextName = pending.next();
100         return true;
101     }
102 
103     
104 
105 
106     public Class<? extends S> next()
107     {
108         if ( !hasNext() )
109         {
110             throw new NoSuchElementException();
111         }
112         String className = nextName;
113         nextName = null;
114         try
115         {
116             Class<?> clazz = classLoader.loadClass( className );
117             if ( !service.isAssignableFrom( clazz ) )
118             {
119                 throw new ServiceConfigurationError( "Provider '" + className + "' is not assignable to Service '"
120                     + service.getName() + "'" );
121             }
122             Class<? extends S> serviceClass = clazz.asSubclass( service );
123             providerTypes.put( className, serviceClass );
124             return serviceClass;
125         }
126         catch ( ClassNotFoundException e )
127         {
128             throw new ServiceConfigurationError( "Provider '" + className + "' not found", e );
129         }
130         catch ( ClassCastException e )
131         {
132             throw new ServiceConfigurationError( "Provider '"
133                                                  + className
134                                                  + "' is not assignable to Service '"
135                                                  + service.getName()
136                                                  + "'", e );
137         }
138         catch ( Throwable e )
139         {
140             throw new ServiceConfigurationError( "Provider '" + className + "' could not be instantiated", e );
141         }
142     }
143 
144     
145 
146 
147     public void remove()
148     {
149         throw new UnsupportedOperationException();
150     }
151 
152     
153 
154 
155 
156 
157 
158 
159     private Iterator<String> parseServiceFile( URL url )
160     {
161         InputStream inputStream = null;
162         Reader reader = null;
163         try
164         {
165             inputStream = url.openStream();
166             reader = new InputStreamReader( inputStream, UTF_8 );
167             ServiceFileParser<S> serviceFileParser = new ServiceFileParser<S>( reader );
168             serviceFileParser.setProviderTypes( providerTypes );
169             serviceFileParser.parse();
170             return serviceFileParser.iterator();
171         }
172         catch ( Exception e )
173         {
174             throw new ServiceConfigurationError( "An error occurred while reading service resource '"
175                                                  + url
176                                                  + "' for service class '"
177                                                  + service.getName()
178                                                  + "'", e );
179         }
180         finally
181         {
182             closeQuietly( reader );
183             closeQuietly( inputStream );
184         }
185     }
186 
187     
188 
189 
190 
191 
192     private static void closeQuietly( Closeable closeable )
193     {
194         if ( closeable != null )
195         {
196             try
197             {
198                 closeable.close();
199             }
200             catch ( IOException e )
201             {
202                 
203             }
204         }
205     }
206 
207 }