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