1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.betwixt.io;
18
19 import java.beans.IntrospectionException;
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Iterator;
24
25 import org.apache.commons.betwixt.AttributeDescriptor;
26 import org.apache.commons.betwixt.BindingConfiguration;
27 import org.apache.commons.betwixt.Descriptor;
28 import org.apache.commons.betwixt.ElementDescriptor;
29 import org.apache.commons.betwixt.Options;
30 import org.apache.commons.betwixt.XMLBeanInfo;
31 import org.apache.commons.betwixt.XMLIntrospector;
32 import org.apache.commons.betwixt.expression.Context;
33 import org.apache.commons.betwixt.expression.Expression;
34 import org.apache.commons.betwixt.io.id.SequentialIDGenerator;
35 import org.apache.commons.collections.ArrayStack;
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.xml.sax.Attributes;
39 import org.xml.sax.InputSource;
40 import org.xml.sax.SAXException;
41 import org.xml.sax.helpers.AttributesImpl;
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 abstract class AbstractBeanWriter {
82
83
84 private XMLIntrospector introspector = new XMLIntrospector();
85
86
87 private Log log = LogFactory.getLog( AbstractBeanWriter.class );
88
89 private ArrayStack beanStack = new ArrayStack();
90
91 private IDGenerator idGenerator = new SequentialIDGenerator();
92
93 private boolean writeEmptyElements = true;
94
95 private BindingConfiguration bindingConfiguration = new BindingConfiguration();
96
97 private WriteContextImpl writeContext = new WriteContextImpl();
98
99 private Collection namespacesDeclared = new ArrayList();
100
101
102
103
104
105
106
107
108 public void start() throws IOException, SAXException {
109 }
110
111
112
113
114
115
116
117
118
119 public void end() throws IOException, SAXException {
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 public void write(Object bean) throws
138 IOException,
139 SAXException,
140 IntrospectionException {
141 if (log.isDebugEnabled()) {
142 log.debug( "Writing bean graph..." );
143 log.debug( bean );
144 }
145 start();
146 writeBean( null, null, null, bean, makeContext( bean ) );
147 end();
148 if (log.isDebugEnabled()) {
149 log.debug( "Finished writing bean graph." );
150 }
151 }
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 public void write(
169 String qualifiedName,
170 Object bean)
171 throws
172 IOException,
173 SAXException,
174 IntrospectionException {
175 start();
176 writeBean( "", qualifiedName, qualifiedName, bean, makeContext( bean ) );
177 end();
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 public void write(Object bean, InputSource source)
198 throws IOException, SAXException, IntrospectionException {
199 writeBean(
200 null,
201 null,
202 null,
203 bean,
204 makeContext( bean ),
205 getXMLIntrospector().introspect(bean.getClass(), source));
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228 private void writeBean (
229 String namespaceUri,
230 String localName,
231 String qualifiedName,
232 Object bean,
233 Context context)
234 throws
235 IOException,
236 SAXException,
237 IntrospectionException {
238
239 if ( log.isTraceEnabled() ) {
240 log.trace( "Writing bean graph (qualified name '" + qualifiedName + "'" );
241 }
242
243
244 XMLBeanInfo beanInfo = introspector.introspect( bean );
245 writeBean(namespaceUri, localName, qualifiedName, bean, context, beanInfo);
246
247 log.trace( "Finished writing bean graph." );
248 }
249
250
251 private void writeBean (
252 String namespaceUri,
253 String localName,
254 String qualifiedName,
255 Object bean,
256 ElementDescriptor parentDescriptor,
257 Context context)
258 throws
259 IOException,
260 SAXException,
261 IntrospectionException {
262
263 if ( log.isTraceEnabled() ) {
264 log.trace( "Writing bean graph (qualified name '" + qualifiedName + "'" );
265 }
266
267
268 XMLBeanInfo beanInfo = findXMLBeanInfo(bean, parentDescriptor);
269 writeBean(namespaceUri, localName, qualifiedName, bean, context, beanInfo);
270
271 log.trace( "Finished writing bean graph." );
272 }
273
274
275
276
277
278
279
280
281 private XMLBeanInfo findXMLBeanInfo(Object bean, ElementDescriptor parentDescriptor) throws IntrospectionException {
282 XMLBeanInfo beanInfo = null;
283 Class introspectedBindType = parentDescriptor.getSingularPropertyType();
284 if ( introspectedBindType == null ) {
285 introspectedBindType = parentDescriptor.getPropertyType();
286 }
287 if ( parentDescriptor.isUseBindTimeTypeForMapping() || introspectedBindType == null ) {
288 beanInfo = introspector.introspect( bean );
289 } else {
290 beanInfo = introspector.introspect( introspectedBindType );
291 }
292 return beanInfo;
293 }
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 private void writeBean(
315 String namespaceUri,
316 String localName,
317 String qualifiedName,
318 Object bean,
319 Context context,
320 XMLBeanInfo beanInfo)
321 throws IOException, SAXException, IntrospectionException {
322 if ( beanInfo != null ) {
323 ElementDescriptor elementDescriptor = beanInfo.getElementDescriptor();
324 if ( elementDescriptor != null ) {
325
326
327 Options combinedOptions = new Options();
328
329
330 combinedOptions.addOptions(elementDescriptor.getOptions());
331
332
333
334
335 if( context.getOptions() != null) {
336 combinedOptions.addOptions(context.getOptions());
337 }
338 context = context.newContext( bean );
339 context.pushOptions(combinedOptions);
340
341 if ( qualifiedName == null ) {
342 qualifiedName = elementDescriptor.getQualifiedName();
343 }
344 if ( namespaceUri == null ) {
345 namespaceUri = elementDescriptor.getURI();
346 }
347 if ( localName == null ) {
348 localName = elementDescriptor.getLocalName();
349 }
350
351 String ref = null;
352 String id = null;
353
354
355 if ( elementDescriptor.isSimple() ) {
356
357 writeElement(
358 namespaceUri,
359 localName,
360 qualifiedName,
361 elementDescriptor,
362 context );
363
364 } else {
365 pushBean ( context.getBean() );
366 if ( getBindingConfiguration().getMapIDs() ) {
367 ref = getBindingConfiguration().getIdMappingStrategy().getReferenceFor(context, context.getBean());
368 }
369 if ( ref == null ) {
370
371 AttributeDescriptor idAttribute = beanInfo.getIDAttribute();
372 if (idAttribute == null) {
373
374 id = idGenerator.nextId();
375 getBindingConfiguration().getIdMappingStrategy().setReference(context, bean, id);
376
377 if ( getBindingConfiguration().getMapIDs() ) {
378
379 writeElement(
380 namespaceUri,
381 localName,
382 qualifiedName,
383 elementDescriptor,
384 context ,
385 beanInfo.getIDAttributeName(),
386 id);
387
388
389 } else {
390
391 writeElement(
392 namespaceUri,
393 localName,
394 qualifiedName,
395 elementDescriptor,
396 context );
397 }
398
399 } else {
400
401
402 Expression idExpression = idAttribute.getTextExpression();
403 if(idExpression == null) {
404 throw new IntrospectionException(
405 "The specified id property wasn't found in the bean ("
406 + idAttribute + ").");
407 }
408 Object exp = idExpression.evaluate( context );
409 if (exp == null) {
410
411 log.debug("Using random id");
412 id = idGenerator.nextId();
413
414 } else {
415
416 id = exp.toString();
417 }
418 getBindingConfiguration().getIdMappingStrategy().setReference(context, bean, id);
419
420
421 writeElement(
422 namespaceUri,
423 localName,
424 qualifiedName,
425 elementDescriptor,
426 context );
427 }
428 } else {
429
430 if ( !ignoreElement( elementDescriptor, namespaceUri, localName, qualifiedName, context )) {
431
432 writeIDREFElement(
433 elementDescriptor,
434 namespaceUri,
435 localName,
436 qualifiedName,
437 beanInfo.getIDREFAttributeName(),
438 ref);
439 }
440 }
441 popBean();
442 }
443
444 context.popOptions();
445 }
446 }
447 }
448
449
450
451
452
453
454
455 public IDGenerator getIdGenerator() {
456 return idGenerator;
457 }
458
459
460
461
462
463
464
465
466 public void setIdGenerator(IDGenerator idGenerator) {
467 this.idGenerator = idGenerator;
468 }
469
470
471
472
473
474
475
476
477 public BindingConfiguration getBindingConfiguration() {
478 return bindingConfiguration;
479 }
480
481
482
483
484
485
486 public void setBindingConfiguration(BindingConfiguration bindingConfiguration) {
487 this.bindingConfiguration = bindingConfiguration;
488 }
489
490
491
492
493
494
495
496
497
498
499 public boolean getWriteIDs() {
500 return getBindingConfiguration().getMapIDs();
501 }
502
503
504
505
506
507
508
509
510
511 public void setWriteIDs(boolean writeIDs) {
512 getBindingConfiguration().setMapIDs( writeIDs );
513 }
514
515
516
517
518
519
520
521
522
523
524
525
526 public boolean getWriteEmptyElements() {
527 return writeEmptyElements;
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541 public void setWriteEmptyElements(boolean writeEmptyElements) {
542 this.writeEmptyElements = writeEmptyElements;
543 }
544
545
546
547
548
549
550
551
552
553
554
555 public XMLIntrospector getXMLIntrospector() {
556 return introspector;
557 }
558
559
560
561
562
563
564
565
566
567
568
569
570 public void setXMLIntrospector(XMLIntrospector introspector) {
571 this.introspector = introspector;
572 }
573
574
575
576
577
578
579 public final Log getAbstractBeanWriterLog() {
580 return log;
581 }
582
583
584
585
586
587
588 public final void setAbstractBeanWriterLog(Log log) {
589 this.log = log;
590 }
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607 protected void startElement(
608 WriteContext context,
609 String uri,
610 String localName,
611 String qName,
612 Attributes attr)
613 throws
614 IOException,
615 SAXException {
616
617 startElement(uri, localName, qName, attr);
618 }
619
620
621
622
623
624
625
626
627
628
629
630
631 protected void endElement(
632 WriteContext context,
633 String uri,
634 String localName,
635 String qName)
636 throws
637 IOException,
638 SAXException {
639
640 endElement(uri, localName, qName);
641 }
642
643
644
645
646
647
648
649
650
651
652 protected void bodyText(WriteContext context, String text)
653 throws IOException, SAXException {
654
655 bodyText(text);
656 }
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673 protected void startElement(
674 String uri,
675 String localName,
676 String qName,
677 Attributes attr)
678 throws
679 IOException,
680 SAXException {}
681
682
683
684
685
686
687
688
689
690
691
692
693 protected void endElement(
694 String uri,
695 String localName,
696 String qName)
697 throws
698 IOException,
699 SAXException {}
700
701
702
703
704
705
706
707
708
709
710 protected void bodyText(String text) throws IOException, SAXException {}
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727 private void writeElement(
728 String namespaceUri,
729 String localName,
730 String qualifiedName,
731 ElementDescriptor elementDescriptor,
732 Context context )
733 throws
734 IOException,
735 SAXException,
736 IntrospectionException {
737 if( log.isTraceEnabled() ) {
738 log.trace( "Writing: " + qualifiedName + " element: " + elementDescriptor );
739 }
740
741 if ( !ignoreElement( elementDescriptor, namespaceUri, localName, qualifiedName, context )) {
742 if ( log.isTraceEnabled() ) {
743 log.trace( "Element " + elementDescriptor + " is empty." );
744 }
745
746 Attributes attributes = addNamespaceDeclarations(
747 new ElementAttributes( elementDescriptor, context ), namespaceUri);
748 writeContext.setCurrentDescriptor(elementDescriptor);
749 startElement(
750 writeContext,
751 namespaceUri,
752 localName,
753 qualifiedName,
754 attributes);
755
756 writeElementContent( elementDescriptor, context ) ;
757 writeContext.setCurrentDescriptor(elementDescriptor);
758 endElement( writeContext, namespaceUri, localName, qualifiedName );
759 }
760 }
761
762
763
764
765
766
767
768 private Attributes addNamespaceDeclarations(Attributes attributes, String elementNamespaceUri) {
769 Attributes result = attributes;
770 AttributesImpl withDeclarations = null;
771 for (int i=-1, size=attributes.getLength(); i<size ; i++) {
772 String uri = null;
773 if (i == -1) {
774 uri = elementNamespaceUri;
775 } else {
776 uri = attributes.getURI(i);
777 }
778 if (uri != null && !"".equals(uri) && !namespacesDeclared.contains(uri)) {
779 if (withDeclarations == null) {
780 withDeclarations = new AttributesImpl(attributes);
781 }
782 withDeclarations.addAttribute("", "", "xmlns:"
783 + getXMLIntrospector().getConfiguration().getPrefixMapper().getPrefix(uri), "NOTATION", uri);
784 namespacesDeclared.add(uri);
785 }
786 }
787
788 if (withDeclarations != null) {
789 result = withDeclarations;
790 }
791 return result;
792 }
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809 private void writeElement(
810 String namespaceUri,
811 String localName,
812 String qualifiedName,
813 ElementDescriptor elementDescriptor,
814 Context context,
815 String idAttribute,
816 String idValue )
817 throws
818 IOException,
819 SAXException,
820 IntrospectionException {
821
822 if ( !ignoreElement( elementDescriptor, namespaceUri, localName, qualifiedName, context ) ) {
823 writeContext.setCurrentDescriptor(elementDescriptor);
824 Attributes attributes = new IDElementAttributes(
825 elementDescriptor,
826 context,
827 idAttribute,
828 idValue );
829 startElement(
830 writeContext,
831 namespaceUri,
832 localName,
833 qualifiedName,
834 addNamespaceDeclarations(attributes, namespaceUri));
835
836 writeElementContent( elementDescriptor, context ) ;
837 writeContext.setCurrentDescriptor(elementDescriptor);
838 endElement( writeContext, namespaceUri, localName, qualifiedName );
839 } else if ( log.isTraceEnabled() ) {
840 log.trace( "Element " + qualifiedName + " is empty." );
841 }
842 }
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857 private void writeRestOfElement(
858 String uri,
859 String localName,
860 String qualifiedName,
861 ElementDescriptor elementDescriptor,
862 Context context )
863 throws
864 IOException,
865 SAXException,
866 IntrospectionException {
867
868 writeElementContent( elementDescriptor, context );
869 }
870
871
872
873
874
875
876
877
878
879
880
881
882
883 private void writeIDREFElement(
884 ElementDescriptor elementDescriptor,
885 String uri,
886 String localName,
887 String qualifiedName,
888 String idrefAttributeName,
889 String idrefAttributeValue )
890 throws
891 IOException,
892 SAXException,
893 IntrospectionException {
894
895
896
897
898 AttributesImpl attributes = new AttributesImpl();
899
900 attributes.addAttribute(
901 "",
902 idrefAttributeName,
903 idrefAttributeName,
904 "IDREF",
905 idrefAttributeValue);
906 writeContext.setCurrentDescriptor(elementDescriptor);
907 startElement( writeContext, uri, localName, qualifiedName, addNamespaceDeclarations(attributes, uri));
908 endElement( writeContext, uri, localName, qualifiedName );
909 }
910
911
912
913
914
915
916
917
918
919
920
921 private void writeElementContent(
922 ElementDescriptor elementDescriptor,
923 Context context )
924 throws
925 IOException,
926 SAXException,
927 IntrospectionException {
928 writeContext.setCurrentDescriptor( elementDescriptor );
929 Descriptor[] childDescriptors = elementDescriptor.getContentDescriptors();
930 if ( childDescriptors != null && childDescriptors.length > 0 ) {
931
932 for ( int i = 0, size = childDescriptors.length; i < size; i++ ) {
933 if (childDescriptors[i] instanceof ElementDescriptor) {
934
935 ElementDescriptor childDescriptor = (ElementDescriptor) childDescriptors[i];
936 Context childContext = context;
937 childContext.pushOptions(childDescriptor.getOptions());
938 Expression childExpression = childDescriptor.getContextExpression();
939 if ( childExpression != null ) {
940 Object childBean = childExpression.evaluate( context );
941 if ( childBean != null ) {
942 String qualifiedName = childDescriptor.getQualifiedName();
943 String namespaceUri = childDescriptor.getURI();
944 String localName = childDescriptor.getLocalName();
945
946 if ( childBean instanceof Iterator ) {
947 for ( Iterator iter = (Iterator) childBean; iter.hasNext(); ) {
948 Object object = iter.next();
949 if (object == null) {
950 continue;
951 }
952 writeBean(
953 namespaceUri,
954 localName,
955 qualifiedName,
956 object,
957 childDescriptor,
958 context );
959 }
960 } else {
961 writeBean(
962 namespaceUri,
963 localName,
964 qualifiedName,
965 childBean,
966 childDescriptor,
967 context );
968 }
969 }
970 } else {
971 writeElement(
972 childDescriptor.getURI(),
973 childDescriptor.getLocalName(),
974 childDescriptor.getQualifiedName(),
975 childDescriptor,
976 childContext );
977 }
978 childContext.popOptions();
979 } else {
980
981
982 Expression expression = childDescriptors[i].getTextExpression();
983 if ( expression != null ) {
984 Object value = expression.evaluate( context );
985 String text = convertToString(
986 value,
987 childDescriptors[i],
988 context );
989 if ( text != null && text.length() > 0 ) {;
990 bodyText( writeContext, text );
991 }
992 }
993 }
994 }
995 } else {
996
997 Expression expression = elementDescriptor.getTextExpression();
998 if ( expression != null ) {
999 Object value = expression.evaluate( context );
1000 String text = convertToString( value, elementDescriptor, context );
1001 if ( text != null && text.length() > 0 ) {
1002 bodyText( writeContext, text );
1003 }
1004 }
1005 }
1006 }
1007
1008
1009
1010
1011
1012
1013
1014 protected void pushBean( Object bean ) {
1015
1016 if ( !getBindingConfiguration().getMapIDs() ) {
1017 Iterator it = beanStack.iterator();
1018 while ( it.hasNext() ) {
1019 Object next = it.next();
1020
1021
1022 if ( bean == next ) {
1023 final String message = "Cyclic reference at bean: " + bean;
1024 log.error(message);
1025 StringBuffer buffer = new StringBuffer(message);
1026 buffer.append(" Stack: ");
1027 Iterator errorStack = beanStack.iterator();
1028 while ( errorStack.hasNext() ) {
1029 Object errorObj = errorStack.next();
1030 if(errorObj != null) {
1031 buffer.append(errorObj.getClass().getName());
1032 buffer.append(": ");
1033 }
1034 buffer.append(errorObj);
1035 buffer.append(";");
1036 }
1037 final String debugMessage = buffer.toString();
1038 log.info( debugMessage );
1039 throw new CyclicReferenceException( debugMessage );
1040 }
1041 }
1042 }
1043 if (log.isTraceEnabled()) {
1044 log.trace( "Pushing onto object stack: " + bean );
1045 }
1046 beanStack.push( bean );
1047 }
1048
1049
1050
1051
1052
1053
1054 protected Object popBean() {
1055 Object bean = beanStack.pop();
1056 if (log.isTraceEnabled()) {
1057 log.trace( "Popped from object stack: " + bean );
1058 }
1059 return bean;
1060 }
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070 private boolean ignoreElement( ElementDescriptor descriptor, String namespaceUri, String localName, String qualifiedName, Context context ) throws IntrospectionException {
1071 if (getBindingConfiguration().getValueSuppressionStrategy().suppressElement(descriptor, namespaceUri, localName, qualifiedName, context.getBean())) {
1072 return true;
1073 }
1074
1075 if ( ! getWriteEmptyElements() ) {
1076 return isEmptyElement( descriptor, context );
1077 }
1078 return false;
1079 }
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094 private boolean isEmptyElement( ElementDescriptor descriptor, Context context ) throws IntrospectionException {
1095
1096
1097 if ( log.isTraceEnabled() ) {
1098 log.trace( "Is " + descriptor + " empty?" );
1099 }
1100
1101
1102 if ( descriptor.hasAttributes() ) {
1103 log.trace( "Element has attributes." );
1104 return false;
1105 }
1106
1107
1108 Expression expression = descriptor.getTextExpression();
1109 if ( expression != null ) {
1110 Object value = expression.evaluate( context );
1111 String text = convertToString( value, descriptor, context );
1112 if ( text != null && text.length() > 0 ) {
1113 log.trace( "Element has body text which isn't empty." );
1114 return false;
1115 }
1116 }
1117
1118
1119 if ( descriptor.isCollective() ) {
1120 log.trace("Loop type so not empty.");
1121 return false;
1122 }
1123
1124
1125
1126 if ( descriptor.hasChildren() ) {
1127 for ( int i=0, size=descriptor.getElementDescriptors().length; i<size; i++ ) {
1128 if ( ! isEmptyElement( descriptor.getElementDescriptors()[i], context ) ) {
1129 log.trace( "Element has child which isn't empty." );
1130 return false;
1131 }
1132 }
1133 }
1134
1135 if ( descriptor.isHollow() )
1136 {
1137 Expression contentExpression = descriptor.getContextExpression();
1138 if (contentExpression != null) {
1139 Object childBean = contentExpression.evaluate(context);
1140 if (childBean != null)
1141 {
1142 XMLBeanInfo xmlBeanInfo = findXMLBeanInfo(childBean, descriptor);
1143 Object currentBean = context.getBean();
1144 context.setBean(childBean);
1145 boolean result = isEmptyElement(xmlBeanInfo.getElementDescriptor(), context);
1146 context.setBean(currentBean);
1147 return result;
1148 }
1149 }
1150 }
1151
1152 log.trace( "Element is empty." );
1153 return true;
1154 }
1155
1156
1157
1158
1159
1160
1161 private class ElementAttributes implements Attributes {
1162
1163 private AttributeDescriptor[] attributes;
1164
1165 private Context context;
1166
1167 private String[] values;
1168
1169 private int length;
1170
1171
1172
1173
1174
1175
1176
1177
1178 ElementAttributes( ElementDescriptor descriptor, Context context ) {
1179 this.context = context;
1180 init(descriptor.getAttributeDescriptors());
1181 }
1182
1183 private void init(AttributeDescriptor[] baseAttributes) {
1184 attributes = new AttributeDescriptor[baseAttributes.length];
1185 values = new String[baseAttributes.length];
1186 int index = 0;
1187 for (int i=0, size=baseAttributes.length; i<size; i++) {
1188 AttributeDescriptor baseAttribute = baseAttributes[i];
1189 String attributeValue = valueAttribute(baseAttribute);
1190 if (attributeValue != null
1191 && !context.getValueSuppressionStrategy()
1192 .suppressAttribute(baseAttribute, attributeValue)) {
1193 values[index] = attributeValue;
1194 attributes[index] = baseAttribute;
1195 index++;
1196 }
1197 }
1198 length = index;
1199 }
1200
1201 private String valueAttribute(AttributeDescriptor attribute) {
1202 Expression expression = attribute.getTextExpression();
1203 if ( expression != null ) {
1204 Object value = expression.evaluate( context );
1205 return convertToString( value, attribute, context );
1206 }
1207
1208 return "";
1209 }
1210
1211
1212
1213
1214
1215
1216
1217 public int getIndex( String qName ) {
1218 for ( int i=0; i<attributes.length; i++ ) {
1219 if (attributes[i].getQualifiedName() != null
1220 && attributes[i].getQualifiedName().equals( qName )) {
1221 return i;
1222 }
1223 }
1224 return -1;
1225 }
1226
1227
1228
1229
1230
1231
1232
1233
1234 public int getIndex( String uri, String localName ) {
1235 for ( int i=0; i<attributes.length; i++ ) {
1236 if (
1237 attributes[i].getURI() != null
1238 && attributes[i].getURI().equals(uri)
1239 && attributes[i].getLocalName() != null
1240 && attributes[i].getURI().equals(localName)) {
1241 return i;
1242 }
1243 }
1244
1245 return -1;
1246 }
1247
1248
1249
1250
1251
1252
1253 public int getLength() {
1254 return length;
1255 }
1256
1257
1258
1259
1260
1261
1262
1263 public String getLocalName( int index ) {
1264 if ( indexInRange( index ) ) {
1265 return attributes[index].getLocalName();
1266 }
1267
1268 return null;
1269 }
1270
1271
1272
1273
1274
1275
1276
1277 public String getQName( int index ) {
1278 if ( indexInRange( index ) ) {
1279 return attributes[index].getQualifiedName();
1280 }
1281
1282 return null;
1283 }
1284
1285
1286
1287
1288
1289
1290
1291 public String getType( int index ) {
1292 if ( indexInRange( index ) ) {
1293 return "CDATA";
1294 }
1295 return null;
1296 }
1297
1298
1299
1300
1301
1302
1303
1304 public String getType( String qName ) {
1305 return getType( getIndex( qName ) );
1306 }
1307
1308
1309
1310
1311
1312
1313
1314
1315 public String getType( String uri, String localName ) {
1316 return getType( getIndex( uri, localName ));
1317 }
1318
1319
1320
1321
1322
1323
1324
1325
1326 public String getURI( int index ) {
1327 if ( indexInRange( index ) ) {
1328 return attributes[index].getURI();
1329 }
1330 return null;
1331 }
1332
1333
1334
1335
1336
1337
1338
1339
1340 public String getValue( int index ) {
1341 if ( indexInRange( index ) ) {
1342 return values[index];
1343 }
1344 return null;
1345 }
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355 public String getValue( String qName ) {
1356 return getValue( getIndex( qName ) );
1357 }
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368 public String getValue( String uri, String localName ) {
1369 return getValue( getIndex( uri, localName ) );
1370 }
1371
1372
1373
1374
1375
1376
1377
1378 private boolean indexInRange( int index ) {
1379 return ( index >= 0 && index < getLength() );
1380 }
1381 }
1382
1383
1384
1385
1386
1387
1388
1389
1390 private class IDElementAttributes extends ElementAttributes {
1391
1392 private String idValue;
1393
1394 private String idAttributeName;
1395
1396 private boolean matchingAttribute = false;
1397 private int length;
1398 private int idIndex;
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408 IDElementAttributes(
1409 ElementDescriptor descriptor,
1410 Context context,
1411 String idAttributeName,
1412 String idValue) {
1413 super(descriptor, context);
1414 this.idValue = idValue;
1415 this.idAttributeName = idAttributeName;
1416
1417
1418 AttributeDescriptor[] attributeDescriptors = descriptor.getAttributeDescriptors();
1419 length = super.getLength();
1420 for (int i=0; i<length; i++) {
1421 if (idAttributeName.equals(attributeDescriptors[i].getQualifiedName())) {
1422 matchingAttribute = true;
1423 idIndex = i;
1424 break;
1425 }
1426 }
1427 if (!matchingAttribute) {
1428 length += 1;
1429 idIndex = length-1;
1430 }
1431 }
1432
1433 public int getIndex(String uri, String localName) {
1434 if (localName.equals(idAttributeName)) {
1435 return idIndex;
1436 }
1437
1438 return super.getIndex(uri, localName);
1439 }
1440
1441 public int getIndex(String qName) {
1442 if (qName.equals(idAttributeName)) {
1443 return idIndex;
1444 }
1445
1446 return super.getIndex(qName);
1447 }
1448
1449 public int getLength() {
1450 return length;
1451 }
1452
1453 public String getLocalName(int index) {
1454 if (index == idIndex) {
1455 return idAttributeName;
1456 }
1457 return super.getLocalName(index);
1458 }
1459
1460 public String getQName(int index) {
1461 if (index == idIndex) {
1462 return idAttributeName;
1463 }
1464 return super.getQName(index);
1465 }
1466
1467 public String getType(int index) {
1468 if (index == idIndex) {
1469 return "ID";
1470 }
1471 return super.getType(index);
1472 }
1473
1474 public String getType(String uri, String localName) {
1475 return getType(getIndex(uri, localName));
1476 }
1477
1478 public String getType(String qName) {
1479 return getType(getIndex(qName));
1480 }
1481
1482 public String getURI(int index) {
1483
1484
1485
1486 if (index == idIndex) {
1487 return "";
1488 }
1489 return super.getURI(index);
1490 }
1491
1492 public String getValue(int index) {
1493 if (index == idIndex) {
1494 return idValue;
1495 }
1496 return super.getValue(index);
1497 }
1498
1499 public String getValue(String uri, String localName) {
1500 return getValue(getIndex(uri, localName));
1501 }
1502
1503 public String getValue(String qName) {
1504 return getValue(getIndex(qName));
1505 }
1506
1507 }
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521 protected int getIndentLevel() {
1522 return 0;
1523 }
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536 protected void expressElementStart(String qualifiedName)
1537 throws IOException, SAXException {
1538
1539 }
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551 protected void expressElementStart(String uri, String localName, String qualifiedName)
1552 throws IOException, SAXException {
1553 expressElementStart( qualifiedName );
1554 }
1555
1556
1557
1558
1559
1560
1561
1562
1563 protected void expressTagClose() throws IOException, SAXException {}
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574 protected void expressElementEnd(String qualifiedName)
1575 throws IOException, SAXException {
1576
1577 }
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590 protected void expressElementEnd(
1591 String uri,
1592 String localName,
1593 String qualifiedName)
1594 throws
1595 IOException,
1596 SAXException {
1597 expressElementEnd(qualifiedName);
1598 }
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608 protected void expressElementEnd() throws IOException, SAXException {}
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619 protected void expressBodyText(String text) throws IOException, SAXException {}
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630 protected void expressAttribute(
1631 String qualifiedName,
1632 String value)
1633 throws
1634 IOException,
1635 SAXException {
1636
1637 }
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650 protected void expressAttribute(
1651 String namespaceUri,
1652 String localName,
1653 String qualifiedName,
1654 String value)
1655 throws
1656 IOException,
1657 SAXException {
1658 expressAttribute(qualifiedName, value);
1659 }
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673 protected void write(
1674 String qualifiedName,
1675 ElementDescriptor elementDescriptor,
1676 Context context )
1677 throws
1678 IOException,
1679 SAXException,
1680 IntrospectionException {
1681 writeElement( "", qualifiedName, qualifiedName, elementDescriptor, context );
1682 }
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697 protected void write(
1698 String qualifiedName,
1699 ElementDescriptor elementDescriptor,
1700 Context context,
1701 String idAttribute,
1702 String idValue )
1703 throws
1704 IOException,
1705 SAXException,
1706 IntrospectionException {
1707 writeElement(
1708 "",
1709 qualifiedName,
1710 qualifiedName,
1711 elementDescriptor,
1712 context,
1713 idAttribute,
1714 idValue );
1715 }
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728 protected void writeRestOfElement(
1729 String qualifiedName,
1730 ElementDescriptor elementDescriptor,
1731 Context context )
1732 throws
1733 IOException,
1734 SAXException,
1735 IntrospectionException {
1736 writeRestOfElement( "", qualifiedName, qualifiedName, elementDescriptor, context );
1737 }
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750 protected void writeIDREFElement(
1751 String qualifiedName,
1752 String idrefAttributeName,
1753 String idrefAttributeValue )
1754 throws
1755 IOException,
1756 SAXException,
1757 IntrospectionException {
1758
1759 AttributesImpl attributes = new AttributesImpl();
1760 attributes.addAttribute(
1761 "",
1762 idrefAttributeName,
1763 idrefAttributeName,
1764 "IDREF",
1765 idrefAttributeValue);
1766 startElement( "", qualifiedName, qualifiedName, attributes);
1767 endElement( "", qualifiedName, qualifiedName );
1768 }
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782 protected boolean writeContent(
1783 ElementDescriptor elementDescriptor,
1784 Context context )
1785 throws
1786 IOException,
1787 SAXException,
1788 IntrospectionException {
1789 return false;
1790 }
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802 protected void writeAttributes(
1803 ElementDescriptor elementDescriptor,
1804 Context context )
1805 throws
1806 IOException, SAXException {
1807 if (!elementDescriptor.isWrapCollectionsInElement()) {
1808 return;
1809 }
1810
1811 AttributeDescriptor[] attributeDescriptors = elementDescriptor.getAttributeDescriptors();
1812 if ( attributeDescriptors != null ) {
1813 for ( int i = 0, size = attributeDescriptors.length; i < size; i++ ) {
1814 AttributeDescriptor attributeDescriptor = attributeDescriptors[i];
1815 writeAttribute( attributeDescriptor, context );
1816 }
1817 }
1818 }
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830 protected void writeAttribute(
1831 AttributeDescriptor attributeDescriptor,
1832 Context context )
1833 throws
1834 IOException, SAXException {
1835 Expression expression = attributeDescriptor.getTextExpression();
1836 if ( expression != null ) {
1837 Object value = expression.evaluate( context );
1838 if ( value != null ) {
1839 String text = value.toString();
1840 if ( text != null && text.length() > 0 ) {
1841 expressAttribute(
1842 attributeDescriptor.getURI(),
1843 attributeDescriptor.getLocalName(),
1844 attributeDescriptor.getQualifiedName(),
1845 text);
1846 }
1847 }
1848 }
1849 }
1850
1851
1852
1853
1854
1855
1856
1857 protected void writePrintln() throws IOException {}
1858
1859
1860
1861
1862
1863
1864
1865
1866 protected void writeIndent() throws IOException {}
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876 private String convertToString( Object value , Descriptor descriptor, Context context ) {
1877 return getBindingConfiguration()
1878 .getObjectStringConverter()
1879 .objectToString( value, descriptor.getPropertyType(), context );
1880 }
1881
1882
1883
1884
1885
1886
1887
1888 private Context makeContext(Object bean) {
1889 return new Context( bean, log, bindingConfiguration );
1890 }
1891
1892
1893
1894
1895
1896 private static class WriteContextImpl extends WriteContext {
1897
1898 private ElementDescriptor currentDescriptor;
1899
1900
1901
1902
1903 public ElementDescriptor getCurrentDescriptor() {
1904 return currentDescriptor;
1905 }
1906
1907
1908
1909
1910
1911 public void setCurrentDescriptor(ElementDescriptor currentDescriptor) {
1912 this.currentDescriptor = currentDescriptor;
1913 }
1914
1915 }
1916 }