1
2
3
4
5
6
7
8 package org.jdtaus.mojo.resource.model.impl.runtime;
9
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.Set;
13
14 import javax.xml.bind.JAXBException;
15 import javax.xml.bind.ValidationEvent;
16 import javax.xml.bind.ValidationEventHandler;
17 import javax.xml.bind.helpers.NotIdentifiableEventImpl;
18 import javax.xml.bind.helpers.ValidationEventLocatorImpl;
19
20 import org.xml.sax.ContentHandler;
21 import org.xml.sax.SAXException;
22 import org.xml.sax.helpers.AttributesImpl;
23
24 import com.sun.xml.bind.JAXBAssertionError;
25 import com.sun.xml.bind.JAXBObject;
26 import com.sun.xml.bind.marshaller.IdentifiableObject;
27 import com.sun.xml.bind.marshaller.Messages;
28 import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
29 import com.sun.xml.bind.serializer.AbortSerializationException;
30 import com.sun.xml.bind.serializer.Util;
31
32
33
34
35
36
37
38
39
40
41 public class SAXMarshaller implements XMLSerializer
42 {
43
44
45
46
47 private final AttributesImpl attributes = new AttributesImpl();
48
49
50 private final ContentHandler writer;
51
52
53 private final MarshallerImpl owner;
54
55
56 private final Set idReferencedObjects = new HashSet();
57
58
59 private final Set objectsWithId = new HashSet();
60
61
62 private JAXBObject currentTarget;
63
64
65
66
67
68 public SAXMarshaller( ContentHandler _writer, NamespacePrefixMapper prefixMapper, MarshallerImpl _owner ) {
69 this.writer = _writer;
70 this.owner = _owner;
71 this.nsContext = new NamespaceContextImpl(
72 prefixMapper!=null?prefixMapper:defaultNamespacePrefixMapper);
73 }
74
75
76 private final NamespaceContextImpl nsContext;
77
78 public NamespaceContext2 getNamespaceContext() { return nsContext; }
79
80
81
82
83
84
85
86
87 private String[] elementStack = new String[16];;
88 private int elementLen=0;
89
90
91
92 private void pushElement( String uri, String local ) {
93 if(elementStack.length==elementLen) {
94
95 String[] buf = new String[elementStack.length*2];
96 System.arraycopy( elementStack, 0, buf, 0, elementStack.length );
97 elementStack = buf;
98 }
99 elementStack[elementLen++] = uri;
100 elementStack[elementLen++] = local;
101 }
102
103 private void popElement() { elementLen-=2; }
104
105 private String getCurrentElementUri() { return elementStack[elementLen-2]; }
106 private String getCurrentElementLocal() { return elementStack[elementLen-1]; }
107
108
109
110
111
112
113
114
115
116
117 public void startElement( String uri, String local ) throws SAXException {
118 boolean isRoot = false;
119 String suggestion = null;
120 if( elementLen==0 ) {
121 isRoot = true;
122
123 suggestion = "";
124 }
125
126 writePendingText();
127 nsContext.startElement();
128 pushElement(uri,local);
129
130
131 nsContext.declareNamespace(uri,suggestion,false);
132
133
134 if( isRoot ) {
135
136 String[] uris = nsContext.getNamespacePrefixMapper().getPreDeclaredNamespaceUris();
137 if( uris!=null ) {
138 for( int i=0; i<uris.length; i++ ) {
139 if( uris[i]!=null )
140 nsContext.declareNamespace(uris[i],null,false);
141 }
142 }
143 }
144 }
145
146
147 private final PrefixCallback startPrefixCallback = new PrefixCallback() {
148 public void onPrefixMapping( String prefix, String nsUri ) throws SAXException {
149 writer.startPrefixMapping(prefix,nsUri);
150 }
151 };
152 private final PrefixCallback endPrefixCallback = new PrefixCallback() {
153 public void onPrefixMapping( String prefix, String nsUri ) throws SAXException {
154 writer.endPrefixMapping(prefix);
155 }
156 };
157
158 public void endNamespaceDecls() throws SAXException {
159 nsContext.endNamespaceDecls();
160 }
161
162
163
164
165
166 public void endAttributes() throws SAXException {
167
168 String uri = getCurrentElementUri();
169 String local = getCurrentElementLocal();
170
171 String prefix = nsContext.getPrefix(uri);
172 _assert(prefix!=null);
173
174 String qname;
175 if(prefix.length()!=0 )
176 qname = prefix+':'+local;
177 else
178 qname = local;
179
180
181 nsContext.iterateDeclaredPrefixes(startPrefixCallback);
182
183
184 writer.startElement( uri, local, qname, attributes );
185
186
187
188 attributes.clear();
189
190
191 textBuf.setLength(0);
192 }
193
194
195
196
197
198 public void endElement() throws SAXException {
199 writePendingText();
200
201 String uri = getCurrentElementUri();
202 String local = getCurrentElementLocal();
203
204 String prefix = nsContext.getPrefix(uri);
205 _assert(prefix!=null);
206
207 String qname;
208 if(prefix.length()!=0)
209 qname = prefix+':'+local;
210 else
211 qname = local;
212
213 writer.endElement( uri, local, qname );
214
215
216
217 nsContext.iterateDeclaredPrefixes(endPrefixCallback);
218
219 popElement();
220
221
222 textBuf.setLength(0);
223
224 nsContext.endElement();
225 }
226
227
228
229 private final StringBuffer textBuf = new StringBuffer();
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 public void text( String text, String fieldName ) throws SAXException {
269
270
271 if(text==null) {
272 reportError(Util.createMissingObjectError(currentTarget,fieldName));
273 return;
274 }
275
276 if(textBuf.length()!=0)
277 textBuf.append(' ');
278 textBuf.append(text);
279 }
280
281
282
283
284
285 private void writePendingText() throws SAXException {
286
287 int len = textBuf.length();
288
289 if(len!=0)
290 writer.characters( textBuf.toString().toCharArray(), 0, len );
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 public void startAttribute( String uri, String local ) {
308
309 textBuf.setLength(0);
310
311
312 this.attNamespaceUri = uri;
313 this.attLocalName = local;
314 }
315
316
317 private String attNamespaceUri;
318 private String attLocalName;
319
320 public void endAttribute() {
321
322
323
324
325
326
327
328
329
330
331
332 String qname;
333 if(attNamespaceUri.length()==0) {
334
335 qname = attLocalName;
336 } else {
337 qname = nsContext.declareNamespace(attNamespaceUri,null,true)+':'+attLocalName;
338 }
339
340 attributes.addAttribute(attNamespaceUri,attLocalName,qname,"CDATA",textBuf.toString());
341 }
342
343 public String onID( IdentifiableObject owner, String value ) throws SAXException {
344 objectsWithId.add(owner);
345 return value;
346 }
347 public String onIDREF( IdentifiableObject obj ) throws SAXException {
348 idReferencedObjects.add(obj);
349 String id = obj.____jaxb____getId();
350 if(id==null) {
351 reportError( new NotIdentifiableEventImpl(
352 ValidationEvent.ERROR,
353 Messages.format(Messages.ERR_NOT_IDENTIFIABLE),
354 new ValidationEventLocatorImpl(obj) ) );
355 }
356 return id;
357 }
358
359 void reconcileID() throws AbortSerializationException {
360
361 idReferencedObjects.removeAll(objectsWithId);
362
363 for( Iterator itr=idReferencedObjects.iterator(); itr.hasNext(); ) {
364 IdentifiableObject o = (IdentifiableObject)itr.next();
365 reportError( new NotIdentifiableEventImpl(
366 ValidationEvent.ERROR,
367 Messages.format(Messages.ERR_DANGLING_IDREF,o.____jaxb____getId()),
368 new ValidationEventLocatorImpl(o) ) );
369 }
370
371
372 idReferencedObjects.clear();
373 objectsWithId.clear();
374 }
375
376
377
378 public void childAsBody( JAXBObject o, String fieldName ) throws SAXException {
379 if(o==null) {
380
381
382 reportMissingObjectError(fieldName);
383
384
385 return;
386 }
387
388 JAXBObject oldTarget = currentTarget;
389 currentTarget = o;
390
391 owner.context.getGrammarInfo().castToXMLSerializable(o).serializeBody(this);
392
393 currentTarget = oldTarget;
394 }
395
396 public void childAsAttributes( JAXBObject o, String fieldName ) throws SAXException {
397 if(o==null) {
398 reportMissingObjectError(fieldName);
399 return;
400 }
401
402 JAXBObject oldTarget = currentTarget;
403 currentTarget = o;
404
405 owner.context.getGrammarInfo().castToXMLSerializable(o).serializeAttributes(this);
406
407 currentTarget = oldTarget;
408 }
409
410 public void childAsURIs( JAXBObject o, String fieldName ) throws SAXException {
411 if(o==null) {
412 reportMissingObjectError(fieldName);
413 return;
414 }
415
416 JAXBObject oldTarget = currentTarget;
417 currentTarget = o;
418
419 owner.context.getGrammarInfo().castToXMLSerializable(o).serializeURIs(this);
420
421 currentTarget = oldTarget;
422 }
423
424
425 public void reportError( ValidationEvent ve ) throws AbortSerializationException {
426 ValidationEventHandler handler;
427
428 try {
429 handler = owner.getEventHandler();
430 } catch( JAXBException e ) {
431 throw new AbortSerializationException(e);
432 }
433
434 if(!handler.handleEvent(ve)) {
435 if(ve.getLinkedException() instanceof Exception)
436 throw new AbortSerializationException((Exception)ve.getLinkedException());
437 else
438 throw new AbortSerializationException(ve.getMessage());
439 }
440 }
441
442
443 public void reportMissingObjectError(String fieldName) throws SAXException {
444 reportError(Util.createMissingObjectError(currentTarget,fieldName));
445 }
446
447
448 private static void _assert( boolean b ) {
449 if(!b)
450 throw new JAXBAssertionError();
451 }
452
453
454
455
456
457 private static NamespacePrefixMapper defaultNamespacePrefixMapper = new NamespacePrefixMapper() {
458 public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
459 if( namespaceUri.equals("http://www.w3.org/2001/XMLSchema-instance") )
460 return "xsi";
461 return suggestion;
462 }
463 };
464 }