KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > impl > JMUnmarshallerHandlerImpl


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15
16  */

17 package org.apache.ws.jaxme.impl;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.List JavaDoc;
21
22 import javax.xml.bind.DatatypeConverterInterface;
23 import javax.xml.bind.JAXBException;
24 import javax.xml.bind.ValidationEvent;
25 import javax.xml.bind.ValidationEventHandler;
26 import javax.xml.bind.helpers.ParseConversionEventImpl;
27 import javax.xml.bind.helpers.ValidationEventImpl;
28 import javax.xml.bind.helpers.ValidationEventLocatorImpl;
29 import javax.xml.namespace.QName JavaDoc;
30
31 import org.apache.ws.jaxme.JMManager;
32 import org.apache.ws.jaxme.JMUnmarshaller;
33 import org.apache.ws.jaxme.JMUnmarshallerHandler;
34 import org.apache.ws.jaxme.Observer;
35 import org.apache.ws.jaxme.ValidationEvents;
36 import org.apache.ws.jaxme.util.NamespaceSupport;
37 import org.xml.sax.Attributes JavaDoc;
38 import org.xml.sax.Locator JavaDoc;
39 import org.xml.sax.SAXException JavaDoc;
40 import org.xml.sax.SAXParseException JavaDoc;
41
42
43 /** <p>Implementation of a JMUnmarshallerHandler; the
44  * UnmarshallerHandler receives SAX events which he silently
45  * discards, as long as the first <code>startElement</code>
46  * event is seen. Depending on namespace URI and local name,
47  * the Unmarshallerhandler creates a new instance of JMHandler
48  * and from now on forwards all SAX events to the JMHandler.</p>
49  */

50 public class JMUnmarshallerHandlerImpl implements JMUnmarshallerHandler {
51     /** State for parsing a simple, atomic element.
52      */

53     private static final int STATE_SIMPLE_ATOMIC = 1;
54     /** State for parsing a complex element. The outer
55      * {@link JMSAXGroupParser} will always be parsing
56      * a complex element.
57      */

58     private static final int STATE_COMPLEX_CONTENT = 3;
59     /** State for parsing an anonymous group. This is
60      * mostly comparable to parsing a complex element,
61      * except that the group doesn't have an outer
62      * start and end element.
63      */

64     private static final int STATE_GROUP = 4;
65
66     private final JMUnmarshaller unmarshaller;
67     private Locator JavaDoc locator;
68     private NamespaceSupport nss = new NamespaceSupport();
69     private final List JavaDoc groupParsers = new ArrayList JavaDoc();
70     private JMSAXGroupParser activeParser;
71     private int level;
72     private int endLevel;
73     private int state;
74     private final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
75     private Observer observer;
76     private Object JavaDoc result;
77
78     public int getLevel() { return level; }
79
80     /** Removes the currently active parser from the stack.
81      */

82     private boolean removeActiveParser() {
83         int size = groupParsers.size();
84         groupParsers.remove(--size);
85         if (size == 0) {
86             return false;
87         }
88         activeParser = (JMSAXGroupParser) groupParsers.get(--size);
89         if (activeParser instanceof JMSAXElementParser) {
90             state = STATE_COMPLEX_CONTENT;
91             endLevel = ((JMSAXElementParser) activeParser).getEndLevel();
92         } else {
93             state = STATE_GROUP;
94         }
95         return true;
96     }
97
98     /** Sets an observer, which will be notified, when the element has
99      * been parsed.
100      */

101     public void setObserver(Observer pObserver) {
102         observer = pObserver;
103     }
104
105     /** Returns the observer, which will be notified, when the element has
106      * been parsed.
107      */

108     public Observer getObserver() {
109         return observer;
110     }
111
112     /** Creates a new instance, controlled by the given
113      * {@link JMUnmarshaller}.
114      */

115     public JMUnmarshallerHandlerImpl(JMUnmarshaller pUnmarshaller) {
116         unmarshaller = pUnmarshaller;
117     }
118
119     /** Returns the {@link JMUnmarshaller}, which created this
120      * handler.
121      */

122     public JMUnmarshaller getJMUnmarshaller() {
123         return unmarshaller;
124     }
125
126     public void setDocumentLocator(Locator JavaDoc pLocator) {
127         locator = pLocator;
128     }
129
130     public void startDocument() throws SAXException JavaDoc {
131     }
132
133     public void endDocument() throws SAXException JavaDoc {
134     }
135
136     public void startPrefixMapping(String JavaDoc pPrefix, String JavaDoc pURI) throws SAXException JavaDoc {
137         nss.declarePrefix(pPrefix, pURI);
138     }
139
140     public void endPrefixMapping(String JavaDoc pPrefix) throws SAXException JavaDoc {
141         nss.undeclarePrefix(pPrefix);
142     }
143
144     /** Tests, whether the group parser accepts the element.
145      * If so, adds the group parser to the stack.
146      */

147     public boolean testGroupParser(JMSAXGroupParser pParser,
148                                    String JavaDoc pNamespaceURI, String JavaDoc pLocalName,
149                                    String JavaDoc pQName, Attributes JavaDoc pAttrs)
150             throws SAXException JavaDoc {
151         groupParsers.add(pParser);
152         activeParser = pParser;
153         state = STATE_GROUP;
154         if (pParser.startElement(pNamespaceURI, pLocalName, pQName, pAttrs)) {
155             return true;
156         } else {
157             removeActiveParser();
158             return false;
159         }
160     }
161
162     /** Adds a parser for an nested element to the stack of parsers.
163      */

164     public void addElementParser(JMSAXElementParser pParser) {
165         endLevel = pParser.getEndLevel();
166         groupParsers.add(pParser);
167         activeParser = pParser;
168         state = STATE_COMPLEX_CONTENT;
169         if (pParser.isAtomic()) {
170             sb.setLength(0);
171         }
172     }
173
174     public void startElement(String JavaDoc pNamespaceURI, String JavaDoc pLocalName,
175                              String JavaDoc pQName, Attributes JavaDoc pAttrs) throws SAXException JavaDoc {
176         if (level++ == 0) {
177             JAXBContextImpl context = unmarshaller.getJAXBContextImpl();
178             JMManager manager;
179             QName JavaDoc qName = new QName JavaDoc(pNamespaceURI, pLocalName);
180             try {
181                 manager = context.getManager(qName);
182             } catch (JAXBException e) {
183                 throw new SAXException JavaDoc("Unable to instantiate manager for element " + qName, e);
184             }
185             Object JavaDoc o = manager.getElementS();
186             JMSAXElementParser parser = manager.getHandler();
187             parser.init(this, o, pNamespaceURI, pLocalName, 1);
188             parser.setAttributes(pAttrs);
189             groupParsers.clear();
190             result = o;
191             addElementParser(parser);
192         } else {
193             if (state == STATE_COMPLEX_CONTENT || state == STATE_GROUP) {
194                 for (;;) {
195                     if (activeParser.startElement(pNamespaceURI, pLocalName, pQName, pAttrs)) {
196                         return;
197                     }
198                     if (state == STATE_GROUP) {
199                         if (removeActiveParser()) {
200                             continue;
201                         }
202                     }
203                     break;
204                 }
205             }
206             QName JavaDoc qName = new QName JavaDoc(pNamespaceURI, pLocalName);
207             validationEvent(ValidationEvent.WARNING,
208                     "Unexpected element: '" + qName + "'",
209                     ValidationEvents.EVENT_UNEXPECTED_CHILD_ELEMENT,
210                     null);
211         }
212     }
213
214     public void endElement(String JavaDoc pNamespaceURI, String JavaDoc pLocalName, String JavaDoc pQName) throws SAXException JavaDoc {
215         int lvl = level--;
216         switch (state) {
217             case STATE_GROUP:
218                 while (state == STATE_GROUP) {
219                     if (activeParser.isFinished()) {
220                         removeActiveParser();
221                     }
222                 }
223                 if (state != STATE_COMPLEX_CONTENT) {
224                     break;
225                 }
226             case STATE_COMPLEX_CONTENT:
227                 JMSAXElementParser elementParser = (JMSAXElementParser) activeParser;
228                 if (lvl != endLevel) {
229                     if (endLevel > lvl) {
230                         validationEvent(ValidationEvent.ERROR,
231                                         "Premature endElement: " + new QName JavaDoc(pNamespaceURI, pLocalName),
232                                         ValidationEvents.EVENT_PREMATURE_END_ELEMENT,
233                                         null);
234                         while (endLevel > lvl) {
235                             terminateComplexType(pNamespaceURI, pLocalName, pQName,
236                                                  elementParser);
237                         }
238                     } else {
239                         throw new IllegalStateException JavaDoc("Expected level " + endLevel
240                                                         + ", got " + lvl);
241                     }
242                 }
243                 if (elementParser.isAtomic()) {
244                     elementParser.endElement(pNamespaceURI, pLocalName, pQName, sb.toString());
245                 }
246                 if (pNamespaceURI.equals(elementParser.getNamespaceURI()) &&
247                     pLocalName.equals(elementParser.getLocalName())) {
248                     if (activeParser.isFinished()) {
249                         terminateComplexType(pNamespaceURI, pLocalName, pQName,
250                                              elementParser);
251                         return;
252                     }
253                 }
254                 break;
255             case STATE_SIMPLE_ATOMIC: {
256                 String JavaDoc s = sb.toString();
257                 resetAtomicState();
258                 activeParser.endElement(pNamespaceURI, pLocalName, pQName, s);
259                 return;
260             }
261             default:
262                 throw new IllegalStateException JavaDoc("Invalid state: " + state);
263         }
264         QName JavaDoc qName = new QName JavaDoc(pNamespaceURI, pLocalName);
265         validationEvent(ValidationEvent.WARNING,
266                         "Unexpected end element: '" + qName + "'",
267                         ValidationEvents.EVENT_PREMATURE_END_ELEMENT,
268                         null);
269     }
270
271     private void terminateComplexType(String JavaDoc pNamespaceURI, String JavaDoc pLocalName, String JavaDoc pQName,
272                                       JMSAXElementParser elementParser) throws SAXException JavaDoc {
273         if (removeActiveParser()) {
274             activeParser.endElement(pNamespaceURI, pLocalName, pQName, elementParser.result);
275         } else {
276             if (observer != null) {
277                 observer.notify(result);
278             }
279         }
280     }
281
282     public void characters(char[] pChars, int pOffset, int pLen) throws SAXException JavaDoc {
283         switch (state) {
284             case STATE_SIMPLE_ATOMIC:
285                 sb.append(pChars, pOffset, pLen);
286                 return;
287             case STATE_COMPLEX_CONTENT:
288                 if (((JMSAXElementParser) activeParser).isAtomic()) {
289                     sb.append(pChars, pOffset, pLen);
290                     return;
291                 }
292                 // Fall through
293
case STATE_GROUP:
294                 activeParser.addText(pChars, pOffset, pLen);
295                 break;
296             default:
297                 throw new IllegalStateException JavaDoc("Invalid state: " + state);
298         }
299     }
300
301     public void ignorableWhitespace(char[] pChars, int pStart, int pLen) throws SAXException JavaDoc {
302         characters(pChars, pStart, pLen);
303     }
304
305     public void processingInstruction(String JavaDoc pTarget, String JavaDoc pData) throws SAXException JavaDoc {
306         validationEvent(ValidationEvent.WARNING,
307                         "Don't know how to handle processing instructions.",
308                         ValidationEvents.EVENT_PROCESSING_INSTRUCTION,
309                         null);
310     }
311
312     /** Posts a {@link javax.xml.bind.ParseConversionEvent}.
313      */

314     public void parseConversionEvent(String JavaDoc pMsg, Exception JavaDoc pException) throws SAXException JavaDoc {
315         ParseConversionEventImpl event = new ParseConversionEventImpl(ValidationEvent.FATAL_ERROR, pMsg, null);
316         handleEvent(event, pException);
317     }
318
319     /** Posts a {@link ValidationEvent}.
320      */

321     public void validationEvent(int pSeverity, String JavaDoc pMsg, String JavaDoc pErrorCode,
322                                 Exception JavaDoc pException) throws SAXException JavaDoc {
323         org.apache.ws.jaxme.impl.ValidationEventImpl event = new org.apache.ws.jaxme.impl.ValidationEventImpl(pSeverity, pMsg, null);
324         event.setErrorCode(pErrorCode);
325         handleEvent(event, pException);
326     }
327
328     private void handleEvent(ValidationEventImpl pEvent, Exception JavaDoc pException) throws SAXException JavaDoc {
329         if (locator != null) {
330             pEvent.setLocator(new ValidationEventLocatorImpl(locator));
331         }
332         if (pException != null) {
333             pEvent.setLinkedException(pException);
334         }
335         ValidationEventHandler eventHandler;
336         try {
337             eventHandler = unmarshaller.getEventHandler();
338         } catch (JAXBException e) {
339             throw new SAXException JavaDoc(e);
340         }
341         if (eventHandler == null || !eventHandler.handleEvent(pEvent)) {
342             String JavaDoc msg = pEvent.getMessage();
343             if (pEvent instanceof org.apache.ws.jaxme.impl.ValidationEventImpl) {
344                 String JavaDoc errorCode = ((org.apache.ws.jaxme.impl.ValidationEventImpl) pEvent).getErrorCode();
345                 if (errorCode != null) {
346                     msg = errorCode + ": " + msg;
347                 }
348             }
349             throw new SAXParseException JavaDoc(msg, locator, pException);
350         }
351     }
352
353     public void skippedEntity(String JavaDoc pName) throws SAXException JavaDoc {
354         validationEvent(ValidationEvent.WARNING,
355                         "Don't know how to handle skipped entities.",
356                         ValidationEvents.EVENT_SKIPPED_ENTITY,
357                         null);
358     }
359
360     public Object JavaDoc getResult() throws JAXBException, IllegalStateException JavaDoc {
361         if (groupParsers.size() > 0 || result == null) {
362             throw new IllegalStateException JavaDoc("Parsing the element is not yet finished.");
363         }
364         return result;
365     }
366
367     public NamespaceSupport getNamespaceSupport() {
368         return nss;
369     }
370
371     public Locator JavaDoc getDocumentLocator() {
372         return locator;
373     }
374
375     public DatatypeConverterInterface getDatatypeConverter() {
376         return unmarshaller.getDatatypeConverter();
377     }
378
379     /** Indicates, that the handler is parsing a simple, atomic element.
380      */

381     public void addSimpleAtomicState() {
382         activeParser = null;
383         sb.setLength(0);
384         state = STATE_SIMPLE_ATOMIC;
385     }
386
387     /** Restores the state after parsing an atomic element.
388      */

389     private void resetAtomicState() {
390         activeParser = (JMSAXGroupParser) groupParsers.get(groupParsers.size()-1);
391         if (activeParser instanceof JMSAXElementParser) {
392             state = STATE_COMPLEX_CONTENT;
393         } else {
394             state = STATE_GROUP;
395         }
396     }
397 }
398
Popular Tags