View Javadoc

1   /*
2    * $Id: AdapterManagerImpl.java,v 1.8 2007/05/24 12:26:17 oeuillot Exp $
3    */
4   package org.rcfaces.core.internal.adapter;
5   
6   import java.util.ArrayList;
7   import java.util.Collection;
8   import java.util.HashMap;
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  
15  import javax.faces.FacesException;
16  import javax.faces.context.FacesContext;
17  
18  import org.apache.commons.digester.Digester;
19  import org.apache.commons.digester.Rule;
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.rcfaces.core.internal.RcfacesContext;
23  import org.rcfaces.core.internal.util.ClassLocator;
24  import org.rcfaces.core.lang.IAdapterFactory;
25  import org.rcfaces.core.provider.AbstractProvider;
26  import org.xml.sax.Attributes;
27  
28  /**
29   * 
30   * @author Eclipse project (latest modification by $Author: oeuillot $)
31   * @version $Revision: 1.8 $ $Date: 2007/05/24 12:26:17 $
32   */
33  public class AdapterManagerImpl extends AbstractProvider implements
34          IAdapterManager {
35      private static final String REVISION = "$Revision: 1.8 $";
36  
37      private static final Log LOG = LogFactory.getLog(AdapterManagerImpl.class);
38  
39      protected final Map factories;
40  
41      protected Map adapterLookup;
42  
43      protected Map classSearchOrderLookup;
44  
45      public AdapterManagerImpl() {
46          factories = new HashMap(5);
47          adapterLookup = null;
48  
49          RcfacesContext rcfacesContext = RcfacesContext.getCurrentInstance();
50  
51          if (rcfacesContext.getAdapterManager() == null) {
52              rcfacesContext.setAdapterManager(this);
53          }
54      }
55  
56      public String getId() {
57          return "AdapterManager";
58      }
59  
60      public void configureRules(Digester digester) {
61          super.configureRules(digester);
62  
63          digester.addRule("rcfaces-config/adapters/adapter", new Rule() {
64              private static final String REVISION = "$Revision: 1.8 $";
65  
66              public void begin(String namespace, String name,
67                      Attributes attributes) throws Exception {
68  
69                  super.digester.push(new AdapterBean());
70              }
71  
72              public void end(String namespace, String name) throws Exception {
73                  AdapterBean adapterBean = (AdapterBean) super.digester.pop();
74  
75                  declareAdapter(adapterBean);
76              }
77          });
78  
79          digester.addBeanPropertySetter(
80                  "rcfaces-config/adapters/adapter/adaptable-class", "className");
81  
82          digester.addBeanPropertySetter(
83                  "rcfaces-config/adapters/adapter/adapterFactory-class",
84                  "adapterFactoryClassName");
85  
86      }
87  
88      protected void declareAdapter(AdapterBean adapterBean) {
89          String adapterClassName = adapterBean.getClassName();
90          String factoryClassName = adapterBean.getAdapterFactoryClassName();
91  
92          LOG.debug("Declare adapter adapterClassName='" + adapterClassName
93                  + "' factoryClassName='" + factoryClassName + "'.");
94  
95          if (adapterClassName == null || adapterClassName.length() < 1
96                  || factoryClassName == null || factoryClassName.length() < 1) {
97              throw new FacesException(
98                      "Invalid adapter configuration. (adapter-class='"
99                              + adapterClassName + "' adapterFactory-class='"
100                             + factoryClassName + "')");
101         }
102 
103         FacesContext facesContext = FacesContext.getCurrentInstance();
104 
105         /*
106          * int dimension = 0; for (;;) { int dim =
107          * adapterClassName.lastIndexOf('['); if (dim < 0) { break; }
108          * dimension++; adapterClassName = adapterClassName.substring(0, dim); }
109          */
110 
111         Class adapterClass;
112         try {
113             adapterClass = ClassLocator.load(adapterClassName, this,
114                     facesContext);
115 
116         } catch (ClassNotFoundException e) {
117             LOG.info("Adapter class not found '" + adapterClassName
118                     + "', ignore adapter !", e);
119             return;
120         }
121 
122         Class factoryClass;
123         try {
124             factoryClass = ClassLocator.load(factoryClassName, this,
125                     facesContext);
126 
127         } catch (ClassNotFoundException e) {
128             LOG.info("Factory class '" + factoryClassName
129                     + "' for adapterClass='" + adapterClassName
130                     + "' is not found, ignore adapter !", e);
131             return;
132         }
133 
134         IAdapterFactory adapterFactory;
135         try {
136             adapterFactory = (IAdapterFactory) factoryClass.newInstance();
137 
138         } catch (Throwable th) {
139             LOG.info("Can not instanciate factory class '" + factoryClassName
140                     + "' for adapterClass='" + adapterClassName
141                     + "', ignore adapter !", th);
142             return;
143         }
144 
145         registerAdapters(adapterFactory, adapterClass);
146     }
147 
148     private Map getFactories(Class adaptable) {
149         // cache reference to lookup to protect against concurrent flush
150         Map lookup = adapterLookup;
151         if (lookup == null) {
152             adapterLookup = lookup = new HashMap(30);
153         }
154 
155         Map table = (Map) lookup.get(adaptable.getName());
156         if (table == null) {
157             // calculate adapters for the class
158             table = new HashMap(4);
159             Class[] classes = computeClassOrder(adaptable);
160             for (int i = 0; i < classes.length; i++) {
161                 addFactoriesFor(classes[i].getName(), table);
162             }
163 
164             // cache the table
165             lookup.put(adaptable.getName(), table);
166         }
167         return table;
168     }
169 
170     public Object getAdapter(Object adaptable, Class adapterType,
171             Object parameter) {
172         IAdapterFactory factory = (IAdapterFactory) getFactories(
173                 adaptable.getClass()).get(adapterType.getName());
174         Object result = null;
175         if (factory != null) {
176             result = factory.getAdapter(adaptable, adapterType, parameter);
177         }
178 
179         if (result == null && adapterType.isInstance(adaptable)) {
180             return adaptable;
181         }
182 
183         return result;
184     }
185 
186     private Class[] computeClassOrder(Class adaptable) {
187         List classes = null;
188         // cache reference to lookup to protect against concurrent flush
189         Map lookup = classSearchOrderLookup;
190         if (lookup != null) {
191             classes = (List) lookup.get(adaptable);
192         }
193 
194         // compute class order only if it hasn't been cached before
195         if (classes == null) {
196             classes = new ArrayList();
197             computeClassOrder(adaptable, classes);
198             if (lookup == null) {
199                 classSearchOrderLookup = lookup = new HashMap();
200             }
201             lookup.put(adaptable, classes);
202         }
203 
204         return (Class[]) classes.toArray(new Class[classes.size()]);
205     }
206 
207     private void computeClassOrder(Class adaptable, Collection classes) {
208         Class clazz = adaptable;
209         Set seen = new HashSet(4);
210         while (clazz != null) {
211             classes.add(clazz);
212             computeInterfaceOrder(clazz.getInterfaces(), classes, seen);
213             clazz = clazz.getSuperclass();
214         }
215     }
216 
217     private void computeInterfaceOrder(Class[] interfaces, Collection classes,
218             Set seen) {
219         List newInterfaces = new ArrayList(interfaces.length);
220         for (int i = 0; i < interfaces.length; i++) {
221             Class interfac = interfaces[i];
222             if (seen.add(interfac)) {
223                 // note we cannot recurse here without changing the resulting
224                 // interface order
225                 classes.add(interfac);
226                 newInterfaces.add(interfac);
227             }
228         }
229 
230         for (Iterator it = newInterfaces.iterator(); it.hasNext();) {
231             computeInterfaceOrder(((Class) it.next()).getInterfaces(), classes,
232                     seen);
233         }
234     }
235 
236     private void addFactoriesFor(String typeName, Map table) {
237         List factoryList;
238         synchronized (factories) {
239             factoryList = (List) factories.get(typeName);
240         }
241 
242         if (factoryList == null) {
243             return;
244         }
245 
246         synchronized (factoryList) {
247             int size = factoryList.size();
248             for (int i = 0; i < size; i++) {
249                 IAdapterFactory factory = (IAdapterFactory) factoryList.get(i);
250 
251                 Class[] adapters = factory.getAdapterList();
252                 for (int j = 0; j < adapters.length; j++) {
253                     String adapterName = adapters[j].getName();
254                     if (table.containsKey(adapterName)) {
255                         continue;
256                     }
257 
258                     table.put(adapterName, factory);
259                 }
260             }
261         }
262     }
263 
264     public void registerAdapters(IAdapterFactory factory, Class adaptable) {
265         registerFactory(factory, adaptable.getName());
266 
267         flushLookup();
268     }
269 
270     private synchronized void flushLookup() {
271         adapterLookup = null;
272         classSearchOrderLookup = null;
273     }
274 
275     private void registerFactory(IAdapterFactory factory, String adaptableType) {
276         List list;
277         synchronized (factories) {
278             list = (List) factories.get(adaptableType);
279             if (list == null) {
280                 list = new ArrayList(5);
281                 factories.put(adaptableType, list);
282             }
283         }
284         synchronized (list) {
285             list.add(factory);
286         }
287     }
288 
289     /**
290      * 
291      * @author Olivier Oeuillot (latest modification by $Author: oeuillot $)
292      * @version $Revision: 1.8 $ $Date: 2007/05/24 12:26:17 $
293      */
294     public static class AdapterBean {
295         private String className;
296 
297         private String adapterFactoryClassName;
298 
299         public final String getAdapterFactoryClassName() {
300             return adapterFactoryClassName;
301         }
302 
303         public final String getClassName() {
304             return className;
305         }
306 
307         public final void setAdapterFactoryClassName(
308                 String adapterFactoryClassName) {
309             this.adapterFactoryClassName = adapterFactoryClassName;
310         }
311 
312         public final void setClassName(String className) {
313             this.className = className;
314         }
315 
316     }
317 
318 }