View Javadoc

1   /*
2    * $Id: ProvidersRegistry.java,v 1.18 2011/06/16 09:29:40 jbmeslin Exp $
3    */
4   package org.rcfaces.core.internal.config;
5   
6   import java.lang.reflect.Constructor;
7   import java.lang.reflect.Modifier;
8   import java.util.ArrayList;
9   import java.util.HashSet;
10  import java.util.Iterator;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.Set;
14  import java.util.TreeMap;
15  
16  import javax.faces.FacesException;
17  import javax.faces.context.FacesContext;
18  
19  import org.apache.commons.digester.Digester;
20  import org.apache.commons.digester.Rule;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.rcfaces.core.internal.util.ClassLocator;
24  import org.rcfaces.core.provider.IProvider;
25  import org.xml.sax.Attributes;
26  
27  /**
28   * 
29   * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
30   * @version $Revision: 1.18 $ $Date: 2011/06/16 09:29:40 $
31   */
32  public class ProvidersRegistry implements IProvidersRegistry {
33      private static final String REVISION = "$Revision: 1.18 $";
34  
35      private static final Log LOG = LogFactory.getLog(ProvidersRegistry.class);
36  
37      private static final Class[] PARENT_PROVIDER_PARAMETER_TYPES = new Class[] { IProvider.class };
38  
39      private final Map providersById = new TreeMap();
40  
41      private Digester digester;
42  
43      public ProvidersRegistry() {
44      }
45  
46      public IProvider getProvider(String providerId) {
47          ProviderBean providerBean = (ProviderBean) providersById
48                  .get(providerId);
49          if (providerBean == null) {
50              return null;
51          }
52  
53          return providerBean.getProvider();
54      }
55  
56      public void addProvider(ProviderBean providerBean) {
57  
58          String id = providerBean.getId();
59  
60          String providerId = providerBean.getProviderId();
61          if (providerId == null) {
62              throw new FacesException("You must specify a provider identifier.");
63          }
64  
65          String className = providerBean.getProviderClassName();
66          if (className == null) {
67              throw new FacesException(
68                      "You must specify the className of the provider. (id='"
69                              + id + "' providerId='" + providerId + "')");
70          }
71  
72          if (LOG.isDebugEnabled()) {
73              LOG.debug("Initialize provider '" + id + "'. (providerId='"
74                      + providerId + "', classname='" + className + "'");
75          }
76  
77          Class clazz;
78          try {
79              clazz = ClassLocator.load(className, null, FacesContext
80                      .getCurrentInstance());
81  
82          } catch (ClassNotFoundException ex) {
83              throw new FacesException("Can not load class '" + className
84                      + "' specified by provider id='" + id + "' (providerId='"
85                      + providerId + "').", ex);
86          }
87  
88          if (IProvider.class.isAssignableFrom(clazz) == false) {
89              throw new FacesException("Class '" + className
90                      + "' specified by provider id='" + id + "'  (providerId='"
91                      + providerId + "') must implement interface 'IProvider'.");
92          }
93  
94          if ((clazz.getModifiers() & Modifier.ABSTRACT) > 0) {
95              throw new FacesException("Class '" + className
96                      + "' specified by provider id='" + id + "'  (providerId='"
97                      + providerId + "') is abstract !");
98          }
99  
100         Constructor constructor;
101         Object parameters[];
102 
103         try {
104             constructor = clazz.getConstructor(PARENT_PROVIDER_PARAMETER_TYPES);
105             parameters = new Object[] { null };
106 
107         } catch (NoSuchMethodException ex) {
108             LOG.trace(
109                     "Can not get constructor with provider parameter for class '"
110                             + className + "' specified by provider id='" + id
111                             + "'  (providerId='" + providerId
112                             + "'), TRY with no parameter !", ex);
113 
114             try {
115                 constructor = clazz.getConstructor((Class[]) null);
116                 parameters = null;
117 
118             } catch (NoSuchMethodException ex2) {
119                 throw new FacesException(
120                         "Can not find accessible (public) constructor of class '"
121                                 + className + "' specified by provider id='"
122                                 + id + "'  (providerId='" + providerId + "').",
123                         ex2);
124             }
125         }
126 
127         LOG.debug("Use constructor '" + constructor
128                 + "' to instanciate provider '" + id + "'.  (providerId='"
129                 + providerId + "', classname='" + className + "'");
130 
131         /*
132          * Ca n'a pas de sens ! if (parameters != null) { ProviderBean pb =
133          * (ProviderBean) providersById.get(providerId); if (bp != null) {
134          * parameters[0] = pb.getProvider(); } }
135          */
136 
137         IProvider provider;
138         try {
139             provider = (IProvider) constructor.newInstance(parameters);
140 
141         } catch (Throwable ex) {
142             throw new FacesException("Can not instanciate class '" + className
143                     + "' specified by provider id='" + id + "' (providerId='"
144                     + providerId + "') using constructor '" + constructor
145                     + "'.", ex);
146         }
147 
148         LOG.trace("addProvider(" + providerId + "," + provider + ")");
149 
150         providerBean.setProvider(provider);
151 
152         providersById.put(providerId, providerBean);
153     }
154 
155     public void configureRules(Digester digester) {
156 
157         digester.addRule("rcfaces-config/providers", new Rule() {
158             private static final String REVISION = "$Revision: 1.18 $";
159 
160             public void begin(String namespace, String name,
161                     Attributes attributes) throws Exception {
162 
163                 super.digester.push(ProvidersRegistry.this);
164             }
165 
166             public void end(String namespace, String name) throws Exception {
167                 super.digester.pop();
168             }
169         });
170 
171         digester.addObjectCreate("rcfaces-config/providers/provider",
172                 ProviderBean.class);
173         digester.addSetProperties("rcfaces-config/providers/provider", "id",
174                 "id");
175         digester.addBeanPropertySetter(
176                 "rcfaces-config/providers/provider/provider-id", "providerId");
177         digester.addBeanPropertySetter(
178                 "rcfaces-config/providers/provider/provider-class",
179                 "providerClassName");
180 
181         digester.addRule("rcfaces-config/providers/provider/requires",
182                 new Rule() {
183 
184                     public void body(String namespace, String name, String text)
185                             throws Exception {
186 
187                         ProviderBean providerBean = (ProviderBean) super.digester
188                                 .peek();
189 
190                         providerBean.addRequired(text);
191                     }
192 
193                 });
194 
195         digester.addSetNext("rcfaces-config/providers/provider", "addProvider");
196     }
197 
198     /**
199      * 
200      * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
201      * @version $Revision: 1.18 $ $Date: 2011/06/16 09:29:40 $
202      */
203     public static class ProviderBean {
204         private static final String REVISION = "$Revision: 1.18 $";
205 
206         private String id;
207 
208         private String providerClassName;
209 
210         private String providerId;
211 
212         private List requirements;
213 
214         private IProvider provider;
215 
216         public String getProviderId() {
217             return providerId;
218         }
219 
220         public void addRequired(String required) {
221             if (requirements == null) {
222                 requirements = new ArrayList();
223             }
224 
225             requirements.add(required);
226         }
227 
228         public String[] listRequirements() {
229             if (requirements == null) {
230                 return new String[0]; // Quel est le mieux ?
231             }
232             return (String[]) requirements.toArray(new String[requirements
233                     .size()]);
234         }
235 
236         public void setProviderId(String providerId) {
237             this.providerId = providerId;
238         }
239 
240         public final String getProviderClassName() {
241             return providerClassName;
242         }
243 
244         public final void setProviderClassName(String className) {
245             this.providerClassName = className;
246         }
247 
248         public final String getId() {
249             return id;
250         }
251 
252         public final void setId(String id) {
253             this.id = id;
254         }
255 
256         public IProvider getProvider() {
257             return provider;
258         }
259 
260         public void setProvider(IProvider provider) {
261             this.provider = provider;
262         }
263 
264     }
265 
266     public Digester getConfigDigester() {
267         return digester;
268     }
269 
270     public void loadProvidersConfiguration(IProvidersConfigurator configurator) {
271         Digester digester = new Digester();
272 
273         for (Iterator it = providersById.entrySet().iterator(); it.hasNext();) {
274             Map.Entry entry = (Map.Entry) it.next();
275 
276             ProviderBean providerBean = (ProviderBean) entry.getValue();
277             IProvider provider = providerBean.getProvider();
278 
279             provider.configureRules(digester);
280         }
281 
282         if (digester.getRules().rules().isEmpty()) {
283             return;
284         }
285 
286         configurator.parseConfiguration(digester);
287     }
288 
289     public void startupProviders(FacesContext facesContext) {
290 
291         Set started = new HashSet();
292 
293         boolean startedProcess = true;
294 
295         for (; startedProcess;) {
296             startedProcess = false;
297 
298             next_provider: for (Iterator it = providersById.entrySet()
299                     .iterator(); it.hasNext();) {
300                 Map.Entry entry = (Map.Entry) it.next();
301 
302                 String providerId = (String) entry.getKey();
303                 if (started.contains(providerId)) {
304                     continue;
305                 }
306 
307                 ProviderBean providerBean = (ProviderBean) entry.getValue();
308 
309                 String requirements[] = providerBean.listRequirements();
310                 for (int i = 0; i < requirements.length; i++) {
311                     String requirement = requirements[i];
312 
313                     if (providersById.containsKey(requirement) == false) {
314                         LOG.error("Invalid dependency provider='" + providerId
315                                 + "' requires unknown provider '" + requirement
316                                 + "'.");
317                     } else if (started.contains(requirement) == false) {
318                         continue next_provider;
319                     }
320                 }
321 
322                 startedProcess = true;
323                 started.add(providerId);
324 
325                 IProvider provider = providerBean.getProvider();
326 
327                 try {
328                     LOG.debug("Start provider '" + providerId + "' ...");
329 
330                     provider.startup(facesContext);
331 
332                     LOG.debug("Start provider '" + providerId + "' done");
333 
334                 } catch (Throwable ex) {
335                     it.remove();
336 
337                     LOG.error("Exception when starting up provider '"
338                             + providerId + "', remove it !", ex);
339 
340                     // throw ex;
341                 }
342             }
343         }
344 
345         if (started.size() != providersById.size()) {
346             List l = new ArrayList(providersById.keySet());
347             l.removeAll(started);
348 
349             LOG.error("Providers are failed to startup: " + l);
350         }
351     }
352 }