1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.betwixt.io.read;
18
19 import java.util.Map;
20
21 import org.apache.commons.betwixt.AttributeDescriptor;
22 import org.apache.commons.betwixt.ElementDescriptor;
23 import org.apache.commons.betwixt.TextDescriptor;
24 import org.apache.commons.betwixt.XMLBeanInfo;
25 import org.apache.commons.betwixt.expression.Updater;
26 import org.apache.commons.logging.Log;
27 import org.xml.sax.Attributes;
28
29 /***
30 * Action that creates and binds a new bean instance.
31 *
32 * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
33 * @version $Revision: 438373 $
34 */
35 public class BeanBindAction extends MappingAction.Base {
36
37 /*** Singleton instance */
38 public static final BeanBindAction INSTANCE = new BeanBindAction();
39
40 /***
41 * Begins a new element which is to be bound to a bean.
42 */
43 public MappingAction begin(
44 String namespace,
45 String name,
46 Attributes attributes,
47 ReadContext context)
48 throws Exception {
49
50 Log log = context.getLog();
51
52 ElementDescriptor computedDescriptor = context.getCurrentDescriptor();
53
54 if (log.isTraceEnabled()) {
55 log.trace("Element Pushed: " + name);
56 }
57
58
59 MappingAction action = MappingAction.EMPTY;
60
61 Object instance = null;
62 Class beanClass = null;
63 if (computedDescriptor == null) {
64 log.trace("No Descriptor");
65 } else {
66 beanClass = computedDescriptor.getSingularPropertyType();
67 }
68
69
70 if (beanClass != null && !Map.class.isAssignableFrom(beanClass)) {
71
72 instance =
73 createBean(
74 namespace,
75 name,
76 attributes,
77 computedDescriptor,
78 context);
79
80 if (instance != null) {
81 action = this;
82 if (computedDescriptor.isUseBindTimeTypeForMapping())
83 {
84 beanClass = instance.getClass();
85 }
86 context.markClassMap(beanClass);
87
88 if (log.isTraceEnabled()) {
89 log.trace("Marked: " + beanClass);
90 }
91
92 context.pushBean(instance);
93
94
95
96
97
98 ElementDescriptor typeDescriptor =
99 getElementDescriptor(computedDescriptor, context);
100
101
102 AttributeDescriptor[] attributeDescriptors =
103 typeDescriptor.getAttributeDescriptors();
104 context.populateAttributes(attributeDescriptors, attributes);
105
106 if (log.isTraceEnabled()) {
107 log.trace("Created bean " + instance);
108 }
109
110
111 if (context.getMapIDs()) {
112
113
114
115 String id = attributes.getValue("id");
116 if (id != null) {
117 context.putBean(id, instance);
118 }
119 }
120 }
121 }
122 return action;
123 }
124
125
126 public void body(String text, ReadContext context) throws Exception {
127 Log log = context.getLog();
128
129 ElementDescriptor currentDescriptor = context.getCurrentDescriptor();
130 if (currentDescriptor == null) {
131 if (log.isTraceEnabled()) {
132 log.trace("path descriptor is null:");
133 }
134 } else {
135 TextDescriptor bodyTextdescriptor =
136 currentDescriptor.getPrimaryBodyTextDescriptor();
137 if (bodyTextdescriptor != null) {
138 if (log.isTraceEnabled()) {
139 log.trace("Setting mixed content for:");
140 log.trace(bodyTextdescriptor);
141 }
142 Updater updater = bodyTextdescriptor.getUpdater();
143 if (log.isTraceEnabled())
144 {
145 log.trace("Updating mixed content with:");
146 log.trace(updater);
147 }
148 if (updater != null && text != null) {
149 updater.update(context, text);
150 }
151 }
152 }
153 }
154
155 public void end(ReadContext context) throws Exception {
156
157 Object instance = context.popBean();
158 update(context, instance);
159 }
160
161 private void update(ReadContext context, Object value) throws Exception {
162 Log log = context.getLog();
163
164 Updater updater = context.getCurrentUpdater();
165
166 if ( updater == null ) {
167 if ( context.getLog().isTraceEnabled() ) {
168 context.getLog().trace("No updater for " + context.getCurrentElement());
169 }
170 } else {
171 updater.update(context, value);
172 }
173
174 String poppedElement = context.popElement();
175 }
176
177
178
179
180 /***
181 * Factory method to create new bean instances
182 *
183 * @param namespace the namespace for the element
184 * @param name the local name
185 * @param attributes the <code>Attributes</code> used to match <code>ID/IDREF</code>
186 * @return the created bean
187 */
188 protected Object createBean(
189 String namespace,
190 String name,
191 Attributes attributes,
192 ElementDescriptor descriptor,
193 ReadContext context) {
194
195
196 ElementMapping mapping = new ElementMapping();
197 Class beanClass = descriptor.getSingularPropertyType();
198 if (beanClass != null && beanClass.isArray()) {
199 beanClass = beanClass.getComponentType();
200 }
201
202
203
204 mapping.setType(beanClass);
205 mapping.setNamespace(namespace);
206 mapping.setName(name);
207 mapping.setAttributes(attributes);
208 mapping.setDescriptor(descriptor);
209
210 Object newInstance =
211 context.getBeanCreationChain().create(mapping, context);
212
213 return newInstance;
214 }
215
216 /*** Allows the navigation from a reference to a property object to the
217 * descriptor defining what the property is. i.e. doing the join from a reference
218 * to a type to lookup its descriptor.
219 * This could be done automatically by the NodeDescriptors.
220 * Refer to TODO.txt for more info.
221 *
222 * @param propertyDescriptor find descriptor for property object
223 * referenced by this descriptor
224 * @return descriptor for the singular property class type referenced.
225 */
226 private ElementDescriptor getElementDescriptor(
227 ElementDescriptor propertyDescriptor,
228 ReadContext context) {
229 Log log = context.getLog();
230 Class beanClass = propertyDescriptor.getSingularPropertyType();
231 if (propertyDescriptor.isUseBindTimeTypeForMapping()) {
232
233 Object current = context.getBean();
234 if (current != null) {
235 beanClass = current.getClass();
236 }
237 }
238 if (beanClass != null && !Map.class.isAssignableFrom(beanClass)) {
239 if (beanClass.isArray()) {
240 beanClass = beanClass.getComponentType();
241 }
242
243
244
245 if (log.isTraceEnabled()) {
246 log.trace("Filling descriptor for: " + beanClass);
247 }
248 try {
249 XMLBeanInfo xmlInfo =
250 context.getXMLIntrospector().introspect(beanClass);
251 return xmlInfo.getElementDescriptor();
252
253 } catch (Exception e) {
254 log.warn("Could not introspect class: " + beanClass, e);
255 }
256 }
257
258 return propertyDescriptor;
259 }
260
261 }