View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   */
19  package org.apache.myfaces.trinidad.bean;
20  
21  import java.io.InputStream;
22  import java.io.IOException;
23  import java.net.URL;
24  
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.Enumeration;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Properties;
32  import java.util.concurrent.ConcurrentHashMap;
33  
34  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
35  
36  
37  /**
38   * Base interface for FacesBean storage.
39   *
40   */
41  public class FacesBeanFactory
42  {
43    /**
44     * Create a FacesBean for a component class.
45     */
46    // TODO change from ownerClass to componentFamily?
47    static public FacesBean createFacesBean(
48      Class<?> ownerClass,
49      String   rendererType)
50    {
51      if (ownerClass == null)
52        return null;
53  
54      String className = ownerClass.getName();
55      FacesBean bean = createFacesBean(className, rendererType);
56  
57      if (bean == null && rendererType != null)
58      {
59        bean = createFacesBean(className, null);
60        _cacheFacesBeanClass(bean, className, rendererType);
61      }
62      
63      if (bean == null)
64      {
65        bean = createFacesBean(ownerClass.getSuperclass(), rendererType);
66        _cacheFacesBeanClass(bean, className, rendererType);
67      }
68  
69      return bean;
70    }
71  
72    static public FacesBean createFacesBean(
73      String beanType,
74      String rendererType)
75    {
76      String typeKey = _buildTypeKey(beanType, rendererType);
77  
78      Class<?> type = _TYPES_CLASS.get(typeKey);
79        
80      if(type == null)
81      {
82        String className = (String) _TYPES_MAP.get(typeKey);
83        if (className == null)
84          return null;
85        
86        // At this point we did not have a cached FacesBean class for the
87        // typeKey, but we did have a cached className for the typeKey.
88        //  Get the FacesBean class from the className and cache.
89        // This will improve performance based on tests.
90        try
91        {
92          type = _getClassLoader().loadClass(className);
93          _TYPES_CLASS.put(typeKey, type);
94        }
95        catch (ClassNotFoundException cnfe)
96        {
97          _LOG.severe("CANNOT_FIND_FACESBEAN", className);
98          _LOG.severe(cnfe);
99        }
100     }
101   
102     try
103     {
104       return (FacesBean) type.newInstance();
105     }
106     catch (IllegalAccessException iae)
107     {
108       _LOG.severe("CANNOT_CREATE_FACESBEAN_INSTANCE", type.getName());
109       _LOG.severe(iae);
110     }
111     catch (InstantiationException ie)
112     {
113       _LOG.severe("CANNOT_CREATE_FACESBEAN_INSTANCE", type.getName());
114       _LOG.severe(ie);
115     }
116 
117     return null;
118   }
119 
120   static private void _initializeBeanTypes()
121   {
122     _TYPES_MAP = new HashMap<Object, Object>();
123 
124     List<URL> list = new ArrayList<URL>();
125     try
126     {
127       Enumeration<URL> en = _getClassLoader().getResources(
128                                 "META-INF/faces-bean.properties");
129       while (en.hasMoreElements())
130       {
131         list.add(en.nextElement());
132       }
133 
134       Collections.reverse(list);
135     }
136     catch (IOException ioe)
137     {
138       _LOG.severe(ioe);
139       return;
140     }
141 
142     if (list.isEmpty())
143     {
144       if (_LOG.isInfo())
145         _LOG.info("NO_FACES_BEAN_PROPERTIES_FILES_LOCATED");
146     }
147 
148     for(URL url : list)
149     {
150       _initializeBeanTypes(url);
151     }
152   }
153 
154   static private void _initializeBeanTypes(URL url)
155   {
156     try
157     {
158       Properties properties = new Properties();
159       InputStream is = url.openStream();
160       try
161       {
162         properties.load(is);
163         if (_LOG.isFine())
164           _LOG.fine("Loading bean factory info from " + url);
165         
166         _TYPES_MAP.putAll(properties);
167       }
168       finally
169       {
170         is.close();
171       }
172     }
173     catch (IOException ioe)
174     {
175       _LOG.severe("CANNOT_LOAD_URL", url);
176       _LOG.severe(ioe);
177     }
178   }
179 
180 
181   static private ClassLoader _getClassLoader()
182   {
183     ClassLoader loader = Thread.currentThread().getContextClassLoader();
184     if (loader == null)
185       loader = FacesBeanFactory.class.getClassLoader();
186     return loader;
187   }
188 
189   /* given non-null beanType & rendererType, concatenate together with 
190    * a '|' in between
191    */
192   static private String _buildTypeKey(
193     String beanType, 
194     String rendererType)
195   {
196     if (rendererType != null)
197     {
198       int length = beanType.length() + 1 + rendererType.length();
199       StringBuilder typeKeyBuilder = new StringBuilder(length);
200       
201       typeKeyBuilder.append(beanType).append('|').append(rendererType);
202       
203       return typeKeyBuilder.toString();
204     }
205     else
206       return beanType;
207     
208   }
209   
210   static private void _cacheFacesBeanClass(
211     FacesBean bean,
212     String beanType, 
213     String rendererType)
214   {
215     // cache the typeKey and the bean's class, for performance
216     if(bean != null)
217     {
218       String typeKey = _buildTypeKey(beanType, rendererType);
219       _TYPES_CLASS.put(typeKey, bean.getClass());
220     }
221   }
222 
223   static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(FacesBeanFactory.class);
224   static private Map<Object, Object> _TYPES_MAP;
225   static private Map<String, Class<?>> _TYPES_CLASS = new ConcurrentHashMap<String, Class<?>>();
226 
227   static
228   {
229     _initializeBeanTypes();
230   }
231 }