Package org.apache.ws.jaxme.impl

Source Code of org.apache.ws.jaxme.impl.JMUnmarshallerHandlerImpl

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

*/
package org.apache.ws.jaxme.impl;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.DatatypeConverterInterface;
import javax.xml.bind.JAXBException;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.helpers.ParseConversionEventImpl;
import javax.xml.bind.helpers.ValidationEventImpl;
import javax.xml.bind.helpers.ValidationEventLocatorImpl;
import javax.xml.namespace.QName;

import org.apache.ws.jaxme.JMManager;
import org.apache.ws.jaxme.JMUnmarshaller;
import org.apache.ws.jaxme.JMUnmarshallerHandler;
import org.apache.ws.jaxme.Observer;
import org.apache.ws.jaxme.ValidationEvents;
import org.apache.ws.jaxme.util.NamespaceSupport;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;


/** <p>Implementation of a JMUnmarshallerHandler; the
* UnmarshallerHandler receives SAX events which he silently
* discards, as long as the first <code>startElement</code>
* event is seen. Depending on namespace URI and local name,
* the Unmarshallerhandler creates a new instance of JMHandler
* and from now on forwards all SAX events to the JMHandler.</p>
*/
public class JMUnmarshallerHandlerImpl implements JMUnmarshallerHandler {
    /** State for parsing a simple, atomic element.
     */
    private static final int STATE_SIMPLE_ATOMIC = 1;
    /** State for parsing a complex element. The outer
     * {@link JMSAXGroupParser} will always be parsing
     * a complex element.
     */
    private static final int STATE_COMPLEX_CONTENT = 3;
    /** State for parsing an anonymous group. This is
     * mostly comparable to parsing a complex element,
     * except that the group doesn't have an outer
     * start and end element.
     */
    private static final int STATE_GROUP = 4;

  private final JMUnmarshaller unmarshaller;
    private Locator locator;
    private NamespaceSupport nss = new NamespaceSupport();
    private final List groupParsers = new ArrayList();
    private JMSAXGroupParser activeParser;
    private int level;
    private int endLevel;
    private int state;
    private final StringBuffer sb = new StringBuffer();
  private Observer observer;
  private Object result;

    public int getLevel() { return level; }

    /** Removes the currently active parser from the stack.
     */
    private boolean removeActiveParser() {
        int size = groupParsers.size();
        groupParsers.remove(--size);
        if (size == 0) {
            return false;
        }
        activeParser = (JMSAXGroupParser) groupParsers.get(--size);
        if (activeParser instanceof JMSAXElementParser) {
            state = STATE_COMPLEX_CONTENT;
            endLevel = ((JMSAXElementParser) activeParser).getEndLevel();
        } else {
            state = STATE_GROUP;
        }
        return true;
    }

  /** Sets an observer, which will be notified, when the element has
   * been parsed.
   */
  public void setObserver(Observer pObserver) {
    observer = pObserver;
  }

  /** Returns the observer, which will be notified, when the element has
   * been parsed.
   */
  public Observer getObserver() {
    return observer;
  }

  /** Creates a new instance, controlled by the given
     * {@link JMUnmarshaller}.
     */
    public JMUnmarshallerHandlerImpl(JMUnmarshaller pUnmarshaller) {
        unmarshaller = pUnmarshaller;
    }

    /** Returns the {@link JMUnmarshaller}, which created this
     * handler.
     */
    public JMUnmarshaller getJMUnmarshaller() {
        return unmarshaller;
    }

    public void setDocumentLocator(Locator pLocator) {
        locator = pLocator;
    }

    public void startDocument() throws SAXException {
    }

    public void endDocument() throws SAXException {
    }

    public void startPrefixMapping(String pPrefix, String pURI) throws SAXException {
        nss.declarePrefix(pPrefix, pURI);
    }

    public void endPrefixMapping(String pPrefix) throws SAXException {
        nss.undeclarePrefix(pPrefix);
    }

  /** Tests, whether the group parser accepts the element.
   * If so, adds the group parser to the stack.
   */
  public boolean testGroupParser(JMSAXGroupParser pParser,
                   String pNamespaceURI, String pLocalName,
                   String pQName, Attributes pAttrs)
      throws SAXException {
    groupParsers.add(pParser);
    activeParser = pParser;
    state = STATE_GROUP;
    if (pParser.startElement(pNamespaceURI, pLocalName, pQName, pAttrs)) {
      return true;
    } else {
      removeActiveParser();
      return false;
    }
  }

  /** Adds a parser for an nested element to the stack of parsers.
   */
  public void addElementParser(JMSAXElementParser pParser) {
    endLevel = pParser.getEndLevel();
    groupParsers.add(pParser);
    activeParser = pParser;
    state = STATE_COMPLEX_CONTENT;
    if (pParser.isAtomic()) {
      sb.setLength(0);
    }
  }

    public void startElement(String pNamespaceURI, String pLocalName,
                             String pQName, Attributes pAttrs) throws SAXException {
    if (level++ == 0) {
      JAXBContextImpl context = unmarshaller.getJAXBContextImpl();
      JMManager manager;
      QName qName = new QName(pNamespaceURI, pLocalName);
      try {
        manager = context.getManager(qName);
      } catch (JAXBException e) {
        throw new SAXException("Unable to instantiate manager for element " + qName, e);
      }
      Object o = manager.getElementS();
      JMSAXElementParser parser = manager.getHandler();
      parser.init(this, o, pNamespaceURI, pLocalName, 1);
      parser.setAttributes(pAttrs);
      groupParsers.clear();
      result = o;
      addElementParser(parser);
    } else {
      if (state == STATE_COMPLEX_CONTENT  ||  state == STATE_GROUP) {
        for (;;) {
          if (activeParser.startElement(pNamespaceURI, pLocalName, pQName, pAttrs)) {
            return;
          }
          if (state == STATE_GROUP) {
            if (removeActiveParser()) {
              continue;
            }
          }
          break;
        }
      }
      QName qName = new QName(pNamespaceURI, pLocalName);
      validationEvent(ValidationEvent.WARNING,
          "Unexpected element: '" + qName + "'",
          ValidationEvents.EVENT_UNEXPECTED_CHILD_ELEMENT,
          null);
    }
    }

    public void endElement(String pNamespaceURI, String pLocalName, String pQName) throws SAXException {
    int lvl = level--;
    switch (state) {
      case STATE_GROUP:
        while (state == STATE_GROUP) {
          if (activeParser.isFinished()) {
            removeActiveParser();
          }
        }
        if (state != STATE_COMPLEX_CONTENT) {
          break;
        }
      case STATE_COMPLEX_CONTENT:
        if (lvl != endLevel) {
          throw new IllegalStateException("Expected level " + endLevel
                          + ", got " + lvl);
        }
              JMSAXElementParser elementParser = (JMSAXElementParser) activeParser;
        if (elementParser.isAtomic()) {
          elementParser.endElement(pNamespaceURI, pLocalName, pQName, sb.toString());
        }
              if (pNamespaceURI.equals(elementParser.getNamespaceURI())  &&
                  pLocalName.equals(elementParser.getLocalName())) {
                  if (activeParser.isFinished()) {
                      if (removeActiveParser()) {
              activeParser.endElement(pNamespaceURI, pLocalName, pQName, elementParser.result);
                      } else {
              if (observer != null) {
                observer.notify(result);
              }
                      }
                      return;
                  }
              }
        break;
      case STATE_SIMPLE_ATOMIC: {
        String s = sb.toString();
        resetAtomicState();
        activeParser.endElement(pNamespaceURI, pLocalName, pQName, s);
        return;
      }
      default:
        throw new IllegalStateException("Invalid state: " + state);
        }
        QName qName = new QName(pNamespaceURI, pLocalName);
        validationEvent(ValidationEvent.WARNING,
                        "Unexpected end element: '" + qName + "'",
                        ValidationEvents.EVENT_PREMATURE_END_ELEMENT,
                        null);
    }

    private boolean isEmpty(char[] pChars, int pOffset, int pLen) {
        for (int i = 0;  i < pLen;  i++) {
            if (!Character.isWhitespace(pChars[pOffset+i])) {
                return false;
            }
        }
        return true;
    }

    public void characters(char[] pChars, int pOffset, int pLen) throws SAXException {
        switch (state) {
      case STATE_SIMPLE_ATOMIC:
        sb.append(pChars, pOffset, pLen);
        return;
      case STATE_COMPLEX_CONTENT:
        if (((JMSAXElementParser) activeParser).isAtomic()) {
          sb.append(pChars, pOffset, pLen);
          return;
        }
      case STATE_GROUP:
        if (!isEmpty(pChars, pOffset, pLen)) {
          if (pLen > 100) {
            pLen = 100// Keep the message approximately human readable.
          }
          validationEvent(ValidationEvent.WARNING, "Unexpected non-whitespace characters: '" +
                  new String(pChars, pOffset, pLen) + "'",
                  ValidationEvents.EVENT_UNEXPECTED_TEXTUAL_CONTENTS,
                  null);
        }
        break;
      default:
        throw new IllegalStateException("Invalid state: " + state);
    }
    }

    public void ignorableWhitespace(char[] pChars, int pStart, int pLen) throws SAXException {
    characters(pChars, pStart, pLen);
    }

    public void processingInstruction(String pTarget, String pData) throws SAXException {
    validationEvent(ValidationEvent.WARNING,
                        "Don't know how to handle processing instructions.",
                        ValidationEvents.EVENT_PROCESSING_INSTRUCTION,
                        null);
    }

  /** Posts a {@link javax.xml.bind.ParseConversionEvent}.
   */
  public void parseConversionEvent(String pMsg, Exception pException) throws SAXException {
    ParseConversionEventImpl event = new ParseConversionEventImpl(ValidationEvent.FATAL_ERROR, pMsg, null);
    handleEvent(event, pException);
  }

  /** Posts a {@link ValidationEvent}.
   */
  public void validationEvent(int pSeverity, String pMsg, String pErrorCode,
                Exception pException) throws SAXException {
    org.apache.ws.jaxme.impl.ValidationEventImpl event = new org.apache.ws.jaxme.impl.ValidationEventImpl(pSeverity, pMsg, null);
    event.setErrorCode(pErrorCode);
    handleEvent(event, pException);
  }

  private void handleEvent(ValidationEventImpl pEvent, Exception pException) throws SAXException {
    if (locator != null) {
      pEvent.setLocator(new ValidationEventLocatorImpl(locator));
    }
    if (pException != null) {
      pEvent.setLinkedException(pException);
    }
    ValidationEventHandler eventHandler;
    try {
      eventHandler = unmarshaller.getEventHandler();
    } catch (JAXBException e) {
      throw new SAXException(e);
    }
    if (eventHandler == null  ||  !eventHandler.handleEvent(pEvent)) {
      String msg = pEvent.getMessage();
      if (pEvent instanceof org.apache.ws.jaxme.impl.ValidationEventImpl) {
        String errorCode = ((org.apache.ws.jaxme.impl.ValidationEventImpl) pEvent).getErrorCode();
        if (errorCode != null) {
          msg = errorCode + ": " + msg;
        }
      }
      throw new SAXParseException(msg, locator, pException);
    }
  }

  public void skippedEntity(String pName) throws SAXException {
    validationEvent(ValidationEvent.WARNING,
                        "Don't know how to handle skipped entities.",
                        ValidationEvents.EVENT_SKIPPED_ENTITY,
                        null);
    }

    public Object getResult() throws JAXBException, IllegalStateException {
    if (groupParsers.size() > ||  result == null) {
      throw new IllegalStateException("Parsing the element is not yet finished.");
    }
    return result;
    }

  public NamespaceSupport getNamespaceSupport() {
    return nss;
  }

  public Locator getDocumentLocator() {
    return locator;
  }

  public DatatypeConverterInterface getDatatypeConverter() {
    return unmarshaller.getDatatypeConverter();
  }

  /** Indicates, that the handler is parsing a simple, atomic element.
   */
  public void addSimpleAtomicState() {
    activeParser = null;
    sb.setLength(0);
    state = STATE_SIMPLE_ATOMIC;
  }

  /** Restores the state after parsing an atomic element.
   */
  private void resetAtomicState() {
    activeParser = (JMSAXGroupParser) groupParsers.get(groupParsers.size()-1);
    if (activeParser instanceof JMSAXElementParser) {
      state = STATE_COMPLEX_CONTENT;
    } else {
      state = STATE_GROUP;
    }
  }
}
TOP

Related Classes of org.apache.ws.jaxme.impl.JMUnmarshallerHandlerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.