1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.onemind.commons.relabean.serialize;
16
17 import java.beans.PropertyDescriptor;
18 import java.io.IOException;
19 import java.io.Writer;
20 import java.lang.reflect.Method;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import org.onemind.commons.java.util.StringUtils;
26 import org.onemind.commons.relabean.*;
27 /***
28 * A BeanModelWriter writes bean models, based on as BeanModelDescriptor, into
29 * XML. In addition, it can also write out the meta-model of the bean model.
30 * @author TiongHiang Lee (thlee@onemindsoft.org)
31 * @version $Id: BeanModelWriter.java,v 1.2 2004/08/26 16:29:00 thlee Exp $ $Name: $
32 */
33 public class BeanModelWriter
34 {
35
36 /*** the descriptor * */
37 private RelationalBeanModel _model;
38
39 /*** the name binding * */
40 private NameBinding _binding;
41
42 /*** object cache * */
43 private HashMap _objectCache = new HashMap();
44
45 /***
46 * {@inheritDoc}
47 */
48 public BeanModelWriter(RelationalBeanModel model, NameBinding binding)
49 {
50 _model = model;
51 _binding = binding;
52 if (_binding == null)
53 {
54 _binding = new NameBinding();
55 }
56 }
57
58 /***
59 * Write the meta model from starting from the root class
60 * @param w the writer
61 * @param modelRoot the model root class
62 * @throws IOException if there's IO problem
63 */
64 public void writeMetaModel(Writer w, Class modelRoot) throws IOException
65 {
66 writeMetaModel(w, Collections.singleton(modelRoot));
67 }
68
69 /***
70 * Write multiple meta model from given model root classes
71 * @param w the writer
72 * @param modelRoots the model root classes
73 * @throws IOException if there's IO problem
74 */
75 public void writeMetaModel(Writer w, Collection modelRoots) throws IOException
76 {
77 writeModelHeader(w);
78 w.write("<meta-model name=\"" + _model.getDescriptor().getModelName() + "\">\n");
79 Iterator it = modelRoots.iterator();
80 while (it.hasNext())
81 {
82 Class rootClass = (Class) it.next();
83 RelationalBeanInfo info = _model.getBeanInfo(rootClass);
84 if (info == null)
85 {
86 throw new IllegalArgumentException("Unknown bean class " + rootClass + " in model "
87 + _model.getDescriptor().getModelName());
88 }
89 _writeMetaModelNode(w, "\t", info);
90 }
91 w.write("</meta-model>\n");
92 }
93
94 /***
95 * Write a meta model node
96 * @param w the writer
97 * @param indent the indent
98 * @param info the bean info
99 * @throws IOException if there's IO error
100 */
101 private void _writeMetaModelNode(Writer w, String indent, RelationalBeanInfo info) throws IOException
102 {
103 String name = _binding.getName(info.getBeanClass());
104 if (name == null)
105 {
106 name = info.getBeanClass().getName();
107 }
108 w.write(indent + "<" + name + ">\n");
109 _writeMetaModelNodeProperties(w, indent + "\t", info);
110 w.write(indent + "</" + name + ">\n");
111 }
112
113 /***
114 * Write the header
115 * @param w the writer
116 * @throws IOException if there's IO problem
117 */
118 private void writeModelHeader(Writer w) throws IOException
119 {
120 w.write("<?xml version=\"1.0\"?>\n");
121 w.write("<!-- written by BeanModelWriter -->\n");
122 w.write("<meta-info>\n");
123 _writeBinding(w);
124 _writePrimitives(w);
125 w.write("</meta-info>\n\n");
126 }
127
128 /***
129 * Write the model
130 * @param writer the writer
131 * @param objects the objects
132 * @throws IOException if there's IO problem
133 */
134 public void writeModel(Writer writer, Collection objects) throws IOException
135 {
136 _objectCache.clear();
137 writeModelHeader(writer);
138 Iterator it = objects.iterator();
139 while (it.hasNext())
140 {
141 Object obj = (Object) it.next();
142 writeModelNode(writer, "", obj);
143 }
144 }
145
146 /***
147 * Write the model node
148 * @param writer the writer
149 * @param indent the indent
150 * @param obj the object
151 * @throws IOException if there's IO problem
152 */
153 private void writeModelNode(Writer writer, String indent, Object obj) throws IOException
154 {
155 Integer id = (Integer) _objectCache.get(obj);
156 boolean written = false;
157 if (id == null)
158 {
159 id = new Integer(_objectCache.size());
160 _objectCache.put(obj, id);
161 } else
162 {
163 written = true;
164 }
165 RelationalBeanInfo info = _model.getBeanInfo(obj.getClass());
166 if (info == null)
167 {
168 throw new IllegalArgumentException("Unknown object type " + obj + " in model " + _model.getDescriptor().getModelName());
169 }
170 String name = (String) _binding.getName(obj.getClass());
171 if (name == null)
172 {
173 name = obj.getClass().getName();
174 }
175 if (!written)
176 {
177 writer.write(indent + "<" + name + " _id_=\"" + id + "\">\n ");
178 writeModelNodeProperties(writer, indent + "\t", obj, info);
179 writer.write(indent + "</" + name + ">\n");
180 } else
181 {
182 writer.write(indent + "<" + name + " _refId_=\"" + id + "\"/>\n ");
183 }
184 }
185
186 /***
187 * Writer the model node properties
188 * @param writer the writer
189 * @param indent the string
190 * @param obj the node object
191 * @param info the info
192 * @throws IOException if there's IO problem
193 */
194 private void writeModelNodeProperties(Writer writer, String indent, Object obj, RelationalBeanInfo info) throws IOException
195 {
196 Iterator it = info.getProperties().iterator();
197 while (it.hasNext())
198 {
199 PropertyDescriptor desc = (PropertyDescriptor) it.next();
200 Method m = desc.getReadMethod();
201 Object value;
202 try
203 {
204 value = m.invoke(obj, new Object[]{});
205 } catch (Exception e)
206 {
207 e.printStackTrace();
208 throw new IOException("Cannot get property " + desc.getName() + " from object " + obj + ":" + e.getMessage());
209 }
210 if (value == null)
211 {
212 writer.write(indent + "<property name=\"" + desc.getName() + "\" null=\"true\"/>\n");
213 } else
214 {
215 writer.write(indent + "<property name=\"" + desc.getName() + "\" value=\"" + value + "\">\n");
216 }
217 }
218 it = info.getRelations().iterator();
219 while (it.hasNext())
220 {
221 RelationDescriptor desc = (RelationDescriptor) it.next();
222 Method m = desc.getReadMethod();
223 Object value;
224 try
225 {
226 value = m.invoke(obj, new Object[]{});
227 } catch (Exception e)
228 {
229 e.printStackTrace();
230 throw new IOException("Cannot get property " + desc.getName() + " from object " + obj + ":" + e.getMessage());
231 }
232 String name = desc.getName();
233 if (value == null)
234 {
235 writer.write(indent + "<" + name + " null=\"true\"/>\n");
236 } else
237 {
238 writer.write(indent + "<" + name + ">\n");
239 if (value != null)
240 {
241 if (value instanceof Collection)
242 {
243 Iterator objects = ((Collection) value).iterator();
244 while (objects.hasNext())
245 {
246 Object object = objects.next();
247 if (_model.getDescriptor().isPrimitiveType(object.getClass()))
248 {
249 writePrimitive(writer, indent + "\t", object, info);
250 } else
251 {
252 writeModelNode(writer, indent + "\t", object);
253 }
254 }
255 } else
256 {
257 if (_model.getDescriptor().isPrimitiveType(value.getClass()))
258 {
259 writePrimitive(writer, indent + "\t", value, info);
260 } else
261 {
262 writeModelNode(writer, indent + "\t", value);
263 }
264 }
265 }
266 }
267 writer.write(indent + "</" + name + ">\n");
268 }
269 }
270
271 /***
272 * Writing primitive nodes
273 * @param writer the writer
274 * @param indent the indent
275 * @param object the object
276 * @param info the info
277 */
278 private void writePrimitive(Writer writer, String indent, Object object, RelationalBeanInfo info)
279 {
280
281
282 }
283
284 /***
285 * Resolve the name of class c using the binding setting
286 * @param c the class
287 * @return the name, or the class name if a binding is not found
288 */
289 private String _resolveName(Class c)
290 {
291 String name = _binding.getName(c);
292 if (name == null)
293 {
294 return c.getName();
295 } else
296 {
297 return name;
298 }
299 }
300
301 /***
302 * Write the name binding
303 * @param w the writer
304 * @throws IOException if there's IO problem
305 */
306 private void _writeBinding(Writer w) throws IOException
307 {
308 w.write("\t<name-binding>\n");
309 Iterator it = _binding.getBindings().keySet().iterator();
310 while (it.hasNext())
311 {
312 Class clazz = (Class) it.next();
313 String name = (String) _binding.getName(clazz);
314 w.write("\t\t<binding class=\"" + clazz + "\" name=\"" + name + "\"//>\n");
315 }
316 w.write("\t</name-binding>\n");
317 }
318
319 /***
320 * Write the primitives
321 * @param w the writer
322 * @throws IOException if there's IO problem
323 */
324 private void _writePrimitives(Writer w) throws IOException
325 {
326 w.write("\t<primitives>\n");
327 w.write("\t\t" + StringUtils.concat(_model.getDescriptor().getPrimitiveTypes(), ",\n\t\t") + "\n");
328 w.write("\t</primitives>\n");
329 }
330
331 /***
332 * Writes out meta model node properties
333 * @param w the writer
334 * @param indent the indent
335 * @param info the bean info
336 * @throws IOException if there's IO problem
337 */
338 private void _writeMetaModelNodeProperties(Writer w, String indent, RelationalBeanInfo info) throws IOException
339 {
340 Iterator it = info.getProperties().iterator();
341 while (it.hasNext())
342 {
343 PropertyDescriptor desc = (PropertyDescriptor) it.next();
344 w.write(indent + "<field name=\"" + desc.getName() + "\" type=\"" + desc.getPropertyType().getName() + "\"//>\n");
345 }
346 it = info.getRelations().iterator();
347 while (it.hasNext())
348 {
349 RelationDescriptor desc = (RelationDescriptor) it.next();
350 w.write(indent + "<relation name=\"" + desc.getName() + "\" type=\"" + desc.getRelationType().getName() + "\"//>\n");
351 }
352 }
353
354 /***
355 * Return the binding
356 * @return the binding
357 */
358 public NameBinding getBinding()
359 {
360 return _binding;
361 }
362
363 /***
364 * Get the model
365 * @return the model
366 */
367 public RelationalBeanModel getModel()
368 {
369 return _model;
370 }
371
372 /***
373 * Set the binding
374 * @param binding the binding
375 */
376 public void setBinding(NameBinding binding)
377 {
378 _binding = binding;
379 }
380
381 /***
382 * Set the model
383 * @param model the model
384 */
385 public void setModel(RelationalBeanModel model)
386 {
387 _model = model;
388 }
389 }