1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package com.mindtree.techworks.insight.preferences.xmlpersistence;
26
27 import java.io.OutputStream;
28 import java.io.OutputStreamWriter;
29 import java.io.PrintWriter;
30 import java.io.UnsupportedEncodingException;
31 import java.lang.reflect.Method;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Stack;
36
37 import org.xml.sax.Attributes;
38 import org.xml.sax.Locator;
39 import org.xml.sax.SAXException;
40 import org.xml.sax.SAXParseException;
41 import org.xml.sax.ext.LexicalHandler;
42 import org.xml.sax.helpers.DefaultHandler;
43 import org.xml.sax.helpers.NamespaceSupport;
44
45 import com.mindtree.techworks.insight.preferences.model.Preference;
46 import com.mindtree.techworks.insight.preferences.model.PreferenceAttribute;
47
48
49
50
51
52
53
54
55 public class XMLPreferenceDataWriter extends DefaultHandler implements
56 LexicalHandler, PreferenceXMLNameConstants {
57
58
59
60
61
62
63
64 private static final String KEY_SEPERATOR = "_";
65
66
67
68
69 private static final String ENCODING = "UTF8";
70
71
72
73
74 private static final String ENCODING_XML_STRING = "UTF-8";
75
76
77
78
79 private static final String PI_START = "<?";
80
81
82
83
84 private static final String PI_END = "?>";
85
86
87
88
89 private static final String SPACE = " ";
90
91
92
93
94 private static final String ELEMENT_START = "<";
95
96
97
98
99 private static final String ELEMENT_END = ">";
100
101
102
103
104 private static final String ELEMENT_TERM_START = "</";
105
106
107
108
109 private static final String ATTRIBUTE_START = "=\"";
110
111
112
113
114 private static final String ATTRIBUTE_END = "\"";
115
116
117
118
119 private static final String CDATA_START = "<![CDATA[";
120
121
122
123
124 private static final String CDATA_END = "]]>";
125
126
127
128
129 private static final String COMMENT_START = "<!--";
130
131
132
133
134 private static final String COMMENT_END = "-->";
135
136
137
138
139
140
141
142 private PrintWriter printWriter;
143
144
145
146
147 private Locator documentLocator;
148
149
150
151
152 private int elementDepth;
153
154
155
156
157 private boolean inXML11;
158
159
160
161
162 private boolean inCData;
163
164
165
166
167 private boolean isCanonical;
168
169
170
171
172 private String currentCompletePreferenceId;
173
174
175
176
177 private Stack preferenceIdStack;
178
179
180
181
182 private String currentPreferenceAttributeId;
183
184
185
186
187 private String currentElementToReadDataFor;
188
189
190
191
192 private HashMap preferenceAttributesToSave;
193
194
195
196
197 private NamespaceSupport namespaceSupport;
198
199
200
201
202
203 private boolean isCurrentValueWritten = false;
204
205
206
207
208
209
210
211
212 public XMLPreferenceDataWriter () {
213
214 isCanonical = false;
215 preferenceAttributesToSave = new HashMap();
216 namespaceSupport = new NamespaceSupport();
217 preferenceIdStack = new Stack();
218 }
219
220
221
222
223
224
225
226
227
228
229
230 public void setOutput (OutputStream stream)
231 throws UnsupportedEncodingException {
232
233 java.io.Writer writer = new OutputStreamWriter(stream, ENCODING);
234 printWriter = new PrintWriter(writer);
235
236 }
237
238
239
240
241
242
243 public void setPreferencesToSave (List preferences) {
244
245 if (null != preferences) {
246 for (Iterator preferencesItr = preferences.iterator(); preferencesItr
247 .hasNext();) {
248 Preference preference = (Preference) preferencesItr.next();
249 setPreferenceToSave(preference);
250 }
251 }
252 }
253
254
255
256
257
258
259 private void setPreferenceToSave (Preference preference) {
260
261 String preferenceId = preference.getCompleteId();
262
263 for (Iterator preferenceAttributeItr = preference
264 .iteratePreferenceAttributes(); preferenceAttributeItr
265 .hasNext();) {
266 PreferenceAttribute preferenceAttribute = (PreferenceAttribute) preferenceAttributeItr
267 .next();
268 if (preferenceAttribute.isPersistant()) {
269 preferenceAttributesToSave.put(preferenceId + KEY_SEPERATOR
270 + preferenceAttribute.getId(), preferenceAttribute
271 .getValue());
272 }
273 }
274
275
276 for (Iterator childPreferences = preference.iterateChildPreferences(); null != childPreferences
277 && childPreferences.hasNext();) {
278 Preference childPreference = (Preference) childPreferences.next();
279 setPreferenceToSave(childPreference);
280 }
281 }
282
283
284
285
286
287
288
289
290
291
292
293 public void setDocumentLocator (Locator documentLocator) {
294
295 this.documentLocator = documentLocator;
296 }
297
298
299
300
301
302
303 public void startDocument () throws SAXException {
304
305 elementDepth = 0;
306 inXML11 = false;
307 inCData = false;
308
309 }
310
311
312
313
314
315
316
317 public void processingInstruction (String target, String data)
318 throws SAXException {
319
320 if (elementDepth > 0) {
321 printWriter.print(PI_START);
322 printWriter.print(target);
323 if (null != data && data.length() > 0) {
324 printWriter.print(SPACE);
325 printWriter.print(data);
326 }
327 printWriter.print(PI_END);
328 printWriter.flush();
329 }
330 }
331
332
333
334
335
336
337
338 public void startElement (String uri, String localName, String qName,
339 Attributes attributes) throws SAXException {
340
341
342
343 boolean writeCurrentNamespaceMapping = false;
344 String namespacePrefix = null;
345
346
347
348 if (XMLNAME_PREFERENCE.equals(localName)) {
349 startPreference(attributes);
350 } else if (XMLNAME_PREFERENCE_ATTRIBUTE.equals(localName)) {
351 startPreferenceAttribute(attributes);
352 } else if (XMLNAME_PREF_ATT_VALUE.equals(localName)) {
353 currentElementToReadDataFor = localName;
354 isCurrentValueWritten = false;
355 }
356
357
358 namespaceSupport.pushContext();
359 if (null != uri && uri.equals(namespaceSupport.getURI(""))) {
360
361 } else if (null != uri && uri.length() > 0) {
362 namespacePrefix = namespaceSupport.getPrefix(uri);
363 if (null == namespacePrefix) {
364
365 writeCurrentNamespaceMapping = true;
366 if (elementDepth == 0) {
367
368
369 namespaceSupport.declarePrefix("", uri);
370 } else {
371
372 namespacePrefix = uri.substring(uri.lastIndexOf('/') + 1);
373 int suffixCount = 1;
374 while (null != namespaceSupport.getURI(namespacePrefix)) {
375
376
377 if (namespacePrefix.endsWith(String
378 .valueOf(suffixCount))) {
379 namespacePrefix = namespacePrefix.substring(0,
380 namespacePrefix.lastIndexOf(String
381 .valueOf(suffixCount)));
382 suffixCount++ ;
383 }
384 namespacePrefix = namespacePrefix
385 + String.valueOf(suffixCount);
386 }
387 namespaceSupport.declarePrefix(namespacePrefix, uri);
388 }
389 }
390 }
391
392
393
394 if (elementDepth == 0) {
395 if (documentLocator != null) {
396 inXML11 = "1.1".equals(getVersion());
397 documentLocator = null;
398 }
399
400
401
402
403
404 if (!isCanonical) {
405 if (inXML11) {
406 printWriter.println("<?xml version=\"1.1\" encoding=\""
407 + ENCODING_XML_STRING + "\"?>");
408 } else {
409 printWriter.println("<?xml version=\"1.0\" encoding=\""
410 + ENCODING_XML_STRING + "\"?>");
411 }
412 printWriter.flush();
413 }
414
415
416 }
417
418 elementDepth++ ;
419 printWriter.print(ELEMENT_START);
420 if (null != namespacePrefix) {
421 printWriter.print(namespacePrefix);
422 printWriter.print(":");
423 }
424 printWriter.print(localName);
425
426 if (writeCurrentNamespaceMapping) {
427 writeNamespaceMapping(namespacePrefix, uri);
428 }
429 if (attributes != null) {
430
431
432 int len = attributes.getLength();
433 boolean writeAttributeNamespaceMapping = false;
434 for (int i = 0; i < len; i++ ) {
435 writeAttributeNamespaceMapping = false;
436
437
438 String attributeURI = attributes.getURI(i);
439 String attributeNamespacePrefix = null;
440 if (null != attributeURI
441 && attributeURI.equals(namespaceSupport.getURI(""))) {
442
443 } else if (null != attributeURI && attributeURI.length() > 0) {
444 attributeNamespacePrefix = namespaceSupport
445 .getPrefix(attributeURI);
446 if (null == attributeNamespacePrefix) {
447
448 writeAttributeNamespaceMapping = true;
449
450 attributeNamespacePrefix = attributeURI
451 .substring(attributeURI.lastIndexOf('/') + 1);
452 int suffixCount = 1;
453 while (null != namespaceSupport
454 .getURI(attributeNamespacePrefix)) {
455
456
457
458 if (attributeNamespacePrefix.endsWith(String
459 .valueOf(suffixCount))) {
460 attributeNamespacePrefix = attributeNamespacePrefix
461 .substring(0, attributeNamespacePrefix
462 .lastIndexOf(String
463 .valueOf(suffixCount)));
464 suffixCount++ ;
465 }
466 attributeNamespacePrefix = attributeNamespacePrefix
467 + String.valueOf(suffixCount);
468 }
469 namespaceSupport.declarePrefix(
470 attributeNamespacePrefix, attributeURI);
471 }
472 }
473
474 if (writeAttributeNamespaceMapping) {
475 writeNamespaceMapping(attributeNamespacePrefix,
476 attributeURI);
477 }
478 printWriter.print(SPACE);
479 if (null != attributeNamespacePrefix) {
480 printWriter.print(attributeNamespacePrefix);
481 printWriter.print(':');
482 }
483 printWriter.print(attributes.getLocalName(i));
484 printWriter.print(ATTRIBUTE_START);
485 normalizeAndPrint(attributes.getValue(i), true);
486 printWriter.print(ATTRIBUTE_END);
487 }
488 }
489 printWriter.print(ELEMENT_END);
490 printWriter.flush();
491
492 }
493
494
495
496
497
498
499
500 private void writeNamespaceMapping (String namespacePrefix, String uri) {
501
502 printWriter.print(SPACE);
503 printWriter.print("xmlns");
504 if (null != namespacePrefix) {
505 printWriter.print(":");
506 printWriter.print(namespacePrefix);
507 }
508 printWriter.print(ATTRIBUTE_START);
509 printWriter.print(uri);
510 printWriter.print(ATTRIBUTE_END);
511 }
512
513
514
515
516
517
518 public void characters (char [] ch, int start, int length)
519 throws SAXException {
520
521 if (!inCData) {
522 if (XMLNAME_PREF_ATT_VALUE.equals(currentElementToReadDataFor)) {
523 String value = getCurrentAttributeChangedValue();
524 if (null != value) {
525 if (!isCurrentValueWritten) {
526 normalizeAndPrint(value, false);
527 isCurrentValueWritten = true;
528 }
529
530 } else {
531 normalizeAndPrint(ch, start, length, false);
532 }
533
534
535 } else {
536 normalizeAndPrint(ch, start, length, false);
537 }
538 } else {
539 if (XMLNAME_PREF_ATT_VALUE.equals(currentElementToReadDataFor)) {
540 String value = getCurrentAttributeChangedValue();
541 if (null != value) {
542 if (!isCurrentValueWritten) {
543 printWriter.print(value);
544 isCurrentValueWritten = true;
545 }
546 } else {
547 for (int i = 0; i < length; ++i) {
548 printWriter.print(ch[start + i]);
549 }
550 }
551
552
553 } else {
554 for (int i = 0; i < length; ++i) {
555 printWriter.print(ch[start + i]);
556 }
557 }
558 }
559 printWriter.flush();
560 }
561
562
563
564
565
566
567 public void ignorableWhitespace (char [] ch, int start, int length)
568 throws SAXException {
569
570 characters(ch, start, length);
571 printWriter.flush();
572 }
573
574
575
576
577
578
579
580 public void endElement (String uri, String localName, String qName)
581 throws SAXException {
582
583
584 if (XMLNAME_PREFERENCE.equals(localName)) {
585 endPreference();
586 } else if (XMLNAME_PREFERENCE_ATTRIBUTE.equals(localName)) {
587 endPreferenceAttribute();
588 } else if (XMLNAME_PREF_ATT_VALUE.equals(localName)) {
589 currentElementToReadDataFor = null;
590 }
591
592 printWriter.print(ELEMENT_TERM_START);
593
594 namespaceSupport.pushContext();
595 if (null != uri && uri.equals(namespaceSupport.getURI(""))) {
596
597 } else {
598 String namespacePrefix = namespaceSupport.getPrefix(uri);
599 if (null == namespacePrefix) {
600
601 } else {
602 printWriter.print(namespacePrefix);
603 printWriter.print(":");
604 }
605 }
606 printWriter.print(localName);
607 printWriter.print(ELEMENT_END);
608 printWriter.flush();
609
610 elementDepth-- ;
611 namespaceSupport.popContext();
612 }
613
614
615
616
617
618
619
620
621 public void error (SAXParseException e) throws SAXException {
622
623 System.out.println("Error: " + e.getMessage());
624 }
625
626
627
628
629 public void fatalError (SAXParseException e) throws SAXException {
630
631 System.out.println("Fatal Error: " + e.getMessage());
632 throw e;
633 }
634
635
636
637
638 public void warning (SAXParseException e) throws SAXException {
639
640 System.out.println("Warning: " + e.getMessage());
641 }
642
643
644
645
646
647
648
649
650
651 public void startDTD (String name, String publicId, String systemId)
652 throws SAXException {
653
654
655 }
656
657
658
659
660 public void endDTD () throws SAXException {
661
662
663 }
664
665
666
667
668 public void startEntity (String name) throws SAXException {
669
670
671 }
672
673
674
675
676 public void endEntity (String name) throws SAXException {
677
678
679 }
680
681
682
683
684 public void startCDATA () throws SAXException {
685
686 if (!isCanonical) {
687 printWriter.print(CDATA_START);
688 inCData = true;
689 }
690 }
691
692
693
694
695 public void endCDATA () throws SAXException {
696
697 if (!isCanonical) {
698 inCData = false;
699 printWriter.print(CDATA_END);
700 }
701 }
702
703
704
705
706 public void comment (char [] ch, int start, int length) throws SAXException {
707
708 if (!isCanonical && elementDepth > 0) {
709 printWriter.print(COMMENT_START);
710 for (int i = 0; i < length; ++i) {
711 printWriter.print(ch[start + i]);
712 }
713 printWriter.print(COMMENT_END);
714 printWriter.flush();
715 }
716 }
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755 private void normalizeAndPrint (String s, boolean isAttValue) {
756
757 int len = (s != null) ? s.length() : 0;
758 for (int i = 0; i < len; i++ ) {
759 char c = s.charAt(i);
760 normalizeAndPrint(c, isAttValue);
761 }
762
763 }
764
765
766
767
768
769
770
771
772
773 private void normalizeAndPrint (char [] ch, int offset, int length,
774 boolean isAttValue) {
775
776 for (int i = 0; i < length; i++ ) {
777 normalizeAndPrint(ch[offset + i], isAttValue);
778 }
779 }
780
781
782
783
784
785
786
787 protected void normalizeAndPrint (char c, boolean isAttValue) {
788
789 switch (c) {
790 case '<': {
791 printWriter.print("<");
792 break;
793 }
794 case '>': {
795 printWriter.print(">");
796 break;
797 }
798 case '&': {
799 printWriter.print("&");
800 break;
801 }
802 case '"': {
803
804
805 if (isAttValue) {
806 printWriter.print(""");
807 } else {
808 printWriter.print("\"");
809 }
810 break;
811 }
812 case '\r': {
813
814
815
816
817 printWriter.print("
");
818 break;
819 }
820 case '\n': {
821 if (isCanonical) {
822 printWriter.print("
");
823 break;
824 }
825
826 }
827 default: {
828
829
830
831
832
833
834
835
836
837
838
839 if (inXML11
840 && ((c >= 0x01 && c <= 0x1F && c != 0x09 && c != 0x0A)
841 || (c >= 0x7F && c <= 0x9F) || c == 0x2028)
842 || isAttValue && (c == 0x09 || c == 0x0A)) {
843 printWriter.print("&#x");
844 printWriter.print(Integer.toHexString(c).toUpperCase());
845 printWriter.print(";");
846 } else {
847 printWriter.print(c);
848 }
849 }
850 }
851 }
852
853
854
855
856
857
858 private String getVersion () {
859
860 if (null == documentLocator) {
861 return null;
862 }
863 String version = null;
864 Method getXMLVersion = null;
865 try {
866 getXMLVersion = documentLocator.getClass().getMethod(
867 "getXMLVersion", new Class [] {});
868
869 if (getXMLVersion != null) {
870 version = (String) getXMLVersion.invoke(documentLocator, null);
871 }
872 } catch (Exception e) {
873
874
875 }
876 return version;
877 }
878
879
880
881
882
883
884
885
886
887 private void startPreference (Attributes attributes) {
888
889 if (null != currentCompletePreferenceId) {
890 preferenceIdStack.push(currentCompletePreferenceId);
891 currentCompletePreferenceId = currentCompletePreferenceId
892 + Preference.ID_SEPERATOR
893 + attributes.getValue(XMLNAME_PREFERENCE_ID);
894 } else {
895 currentCompletePreferenceId = attributes
896 .getValue(XMLNAME_PREFERENCE_ID);
897 }
898 }
899
900
901
902
903 private void endPreference () {
904
905 if (!preferenceIdStack.empty()) {
906 currentCompletePreferenceId = (String) preferenceIdStack.pop();
907 } else {
908 currentCompletePreferenceId = null;
909 }
910 }
911
912
913
914
915
916
917 private void startPreferenceAttribute (Attributes attributes) {
918
919 currentPreferenceAttributeId = attributes
920 .getValue(XMLNAME_PREFERENCE_ATT_ID);
921 }
922
923
924
925
926 private void endPreferenceAttribute () {
927
928 currentPreferenceAttributeId = null;
929 }
930
931
932
933
934
935
936
937 private String getCurrentAttributeChangedValue () {
938
939 String key = currentCompletePreferenceId + KEY_SEPERATOR
940 + currentPreferenceAttributeId;
941 if (preferenceAttributesToSave.containsKey(key)) {
942 return (String) preferenceAttributesToSave.get(key);
943 }
944 return null;
945 }
946
947 }