1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.change;
20
21 import java.util.HashMap;
22
23 import javax.el.ValueExpression;
24
25 import javax.faces.component.NamingContainer;
26 import javax.faces.component.UIComponent;
27 import javax.faces.context.FacesContext;
28 import javax.faces.el.ValueBinding;
29
30 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
31
32
33 /**
34 * The base class for all ChangeManagers.
35 * A ChangeManager should manage accumulation of Changes and also
36 * take care of their persistence.
37 * @version $Name: $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/change/ChangeManager.java#0 $) $Date: 10-nov-2005.19:09:58 $
38 */
39 public abstract class ChangeManager
40 {
41 public static void registerDocumentFactory(
42 String targetClassName,
43 String converterClassName)
44 {
45 if ((targetClassName == null) || (targetClassName.length() == 0))
46 throw new IllegalArgumentException(_LOG.getMessage(
47 "TARGET_CLASS_NAME_MUST_BE_PROVIDED"));
48
49 if ((converterClassName == null) || (converterClassName.length() == 0))
50 throw new IllegalArgumentException(_LOG.getMessage(
51 "CONVERTER_CLASS_NAME_MUST_BE_PROVIDED"));
52
53 synchronized (_CLASSNAME_TO_CONVERTER_NAME_MAP)
54 {
55 _CLASSNAME_TO_CONVERTER_NAME_MAP.put(targetClassName, converterClassName);
56 }
57 }
58
59 /**
60 * Use the conversion rules to attempt to retrieve the equivalent
61 * document change for a ComponentChange
62 * @param change to convert
63 */
64 protected static DocumentChange createDocumentChange(
65 ComponentChange change)
66 {
67 Class<? extends ComponentChange> changeClass = change.getClass();
68
69 Object converterObject = null;
70 DocumentChangeFactory converter = null;
71
72 synchronized (_CLASS_TO_CONVERTER_MAP)
73 {
74 converterObject = _CLASS_TO_CONVERTER_MAP.get(changeClass);
75 }
76
77 if (converterObject != null)
78 {
79 converter = (DocumentChangeFactory)converterObject;
80 }
81 else
82 {
83 String converterName = null;
84
85 synchronized (_CLASSNAME_TO_CONVERTER_NAME_MAP)
86 {
87 converterName =
88 _CLASSNAME_TO_CONVERTER_NAME_MAP.get(changeClass.getName());
89 }
90
91 if (converterName != null)
92 {
93 try
94 {
95 ClassLoader contextClassLoader =
96 Thread.currentThread().getContextClassLoader();
97
98 Class<?> converterClass = contextClassLoader.loadClass(converterName);
99 if (DocumentChangeFactory.class.isAssignableFrom(converterClass))
100 {
101 converter = (DocumentChangeFactory)converterClass.newInstance();
102
103 synchronized (_CLASS_TO_CONVERTER_MAP)
104 {
105 _CLASS_TO_CONVERTER_MAP.put(changeClass, converter);
106 }
107 }
108 else
109 {
110
111 _LOG.warning("CONVERSION_CLASS_TYPE", new Object[] {converterClass, DocumentChangeFactory.class});
112 }
113 }
114 catch (Throwable e)
115 {
116 _LOG.warning("UNABLE_INSTANTIATE_CONVERTERCLASS", converterName);
117 _LOG.warning(e);
118 }
119
120
121
122 if (converter == null)
123 {
124
125 _CLASSNAME_TO_CONVERTER_NAME_MAP.remove(converterName);
126
127 return null;
128 }
129 }
130 }
131
132
133 if (converter != null)
134 return converter.convert(change);
135
136 return null;
137 }
138
139 /**
140 * Add a ComponentChange to this current request for a specified component.
141 * @throws IllegalArgumentException if any of the supplied parameters were to
142 * be null.
143 */
144 public abstract void addComponentChange(
145 FacesContext facesContext,
146 UIComponent uiComponent,
147 ComponentChange change);
148
149 /**
150 * Add a DocumentChange to this current request for a specified component.
151 * @throws IllegalArgumentException if any of the supplied parameters were to
152 * be null.
153 */
154 public void addDocumentChange(
155 FacesContext facesContext,
156 UIComponent uiComponent,
157 DocumentChange change)
158 {
159 if (facesContext == null || uiComponent == null || change == null)
160 throw new IllegalArgumentException(_LOG.getMessage(
161 "CANNOT_ADD_CHANGE_WITH_FACECONTEXT_OR_UICOMPONENT_OR_NULL"));
162 }
163
164 /**
165 * Applies all the ComponentChanges added so far for the current view.
166 * Developers should not need to call this method. Internal implementation
167 * will call it as the component tree is built and is ready to take changes.
168 * @param facesContext The FacesContext instance for the current request.
169 */
170 public void applyComponentChangesForCurrentView(FacesContext facesContext)
171 {
172 throw new UnsupportedOperationException("Subclassers must implement");
173 }
174
175 /**
176 * Applies the ComponentChanges added so far for components underneath
177 * the specified NamingContainer.
178 * Developers should not need to call this method. Internal implementation
179 * will call it as the component tree is built and is ready to take changes.
180 * @param facesContext The FacesContext instance for the current request.
181 * @param root The NamingContainer that contains the component subtree
182 * to which ComponentChanges should be applied. If null, all changes are
183 * applied.
184 * @throws IllegalArgumentException if the root NamingContainer is not a
185 * UIComponent instance.
186 */
187 public void applyComponentChangesForSubtree(
188 FacesContext facesContext,
189 NamingContainer root
190 )
191 {
192 throw new UnsupportedOperationException("Subclassers must implement");
193 }
194
195 private static class AttributeConverter extends DocumentChangeFactory
196 {
197 @Override
198 public DocumentChange convert(ComponentChange compChange)
199 {
200 if (compChange instanceof AttributeComponentChange)
201 {
202 AttributeComponentChange change = (AttributeComponentChange)compChange;
203
204 Object value = change.getAttributeValue();
205
206
207 String valueString = null;
208 if ((value == null) ||
209 (value instanceof CharSequence) ||
210 (value instanceof Number) ||
211 (value instanceof Boolean))
212 {
213 valueString = (value != null)? value.toString() : null;
214 }
215 else if (value instanceof ValueExpression)
216 {
217 valueString = ((ValueExpression)value).getExpressionString();
218 }
219 else if (value instanceof ValueBinding)
220 {
221 valueString = ((ValueBinding)value).getExpressionString();
222 }
223
224 if (valueString != null)
225 return new AttributeDocumentChange(change.getAttributeName(),
226 valueString);
227 }
228
229
230 return null;
231 }
232 }
233
234 private static HashMap<String, String> _CLASSNAME_TO_CONVERTER_NAME_MAP =
235 new HashMap<String, String>();
236
237 private static HashMap<Class<? extends ComponentChange>, DocumentChangeFactory> _CLASS_TO_CONVERTER_MAP =
238 new HashMap<Class<? extends ComponentChange>, DocumentChangeFactory>();
239
240 static private final TrinidadLogger _LOG =
241 TrinidadLogger.createTrinidadLogger(ChangeManager.class);
242
243 static
244 {
245
246 _CLASS_TO_CONVERTER_MAP.put(AttributeComponentChange.class,
247 new AttributeConverter());
248 }
249
250 }