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  
20  package org.apache.myfaces.cdi.model;
21  
22  import java.lang.reflect.Constructor;
23  import java.lang.reflect.InvocationTargetException;
24  import java.util.Collections;
25  import java.util.Map;
26  import java.util.concurrent.ConcurrentHashMap;
27  import javax.enterprise.context.ApplicationScoped;
28  import javax.faces.FacesException;
29  import javax.faces.context.FacesContext;
30  import javax.faces.model.DataModel;
31  
32  /**
33   *
34   */
35  @ApplicationScoped
36  public class FacesDataModelClassBeanHolder extends DataModelBuilder
37  {
38      private volatile Map<Class<?>,Class<? extends DataModel>> 
39              classInstanceToDataModelWrapperClassMap = new ConcurrentHashMap<Class<?>, Class<? extends DataModel>>();
40      private Map<Class<?>,Class<? extends DataModel>> umclassInstanceToDataModelWrapperClassMap = null;
41      
42      /**
43       * @return the classInstanceToDataModelWrapperClassMap
44       */
45      public Map<Class<?>,Class<? extends DataModel>> getClassInstanceToDataModelWrapperClassMap()
46      {
47          if (umclassInstanceToDataModelWrapperClassMap == null)
48          {
49              umclassInstanceToDataModelWrapperClassMap = 
50                      Collections.unmodifiableMap(classInstanceToDataModelWrapperClassMap);
51          }
52          return umclassInstanceToDataModelWrapperClassMap;
53      }
54      
55      public void addFacesDataModel(Class<?> forClass, Class<? extends DataModel> dataModelClass)
56      {
57          classInstanceToDataModelWrapperClassMap.put(forClass, dataModelClass);
58      }
59  
60      @Override
61      public DataModel createDataModel(FacesContext facesContext, Class<?> forClass, Object value)
62      {
63          Class<? extends DataModel> dataModelClass = getClassInstanceToDataModelWrapperClassMap().get(forClass);
64          if (dataModelClass != null)
65          {
66              return createDataModel(forClass, value, dataModelClass);
67          }
68          else
69          {
70              // Iterate over map and try to find a valid match if any.
71              Class<?> entryForClass = null;
72              Class<? extends DataModel> valueForClass = null;
73              for (Map.Entry<Class<?>,Class<? extends DataModel>> entry : 
74                      getClassInstanceToDataModelWrapperClassMap().entrySet())
75              {
76                  if (entry.getKey().isAssignableFrom(forClass))
77                  {
78                      if (entryForClass != null)
79                      {
80                          // Both models work, but we need to prefer the one
81                          // that is closest to in the hierarchy.
82                          if (entryForClass.isAssignableFrom(entry.getKey()))
83                          {
84                              entryForClass = entry.getKey();
85                              valueForClass = entry.getValue();
86                          }
87                      }
88                      else
89                      {
90                          entryForClass = entry.getKey();
91                          valueForClass = entry.getValue();
92                      }
93                  }
94              }
95              if(entryForClass != null)
96              {
97                  return createDataModel(forClass, value, valueForClass);
98              }
99          }
100         return null;
101     }
102     
103     private DataModel createDataModel(Class<?> forClass, Object value,
104             Class<? extends DataModel> dataModelClass)
105     {
106         try
107         {
108             Constructor selectedConstructor = null;
109             boolean equalsFound = false;
110             for (Constructor constructor : dataModelClass.getConstructors())
111             {
112                 if (constructor.getParameterCount() == 1)
113                 {
114                     if (constructor.getParameterTypes()[0].equals(forClass))
115                     {
116                         selectedConstructor = constructor;
117                         equalsFound = true;
118                     }
119                     else if (constructor.getParameterTypes()[0].isAssignableFrom(forClass))
120                     {
121                         if (!equalsFound)
122                         {
123                             selectedConstructor = constructor;
124                         }
125                     }
126                 }
127             }
128             
129             Constructor constructor = null;
130             if (selectedConstructor != null)
131             {
132                 constructor = selectedConstructor;
133                 return (DataModel) constructor.newInstance(value);
134             }
135             else
136             {
137                 constructor = dataModelClass.getConstructor();
138                 DataModel dm = (DataModel) constructor.newInstance();
139                 dm.setWrappedData(value);
140                 return dm;
141             }
142         } 
143         catch (NoSuchMethodException ex)
144         {
145             throw new FacesException(
146                     "Cannot find constructor of DataModel with "+forClass.getName()+" as parameter", ex);
147         }
148         catch (SecurityException ex)
149         {
150             throw new FacesException(
151                     "Cannot access constructor of DataModel with "+forClass.getName()+" as parameter", ex);
152         } 
153         catch (InstantiationException ex)
154         {
155             throw new FacesException(
156                     "Cannot access constructor of DataModel with "+forClass.getName()+" as parameter", ex);
157         }
158         catch (IllegalAccessException ex)
159         {
160             throw new FacesException(
161                     "Cannot access constructor of DataModel with "+forClass.getName()+" as parameter", ex);
162         } 
163         catch (IllegalArgumentException ex)
164         {
165             throw new FacesException(
166                     "Cannot find constructor of DataModel with "+forClass.getName()+" as parameter", ex);
167         } 
168         catch (InvocationTargetException ex)
169         {
170             throw new FacesException(
171                     "Cannot find constructor of DataModel with "+forClass.getName()+" as parameter", ex);
172         }
173     }
174 }