View Javadoc

1   package org.apache.onami.spi.core;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static java.lang.String.format;
23  
24  import java.util.Iterator;
25  import java.util.NoSuchElementException;
26  
27  import com.google.inject.ProvisionException;
28  
29  /**
30   * Lazy-loading iterator over the discovered classes.
31   *
32   * @param <S> The service type being loaded.
33   */
34  abstract class AbstractServiceClassIterator<S>
35      implements Iterator<Class<? extends S>>
36  {
37  
38      /**
39       * The class or interface representing the service being loaded.
40       */
41      private final Class<S> service;
42  
43      /**
44       * The class loader used to locate, load, and instantiate providers.
45       */
46      private final ClassLoader classLoader;
47  
48      /**
49       * The pending providers Class names.
50       */
51      private Iterator<String> pending = null;
52  
53      /**
54       * The reference to the next provider Class name.
55       */
56      private String nextName = null;
57  
58      /**
59       * Creates a new Provider classes Iterator.
60       *
61       * @param service The Service being loaded.
62       * @param classLoader The ClassLoader used to load Provider classes.
63       */
64      public AbstractServiceClassIterator( Class<S> service, ClassLoader classLoader )
65      {
66          this.service = service;
67          this.classLoader = classLoader;
68      }
69  
70      /**
71       * {@inheritDoc}
72       */
73      public final boolean hasNext()
74      {
75          if ( nextName != null )
76          {
77              return true;
78          }
79  
80          while ( ( pending == null ) || !pending.hasNext() )
81          {
82              if ( !hasMorePendingNames() )
83              {
84                  return false;
85              }
86              pending = getPendingNames();
87          }
88  
89          nextName = pending.next();
90          return true;
91      }
92  
93      /**
94       * Checks if there are still providers names to be loaded.
95       *
96       * @return true if there are still providers names to be loaded, false otherwise.
97       */
98      protected abstract boolean hasMorePendingNames();
99  
100     /**
101      * Returns the iterator over next pending Providers names.
102      *
103      * @return the iterator over next pending Providers names.
104      */
105     protected abstract Iterator<String> getPendingNames();
106 
107     /**
108      * {@inheritDoc}
109      */
110     public final Class<? extends S> next()
111     {
112         if ( !hasNext() )
113         {
114             throw new NoSuchElementException();
115         }
116         String className = nextName;
117         nextName = null;
118         try
119         {
120             Class<?> clazz = classLoader.loadClass( className );
121             if ( !service.isAssignableFrom( clazz ) )
122             {
123                 throw new ProvisionException( format( "Provider '%s' is not assignable to Service '%s'",
124                                                       className, service.getName() ) );
125             }
126             return clazz.asSubclass( service );
127         }
128         catch ( ClassNotFoundException e )
129         {
130             throw new ProvisionException( format( "Provider '%s' not found: %s", className, e.getMessage() ) );
131         }
132         catch ( ClassCastException e )
133         {
134             throw new ProvisionException( format( "Provider '%s' is not assignable to Service '%s'",
135                                                   className, service.getName() ) );
136         }
137     }
138 
139     /**
140      * {@inheritDoc}
141      */
142     public final void remove()
143     {
144         throw new UnsupportedOperationException();
145     }
146 
147 }