1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.gridsystems;
18
19 import java.io.IOException;
20 import java.io.ObjectStreamField;
21 import java.io.Writer;
22 import java.lang.reflect.Array;
23 import java.lang.reflect.Field;
24 import java.lang.reflect.Modifier;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.LinkedHashMap;
31 import java.util.LinkedHashSet;
32 import java.util.Map;
33 import java.util.SortedMap;
34 import java.util.SortedSet;
35 import java.util.TreeMap;
36 import java.util.Vector;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class GridXMLSerializer {
82
83
84
85
86 private static Log log = LogFactory.getLog(GridXMLSerializer.class);
87
88
89
90
91 private static final String SPACER = " ";
92
93
94
95
96 private Writer outWriter = null;
97
98
99
100
101
102
103 public GridXMLSerializer(Writer output) {
104 outWriter = output;
105
106 log.debug("New GridXMLSerializer created");
107 }
108
109
110
111
112
113
114
115 public void begin() throws IOException {
116 outWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
117 outWriter.write("<main>\n");
118
119 log.debug("Serialization started");
120 }
121
122
123
124
125
126
127
128
129 public void end() throws IOException {
130 outWriter.write("</main>\n");
131
132 log.debug("Serialization ended");
133 }
134
135
136
137
138
139
140
141
142
143
144
145 public void write(Object obj, String excluded) throws IOException {
146 outWriter.write(serialize(obj, SPACER, excluded));
147 }
148
149
150
151
152
153
154
155
156 public void write(Object obj) throws IOException {
157 outWriter.write(serialize(obj, SPACER, null));
158 }
159
160
161
162
163
164
165
166
167 private static Class[] getSuperClasses(Class origin) {
168
169 log.debug("getting super classes of " + origin.getName());
170
171 if (origin == Object.class) {
172
173 return new Class[0];
174 }
175
176 Class aux = origin;
177 int classDepth = 0;
178 do {
179 classDepth++;
180 aux = aux.getSuperclass();
181 } while (aux != Object.class);
182
183 Class[] superClasses = new Class[classDepth];
184 aux = origin;
185 int i = 0;
186 do {
187 superClasses[i++] = aux;
188 aux = aux.getSuperclass();
189 } while (aux != Object.class);
190
191 log.debug("super classes of " + origin.getName() + " got successfully");
192
193 return superClasses;
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207 private static Field[] getFields(Object obj) {
208 Class origin = obj.getClass();
209 Field[] fieldsArray;
210 Vector<Field> fieldsVector = new Vector<Field>();
211 ObjectStreamField[] xmlFields = null;
212 Class[] superClasses = getSuperClasses(origin);
213 boolean includeField;
214
215 log.debug("getting serializable fields from " + origin.getName());
216
217
218 try {
219 Field specialField = origin.getDeclaredField("xmlPersistentFields");
220 specialField.setAccessible(true);
221 xmlFields = (ObjectStreamField[]) specialField.get(obj);
222 } catch (NoSuchFieldException e) {
223
224 } catch (IllegalAccessException e) {
225
226 }
227
228 for (int i = 0; i < superClasses.length; i++) {
229 fieldsArray = superClasses[i].getDeclaredFields();
230
231 for (int j = 0; j < fieldsArray.length; j++) {
232
233 if (xmlFields == null) {
234 includeField = !Modifier.isStatic(fieldsArray[j].getModifiers());
235 } else {
236 includeField = false;
237 for (int k = 0; k < xmlFields.length; k++) {
238 if (fieldsArray[j].getName().equals(xmlFields[k].getName())) {
239 includeField = true;
240 }
241 }
242 }
243 if (includeField) {
244 fieldsVector.add(fieldsArray[j]);
245 }
246 }
247 }
248
249 fieldsArray = new Field[fieldsVector.size()];
250 fieldsVector.copyInto(fieldsArray);
251
252 Arrays.sort(fieldsArray, new Comparator<Field>() {
253 public int compare(Field f1, Field f2) {
254 String n1 = (f1 == null) ? null : f1.getName();
255 String n2 = (f2 == null) ? null : f2.getName();
256 if (n1 == null) {
257 return -1;
258 } else if (n2 == null) {
259 return 1;
260 } else {
261 return n1.compareTo(n2);
262 }
263 }
264 });
265 Field.setAccessible(fieldsArray, true);
266
267 log.debug("serializable fields from " + origin.getName() + " got successfully");
268
269 return fieldsArray;
270 }
271
272
273
274
275
276 private static boolean isBasicType(Class c) {
277 if (Number.class.isAssignableFrom(c) || CharSequence.class.isAssignableFrom(c)) {
278 return true;
279 } else if (c == Boolean.class || c == Character.class) {
280 return true;
281 }
282 return false;
283 }
284
285
286
287
288
289
290
291
292
293
294 private static String serialize(Object obj, String indent, String excluded) {
295 StringBuffer output = new StringBuffer();
296 Class objectClass = obj.getClass();
297
298 log.debug("starting serialization of object from class " + objectClass.getName());
299
300 output.append(indent);
301 output.append("<object class=\"");
302
303 if (objectClass.isArray()) {
304 output.append("Array\" componentType=\"");
305 if (objectClass.getComponentType().isArray()) {
306 output.append("Array");
307 } else {
308 output.append(objectClass.getComponentType().getName());
309 }
310 } else {
311 output.append(objectClass.getName());
312 }
313 output.append("\">");
314
315
316 if (isBasicType(objectClass)) {
317
318 output.append(encodeXML(obj.toString()));
319 output.append("</object>\n");
320 } else {
321
322 output.append("\n");
323 if (objectClass.isArray()) {
324 serializeArray(obj, indent, excluded, output, objectClass);
325 } else {
326
327
328 if (obj instanceof Collection) {
329 serializeCollection((Collection)obj, indent, excluded, output);
330 } else if (obj instanceof Map) {
331 serializeMap((Map)obj, indent, excluded, output);
332 } else {
333 serializeObject(obj, indent, excluded, output);
334 }
335 }
336 output.append(indent);
337 output.append("</object>\n");
338 }
339
340 log.debug("serialization of object from class " + objectClass.getName()
341 + " successfully");
342
343 return output.toString();
344 }
345
346
347
348
349
350
351
352
353
354 private static void serializeArray(Object obj, String indent, String excluded,
355 StringBuffer output, Class objectClass) {
356 Object item;
357 boolean exclude = false;
358
359
360 log.debug("serializing array...");
361 if (objectClass.getComponentType().isPrimitive()) {
362
363 for (int i = 0; i < Array.getLength(obj); i++) {
364 item = Array.get(obj, i);
365 if (item.toString().equalsIgnoreCase(excluded)) {
366 exclude = true;
367 break;
368 }
369 }
370 if (!exclude) {
371 for (int i = 0; i < Array.getLength(obj); i++) {
372 item = Array.get(obj, i);
373 output.append(indent + SPACER);
374 output.append("<arrayItem index=\"");
375 output.append(i);
376 output.append("\">");
377 output.append(encodeXML(item.toString()));
378 output.append("</arrayItem>\n");
379 }
380 }
381 } else {
382 for (int i = 0; i < Array.getLength(obj); i++) {
383 item = Array.get(obj, i);
384 output.append(indent + SPACER);
385 output.append("<arrayItem index=\"");
386 output.append(i);
387 output.append("\">\n");
388 if (item != null) {
389 output.append(serialize(item, indent + SPACER + SPACER, excluded));
390 }
391 output.append(indent + SPACER);
392 output.append("</arrayItem>\n");
393 }
394 }
395 log.debug("...array serialized");
396 }
397
398
399
400
401
402
403
404
405 private static void serializeObject(Object obj, String indent, String excluded,
406 StringBuffer output) {
407
408 log.debug("serializing " + obj.getClass().getName() + "...");
409
410 Field[] fields = getFields(obj);
411
412 for (int i = 0; i < fields.length; i++) {
413 if (fields[i].getType().isPrimitive() && fields[i].toString().equals(excluded)) {
414 log.debug("...object not serialized. Excluded because it has a "
415 + excluded + " component");
416 return;
417 }
418 }
419
420 for (int i = 0; i < fields.length; i++) {
421 output.append(serializeField(obj, fields[i], indent + SPACER, excluded));
422 }
423 }
424
425
426
427
428
429
430
431
432 private static void serializeMap(Map map, String indent, String excluded,
433 StringBuffer output) {
434 Object item;
435
436 log.debug("serializing map...");
437
438 if (excluded != null) {
439 if (map.containsKey(excluded) || map.containsValue(excluded)) {
440 log.debug("...map not serialized. Excluded because it has a "
441 + excluded + " component");
442 return;
443 }
444 }
445
446
447 Map sorted = sort(map);
448
449 final String spacer = indent + " ";
450
451 for (Object key : sorted.keySet()) {
452 Map myMap = (Map) map;
453 item = myMap.get(key);
454 output.append(indent).append(" <mapItem>\n");
455 output.append(indent).append(" <key>\n");
456 output.append(serialize(key, spacer, excluded));
457 output.append(indent).append(" </key>\n");
458 if (item != null) {
459 output.append(indent).append(" <value>\n");
460 output.append(serialize(item, spacer, excluded));
461 output.append(indent).append(" </value>\n");
462 }
463 output.append(indent).append(" </mapItem>\n");
464 }
465 log.debug("...map serialized");
466 }
467
468
469
470
471
472
473
474
475 private static void serializeCollection(Collection col,
476 String indent, String excluded, StringBuffer output) {
477
478
479
480 log.debug("serializing collection...");
481
482
483 if (excluded != null && col.contains(excluded)) {
484 log.debug("...collection not serialized. Excluded because it has a "
485 + excluded + " component");
486 return;
487 }
488
489
490 Collection sorted = sort(col);
491 for (Object item : sorted) {
492 if (item != null) {
493 output.append(indent).append(SPACER).append("<collectionItem>\n");
494 output.append(serialize(item, indent + SPACER + SPACER, excluded));
495 output.append(indent).append(SPACER).append("</collectionItem>\n");
496 }
497 }
498 log.debug("...collection serialized");
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514 private static String serializeField(Object obj, Field classField,
515 String indent, String excluded) {
516
517
518 log.debug("starting serialization of field " + classField.getName()
519 + " from class " + obj.getClass().getName());
520
521 StringBuffer output = new StringBuffer();
522 try {
523 Object field = classField.get(obj);
524
525 output.append(indent).append("<field name=\"");
526 output.append(classField.getName());
527 if (field != null && classField.getType().isPrimitive()) {
528 output.append("\" type=\"");
529 output.append(classField.getType().getName());
530 }
531 output.append("\">");
532
533 if (field == null) {
534 output.append("</field>\n");
535 } else if (classField.getType().isPrimitive()) {
536 output.append(encodeXML(field.toString()) + "</field>\n");
537 } else {
538 output.append("\n");
539 output.append(serialize(field, indent + SPACER, excluded));
540 output.append(indent).append("</field>\n");
541 }
542
543 log.debug("serialization of field " + classField.getName()
544 + " from class " + obj.getClass().getName() + " successful");
545 } catch (IllegalAccessException e) {
546 log.error("Field " + obj.getClass().getName()
547 + "#" + classField.getName() + " not available.");
548 }
549 return output.toString();
550 }
551
552
553
554
555
556
557
558
559
560
561 public static String encodeXML(String in) {
562 StringBuffer out = new StringBuffer(in.length());
563 for (int i = 0; i < in.length(); i++) {
564 char c = in.charAt(i);
565 switch (c) {
566 case '&':
567 out.append("&");
568 break;
569 case '<':
570 out.append("<");
571 break;
572 case '>':
573 out.append(">");
574 break;
575 case '\'':
576 out.append("'");
577 break;
578 case '"':
579 out.append(""");
580 break;
581 default:
582 out.append(c);
583 }
584 }
585 return out.toString();
586 }
587
588
589
590
591
592
593
594
595
596
597 @SuppressWarnings("unchecked")
598 private static Collection sort(Collection c) {
599 try {
600 if (c instanceof SortedSet || c instanceof LinkedHashSet) {
601 return c;
602 } else {
603 ArrayList list = new ArrayList(c);
604 Collections.sort(list);
605 return list;
606 }
607 } catch (Throwable t) {
608
609 return c;
610 }
611 }
612
613
614
615
616
617
618
619
620
621
622
623
624 @SuppressWarnings("unchecked")
625 private static Map sort(Map map) {
626 try {
627 if (map instanceof SortedMap || map instanceof LinkedHashMap) {
628 return map;
629 } else {
630 return new TreeMap(map);
631 }
632 } catch (Exception e) {
633 return map;
634 }
635 }
636 }