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/'>Jakarta Commons Team</a>
32 * @version $Revision: 1.2 $
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 context.markClassMap(beanClass);
82
83 if (log.isTraceEnabled()) {
84 log.trace("Marked: " + beanClass);
85 }
86
87 context.pushBean(instance);
88
89
90
91
92
93 ElementDescriptor typeDescriptor =
94 getElementDescriptor(computedDescriptor, context);
95
96
97
98 AttributeDescriptor[] attributeDescriptors =
99 typeDescriptor.getAttributeDescriptors();
100 context.populateAttributes(attributeDescriptors, attributes);
101
102 if (log.isTraceEnabled()) {
103 log.trace("Created bean " + instance);
104 }
105
106
107 if (context.getMapIDs()) {
108
109
110
111 String id = attributes.getValue("id");
112 if (id != null) {
113 context.putBean(id, instance);
114 }
115 }
116 }
117 }
118 return action;
119 }
120
121
122 public void body(String text, ReadContext context) throws Exception {
123 Log log = context.getLog();
124
125 ElementDescriptor currentDescriptor = context.getCurrentDescriptor();
126 if (currentDescriptor == null) {
127 if (log.isTraceEnabled()) {
128 log.trace("path descriptor is null:");
129 }
130 } else {
131 TextDescriptor bodyTextdescriptor =
132 currentDescriptor.getPrimaryBodyTextDescriptor();
133 if (bodyTextdescriptor != null) {
134 if (log.isTraceEnabled()) {
135 log.trace("Setting mixed content for:");
136 log.trace(bodyTextdescriptor);
137 }
138 Updater updater = bodyTextdescriptor.getUpdater();
139 if (log.isTraceEnabled())
140 {
141 log.trace("Updating mixed content with:");
142 log.trace(updater);
143 }
144 if (updater != null && text != null) {
145 updater.update(context, text);
146 }
147 }
148 }
149 }
150
151 public void end(ReadContext context) throws Exception {
152
153 Object instance = context.popBean();
154 update(context, instance);
155 }
156
157 private void update(ReadContext context, Object value) throws Exception {
158 Log log = context.getLog();
159
160 Updater updater = context.getCurrentUpdater();
161
162 if ( updater == null ) {
163 if ( context.getLog().isTraceEnabled() ) {
164 context.getLog().trace("No updater for " + context.getCurrentElement());
165 }
166 } else {
167 updater.update(context, value);
168 }
169
170 String poppedElement = context.popElement();
171 }
172
173
174
175
176 /***
177 * Factory method to create new bean instances
178 *
179 * @param namespace the namespace for the element
180 * @param name the local name
181 * @param attributes the <code>Attributes</code> used to match <code>ID/IDREF</code>
182 * @return the created bean
183 */
184 protected Object createBean(
185 String namespace,
186 String name,
187 Attributes attributes,
188 ElementDescriptor descriptor,
189 ReadContext context) {
190
191
192 ElementMapping mapping = new ElementMapping();
193 Class beanClass = descriptor.getSingularPropertyType();
194 if (beanClass != null && beanClass.isArray()) {
195 beanClass = beanClass.getComponentType();
196 }
197
198
199
200 mapping.setType(beanClass);
201 mapping.setNamespace(namespace);
202 mapping.setName(name);
203 mapping.setAttributes(attributes);
204 mapping.setDescriptor(descriptor);
205
206 Object newInstance =
207 context.getBeanCreationChain().create(mapping, context);
208
209 return newInstance;
210 }
211
212 /*** Allows the navigation from a reference to a property object to the
213 * descriptor defining what the property is. i.e. doing the join from a reference
214 * to a type to lookup its descriptor.
215 * This could be done automatically by the NodeDescriptors.
216 * Refer to TODO.txt for more info.
217 *
218 * @param propertyDescriptor find descriptor for property object
219 * referenced by this descriptor
220 * @return descriptor for the singular property class type referenced.
221 */
222 ElementDescriptor getElementDescriptor(
223 ElementDescriptor propertyDescriptor,
224 ReadContext context) {
225 Log log = context.getLog();
226 Class beanClass = propertyDescriptor.getSingularPropertyType();
227 if (beanClass != null && !Map.class.isAssignableFrom(beanClass)) {
228 if (beanClass.isArray()) {
229 beanClass = beanClass.getComponentType();
230 }
231 if (log.isTraceEnabled()) {
232 log.trace("Filling descriptor for: " + beanClass);
233 }
234 try {
235 XMLBeanInfo xmlInfo =
236 context.getXMLIntrospector().introspect(beanClass);
237 return xmlInfo.getElementDescriptor();
238
239 } catch (Exception e) {
240 log.warn("Could not introspect class: " + beanClass, e);
241 }
242 }
243
244 return propertyDescriptor;
245 }
246
247 }