org.iterx.miru.dispatcher.handler.factory.XmlHandlerChainParser.java Source code

Java tutorial

Introduction

Here is the source code for org.iterx.miru.dispatcher.handler.factory.XmlHandlerChainParser.java

Source

/*
  org.iterx.miru.dispatcher.handler.factory.XmlHandlerChainParser
    
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
    
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
    
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
  Copyright (C)2004-2005 Darren Graves <darren@iterx.org>
  All Rights Reserved.
*/

package org.iterx.miru.dispatcher.handler.factory;

import java.io.IOException;
import java.util.List;
import java.util.ArrayList;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import org.xml.sax.Attributes;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.iterx.miru.io.stream.StreamSource;

import org.iterx.miru.bean.BeanProvider;
import org.iterx.miru.bean.BeanWrapperAware;
import org.iterx.miru.bean.BeanWrapper;
import org.iterx.miru.bean.BeanException;

import org.iterx.miru.dispatcher.handler.HandlerWrapper;
import org.iterx.miru.dispatcher.handler.HandlerChain;
import org.iterx.miru.context.RequestContext;
import org.iterx.miru.context.ResponseContext;

public class XmlHandlerChainParser<S extends RequestContext, T extends ResponseContext> extends DefaultHandler {

    public static final String MIRU_CHAINS_NS = "context://iterx.org/miru/1.0/chains";

    private static final String TAG_CHAINS = "chains";
    private static final String TAG_CHAIN = "chain";
    private static final String TAG_HANDLER = "handler";
    private static final String TAG_MATCHER = "matcher";
    private static final String TAG_LIST = "list";

    private static final int STATE_UNKNOWN = 0;
    private static final int STATE_CHAIN = 1;
    private static final int STATE_HANDLER = 2;
    private static final int STATE_MATCHER = 3;

    private static final Log LOGGER = LogFactory.getLog(XmlHandlerChainParser.class);

    private XmlHandlerChainFactory<S, T> handlerChainFactory;
    private BeanProvider beanProvider;

    private List<Object> stack;
    private Object object;

    private int state;

    public XmlHandlerChainParser(XmlHandlerChainFactory<? extends S, ? extends T> handlerChainFactory) {

        if (handlerChainFactory == null)
            throw new IllegalArgumentException("handlerChainFactory == null");

        this.handlerChainFactory = (XmlHandlerChainFactory<S, T>) handlerChainFactory;
        this.beanProvider = handlerChainFactory.getBeanProvider();
    }

    public void parse(StreamSource source) throws IOException {
        try {
            SAXParserFactory factory;
            SAXParser parser;

            factory = SAXParserFactory.newInstance();
            factory.setNamespaceAware(true);
            factory.setValidating(true);

            parser = factory.newSAXParser();
            parser.parse(source.getInputStream(), this);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            if (LOGGER.isErrorEnabled())
                LOGGER.error(e);
            throw new IOException("Invalid xml stream [" + source + "]. " + e.getMessage());
        }
    }

    public void startDocument() throws SAXException {

        state = STATE_UNKNOWN;
        stack = new ArrayList<Object>();
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {

        switch (state) {
        case STATE_UNKNOWN:
            if (TAG_CHAINS.equals(localName) && MIRU_CHAINS_NS.equals(uri))
                state = STATE_CHAIN;
            break;
        case STATE_CHAIN:
            if (MIRU_CHAINS_NS.equals(uri)) {
                if (TAG_CHAIN.equals(localName)) {
                    HandlerChain handlerChain;

                    handlerChain = handlerChainFactory.createHandlerChain();
                    handlerChain.setId(attributes.getValue("id"));

                    stack.add(handlerChainFactory.assignHandlerWrapper(handlerChain));
                    state = STATE_HANDLER;
                    break;
                }
            }
            throw new SAXException("Invalid element '" + qName + "'.");
        case STATE_MATCHER:
        case STATE_HANDLER:
            if (MIRU_CHAINS_NS.equals(uri)) {
                Object object;

                if (TAG_HANDLER.equals(localName)) {
                    stack.add(this.object);
                    this.object = null;
                    state = STATE_HANDLER;
                    break;
                } else if (TAG_MATCHER.equals(localName)) {
                    stack.add(this.object);
                    this.object = null;
                    state = STATE_MATCHER;
                    break;
                } else if (TAG_LIST.equals(localName)) {
                    stack.add(new ArrayList());
                    this.object = null;
                    break;
                } else if ((object = beanProvider.getBean(localName)) != null) {
                    BeanWrapper beanWrapper;
                    int length;

                    beanWrapper = ((state == STATE_MATCHER)
                            ? ((BeanWrapperAware) beanProvider).assignBeanWrapper(object)
                            : handlerChainFactory.assignHandlerWrapper(object));

                    if ((length = attributes.getLength()) > 0) {
                        if (beanProvider.isSingleton(localName))
                            throw new BeanException("Singleton beans are not mutable.");

                        for (int i = length; i-- > 0;) {
                            beanWrapper.setValue(attributes.getLocalName(i), attributes.getValue(i));
                        }

                    }
                    this.object = beanWrapper;
                    break;

                }
            }
            throw new SAXException("Invalid element '" + qName + "'.");
        }
    }

    public void characters(char ch[], int start, int length) throws SAXException {
    }

    public void endElement(String uri, String localName, String qName) throws SAXException {

        switch (state) {
        case STATE_UNKNOWN:
            break;
        case STATE_CHAIN:
            if (MIRU_CHAINS_NS.equals(uri)) {
                if (TAG_CHAINS.equals(localName)) {
                    state = STATE_UNKNOWN;
                    break;
                }
            }
            throw new SAXException("Invalid element '" + qName + "'.");
        case STATE_MATCHER:
            if (MIRU_CHAINS_NS.equals(uri)) {
                Object parent;

                if (TAG_MATCHER.equals(localName)) {
                    object = stack.remove(stack.size() - 1);
                    if (object instanceof HandlerWrapper)
                        state = STATE_HANDLER;
                } else if (TAG_LIST.equals(localName)) {
                    Object object;

                    object = stack.remove(stack.size() - 1);
                    parent = stack.get(stack.size() - 1);
                    ((BeanWrapper) parent).setValue("matchers", object);
                } else {
                    BeanWrapper object;

                    object = (BeanWrapper) this.object;
                    parent = stack.get(stack.size() - 1);

                    if (parent instanceof List)
                        ((List<Object>) parent).add(object.getWrappedInstance());
                    else if (parent instanceof BeanWrapper)
                        ((BeanWrapper) parent).setValue("matcher", object.getWrappedInstance());

                    ((BeanWrapperAware) beanProvider).recycleBeanWrapper(object);
                    this.object = null;
                }
                break;
            }
            throw new SAXException("Invalid element '" + qName + "'.");
        case STATE_HANDLER:
            if (MIRU_CHAINS_NS.equals(uri)) {
                Object parent;

                if (TAG_CHAIN.equals(localName)) {
                    HandlerWrapper<S, T> object;

                    object = (HandlerWrapper<S, T>) stack.remove(stack.size() - 1);
                    handlerChainFactory.addHandlerChain((HandlerChain<S, T>) object.getWrappedInstance());
                    handlerChainFactory.recycleHandlerWrapper(object);

                    this.object = null;
                    state = STATE_CHAIN;
                } else if (TAG_HANDLER.equals(localName)) {
                    object = stack.remove(stack.size() - 1);
                    state = STATE_HANDLER;
                } else if (TAG_LIST.equals(localName)) {
                    Object object;

                    object = stack.remove(stack.size() - 1);
                    parent = stack.get(stack.size() - 1);
                    ((HandlerWrapper<S, T>) parent).setHandlers((List) object);
                } else {
                    HandlerWrapper<S, T> object;

                    parent = stack.get(stack.size() - 1);
                    object = (HandlerWrapper<S, T>) this.object;

                    if (parent instanceof List)
                        ((List<Object>) parent).add(object.getWrappedInstance());
                    else if (parent instanceof HandlerWrapper)
                        ((HandlerWrapper) parent).setHandler(object.getWrappedInstance());

                    handlerChainFactory.recycleHandlerWrapper(object);
                    this.object = null;
                }
                break;
            }
            throw new SAXException("Invalid element '" + qName + "'.");
        }
    }

    public void endDocument() throws SAXException {

        stack = null;
    }

}